From 9d1a97827c1667c68cc5b83d51a92a98ca78f33e Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Sun, 3 Mar 2024 20:53:17 +0100 Subject: [PATCH 01/25] Initial migration to pitchfork specification --- .clang-format | 142 +++++ .gitmodules | 21 - .travis.yml | 118 +++- CMakeLists.txt | 196 ++----- ci/after_success.sh | 19 - ci/build.sh | 30 - ci/ccache_clang | 3 - ci/ccache_clang++ | 3 - ci/install.sh | 17 - ci/test.sh | 31 - cmake/CheckGit.cmake | 83 --- cmake/CodeCoverage.cmake | 452 --------------- cmake/Hunter/config.cmake | 152 ----- cmake/Hunter/passwords.cmake | 8 - cmake/HunterGate.cmake | 539 ------------------ cmake/gcov_for_clang.sh | 8 - cmake/git_version.cpp.in | 3 - cmake/git_version.h | 3 - .../koinos/chain/chronicler.hpp | 0 .../koinos/chain/constants.hpp | 0 .../koinos/chain/controller.hpp | 0 .../koinos/chain/exceptions.hpp | 0 .../koinos/chain/execution_context.hpp | 0 .../koinos/chain/host_api.hpp | 0 .../koinos/chain/indexer.hpp | 0 .../koinos/chain/proto_utils.hpp | 0 .../koinos/chain/resource_meter.hpp | 0 .../koinos/chain/session.hpp | 0 .../koinos/chain/state.hpp | 0 .../koinos/chain/system_calls.hpp | 0 .../koinos/chain/thunk_dispatcher.hpp | 0 .../koinos/chain/thunk_utils.hpp | 0 .../koinos/chain/types.hpp | 0 .../koinos/vm_manager/exceptions.hpp | 0 .../koinos/vm_manager/fizzy/exceptions.hpp | 0 .../vm_manager/fizzy/fizzy_vm_backend.hpp | 0 .../koinos/vm_manager/fizzy/module_cache.hpp | 0 .../koinos/vm_manager/host_api.hpp | 0 .../koinos/vm_manager/vm_backend.hpp | 0 libraries/CMakeLists.txt | 2 - libraries/crypto | 1 - libraries/exception | 1 - libraries/log | 1 - libraries/mq | 1 - libraries/proto | 1 - libraries/state_db | 1 - libraries/util | 1 - libraries/vm_manager/CMakeLists.txt | 13 - programs/CMakeLists.txt | 2 - programs/koinos_chain/CMakeLists.txt | 8 - programs/koinos_vm_driver/CMakeLists.txt | 4 - src/CMakeLists.txt | 104 ++++ .../koinos}/chain/CMakeLists.txt | 0 .../koinos}/chain/chronicler.cpp | 0 .../koinos}/chain/controller.cpp | 0 .../koinos}/chain/execution_context.cpp | 0 {libraries => src/koinos}/chain/host_api.cpp | 0 {libraries => src/koinos}/chain/indexer.cpp | 0 .../koinos}/chain/proto_utils.cpp | 0 .../koinos}/chain/resource_meter.cpp | 0 {libraries => src/koinos}/chain/session.cpp | 0 {libraries => src/koinos}/chain/state.cpp | 0 .../koinos}/chain/system_calls.cpp | 0 .../koinos}/chain/thunk_dispatcher.cpp | 0 .../vm_manager/fizzy/fizzy_vm_backend.cpp | 0 .../koinos}/vm_manager/fizzy/module_cache.cpp | 0 .../koinos}/vm_manager/host_api.cpp | 0 .../koinos}/vm_manager/vm_backend.cpp | 0 .../main.cpp => src/koinos_chain.cpp | 0 .../main.cpp => src/koinos_vm_driver.cpp | 0 tests/BoostTestTargetConfig.h | 7 - tests/BoostTestTargets.cmake | 242 -------- tests/BoostTestTargetsDynamic.h | 8 - tests/BoostTestTargetsIncluded.h | 7 - tests/BoostTestTargetsStatic.h | 7 - tests/CMakeLists.txt | 93 ++- tests/CopyResourcesToBuildTree.cmake | 83 --- tests/GetForceIncludeDefinitions.cmake | 44 -- tests/{tests => }/contracts.cpp | 0 tests/{tests => }/controller_test.cpp | 0 tests/main.cpp | 3 + tests/{tests => }/stack_test.cpp | 0 tests/tests/main.cpp | 3 - tests/{tests => }/thunk_test.cpp | 0 84 files changed, 424 insertions(+), 2041 deletions(-) create mode 100644 .clang-format delete mode 100755 ci/after_success.sh delete mode 100755 ci/build.sh delete mode 100755 ci/ccache_clang delete mode 100755 ci/ccache_clang++ delete mode 100755 ci/install.sh delete mode 100755 ci/test.sh delete mode 100644 cmake/CheckGit.cmake delete mode 100644 cmake/CodeCoverage.cmake delete mode 100644 cmake/Hunter/config.cmake delete mode 100644 cmake/Hunter/passwords.cmake delete mode 100644 cmake/HunterGate.cmake delete mode 100755 cmake/gcov_for_clang.sh delete mode 100644 cmake/git_version.cpp.in delete mode 100644 cmake/git_version.h rename {libraries/chain/include => include}/koinos/chain/chronicler.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/constants.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/controller.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/exceptions.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/execution_context.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/host_api.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/indexer.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/proto_utils.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/resource_meter.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/session.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/state.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/system_calls.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/thunk_dispatcher.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/thunk_utils.hpp (100%) rename {libraries/chain/include => include}/koinos/chain/types.hpp (100%) rename {libraries/vm_manager/include => include}/koinos/vm_manager/exceptions.hpp (100%) rename {libraries/vm_manager/include => include}/koinos/vm_manager/fizzy/exceptions.hpp (100%) rename {libraries/vm_manager/include => include}/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp (100%) rename {libraries/vm_manager/include => include}/koinos/vm_manager/fizzy/module_cache.hpp (100%) rename {libraries/vm_manager/include => include}/koinos/vm_manager/host_api.hpp (100%) rename {libraries/vm_manager/include => include}/koinos/vm_manager/vm_backend.hpp (100%) delete mode 100644 libraries/CMakeLists.txt delete mode 160000 libraries/crypto delete mode 160000 libraries/exception delete mode 160000 libraries/log delete mode 160000 libraries/mq delete mode 160000 libraries/proto delete mode 160000 libraries/state_db delete mode 160000 libraries/util delete mode 100644 libraries/vm_manager/CMakeLists.txt delete mode 100644 programs/CMakeLists.txt delete mode 100644 programs/koinos_chain/CMakeLists.txt delete mode 100644 programs/koinos_vm_driver/CMakeLists.txt create mode 100644 src/CMakeLists.txt rename {libraries => src/koinos}/chain/CMakeLists.txt (100%) rename {libraries => src/koinos}/chain/chronicler.cpp (100%) rename {libraries => src/koinos}/chain/controller.cpp (100%) rename {libraries => src/koinos}/chain/execution_context.cpp (100%) rename {libraries => src/koinos}/chain/host_api.cpp (100%) rename {libraries => src/koinos}/chain/indexer.cpp (100%) rename {libraries => src/koinos}/chain/proto_utils.cpp (100%) rename {libraries => src/koinos}/chain/resource_meter.cpp (100%) rename {libraries => src/koinos}/chain/session.cpp (100%) rename {libraries => src/koinos}/chain/state.cpp (100%) rename {libraries => src/koinos}/chain/system_calls.cpp (100%) rename {libraries => src/koinos}/chain/thunk_dispatcher.cpp (100%) rename {libraries => src/koinos}/vm_manager/fizzy/fizzy_vm_backend.cpp (100%) rename {libraries => src/koinos}/vm_manager/fizzy/module_cache.cpp (100%) rename {libraries => src/koinos}/vm_manager/host_api.cpp (100%) rename {libraries => src/koinos}/vm_manager/vm_backend.cpp (100%) rename programs/koinos_chain/main.cpp => src/koinos_chain.cpp (100%) rename programs/koinos_vm_driver/main.cpp => src/koinos_vm_driver.cpp (100%) delete mode 100644 tests/BoostTestTargetConfig.h delete mode 100644 tests/BoostTestTargets.cmake delete mode 100644 tests/BoostTestTargetsDynamic.h delete mode 100644 tests/BoostTestTargetsIncluded.h delete mode 100644 tests/BoostTestTargetsStatic.h delete mode 100644 tests/CopyResourcesToBuildTree.cmake delete mode 100644 tests/GetForceIncludeDefinitions.cmake rename tests/{tests => }/contracts.cpp (100%) rename tests/{tests => }/controller_test.cpp (100%) create mode 100644 tests/main.cpp rename tests/{tests => }/stack_test.cpp (100%) delete mode 100644 tests/tests/main.cpp rename tests/{tests => }/thunk_test.cpp (100%) diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..6767e56d --- /dev/null +++ b/.clang-format @@ -0,0 +1,142 @@ +--- +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Right +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + PadOperators: true +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + PadOperators: true +AlignConsecutiveDeclarations: + Enabled: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: False +AllowAllParametersOfDeclarationOnNextLine: False +# clang-18 +#AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: False +AllowShortEnumsOnASingleLine: False +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: False +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: False +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: False +BinPackParameters: False +BitFieldColonSpacing: Both +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: True + AfterClass: True + AfterControlStatement: Always + AfterEnum: True + AfterFunction: True + AfterNamespace: False + AfterObjCDeclaration: True + AfterStruct: True + AfterUnion: True + AfterExternBlock: True + BeforeCatch: True + BeforeElse: True + BeforeLambdaBody: True + BeforeWhile: True + IndentBraces: False + SplitEmptyFunction: False + SplitEmptyRecord: False + SplitEmptyNamespace: False +# clang-17 +#BracedInitializerIndentWidth: 2 +BreakAfterAttributes: Always +BreakArrays: False +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeConceptDeclarations: Always +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: True +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterComma +BreakStringLiterals: False +ColumnLimit: 120 +CompactNamespaces: True +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: True +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Always +FixNamespaceComments: true +IndentAccessModifiers: False +IndentCaseBlocks: True +IndentCaseLabels: True +IndentExternBlock: Indent +IndentGotoLabels: False +IndentPPDirectives: AfterHash +IndentWidth: 2 +IndentWrappedFunctionNames: False +InsertBraces: False +InsertNewlineAtEOF: True +IntegerLiteralSeparator: + Binary: 0 + Decimal: 3 + Hex: 0 +KeepEmptyLinesAtTheStartOfBlocks: False +LambdaBodyIndentation: Signature +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PackConstructorInitializers: Never +PointerAlignment: Left +QualifierAlignment: Left +ReferenceAlignment: Left +ReflowComments: True +RemoveBracesLLVM: False +# clang-17 +#RemoveParentheses: False +RemoveSemicolon: False +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 0 +SortIncludes: CaseInsensitive +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: False +SpaceAfterLogicalNot: False +SpaceAfterTemplateKeyword: False +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: True +SpaceBeforeCaseColon: False +SpaceBeforeCpp11BracedList: False +SpaceBeforeCtorInitializerColon: False +SpaceBeforeInheritanceColon: False +SpaceBeforeParens: Never +SpaceBeforeRangeBasedForLoopColon: False +SpaceBeforeSquareBrackets: False +SpaceInEmptyBlock: False +SpaceInEmptyParentheses: False +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Always +SpacesInCStyleCastParentheses: False +SpacesInConditionalStatement: True +SpacesInContainerLiterals: True +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: True +SpacesInSquareBrackets: True +Standard: c++20 +TabWidth: 2 +UseTab: Never diff --git a/.gitmodules b/.gitmodules index d1c38e8a..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,21 +0,0 @@ -[submodule "libraries/log"] - path = libraries/log - url = https://github.com/koinos/koinos-log-cpp.git -[submodule "libraries/util"] - path = libraries/util - url = https://github.com/koinos/koinos-util-cpp.git -[submodule "libraries/exception"] - path = libraries/exception - url = https://github.com/koinos/koinos-exception-cpp.git -[submodule "libraries/mq"] - path = libraries/mq - url = https://github.com/koinos/koinos-mq-cpp.git -[submodule "libraries/crypto"] - path = libraries/crypto - url = https://github.com/koinos/koinos-crypto-cpp.git -[submodule "libraries/proto"] - path = libraries/proto - url = https://github.com/koinos/koinos-proto-cpp.git -[submodule "libraries/state_db"] - path = libraries/state_db - url = https://github.com/koinos/koinos-state-db-cpp.git diff --git a/.travis.yml b/.travis.yml index 6d7b845a..ab2dc5e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,49 +2,113 @@ language: c++ cache: ccache: true - pip: true addons: apt: - packages: - - python3 - - python3-pip - - python3-setuptools update: true + packages: + - clang + - clang-format + - llvm + - llvm-dev + - lcov + - ruby + - gcc-12 + - g++-12 + +env: + global: + - CMAKE_C_COMPILER_LAUNCHER=ccache + - CMAKE_CXX_COMPILER_LAUNCHER=ccache jobs: include: - - os: linux + - name: "Static Analysis" + os: linux dist: jammy env: - - RUN_TYPE=coverage - - MATRIX_EVAL="CC=clang-11 && CXX=clang++-11" - - os: linux + - CC=clang + - CXX=clang++ + before_script: + - cmake -DCMAKE_BUILD_TYPE=Debug -DSTATIC_ANALYSIS=ON . + script: + - cmake --build . --config Debug --parallel 3 + + - name: "Sanitizer" + os: linux dist: jammy env: - - RUN_TYPE=test - - MATRIX_EVAL="CC=gcc && CXX=g++" - - os: linux + - CC=clang + - CXX=clang++ + before_script: + - mkdir build-address + - pushd build-address + - cmake -DCMAKE_BUILD_TYPE=Debug -DSANITIZER=Address .. + - cmake --build . --config Debug --parallel 3 + - popd + - mkdir build-stack + - pushd build-stack + - cmake -DCMAKE_BUILD_TYPE=Debug -DSANITIZER=Stack .. + - cmake --build . --config Debug --parallel 3 + - popd + - mkdir build-thread + - pushd build-thread + - cmake -DCMAKE_BUILD_TYPE=Debug -DSANITIZER=Thread .. + - cmake --build . --config Debug --parallel 3 + - popd + script: + - pushd build-address/tests + - ctest -j1 --output-on-failure + - popd + - pushd build-stack/tests + - ctest -j1 --output-on-failure + - popd + - pushd build-thread/tests + - ctest -j1 --output-on-failure + + - name: "Coverage" + os: linux dist: jammy env: - - RUN_TYPE=test - - MATRIX_EVAL="CC=clang-11 && CXX=clang++-11" - - os: linux + - CC=clang + - CXX=clang++ + install: + - sudo gem install coveralls-lcov + before_script: + - mkdir build + - cd build + - cmake -DCMAKE_BUILD_TYPE=Debug -DCOVERAGE=ON .. + script: + - cmake --build . --config Debug --parallel 3 --target coverage + after_success: + - coveralls-lcov --repo-token $COVERALLS_REPO_TOKEN --service-name travis-pro --service-job-id $TRAVIS_JOB_ID ./coverage.info + + - name: "GCC Unit Tests" + os: linux dist: jammy env: - - BUILD_DOCKER=1 + - CC=gcc-12 + - CXX=g++-12 + before_script: + - cmake -DCMAKE_BUILD_TYPE=Release . + - cmake --build . --config Release --parallel 3 + script: + - cd tests + - ctest -j3 --output-on-failure -before_install: - - eval "${MATRIX_EVAL}" - -install: - - ci/install.sh - -script: - - ci/build.sh && ci/test.sh - -after_success: - - ci/after_success.sh + - name: "Clang Unit Tests and Formatting" + os: linux + dist: jammy + env: + - CC=clang + - CXX=clang++ + before_script: + - cmake -DCMAKE_BUILD_TYPE=Release . + - cmake --build . --config Release --parallel 3 + script: + - cmake --build . --config Release --parallel 3 --target format.check + - cd tests + - ctest -j3 --output-on-failure notifications: slack: diff --git a/CMakeLists.txt b/CMakeLists.txt index dcfe2639..6e4fbe36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,149 +1,49 @@ - -cmake_minimum_required(VERSION 3.10.2) - -include("cmake/CheckGit.cmake") -CheckGitSetup() - -find_program(CCACHE_PROGRAM ccache) -if(CCACHE_PROGRAM) - set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") - set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_SOURCE_DIR}/ci/ccache_clang") - set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_SOURCE_DIR}/ci/ccache_clang++") - set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_SOURCE_DIR}/ci/ccache_clang") - set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_SOURCE_DIR}/ci/ccache_clang++") -endif() - -option(HUNTER_RUN_UPLOAD "Upload Hunter packages to binary cache server" OFF) - -set( - HUNTER_CACHE_SERVERS - "https://github.com/koinos/hunter-cache" - CACHE - STRING - "Default cache server" -) - -set( - HUNTER_PASSWORDS_PATH - "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/passwords.cmake" - CACHE - FILEPATH - "Hunter passwords" -) - -include("cmake/HunterGate.cmake") - -HunterGate( - URL "https://github.com/cpp-pm/hunter/archive/v0.24.14.tar.gz" - SHA1 "00901c19eefc02d24b16705b5f5a2b4f093a73fb" - LOCAL -) - -project(koinos_chain VERSION 1.2.0 LANGUAGES CXX C) -add_compile_definitions(KOINOS_MAJOR_VERSION=${PROJECT_VERSION_MAJOR}) -add_compile_definitions(KOINOS_MINOR_VERSION=${PROJECT_VERSION_MINOR}) -add_compile_definitions(KOINOS_PATCH_VERSION=${PROJECT_VERSION_PATCH}) - -if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") - cmake_policy(SET CMP0074 NEW) -endif () - -option(FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." OFF) - -# This is to force color output when using ccache with Unix Makefiles -if(${FORCE_COLORED_OUTPUT}) - if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) - add_compile_options (-fdiagnostics-color=always) - elseif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang" ) - add_compile_options (-fcolor-diagnostics) - endif () -endif () - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_VISIBILITY_PRESET hidden) -set(Boost_NO_BOOST_CMAKE ON) - -if (MSVC) - # warning level 4 and all warnings as errors - add_compile_options(/W4 /WX) -else() - # lots of warnings and all warnings as errors - add_compile_options(-Werror -Wno-unknown-pragmas) -endif() - -if(${CMAKE_GENERATOR} MATCHES "Xcode") - set(CMAKE_XCODE_GENERATE_SCHEME YES) -endif() - -if(COVERAGE) - include(CodeCoverage) - append_coverage_compiler_flags() - setup_target_for_coverage_lcov( - NAME coverage - LCOV_ARGS "--quiet" "--no-external" - EXECUTABLE koinos_tests - EXCLUDE - "build/*" - "libraries/crypto/*" - "libraries/exception/*" - "libraries/log/*" - "libraries/types/*" - "libraries/util/*" - "libraries/vendor/*") -endif() - -hunter_add_package(Boost COMPONENTS system log thread date_time filesystem chrono test program_options) -hunter_add_package(ethash) -hunter_add_package(libsecp256k1-vrf) -hunter_add_package(nlohmann_json) -hunter_add_package(OpenSSL) -hunter_add_package(rabbitmq-c) -hunter_add_package(rocksdb) -hunter_add_package(yaml-cpp) -hunter_add_package(Protobuf) -hunter_add_package(fizzy) -hunter_add_package(gRPC) -hunter_add_package(abseil) -hunter_add_package(re2) -hunter_add_package(c-ares) -hunter_add_package(ZLIB) - -hunter_add_package(koinos_log) -hunter_add_package(koinos_util) -hunter_add_package(koinos_proto) -hunter_add_package(koinos_exception) -hunter_add_package(koinos_crypto) -hunter_add_package(koinos_mq) -hunter_add_package(koinos_state_db) - -find_package(Boost CONFIG REQUIRED COMPONENTS system log log_setup thread date_time filesystem chrono program_options) -find_package(ethash CONFIG REQUIRED) -find_package(libsecp256k1-vrf CONFIG REQUIRED) -find_package(nlohmann_json CONFIG REQUIRED) -find_package(OpenSSL REQUIRED) -find_package(rabbitmq-c CONFIG REQUIRED) -find_package(RocksDB CONFIG REQUIRED) -find_package(yaml-cpp CONFIG REQUIRED) -find_package(Protobuf CONFIG REQUIRED) -find_package(fizzy CONFIG REQUIRED) -find_package(gRPC CONFIG REQUIRED) -find_package(absl CONFIG REQUIRED) -find_package(re2 CONFIG REQUIRED) -find_package(c-ares CONFIG REQUIRED) -find_package(ZLIB CONFIG REQUIRED) - -find_package(koinos_crypto CONFIG REQUIRED) -find_package(koinos_exception CONFIG REQUIRED) -find_package(koinos_log CONFIG REQUIRED) -find_package(koinos_mq CONFIG REQUIRED) -find_package(koinos_proto CONFIG REQUIRED) -find_package(koinos_util CONFIG REQUIRED) -find_package(koinos_state_db CONFIG REQUIRED) - -add_subdirectory(programs) -add_subdirectory(libraries) +cmake_minimum_required(VERSION 3.19.0) + +cmake_policy(VERSION 3.19.0...3.27.4) + +include(FetchContent) +FetchContent_Declare( + koinos_cmake + GIT_REPOSITORY https://github.com/koinos/koinos-cmake.git + GIT_TAG bf62292ba053f8871dc8aefd524ca8037317a166) +FetchContent_MakeAvailable(koinos_cmake) + +include("${koinos_cmake_SOURCE_DIR}/Koinos.cmake") + +project(koinos_chain + VERSION 1.2.0 + DESCRIPTION "The Koinos chain" + LANGUAGES CXX C) + +koinos_define_version() + +koinos_add_package(Boost CONFIG REQUIRED + ADD_COMPONENTS system log thread date_time filesystem chrono test program_options exception + FIND_COMPONENTS system log log_setup thread date_time filesystem chrono program_options exception) + +koinos_add_package(ethash CONFIG REQUIRED) +koinos_add_package(libsecp256k1-vrf CONFIG REQUIRED) +koinos_add_package(nlohmann_json CONFIG REQUIRED) +koinos_add_package(OpenSSL REQUIRED) +koinos_add_package(rabbitmq-c CONFIG REQUIRED) +koinos_add_package(rocksdb NAME RocksDB CONFIG REQUIRED) +koinos_add_package(yaml-cpp CONFIG REQUIRED) +koinos_add_package(Protobuf CONFIG REQUIRED) +koinos_add_package(fizzy CONFIG REQUIRED) +koinos_add_package(gRPC CONFIG REQUIRED) +koinos_add_package(abseil NAME absl CONFIG REQUIRED) +koinos_add_package(re2 CONFIG REQUIRED) +koinos_add_package(c-ares CONFIG REQUIRED) +koinos_add_package(ZLIB CONFIG REQUIRED) + +koinos_add_package(koinos_log CONFIG REQUIRED) +koinos_add_package(koinos_util CONFIG REQUIRED) +koinos_add_package(koinos_proto CONFIG REQUIRED) +koinos_add_package(koinos_exception CONFIG REQUIRED) +koinos_add_package(koinos_crypto CONFIG REQUIRED) +koinos_add_package(koinos_mq CONFIG REQUIRED) +koinos_add_package(koinos_state_db CONFIG REQUIRED) + +add_subdirectory(src) add_subdirectory(tests) diff --git a/ci/after_success.sh b/ci/after_success.sh deleted file mode 100755 index 3b21dc78..00000000 --- a/ci/after_success.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -if [ "$RUN_TYPE" = "coverage" ]; then - coveralls-lcov --repo-token "$COVERALLS_REPO_TOKEN" --service-name travis-pro --service-job-id "$TRAVIS_JOB_ID" ./build/coverage.info -fi - -if ! [[ -z $BUILD_DOCKER ]]; then - if [ "$TRAVIS_PULL_REQUEST_BRANCH" != "" ]; then - exit 0 - fi - - TAG="$TRAVIS_BRANCH" - if [ "$TAG" = "master" ]; then - TAG="latest" - fi - - echo "$DOCKER_PASSWORD" | docker login -u $DOCKER_USERNAME --password-stdin - docker push koinos/koinos-chain:$TAG -fi diff --git a/ci/build.sh b/ci/build.sh deleted file mode 100755 index 8dbd00c7..00000000 --- a/ci/build.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -e -set -x - -if [[ -z $BUILD_DOCKER ]]; then - mkdir build - cd build - - if [ "$RUN_TYPE" = "test" ]; then - cmake -DCMAKE_BUILD_TYPE=Release .. - cmake --build . --config Release --parallel 3 - elif [ "$RUN_TYPE" = "coverage" ]; then - cmake -DCMAKE_BUILD_TYPE=Debug -DCOVERAGE=ON .. - cmake --build . --config Debug --parallel 3 --target coverage - fi -else - TAG="$TRAVIS_BRANCH" - if [ "$TAG" = "master" ]; then - TAG="latest" - fi - - echo "$DOCKER_PASSWORD" | docker login -u $DOCKER_USERNAME --password-stdin - - cp -R ~/.ccache ./.ccache - docker build . -t koinos-chain-ccache --target builder - docker build . -t koinos/koinos-chain:$TAG - docker run -td --name ccache koinos-chain-ccache - docker cp ccache:/koinos-chain/.ccache ~/ -fi diff --git a/ci/ccache_clang b/ci/ccache_clang deleted file mode 100755 index 7aef1a2d..00000000 --- a/ci/ccache_clang +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec ccache clang "$@" diff --git a/ci/ccache_clang++ b/ci/ccache_clang++ deleted file mode 100755 index 49b63415..00000000 --- a/ci/ccache_clang++ +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec ccache clang++ "$@" diff --git a/ci/install.sh b/ci/install.sh deleted file mode 100755 index e8802510..00000000 --- a/ci/install.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -if [[ -z $BUILD_DOCKER ]]; then - sudo apt-get install -yq --allow-downgrades libc6=2.31-0ubuntu9.2 libc6-dev=2.31-0ubuntu9.2 - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --allow-downgrades --allow-remove-essential --allow-change-held-packages install clang-11 llvm-11 -o Debug::pkgProblemResolver=yes - - if [ "$RUN_TYPE" = "coverage" ]; then - sudo apt-get install -y lcov ruby valgrind - sudo gem install coveralls-lcov - fi - - pip3 install --user dataclasses_json Jinja2 importlib_resources pluginbase gitpython -else - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - sudo chmod +x /usr/local/bin/docker-compose - docker-compose --version -fi diff --git a/ci/test.sh b/ci/test.sh deleted file mode 100755 index 92c4730f..00000000 --- a/ci/test.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -set -e -set -x - -if [[ -z $BUILD_DOCKER ]]; then - cd $(dirname "$0")/../build/tests - if [ "$RUN_TYPE" = "test" ]; then - exec ctest -j3 --output-on-failure && ../libraries/vendor/mira/test/mira_test - elif [ "$RUN_TYPE" = "coverage" ]; then - exec valgrind --error-exitcode=1 --leak-check=yes ./koinos_tests - fi -fi - -if ! [[ -z $BUILD_DOCKER ]]; then - eval "$(gimme 1.18.1)" - source ~/.gimme/envs/go1.18.1.env - - TAG="$TRAVIS_BRANCH" - if [ "$TAG" = "master" ]; then - TAG="latest" - fi - - export CHAIN_TAG=$TAG - - git clone https://github.com/koinos/koinos-integration-tests.git - - cd koinos-integration-tests - go get ./... - ./run.sh -fi diff --git a/cmake/CheckGit.cmake b/cmake/CheckGit.cmake deleted file mode 100644 index ebab2e25..00000000 --- a/cmake/CheckGit.cmake +++ /dev/null @@ -1,83 +0,0 @@ -set(CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}) -if (NOT DEFINED pre_configure_dir) - set(pre_configure_dir ${CMAKE_CURRENT_LIST_DIR}) -endif () - -if (NOT DEFINED post_configure_dir) - set(post_configure_dir ${CMAKE_BINARY_DIR}/generated) -endif () - -set(pre_configure_file ${pre_configure_dir}/git_version.cpp.in) -set(post_configure_file ${post_configure_dir}/git_version.cpp) - -function(CheckGitWrite git_hash) - file(WRITE ${CMAKE_BINARY_DIR}/git-state.txt ${git_hash}) -endfunction() - -function(CheckGitRead git_hash) - if (EXISTS ${CMAKE_BINARY_DIR}/git-state.txt) - file(STRINGS ${CMAKE_BINARY_DIR}/git-state.txt CONTENT) - LIST(GET CONTENT 0 var) - - set(${git_hash} ${var} PARENT_SCOPE) - endif () -endfunction() - -function(CheckGitVersion) - # Get the latest abbreviated commit hash of the working branch - execute_process( - COMMAND git log -1 --format=%h - WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} - OUTPUT_VARIABLE GIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - CheckGitRead(GIT_HASH_CACHE) - if (NOT EXISTS ${post_configure_dir}) - file(MAKE_DIRECTORY ${post_configure_dir}) - endif () - - if (NOT EXISTS ${post_configure_dir}/git_version.h) - file(COPY ${pre_configure_dir}/git_version.h DESTINATION ${post_configure_dir}) - endif() - - if (NOT DEFINED GIT_HASH_CACHE) - set(GIT_HASH_CACHE "INVALID") - endif () - - # Only update the git_version.cpp if the hash has changed. This will - # prevent us from rebuilding the project more than we need to. - if (NOT ${GIT_HASH} STREQUAL ${GIT_HASH_CACHE} OR NOT EXISTS ${post_configure_file}) - # Set che GIT_HASH_CACHE variable the next build won't have - # to regenerate the source file. - CheckGitWrite(${GIT_HASH}) - - configure_file(${pre_configure_file} ${post_configure_file} @ONLY) - endif () - -endfunction() - -function(CheckGitSetup) - - add_custom_target(check_git COMMAND ${CMAKE_COMMAND} - -DRUN_CHECK_GIT_VERSION=1 - -Dpre_configure_dir=${pre_configure_dir} - -Dpost_configure_file=${post_configure_dir} - -DGIT_HASH_CACHE=${GIT_HASH_CACHE} - -P ${CURRENT_LIST_DIR}/CheckGit.cmake - BYPRODUCTS ${post_configure_file} - ) - - add_library(git_version ${CMAKE_BINARY_DIR}/generated/git_version.cpp) - target_include_directories(git_version PUBLIC ${CMAKE_BINARY_DIR}/generated) - add_dependencies(git_version check_git) - add_library(Koinos::git ALIAS git_version) - - CheckGitVersion() -endfunction() - -# This is used to run this function from an external cmake process. -if (RUN_CHECK_GIT_VERSION) - CheckGitVersion() -endif () - diff --git a/cmake/CodeCoverage.cmake b/cmake/CodeCoverage.cmake deleted file mode 100644 index 53e9cd0c..00000000 --- a/cmake/CodeCoverage.cmake +++ /dev/null @@ -1,452 +0,0 @@ -# Copyright (c) 2012 - 2017, Lars Bilke -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its contributors -# may be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# CHANGES: -# -# 2012-01-31, Lars Bilke -# - Enable Code Coverage -# -# 2013-09-17, Joakim Söderberg -# - Added support for Clang. -# - Some additional usage instructions. -# -# 2016-02-03, Lars Bilke -# - Refactored functions to use named parameters -# -# 2017-06-02, Lars Bilke -# - Merged with modified version from github.com/ufz/ogs -# -# 2019-05-06, Anatolii Kurotych -# - Remove unnecessary --coverage flag -# -# 2019-12-13, FeRD (Frank Dana) -# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor -# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments. -# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY -# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list -# - Set lcov basedir with -b argument -# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be -# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().) -# - Delete output dir, .info file on 'make clean' -# - Remove Python detection, since version mismatches will break gcovr -# - Minor cleanup (lowercase function names, update examples...) -# -# 2019-12-19, FeRD (Frank Dana) -# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets -# -# 2020-01-19, Bob Apthorpe -# - Added gfortran support -# -# 2020-02-17, FeRD (Frank Dana) -# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters -# in EXCLUDEs, and remove manual escaping from gcovr targets -# -# USAGE: -# -# 1. Copy this file into your cmake modules path. -# -# 2. Add the following line to your CMakeLists.txt (best inside an if-condition -# using a CMake option() to enable it just optionally): -# include(CodeCoverage) -# -# 3. Append necessary compiler flags: -# append_coverage_compiler_flags() -# -# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og -# -# 4. If you need to exclude additional directories from the report, specify them -# using full paths in the COVERAGE_EXCLUDES variable before calling -# setup_target_for_coverage_*(). -# Example: -# set(COVERAGE_EXCLUDES -# '${PROJECT_SOURCE_DIR}/src/dir1/*' -# '/path/to/my/src/dir2/*') -# Or, use the EXCLUDE argument to setup_target_for_coverage_*(). -# Example: -# setup_target_for_coverage_lcov( -# NAME coverage -# EXECUTABLE testrunner -# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") -# -# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set -# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) -# Example: -# set(COVERAGE_EXCLUDES "dir1/*") -# setup_target_for_coverage_gcovr_html( -# NAME coverage -# EXECUTABLE testrunner -# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" -# EXCLUDE "dir2/*") -# -# 5. Use the functions described below to create a custom make target which -# runs your test executable and produces a code coverage report. -# -# 6. Build a Debug build: -# cmake -DCMAKE_BUILD_TYPE=Debug .. -# make -# make my_coverage_target -# - -include(CMakeParseArguments) - -# Check prereqs -find_program( GCOV_PATH gcov ) -find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl) -find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat ) -if (NOT APPLE) - find_program( LLVM_COV_PATH llvm-cov ) -endif() -find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) -find_program( CPPFILT_PATH NAMES c++filt ) - -if(NOT GCOV_PATH) - message(FATAL_ERROR "gcov not found! Aborting...") -endif() # NOT GCOV_PATH - -if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") - if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3) - message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") - endif() -elseif(NOT CMAKE_COMPILER_IS_GNUCXX) - if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang") - # Do nothing; exit conditional without error if true - elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU") - # Do nothing; exit conditional without error if true - else() - message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") - endif() -endif() - -set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage" - CACHE INTERNAL "") - -set(CMAKE_Fortran_FLAGS_COVERAGE - ${COVERAGE_COMPILER_FLAGS} - CACHE STRING "Flags used by the Fortran compiler during coverage builds." - FORCE ) -set(CMAKE_CXX_FLAGS_COVERAGE - ${COVERAGE_COMPILER_FLAGS} - CACHE STRING "Flags used by the C++ compiler during coverage builds." - FORCE ) -set(CMAKE_C_FLAGS_COVERAGE - ${COVERAGE_COMPILER_FLAGS} - CACHE STRING "Flags used by the C compiler during coverage builds." - FORCE ) -set(CMAKE_EXE_LINKER_FLAGS_COVERAGE - "" - CACHE STRING "Flags used for linking binaries during coverage builds." - FORCE ) -set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE - "" - CACHE STRING "Flags used by the shared libraries linker during coverage builds." - FORCE ) -mark_as_advanced( - CMAKE_Fortran_FLAGS_COVERAGE - CMAKE_CXX_FLAGS_COVERAGE - CMAKE_C_FLAGS_COVERAGE - CMAKE_EXE_LINKER_FLAGS_COVERAGE - CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) - -if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") -endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" - -if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") - link_libraries(gcov) -endif() - -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_lcov( -# NAME testrunner_coverage # New target name -# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES testrunner # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative -# # to BASE_DIRECTORY, with CMake 3.4+) -# NO_DEMANGLE # Don't demangle C++ symbols -# # even if c++filt is found -# ) -function(setup_target_for_coverage_lcov) - - set(options NO_DEMANGLE) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT LCOV_PATH) - message(FATAL_ERROR "lcov not found! Aborting...") - endif() # NOT LCOV_PATH - - if(NOT APPLE) - # Needed for gcov_for_clang.sh - if(NOT LLVM_COV_PATH) - message(FATAL_ERROR "llvm-cov not found! Aborting...") - endif() # NOT LLVM_COV_PATH - endif() - - if(NOT GENHTML_PATH) - message(FATAL_ERROR "genhtml not found! Aborting...") - endif() # NOT GENHTML_PATH - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(${Coverage_BASE_DIRECTORY}) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (CMake 3.4+: Also compute absolute paths) - set(LCOV_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) - get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() - list(APPEND LCOV_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES LCOV_EXCLUDES) - - # Conditional arguments - if(NOT APPLE) - if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) - set(GENHTML_EXTRA_ARGS "--demangle-cpp") - endif() - endif() - - if (NOT APPLE) - set(GCOV_PATH ${CMAKE_SOURCE_DIR}/cmake/gcov_for_clang.sh) - endif() - - # Setup target - add_custom_target(${Coverage_NAME} - - # Cleanup lcov - COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . -b ${BASEDIR} --zerocounters - # Create baseline to make sure untouched files show up in the report - COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b ${BASEDIR} -o ${Coverage_NAME}.base - - # Run tests - COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - - # Capturing lcov counters and generating report - COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture - # add baseline counters - COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total - # filter collected data to final coverage report - COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info - - # Generate HTML output - COMMAND ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${Coverage_NAME}.info - - # Set output files as GENERATED (will be removed on 'make clean') - BYPRODUCTS - ${Coverage_NAME}.base - ${Coverage_NAME}.capture - ${Coverage_NAME}.total - ${Coverage_NAME}.info - ${Coverage_NAME} # report directory - - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." - ) - - # Show where to find the lcov info report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info." - ) - - # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." - ) - -endfunction() # setup_target_for_coverage_lcov - -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_gcovr_xml( -# NAME ctest_coverage # New target name -# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES executable_target # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative -# # to BASE_DIRECTORY, with CMake 3.4+) -# ) -function(setup_target_for_coverage_gcovr_xml) - - set(options NONE) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT GCOVR_PATH) - message(FATAL_ERROR "gcovr not found! Aborting...") - endif() # NOT GCOVR_PATH - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(${Coverage_BASE_DIRECTORY}) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (CMake 3.4+: Also compute absolute paths) - set(GCOVR_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) - get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() - list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES GCOVR_EXCLUDES) - - # Combine excludes to several -e arguments - set(GCOVR_EXCLUDE_ARGS "") - foreach(EXCLUDE ${GCOVR_EXCLUDES}) - list(APPEND GCOVR_EXCLUDE_ARGS "-e") - list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") - endforeach() - - add_custom_target(${Coverage_NAME} - # Run tests - ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - - # Running gcovr - COMMAND ${GCOVR_PATH} --xml - -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS} - --object-directory=${PROJECT_BINARY_DIR} - -o ${Coverage_NAME}.xml - BYPRODUCTS ${Coverage_NAME}.xml - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Running gcovr to produce Cobertura code coverage report." - ) - - # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." - ) -endfunction() # setup_target_for_coverage_gcovr_xml - -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_gcovr_html( -# NAME ctest_coverage # New target name -# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES executable_target # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative -# # to BASE_DIRECTORY, with CMake 3.4+) -# ) -function(setup_target_for_coverage_gcovr_html) - - set(options NONE) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT GCOVR_PATH) - message(FATAL_ERROR "gcovr not found! Aborting...") - endif() # NOT GCOVR_PATH - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(${Coverage_BASE_DIRECTORY}) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (CMake 3.4+: Also compute absolute paths) - set(GCOVR_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) - get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() - list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES GCOVR_EXCLUDES) - - # Combine excludes to several -e arguments - set(GCOVR_EXCLUDE_ARGS "") - foreach(EXCLUDE ${GCOVR_EXCLUDES}) - list(APPEND GCOVR_EXCLUDE_ARGS "-e") - list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") - endforeach() - - add_custom_target(${Coverage_NAME} - # Run tests - ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - - # Create folder - COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME} - - # Running gcovr - COMMAND ${GCOVR_PATH} --html --html-details - -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS} - --object-directory=${PROJECT_BINARY_DIR} - -o ${Coverage_NAME}/index.html - - BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME} # report directory - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Running gcovr to produce HTML code coverage report." - ) - - # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." - ) - -endfunction() # setup_target_for_coverage_gcovr_html - -function(append_coverage_compiler_flags) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) - set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) - message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") -endfunction() # append_coverage_compiler_flags diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake deleted file mode 100644 index ff968a7b..00000000 --- a/cmake/Hunter/config.cmake +++ /dev/null @@ -1,152 +0,0 @@ -hunter_config(Boost - VERSION ${HUNTER_Boost_VERSION} - CMAKE_ARGS - USE_CONFIG_FROM_BOOST=ON - Boost_USE_STATIC_LIBS=ON - Boost_NO_BOOST_CMAKE=ON -) - -hunter_config(Protobuf - URL "https://github.com/koinos/protobuf/archive/e1b1477875a8b022903b548eb144f2c7bf4d9561.tar.gz" - SHA1 "5796707a98eec15ffb3ad86ff50e8eec5fa65e68" - CMAKE_ARGS - CMAKE_CXX_FLAGS=-fvisibility=hidden - CMAKE_C_FLAGS=-fvisibility=hidden -) - -hunter_config(rocksdb - URL "https://github.com/facebook/rocksdb/archive/v6.15.2.tar.gz" - SHA1 "daf7ef3946fd39c910acaaa57789af8515b39251" - CMAKE_ARGS - WITH_TESTS=OFF - WITH_TOOLS=OFF - WITH_JNI=OFF - WITH_BENCHMARK_TOOLS=OFF - WITH_CORE_TOOLS=OFF - WITH_GFLAGS=OFF - PORTABLE=ON - FAIL_ON_WARNINGS=OFF - ROCKSDB_BUILD_SHARED=OFF - CMAKE_CXX_FLAGS=-fvisibility=hidden - CMAKE_C_FLAGS=-fvisibility=hidden -) - -hunter_config(fizzy - URL "https://github.com/koinos/fizzy/archive/928e89736c3dc26006858619c9267a0595d6dc5d.tar.gz" - SHA1 "b01e92622d11fedb69b603d9a6478449879f25d1" -) - -hunter_config(rabbitmq-c - URL "https://github.com/alanxz/rabbitmq-c/archive/b8e5f43b082c5399bf1ee723c3fd3c19cecd843e.tar.gz" - SHA1 "35d4ce3e4f0a5348de64bbed25c6e1df72da2594" - CMAKE_ARGS - ENABLE_SSL_SUPPORT=OFF -) - -hunter_config(libsecp256k1 - URL "https://github.com/soramitsu/soramitsu-libsecp256k1/archive/c7630e1bac638c0f16ee66d4dce7b5c49eecbaa5.tar.gz" - SHA1 "0534fa8948f279b26fd102905215a56f0ad7fa18" -) - -hunter_config(libsecp256k1-vrf - URL "https://github.com/koinos/secp256k1-vrf/archive/db479e83be5685f652a9bafefaef77246fdf3bbe.tar.gz" - SHA1 "62df75e061c4afd6f0548f1e8267cc3da6abee15" -) - -hunter_config(yaml-cpp - VERSION "0.6.3" - CMAKE_ARGS - CMAKE_CXX_FLAGS=-fvisibility=hidden - CMAKE_C_FLAGS=-fvisibility=hidden -) - -hunter_config(ethash - URL "https://github.com/chfast/ethash/archive/refs/tags/v0.8.0.tar.gz" - SHA1 "41fd440f70b6a8dfc3fd29b20f471dcbd1345ad0" - CMAKE_ARGS - CMAKE_CXX_STANDARD=17 - CMAKE_CXX_STANDARD_REQUIRED=ON -) - - -hunter_config(gRPC - VERSION 1.31.0-p0 - CMAKE_ARGS - CMAKE_POSITION_INDEPENDENT_CODE=ON - CMAKE_CXX_STANDARD=17 - CMAKE_CXX_STANDARD_REQUIRED=ON -) - -hunter_config(abseil - VERSION ${HUNTER_abseil_VERSION} - CMAKE_ARGS - CMAKE_POSITION_INDEPENDENT_CODE=ON - CMAKE_CXX_STANDARD=17 - CMAKE_CXX_STANDARD_REQUIRED=ON -) - -hunter_config(re2 - VERSION ${HUNTER_re2_VERSION} - CMAKE_ARGS - CMAKE_POSITION_INDEPENDENT_CODE=ON - CMAKE_CXX_STANDARD=17 - CMAKE_CXX_STANDARD_REQUIRED=ON -) - -hunter_config(c-ares - VERSION ${HUNTER_c-ares_VERSION} - CMAKE_ARGS - CMAKE_POSITION_INDEPENDENT_CODE=ON - CMAKE_CXX_STANDARD=17 - CMAKE_CXX_STANDARD_REQUIRED=ON -) - -hunter_config(ZLIB - VERSION ${HUNTER_ZLIB_VERSION} - CMAKE_ARGS - CMAKE_POSITION_INDEPENDENT_CODE=ON - CMAKE_CXX_STANDARD=17 - CMAKE_CXX_STANDARD_REQUIRED=ON -) - -hunter_config(koinos_log - GIT_SUBMODULE "libraries/log" - CMAKE_ARGS - BUILD_TESTS=OFF -) - -hunter_config(koinos_util - GIT_SUBMODULE "libraries/util" - CMAKE_ARGS - BUILD_TESTS=OFF -) - -hunter_config(koinos_proto - GIT_SUBMODULE "libraries/proto" - CMAKE_ARGS - BUILD_TESTS=OFF -) - -hunter_config(koinos_exception - GIT_SUBMODULE "libraries/exception" - CMAKE_ARGS - BUILD_TESTS=OFF -) - -hunter_config(koinos_crypto - GIT_SUBMODULE "libraries/crypto" - CMAKE_ARGS - BUILD_TESTS=OFF -) - -hunter_config(koinos_mq - GIT_SUBMODULE "libraries/mq" - CMAKE_ARGS - BUILD_TESTS=OFF -) - -hunter_config(koinos_state_db - GIT_SUBMODULE "libraries/state_db" - CMAKE_ARGS - BUILD_TESTS=OFF -) \ No newline at end of file diff --git a/cmake/Hunter/passwords.cmake b/cmake/Hunter/passwords.cmake deleted file mode 100644 index 357202e2..00000000 --- a/cmake/Hunter/passwords.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# cmake/Hunter/passwords.cmake - -hunter_upload_password( - REPO_OWNER "koinos" - REPO "hunter-cache" - USERNAME "koinos-ci" - PASSWORD "$ENV{GITHUB_USER_PASSWORD}" -) diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake deleted file mode 100644 index 6d9cc240..00000000 --- a/cmake/HunterGate.cmake +++ /dev/null @@ -1,539 +0,0 @@ -# Copyright (c) 2013-2019, Ruslan Baratov -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# This is a gate file to Hunter package manager. -# Include this file using `include` command and add package you need, example: -# -# cmake_minimum_required(VERSION 3.2) -# -# include("cmake/HunterGate.cmake") -# HunterGate( -# URL "https://github.com/path/to/hunter/archive.tar.gz" -# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" -# ) -# -# project(MyProject) -# -# hunter_add_package(Foo) -# hunter_add_package(Boo COMPONENTS Bar Baz) -# -# Projects: -# * https://github.com/hunter-packages/gate/ -# * https://github.com/ruslo/hunter - -option(HUNTER_ENABLED "Enable Hunter package manager support" ON) - -if(HUNTER_ENABLED) - if(CMAKE_VERSION VERSION_LESS "3.2") - message( - FATAL_ERROR - "At least CMake version 3.2 required for Hunter dependency management." - " Update CMake or set HUNTER_ENABLED to OFF." - ) - endif() -endif() - -include(CMakeParseArguments) # cmake_parse_arguments - -option(HUNTER_STATUS_PRINT "Print working status" ON) -option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) -option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) - -set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors") - -function(hunter_gate_status_print) - if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) - foreach(print_message ${ARGV}) - message(STATUS "[hunter] ${print_message}") - endforeach() - endif() -endfunction() - -function(hunter_gate_status_debug) - if(HUNTER_STATUS_DEBUG) - foreach(print_message ${ARGV}) - string(TIMESTAMP timestamp) - message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") - endforeach() - endif() -endfunction() - -function(hunter_gate_error_page error_page) - message("------------------------------ ERROR ------------------------------") - message(" ${HUNTER_ERROR_PAGE}/${error_page}.html") - message("-------------------------------------------------------------------") - message("") - message(FATAL_ERROR "") -endfunction() - -function(hunter_gate_internal_error) - message("") - foreach(print_message ${ARGV}) - message("[hunter ** INTERNAL **] ${print_message}") - endforeach() - message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") - message("") - hunter_gate_error_page("error.internal") -endfunction() - -function(hunter_gate_fatal_error) - cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}") - if("${hunter_ERROR_PAGE}" STREQUAL "") - hunter_gate_internal_error("Expected ERROR_PAGE") - endif() - message("") - foreach(x ${hunter_UNPARSED_ARGUMENTS}) - message("[hunter ** FATAL ERROR **] ${x}") - endforeach() - message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") - message("") - hunter_gate_error_page("${hunter_ERROR_PAGE}") -endfunction() - -function(hunter_gate_user_error) - hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data") -endfunction() - -function(hunter_gate_self root version sha1 result) - string(COMPARE EQUAL "${root}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("root is empty") - endif() - - string(COMPARE EQUAL "${version}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("version is empty") - endif() - - string(COMPARE EQUAL "${sha1}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("sha1 is empty") - endif() - - string(SUBSTRING "${sha1}" 0 7 archive_id) - - if(EXISTS "${root}/cmake/Hunter") - set(hunter_self "${root}") - else() - set( - hunter_self - "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" - ) - endif() - - set("${result}" "${hunter_self}" PARENT_SCOPE) -endfunction() - -# Set HUNTER_GATE_ROOT cmake variable to suitable value. -function(hunter_gate_detect_root) - # Check CMake variable - string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) - if(not_empty) - set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") - return() - endif() - - # Check environment variable - string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) - if(not_empty) - set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") - return() - endif() - - # Check HOME environment variable - string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") - return() - endif() - - # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) - if(WIN32) - string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug( - "HUNTER_ROOT set using SYSTEMDRIVE environment variable" - ) - return() - endif() - - string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug( - "HUNTER_ROOT set using USERPROFILE environment variable" - ) - return() - endif() - endif() - - hunter_gate_fatal_error( - "Can't detect HUNTER_ROOT" - ERROR_PAGE "error.detect.hunter.root" - ) -endfunction() - -function(hunter_gate_download dir) - string( - COMPARE - NOTEQUAL - "$ENV{HUNTER_DISABLE_AUTOINSTALL}" - "" - disable_autoinstall - ) - if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) - hunter_gate_fatal_error( - "Hunter not found in '${dir}'" - "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" - "Settings:" - " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" - " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" - ERROR_PAGE "error.run.install" - ) - endif() - string(COMPARE EQUAL "${dir}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("Empty 'dir' argument") - endif() - - string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") - endif() - - string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("HUNTER_GATE_URL empty") - endif() - - set(done_location "${dir}/DONE") - set(sha1_location "${dir}/SHA1") - - set(build_dir "${dir}/Build") - set(cmakelists "${dir}/CMakeLists.txt") - - hunter_gate_status_debug("Locking directory: ${dir}") - file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) - hunter_gate_status_debug("Lock done") - - if(EXISTS "${done_location}") - # while waiting for lock other instance can do all the job - hunter_gate_status_debug("File '${done_location}' found, skip install") - return() - endif() - - file(REMOVE_RECURSE "${build_dir}") - file(REMOVE_RECURSE "${cmakelists}") - - file(MAKE_DIRECTORY "${build_dir}") # check directory permissions - - # Disabling languages speeds up a little bit, reduces noise in the output - # and avoids path too long windows error - file( - WRITE - "${cmakelists}" - "cmake_minimum_required(VERSION 3.2)\n" - "project(HunterDownload LANGUAGES NONE)\n" - "include(ExternalProject)\n" - "ExternalProject_Add(\n" - " Hunter\n" - " URL\n" - " \"${HUNTER_GATE_URL}\"\n" - " URL_HASH\n" - " SHA1=${HUNTER_GATE_SHA1}\n" - " DOWNLOAD_DIR\n" - " \"${dir}\"\n" - " TLS_VERIFY\n" - " ${HUNTER_TLS_VERIFY}\n" - " SOURCE_DIR\n" - " \"${dir}/Unpacked\"\n" - " CONFIGURE_COMMAND\n" - " \"\"\n" - " BUILD_COMMAND\n" - " \"\"\n" - " INSTALL_COMMAND\n" - " \"\"\n" - ")\n" - ) - - if(HUNTER_STATUS_DEBUG) - set(logging_params "") - else() - set(logging_params OUTPUT_QUIET) - endif() - - hunter_gate_status_debug("Run generate") - - # Need to add toolchain file too. - # Otherwise on Visual Studio + MDD this will fail with error: - # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" - if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") - get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) - set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") - else() - # 'toolchain_arg' can't be empty - set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") - endif() - - string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) - if(no_make) - set(make_arg "") - else() - # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM - set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") - endif() - - execute_process( - COMMAND - "${CMAKE_COMMAND}" - "-H${dir}" - "-B${build_dir}" - "-G${CMAKE_GENERATOR}" - "${toolchain_arg}" - ${make_arg} - WORKING_DIRECTORY "${dir}" - RESULT_VARIABLE download_result - ${logging_params} - ) - - if(NOT download_result EQUAL 0) - hunter_gate_internal_error( - "Configure project failed." - "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}" - "In directory ${dir}" - ) - endif() - - hunter_gate_status_print( - "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" - " ${HUNTER_GATE_URL}" - " -> ${dir}" - ) - execute_process( - COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" - WORKING_DIRECTORY "${dir}" - RESULT_VARIABLE download_result - ${logging_params} - ) - - if(NOT download_result EQUAL 0) - hunter_gate_internal_error("Build project failed") - endif() - - file(REMOVE_RECURSE "${build_dir}") - file(REMOVE_RECURSE "${cmakelists}") - - file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") - file(WRITE "${done_location}" "DONE") - - hunter_gate_status_debug("Finished") -endfunction() - -# Must be a macro so master file 'cmake/Hunter' can -# apply all variables easily just by 'include' command -# (otherwise PARENT_SCOPE magic needed) -macro(HunterGate) - if(HUNTER_GATE_DONE) - # variable HUNTER_GATE_DONE set explicitly for external project - # (see `hunter_download`) - set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) - endif() - - # First HunterGate command will init Hunter, others will be ignored - get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) - - if(NOT HUNTER_ENABLED) - # Empty function to avoid error "unknown function" - function(hunter_add_package) - endfunction() - - set( - _hunter_gate_disabled_mode_dir - "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" - ) - if(EXISTS "${_hunter_gate_disabled_mode_dir}") - hunter_gate_status_debug( - "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" - ) - list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") - endif() - elseif(_hunter_gate_done) - hunter_gate_status_debug("Secondary HunterGate (use old settings)") - hunter_gate_self( - "${HUNTER_CACHED_ROOT}" - "${HUNTER_VERSION}" - "${HUNTER_SHA1}" - _hunter_self - ) - include("${_hunter_self}/cmake/Hunter") - else() - set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") - - string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) - if(_have_project_name) - hunter_gate_fatal_error( - "Please set HunterGate *before* 'project' command. " - "Detected project: ${PROJECT_NAME}" - ERROR_PAGE "error.huntergate.before.project" - ) - endif() - - cmake_parse_arguments( - HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} - ) - - string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) - string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) - string( - COMPARE - NOTEQUAL - "${HUNTER_GATE_UNPARSED_ARGUMENTS}" - "" - _have_unparsed - ) - string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) - string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) - - if(_have_unparsed) - hunter_gate_user_error( - "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" - ) - endif() - if(_empty_sha1) - hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") - endif() - if(_empty_url) - hunter_gate_user_error("URL suboption of HunterGate is mandatory") - endif() - if(_have_global) - if(HUNTER_GATE_LOCAL) - hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") - endif() - if(_have_filepath) - hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") - endif() - endif() - if(HUNTER_GATE_LOCAL) - if(_have_global) - hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") - endif() - if(_have_filepath) - hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") - endif() - endif() - if(_have_filepath) - if(_have_global) - hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") - endif() - if(HUNTER_GATE_LOCAL) - hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") - endif() - endif() - - hunter_gate_detect_root() # set HUNTER_GATE_ROOT - - # Beautify path, fix probable problems with windows path slashes - get_filename_component( - HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE - ) - hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") - if(NOT HUNTER_ALLOW_SPACES_IN_PATH) - string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) - if(NOT _contain_spaces EQUAL -1) - hunter_gate_fatal_error( - "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." - "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" - "(Use at your own risk!)" - ERROR_PAGE "error.spaces.in.hunter.root" - ) - endif() - endif() - - string( - REGEX - MATCH - "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" - HUNTER_GATE_VERSION - "${HUNTER_GATE_URL}" - ) - string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) - if(_is_empty) - set(HUNTER_GATE_VERSION "unknown") - endif() - - hunter_gate_self( - "${HUNTER_GATE_ROOT}" - "${HUNTER_GATE_VERSION}" - "${HUNTER_GATE_SHA1}" - _hunter_self - ) - - set(_master_location "${_hunter_self}/cmake/Hunter") - if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") - # Hunter downloaded manually (e.g. by 'git clone') - set(_unused "xxxxxxxxxx") - set(HUNTER_GATE_SHA1 "${_unused}") - set(HUNTER_GATE_VERSION "${_unused}") - else() - get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) - set(_done_location "${_archive_id_location}/DONE") - set(_sha1_location "${_archive_id_location}/SHA1") - - # Check Hunter already downloaded by HunterGate - if(NOT EXISTS "${_done_location}") - hunter_gate_download("${_archive_id_location}") - endif() - - if(NOT EXISTS "${_done_location}") - hunter_gate_internal_error("hunter_gate_download failed") - endif() - - if(NOT EXISTS "${_sha1_location}") - hunter_gate_internal_error("${_sha1_location} not found") - endif() - file(READ "${_sha1_location}" _sha1_value) - string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) - if(NOT _is_equal) - hunter_gate_internal_error( - "Short SHA1 collision:" - " ${_sha1_value} (from ${_sha1_location})" - " ${HUNTER_GATE_SHA1} (HunterGate)" - ) - endif() - if(NOT EXISTS "${_master_location}") - hunter_gate_user_error( - "Master file not found:" - " ${_master_location}" - "try to update Hunter/HunterGate" - ) - endif() - endif() - include("${_master_location}") - set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) - endif() -endmacro() diff --git a/cmake/gcov_for_clang.sh b/cmake/gcov_for_clang.sh deleted file mode 100755 index 2788ba9b..00000000 --- a/cmake/gcov_for_clang.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -which llvm-cov-11 > /dev/null -if [ $? -eq 0 ]; then - exec llvm-cov-11 gcov "$@" -else - exec llvm-cov gcov "$@" -fi diff --git a/cmake/git_version.cpp.in b/cmake/git_version.cpp.in deleted file mode 100644 index 37447598..00000000 --- a/cmake/git_version.cpp.in +++ /dev/null @@ -1,3 +0,0 @@ -#include "git_version.h" -const char *KOINOS_GIT_HASH = "@GIT_HASH@"; - diff --git a/cmake/git_version.h b/cmake/git_version.h deleted file mode 100644 index f7dcab81..00000000 --- a/cmake/git_version.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -extern const char *KOINOS_GIT_HASH; - diff --git a/libraries/chain/include/koinos/chain/chronicler.hpp b/include/koinos/chain/chronicler.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/chronicler.hpp rename to include/koinos/chain/chronicler.hpp diff --git a/libraries/chain/include/koinos/chain/constants.hpp b/include/koinos/chain/constants.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/constants.hpp rename to include/koinos/chain/constants.hpp diff --git a/libraries/chain/include/koinos/chain/controller.hpp b/include/koinos/chain/controller.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/controller.hpp rename to include/koinos/chain/controller.hpp diff --git a/libraries/chain/include/koinos/chain/exceptions.hpp b/include/koinos/chain/exceptions.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/exceptions.hpp rename to include/koinos/chain/exceptions.hpp diff --git a/libraries/chain/include/koinos/chain/execution_context.hpp b/include/koinos/chain/execution_context.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/execution_context.hpp rename to include/koinos/chain/execution_context.hpp diff --git a/libraries/chain/include/koinos/chain/host_api.hpp b/include/koinos/chain/host_api.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/host_api.hpp rename to include/koinos/chain/host_api.hpp diff --git a/libraries/chain/include/koinos/chain/indexer.hpp b/include/koinos/chain/indexer.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/indexer.hpp rename to include/koinos/chain/indexer.hpp diff --git a/libraries/chain/include/koinos/chain/proto_utils.hpp b/include/koinos/chain/proto_utils.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/proto_utils.hpp rename to include/koinos/chain/proto_utils.hpp diff --git a/libraries/chain/include/koinos/chain/resource_meter.hpp b/include/koinos/chain/resource_meter.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/resource_meter.hpp rename to include/koinos/chain/resource_meter.hpp diff --git a/libraries/chain/include/koinos/chain/session.hpp b/include/koinos/chain/session.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/session.hpp rename to include/koinos/chain/session.hpp diff --git a/libraries/chain/include/koinos/chain/state.hpp b/include/koinos/chain/state.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/state.hpp rename to include/koinos/chain/state.hpp diff --git a/libraries/chain/include/koinos/chain/system_calls.hpp b/include/koinos/chain/system_calls.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/system_calls.hpp rename to include/koinos/chain/system_calls.hpp diff --git a/libraries/chain/include/koinos/chain/thunk_dispatcher.hpp b/include/koinos/chain/thunk_dispatcher.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/thunk_dispatcher.hpp rename to include/koinos/chain/thunk_dispatcher.hpp diff --git a/libraries/chain/include/koinos/chain/thunk_utils.hpp b/include/koinos/chain/thunk_utils.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/thunk_utils.hpp rename to include/koinos/chain/thunk_utils.hpp diff --git a/libraries/chain/include/koinos/chain/types.hpp b/include/koinos/chain/types.hpp similarity index 100% rename from libraries/chain/include/koinos/chain/types.hpp rename to include/koinos/chain/types.hpp diff --git a/libraries/vm_manager/include/koinos/vm_manager/exceptions.hpp b/include/koinos/vm_manager/exceptions.hpp similarity index 100% rename from libraries/vm_manager/include/koinos/vm_manager/exceptions.hpp rename to include/koinos/vm_manager/exceptions.hpp diff --git a/libraries/vm_manager/include/koinos/vm_manager/fizzy/exceptions.hpp b/include/koinos/vm_manager/fizzy/exceptions.hpp similarity index 100% rename from libraries/vm_manager/include/koinos/vm_manager/fizzy/exceptions.hpp rename to include/koinos/vm_manager/fizzy/exceptions.hpp diff --git a/libraries/vm_manager/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp b/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp similarity index 100% rename from libraries/vm_manager/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp rename to include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp diff --git a/libraries/vm_manager/include/koinos/vm_manager/fizzy/module_cache.hpp b/include/koinos/vm_manager/fizzy/module_cache.hpp similarity index 100% rename from libraries/vm_manager/include/koinos/vm_manager/fizzy/module_cache.hpp rename to include/koinos/vm_manager/fizzy/module_cache.hpp diff --git a/libraries/vm_manager/include/koinos/vm_manager/host_api.hpp b/include/koinos/vm_manager/host_api.hpp similarity index 100% rename from libraries/vm_manager/include/koinos/vm_manager/host_api.hpp rename to include/koinos/vm_manager/host_api.hpp diff --git a/libraries/vm_manager/include/koinos/vm_manager/vm_backend.hpp b/include/koinos/vm_manager/vm_backend.hpp similarity index 100% rename from libraries/vm_manager/include/koinos/vm_manager/vm_backend.hpp rename to include/koinos/vm_manager/vm_backend.hpp diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt deleted file mode 100644 index 3d9c2f51..00000000 --- a/libraries/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(chain) -add_subdirectory(vm_manager) diff --git a/libraries/crypto b/libraries/crypto deleted file mode 160000 index 2f91acfd..00000000 --- a/libraries/crypto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2f91acfd683b824439b9844095cdc2e89f371037 diff --git a/libraries/exception b/libraries/exception deleted file mode 160000 index 5501569e..00000000 --- a/libraries/exception +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5501569e8bec1c97ddc1257e25ec1149bc2b50e9 diff --git a/libraries/log b/libraries/log deleted file mode 160000 index 89b59cd4..00000000 --- a/libraries/log +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 89b59cd48bd4e41ca1d377890af1de3d393f60f8 diff --git a/libraries/mq b/libraries/mq deleted file mode 160000 index f5cdac05..00000000 --- a/libraries/mq +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f5cdac05a46f9a3e5b8310559f6520d9b53ca9ca diff --git a/libraries/proto b/libraries/proto deleted file mode 160000 index 16fa52a3..00000000 --- a/libraries/proto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 16fa52a3e29a52edef42e9228b50f5b5035db10b diff --git a/libraries/state_db b/libraries/state_db deleted file mode 160000 index 8d25c579..00000000 --- a/libraries/state_db +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8d25c579abf71aeb40e5a4489a45c5a96e593437 diff --git a/libraries/util b/libraries/util deleted file mode 160000 index dd3e15f0..00000000 --- a/libraries/util +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dd3e15f0b08a99082b736b901bb78c0af4ed1982 diff --git a/libraries/vm_manager/CMakeLists.txt b/libraries/vm_manager/CMakeLists.txt deleted file mode 100644 index 061883b8..00000000 --- a/libraries/vm_manager/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -file(GLOB HEADERS "include/koinos/vm_manager/*.hpp" "include/koinos/vm_manager") -add_library(koinos_vm_manager_lib - - host_api.cpp - vm_backend.cpp - - fizzy/fizzy_vm_backend.cpp - fizzy/module_cache.cpp - - ${HEADERS}) -target_link_libraries(koinos_vm_manager_lib Koinos::exception Koinos::log Koinos::util fizzy::fizzy) -target_include_directories(koinos_vm_manager_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) -add_library(Koinos::vm_manager ALIAS koinos_vm_manager_lib) diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt deleted file mode 100644 index 0452292e..00000000 --- a/programs/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(koinos_chain) -add_subdirectory(koinos_vm_driver) diff --git a/programs/koinos_chain/CMakeLists.txt b/programs/koinos_chain/CMakeLists.txt deleted file mode 100644 index 6ddce843..00000000 --- a/programs/koinos_chain/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_executable(koinos_chain main.cpp) -target_link_libraries(koinos_chain Koinos::exception Koinos::crypto Koinos::proto Koinos::log Koinos::mq Koinos::util Koinos::chain Boost::program_options Koinos::git yaml-cpp) -install(TARGETS - koinos_chain - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -) diff --git a/programs/koinos_vm_driver/CMakeLists.txt b/programs/koinos_vm_driver/CMakeLists.txt deleted file mode 100644 index 7fb25b96..00000000 --- a/programs/koinos_vm_driver/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -find_package(Boost CONFIG REQUIRED COMPONENTS program_options) - -add_executable(koinos_vm_driver main.cpp) -target_link_libraries(koinos_vm_driver PUBLIC Koinos::chain Boost::program_options) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..599838ca --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,104 @@ +# libkoinos_chain + +add_library(chain + koinos/chain/chronicler.cpp + koinos/chain/controller.cpp + koinos/chain/execution_context.cpp + koinos/chain/host_api.cpp + koinos/chain/indexer.cpp + koinos/chain/proto_utils.cpp + koinos/chain/resource_meter.cpp + koinos/chain/session.cpp + koinos/chain/state.cpp + koinos/chain/system_calls.cpp + koinos/chain/thunk_dispatcher.cpp + + ${PROJECT_SOURCE_DIR}/include/koinos/chain/chronicler.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/constants.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/controller.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/exceptions.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/execution_context.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/host_api.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/indexer.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/proto_utils.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/resource_meter.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/session.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/state.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/system_calls.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/thunk_dispatcher.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/thunk_utils.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/chain/types.hpp +) + +target_link_libraries( + chain + PUBLIC + Koinos::state_db + Koinos::exception + Koinos::crypto + Koinos::log + Koinos::util + Koinos::mq + vm_manager) + +target_include_directories( + chain + PUBLIC + $ + $) + +koinos_add_format(TARGET chain) + +# libkoinos_vm_manager + +add_library(vm_manager + koinos/vm_manager/host_api.cpp + koinos/vm_manager/vm_backend.cpp + koinos/vm_manager/fizzy/fizzy_vm_backend.cpp + koinos/vm_manager/fizzy/module_cache.cpp + + ${PROJECT_SOURCE_DIR}/include/koinos/vm_manager/fizzy/exceptions.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp + ${PROJECT_SOURCE_DIR}/include/koinos/vm_manager/fizzy/module_cache.hpp +) + +target_link_libraries( + vm_manager + PUBLIC + Koinos::exception + Koinos::log + Koinos::util + fizzy::fizzy) + +target_include_directories( + vm_manager + PUBLIC + $ + $) + +koinos_add_format(TARGET vm_manager) + +# koinos_chain + +add_executable(koinos_chain koinos_chain.cpp) +target_link_libraries( + koinos_chain + PRIVATE + chain + Koinos::git + Boost::program_options) + +koinos_add_format(TARGET koinos_chain) + +# koinos_vm_driver + +add_executable(koinos_vm_driver koinos_vm_driver.cpp) +target_link_libraries( + koinos_vm_driver + PRIVATE + chain + Boost::program_options) + +koinos_add_format(TARGET koinos_vm_driver) + +koinos_install(TARGETS koinos_chain koinos_vm_driver) diff --git a/libraries/chain/CMakeLists.txt b/src/koinos/chain/CMakeLists.txt similarity index 100% rename from libraries/chain/CMakeLists.txt rename to src/koinos/chain/CMakeLists.txt diff --git a/libraries/chain/chronicler.cpp b/src/koinos/chain/chronicler.cpp similarity index 100% rename from libraries/chain/chronicler.cpp rename to src/koinos/chain/chronicler.cpp diff --git a/libraries/chain/controller.cpp b/src/koinos/chain/controller.cpp similarity index 100% rename from libraries/chain/controller.cpp rename to src/koinos/chain/controller.cpp diff --git a/libraries/chain/execution_context.cpp b/src/koinos/chain/execution_context.cpp similarity index 100% rename from libraries/chain/execution_context.cpp rename to src/koinos/chain/execution_context.cpp diff --git a/libraries/chain/host_api.cpp b/src/koinos/chain/host_api.cpp similarity index 100% rename from libraries/chain/host_api.cpp rename to src/koinos/chain/host_api.cpp diff --git a/libraries/chain/indexer.cpp b/src/koinos/chain/indexer.cpp similarity index 100% rename from libraries/chain/indexer.cpp rename to src/koinos/chain/indexer.cpp diff --git a/libraries/chain/proto_utils.cpp b/src/koinos/chain/proto_utils.cpp similarity index 100% rename from libraries/chain/proto_utils.cpp rename to src/koinos/chain/proto_utils.cpp diff --git a/libraries/chain/resource_meter.cpp b/src/koinos/chain/resource_meter.cpp similarity index 100% rename from libraries/chain/resource_meter.cpp rename to src/koinos/chain/resource_meter.cpp diff --git a/libraries/chain/session.cpp b/src/koinos/chain/session.cpp similarity index 100% rename from libraries/chain/session.cpp rename to src/koinos/chain/session.cpp diff --git a/libraries/chain/state.cpp b/src/koinos/chain/state.cpp similarity index 100% rename from libraries/chain/state.cpp rename to src/koinos/chain/state.cpp diff --git a/libraries/chain/system_calls.cpp b/src/koinos/chain/system_calls.cpp similarity index 100% rename from libraries/chain/system_calls.cpp rename to src/koinos/chain/system_calls.cpp diff --git a/libraries/chain/thunk_dispatcher.cpp b/src/koinos/chain/thunk_dispatcher.cpp similarity index 100% rename from libraries/chain/thunk_dispatcher.cpp rename to src/koinos/chain/thunk_dispatcher.cpp diff --git a/libraries/vm_manager/fizzy/fizzy_vm_backend.cpp b/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp similarity index 100% rename from libraries/vm_manager/fizzy/fizzy_vm_backend.cpp rename to src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp diff --git a/libraries/vm_manager/fizzy/module_cache.cpp b/src/koinos/vm_manager/fizzy/module_cache.cpp similarity index 100% rename from libraries/vm_manager/fizzy/module_cache.cpp rename to src/koinos/vm_manager/fizzy/module_cache.cpp diff --git a/libraries/vm_manager/host_api.cpp b/src/koinos/vm_manager/host_api.cpp similarity index 100% rename from libraries/vm_manager/host_api.cpp rename to src/koinos/vm_manager/host_api.cpp diff --git a/libraries/vm_manager/vm_backend.cpp b/src/koinos/vm_manager/vm_backend.cpp similarity index 100% rename from libraries/vm_manager/vm_backend.cpp rename to src/koinos/vm_manager/vm_backend.cpp diff --git a/programs/koinos_chain/main.cpp b/src/koinos_chain.cpp similarity index 100% rename from programs/koinos_chain/main.cpp rename to src/koinos_chain.cpp diff --git a/programs/koinos_vm_driver/main.cpp b/src/koinos_vm_driver.cpp similarity index 100% rename from programs/koinos_vm_driver/main.cpp rename to src/koinos_vm_driver.cpp diff --git a/tests/BoostTestTargetConfig.h b/tests/BoostTestTargetConfig.h deleted file mode 100644 index dd3cddae..00000000 --- a/tests/BoostTestTargetConfig.h +++ /dev/null @@ -1,7 +0,0 @@ -// Small header computed by CMake to set up boost test. -// include AFTER #define BOOST_TEST_MODULE whatever -// but before any other boost test includes. - -// Using the Boost UTF static library - -#include diff --git a/tests/BoostTestTargets.cmake b/tests/BoostTestTargets.cmake deleted file mode 100644 index 799c9023..00000000 --- a/tests/BoostTestTargets.cmake +++ /dev/null @@ -1,242 +0,0 @@ -# - Add tests using boost::test -# -# Add this line to your test files in place of including a basic boost test header: -# #include -# -# If you cannot do that and must use the included form for a given test, -# include the line -# // OVERRIDE_BOOST_TEST_INCLUDED_WARNING -# in the same file with the boost test include. -# -# include(BoostTestTargets) -# add_boost_test( SOURCES [] -# [FAIL_REGULAR_EXPRESSION ] -# [LAUNCHER ] -# [LIBRARIES [...]] -# [RESOURCES [...]] -# [TESTS [...]]) -# -# If for some reason you need access to the executable target created, -# it can be found in ${${testdriver_name}_TARGET_NAME} as specified when -# you called add_boost_test -# -# Requires CMake 2.6 or newer (uses the 'function' command) -# -# Requires: -# GetForceIncludeDefinitions -# CopyResourcesToBuildTree -# -# Original Author: -# 2009-2010 Ryan Pavlik -# http://academic.cleardefinition.com -# Iowa State University HCI Graduate Program/VRAC -# -# Copyright Iowa State University 2009-2010. -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -if(__add_boost_test) - return() -endif() -set(__add_boost_test YES) - -set(BOOST_TEST_TARGET_PREFIX "boosttest") - -if(NOT Boost_FOUND) - find_package(Boost 1.34.0 QUIET) -endif() - -include(GetForceIncludeDefinitions.cmake) -include(CopyResourcesToBuildTree.cmake) - -if(Boost_FOUND) - set(_boosttesttargets_libs) - set(_boostConfig "BoostTestTargetsIncluded.h") - if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY) - find_package(Boost 1.34.0 QUIET COMPONENTS unit_test_framework) - endif() - if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY) - set(_boosttesttargets_libs "${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}") - if(Boost_USE_STATIC_LIBS) - set(_boostConfig "BoostTestTargetsStatic.h") - else() - if(NOT APPLE) - set(_boostConfig "BoostTestTargetsDynamic.h") - endif() - endif() - endif() - get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} PATH) - configure_file("${_moddir}/${_boostConfig}" - "${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h" - COPYONLY) - include_directories("${CMAKE_CURRENT_BINARY_DIR}") -endif() - -function(add_boost_test _name) - if(NOT BUILD_TESTING) - return() - endif() - - # parse arguments - set(_nowhere) - set(_curdest _nowhere) - set(_val_args - SOURCES - FAIL_REGULAR_EXPRESSION - LAUNCHER - LIBRARIES - RESOURCES - TESTS) - set(_bool_args - USE_COMPILED_LIBRARY) - foreach(_arg ${_val_args} ${_bool_args}) - set(${_arg}) - endforeach() - foreach(_element ${ARGN}) - list(FIND _val_args "${_element}" _val_arg_find) - list(FIND _bool_args "${_element}" _bool_arg_find) - if("${_val_arg_find}" GREATER "-1") - set(_curdest "${_element}") - elseif("${_bool_arg_find}" GREATER "-1") - set("${_element}" ON) - set(_curdest _nowhere) - else() - list(APPEND ${_curdest} "${_element}") - endif() - endforeach() - - if(_nowhere) - message(FATAL_ERROR "Syntax error in use of add_boost_test!") - endif() - - if(NOT SOURCES) - message(FATAL_ERROR - "Syntax error in use of add_boost_test: at least one source file required!") - endif() - - if(Boost_FOUND) - - include_directories(${Boost_INCLUDE_DIRS}) - - set(includeType) - foreach(src ${SOURCES}) - file(READ ${src} thefile) - if("${thefile}" MATCHES ".*BoostTestTargetConfig.h.*") - set(includeType CONFIGURED) - set(includeFileLoc ${src}) - break() - elseif("${thefile}" MATCHES ".*boost/test/included/unit_test.hpp.*") - set(includeType INCLUDED) - set(includeFileLoc ${src}) - set(_boosttesttargets_libs) # clear this out - linking would be a bad idea - if(NOT - "${thefile}" - MATCHES - ".*OVERRIDE_BOOST_TEST_INCLUDED_WARNING.*") - message("Please replace the include line in ${src} with this alternate include line instead:") - message(" \#include ") - message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)") - endif() - break() - endif() - endforeach() - - if(NOT _boostTestTargetsNagged${_name} STREQUAL "${includeType}") - if("${includeType}" STREQUAL "CONFIGURED") - message(STATUS - "Test '${_name}' uses the CMake-configurable form of the boost test framework - congrats! (Including File: ${includeFileLoc})") - elseif("${includeType}" STREQUAL "INCLUDED") - message("In test '${_name}': ${includeFileLoc} uses the 'included' form of the boost unit test framework.") - else() - message("In test '${_name}': Didn't detect the CMake-configurable boost test include.") - message("Please replace your existing boost test include in that test with the following:") - message(" \#include ") - message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)") - endif() - endif() - set(_boostTestTargetsNagged${_name} - "${includeType}" - CACHE - INTERNAL - "" - FORCE) - - - if(RESOURCES) - list(APPEND SOURCES ${RESOURCES}) - endif() - - # Generate a unique target name, using the relative binary dir - # and provided name. (transform all / into _ and remove all other - # non-alphabet characters) - file(RELATIVE_PATH - targetpath - "${CMAKE_BINARY_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}") - string(REGEX REPLACE "[^A-Za-z/_]" "" targetpath "${targetpath}") - string(REPLACE "/" "_" targetpath "${targetpath}") - - set(_target_name ${_name}) - set(${_name}_TARGET_NAME "${_target_name}" PARENT_SCOPE) - - # Build the test. - add_executable(${_target_name} ${SOURCES}) - - list(APPEND LIBRARIES ${_boosttesttargets_libs}) - - if(LIBRARIES) - target_link_libraries(${_target_name} ${LIBRARIES}) - endif() - - if(RESOURCES) - set_property(TARGET ${_target_name} PROPERTY RESOURCE ${RESOURCES}) - copy_resources_to_build_tree(${_target_name}) - endif() - - if(NOT Boost_TEST_FLAGS) -# set(Boost_TEST_FLAGS --catch_system_error=yes --output_format=XML) - set(Boost_TEST_FLAGS --catch_system_error=yes) - endif() - - # TODO: Figure out why only recent boost handles individual test running properly - - if(LAUNCHER) - set(_test_command ${LAUNCHER} "\$") - else() - set(_test_command ${_target_name}) - endif() - - if(TESTS) - foreach(_test ${TESTS}) - add_test( - ${_name}-${_test} - ${_test_command} --run_test=${_test} ${Boost_TEST_FLAGS} - ) - if(FAIL_REGULAR_EXPRESSION) - set_tests_properties(${_name}-${_test} - PROPERTIES - FAIL_REGULAR_EXPRESSION - "${FAIL_REGULAR_EXPRESSION}") - endif() - endforeach() - else() - add_test( - ${_name}-boost_test - ${_test_command} ${Boost_TEST_FLAGS} - ) - if(FAIL_REGULAR_EXPRESSION) - set_tests_properties(${_name}-boost_test - PROPERTIES - FAIL_REGULAR_EXPRESSION - "${FAIL_REGULAR_EXPRESSION}") - endif() - endif() - - # CppCheck the test if we can. - if(COMMAND add_cppcheck) - add_cppcheck(${_target_name} STYLE UNUSED_FUNCTIONS) - endif() - - endif() -endfunction() diff --git a/tests/BoostTestTargetsDynamic.h b/tests/BoostTestTargetsDynamic.h deleted file mode 100644 index 4bff5677..00000000 --- a/tests/BoostTestTargetsDynamic.h +++ /dev/null @@ -1,8 +0,0 @@ -// Small header computed by CMake to set up boost test. -// include AFTER #define BOOST_TEST_MODULE whatever -// but before any other boost test includes. - -// Using the Boost UTF dynamic library - -#define BOOST_TEST_DYN_LINK -#include diff --git a/tests/BoostTestTargetsIncluded.h b/tests/BoostTestTargetsIncluded.h deleted file mode 100644 index 253133ce..00000000 --- a/tests/BoostTestTargetsIncluded.h +++ /dev/null @@ -1,7 +0,0 @@ -// Small header computed by CMake to set up boost test. -// include AFTER #define BOOST_TEST_MODULE whatever -// but before any other boost test includes. - -// Using the Boost UTF included framework - -#include diff --git a/tests/BoostTestTargetsStatic.h b/tests/BoostTestTargetsStatic.h deleted file mode 100644 index dd3cddae..00000000 --- a/tests/BoostTestTargetsStatic.h +++ /dev/null @@ -1,7 +0,0 @@ -// Small header computed by CMake to set up boost test. -// include AFTER #define BOOST_TEST_MODULE whatever -// but before any other boost test includes. - -// Using the Boost UTF static library - -#include diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0f6ad02d..7544c0fc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,61 +1,40 @@ -find_package(Gperftools QUIET) -if(GPERFTOOLS_FOUND) - message(STATUS "Found gperftools; compiling tests with TCMalloc") - list(APPEND PLATFORM_SPECIFIC_LIBS tcmalloc) +if (NOT BUILD_TESTING) + return() endif() include(CTest) -enable_testing() - -file(GLOB UNIT_TESTS "tests/*.cpp") -file(GLOB_RECURSE TEST_FIXTURES "include/*.hpp") - -include(BoostTestTargets.cmake) - -function(parse_unit_tests RESULT) - set(SOURCES) - foreach(_element ${ARGN}) - list(APPEND SOURCES "${_element}") - endforeach() - - set(tests) - - foreach(src ${SOURCES}) - file(READ ${src} thefile) - string(REGEX MATCH "BOOST_FIXTURE_TEST_SUITE\\([A-Za-z0-9_,<> ]*\\)" test_suite "${thefile}" ) - - if( NOT (test_suite STREQUAL "") ) - string(SUBSTRING "${test_suite}" 25 -1 test_suite) - string(FIND "${test_suite}" "," comma_loc ) - string(SUBSTRING "${test_suite}" 0 ${comma_loc} test_suite) - string(STRIP "${test_suite}" test_suite) - - string( REGEX MATCHALL "BOOST_AUTO_TEST_CASE\\([A-Za-z0-9_,<> ]*\\)" cases "${thefile}" ) - - foreach( test_case ${cases} ) - string(SUBSTRING "${test_case}" 21 -1 test_case) - string(FIND "${test_case}" ")" paren_loc ) - string(SUBSTRING "${test_case}" 0 ${paren_loc} test_case) - string(STRIP "${test_case}" test_case) - - list(APPEND tests "${test_suite}/${test_case}") - endforeach() - endif() - endforeach() - - set(${RESULT} ${tests} PARENT_SCOPE) -endfunction() - -parse_unit_tests(TEST_CASES ${UNIT_TESTS}) - -add_boost_test(koinos_tests - SOURCES ${UNIT_TESTS} ${TEST_FIXTURES} - TESTS ${TEST_CASES} -) - -target_link_libraries(koinos_tests Koinos::proto Koinos::chain Koinos::crypto Koinos::state_db Koinos::log Koinos::util Koinos::exception ${PLATFORM_SPECIFIC_LIBS}) -target_include_directories(koinos_tests PUBLIC - $ - $ # /include -) +koinos_add_test( + chain_tests + SOURCES + main.cpp + contracts.cpp + controller_test.cpp + stack_test.cpp + thunk_test.cpp) + +target_link_libraries( + chain_tests + PRIVATE + chain + Koinos::proto + Koinos::crypto + Koinos::state_db + Koinos::log + Koinos::util + Koinos::exception) + +target_include_directories( + chain_tests + PUBLIC + $ + $ + $) + +koinos_add_format(TARGET chain_tests) + +koinos_coverage( + EXECUTABLE + chain_tests + EXCLUDE + "tests/*") diff --git a/tests/CopyResourcesToBuildTree.cmake b/tests/CopyResourcesToBuildTree.cmake deleted file mode 100644 index 3512cc48..00000000 --- a/tests/CopyResourcesToBuildTree.cmake +++ /dev/null @@ -1,83 +0,0 @@ -# - Copy the resources your app needs to the build tree. -# -# copy_resources_to_build_tree() -# -# Requires CMake 2.6 or newer (uses the 'function' command) -# -# Original Author: -# 2009-2010 Ryan Pavlik -# http://academic.cleardefinition.com -# Iowa State University HCI Graduate Program/VRAC -# -# Copyright Iowa State University 2009-2010. -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -if(__copy_resources_to_build_tree) - return() -endif() -set(__copy_resources_to_build_tree YES) - -function(copy_resources_to_build_tree _target) - get_target_property(_resources ${_target} RESOURCE) - if(NOT _resources) - # Bail if no resources - message(STATUS - "Told to copy resources for target ${_target}, but " - "no resources are set!") - return() - endif() - - get_target_property(_path ${_target} LOCATION) - get_filename_component(_path "${_path}" PATH) - - if(NOT MSVC AND NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles") - foreach(_config ${CMAKE_CONFIGURATION_TYPES}) - get_target_property(_path${_config} ${_target} LOCATION_${_config}) - get_filename_component(_path${_config} "${_path${_config}}" PATH) - add_custom_command(TARGET ${_target} - POST_BUILD - COMMAND - ${CMAKE_COMMAND} - ARGS -E make_directory "${_path${_config}}/" - COMMENT "Creating directory ${_path${_config}}/") - endforeach() - endif() - - foreach(_res ${_resources}) - if(NOT IS_ABSOLUTE "${_res}") - get_filename_component(_res "${_res}" ABSOLUTE) - endif() - get_filename_component(_name "${_res}" NAME) - - if(MSVC) - # Working dir is solution file dir, not exe file dir. - add_custom_command(TARGET ${_target} - POST_BUILD - COMMAND - ${CMAKE_COMMAND} - ARGS -E copy "${_res}" "${CMAKE_BINARY_DIR}/" - COMMENT "Copying ${_name} to ${CMAKE_BINARY_DIR}/ for MSVC") - else() - if("${CMAKE_GENERATOR}" MATCHES "Makefiles") - add_custom_command(TARGET ${_target} - POST_BUILD - COMMAND - ${CMAKE_COMMAND} - ARGS -E copy "${_res}" "${_path}/" - COMMENT "Copying ${_name} to ${_path}/") - else() - foreach(_config ${CMAKE_CONFIGURATION_TYPES}) - add_custom_command(TARGET ${_target} - POST_BUILD - COMMAND - ${CMAKE_COMMAND} - ARGS -E copy "${_res}" "${_path${_config}}" - COMMENT "Copying ${_name} to ${_path${_config}}") - endforeach() - - endif() - endif() - endforeach() -endfunction() diff --git a/tests/GetForceIncludeDefinitions.cmake b/tests/GetForceIncludeDefinitions.cmake deleted file mode 100644 index efcca047..00000000 --- a/tests/GetForceIncludeDefinitions.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# - Get the platform-appropriate flags to add to force inclusion of a file -# -# The most common use of this is to use a generated config.h-type file -# placed out of the source tree in all files. -# -# get_force_include_definitions(var forcedincludefiles...) - -# where var is the name of your desired output variable, and everything -# else is a source file to forcibly include. -# a list item to be filtered. -# -# Original Author: -# 2009-2010 Ryan Pavlik -# http://academic.cleardefinition.com -# Iowa State University HCI Graduate Program/VRAC -# -# Copyright Iowa State University 2009-2010. -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -if(__get_force_include_definitions) - return() -endif() -set(__get_force_include_definitions YES) - -function(get_force_include_definitions var) - set(_flagprefix) - if(CMAKE_COMPILER_IS_GNUCXX) - set(_flag "-include") - elseif(MSVC) - set(_flag "/FI") - else() - message(SEND_ERROR "You don't seem to be using MSVC or GCC, but") - message(SEND_ERROR "the project called get_force_include_definitions.") - message(SEND_ERROR "Contact this project with the name of your") - message(FATAL_ERROR "compiler and preferably the flag to force includes") - endif() - - set(_out) - foreach(_item ${ARGN}) - list(APPEND _out "${_flag} \"${_item}\"") - endforeach() - set(${var} "${_out}" PARENT_SCOPE) -endfunction() diff --git a/tests/tests/contracts.cpp b/tests/contracts.cpp similarity index 100% rename from tests/tests/contracts.cpp rename to tests/contracts.cpp diff --git a/tests/tests/controller_test.cpp b/tests/controller_test.cpp similarity index 100% rename from tests/tests/controller_test.cpp rename to tests/controller_test.cpp diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 00000000..fa472287 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,3 @@ +#define BOOST_TEST_MODULE chain_tests +// OVERRIDE_BOOST_TEST_INCLUDED_WARNING +#include \ No newline at end of file diff --git a/tests/tests/stack_test.cpp b/tests/stack_test.cpp similarity index 100% rename from tests/tests/stack_test.cpp rename to tests/stack_test.cpp diff --git a/tests/tests/main.cpp b/tests/tests/main.cpp deleted file mode 100644 index e353cb44..00000000 --- a/tests/tests/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#define BOOST_TEST_MODULE koinos_tests -#include -#include diff --git a/tests/tests/thunk_test.cpp b/tests/thunk_test.cpp similarity index 100% rename from tests/tests/thunk_test.cpp rename to tests/thunk_test.cpp From 61d6f2fdf54bde5690d3dae2bcb7b2b6f9720c55 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Sun, 3 Mar 2024 21:00:50 +0100 Subject: [PATCH 02/25] Run clang format on codebase --- include/koinos/chain/chronicler.hpp | 36 +- include/koinos/chain/constants.hpp | 2 +- include/koinos/chain/controller.hpp | 62 +- include/koinos/chain/exceptions.hpp | 48 +- include/koinos/chain/execution_context.hpp | 236 +- include/koinos/chain/host_api.hpp | 33 +- include/koinos/chain/indexer.hpp | 42 +- include/koinos/chain/proto_utils.hpp | 24 +- include/koinos/chain/resource_meter.hpp | 67 +- include/koinos/chain/session.hpp | 33 +- include/koinos/chain/state.hpp | 48 +- include/koinos/chain/system_calls.hpp | 71 +- include/koinos/chain/thunk_dispatcher.hpp | 683 ++- include/koinos/chain/thunk_utils.hpp | 553 +- include/koinos/chain/types.hpp | 12 +- .../koinos/vm_manager/fizzy/exceptions.hpp | 2 +- .../vm_manager/fizzy/fizzy_vm_backend.hpp | 20 +- .../koinos/vm_manager/fizzy/module_cache.hpp | 69 +- src/koinos/chain/chronicler.cpp | 26 +- src/koinos/chain/controller.cpp | 1487 ++--- src/koinos/chain/execution_context.cpp | 422 +- src/koinos/chain/host_api.cpp | 304 +- src/koinos/chain/indexer.cpp | 364 +- src/koinos/chain/proto_utils.cpp | 395 +- src/koinos/chain/resource_meter.cpp | 178 +- src/koinos/chain/session.cpp | 30 +- src/koinos/chain/state.cpp | 104 +- src/koinos/chain/system_calls.cpp | 2262 ++++---- src/koinos/chain/thunk_dispatcher.cpp | 26 +- .../vm_manager/fizzy/fizzy_vm_backend.cpp | 551 +- src/koinos/vm_manager/fizzy/module_cache.cpp | 56 +- src/koinos/vm_manager/host_api.cpp | 2 +- src/koinos/vm_manager/vm_backend.cpp | 25 +- src/koinos_chain.cpp | 816 +-- src/koinos_vm_driver.cpp | 159 +- tests/contracts.cpp | 12 +- tests/main.cpp | 2 +- tests/stack_test.cpp | 1370 ++--- tests/thunk_test.cpp | 4987 +++++++++-------- 39 files changed, 8353 insertions(+), 7266 deletions(-) diff --git a/include/koinos/chain/chronicler.hpp b/include/koinos/chain/chronicler.hpp index 7b8d5951..c613deb7 100644 --- a/include/koinos/chain/chronicler.hpp +++ b/include/koinos/chain/chronicler.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include #include +#include #include namespace koinos::chain { @@ -11,27 +11,29 @@ using event_bundle = std::pair< std::optional< std::string >, protocol::event_da struct abstract_chronicler_session { - virtual ~abstract_chronicler_session() = default; + virtual ~abstract_chronicler_session() = default; - virtual void push_event( const protocol::event_data& ev ) = 0; - virtual const std::vector< protocol::event_data >& events() = 0; + virtual void push_event( const protocol::event_data& ev ) = 0; + virtual const std::vector< protocol::event_data >& events() = 0; - virtual void push_log( const std::string& log ) = 0; - virtual const std::vector< std::string >& logs() = 0; + virtual void push_log( const std::string& log ) = 0; + virtual const std::vector< std::string >& logs() = 0; }; -class chronicler final { +class chronicler final +{ public: - void set_session( std::shared_ptr< abstract_chronicler_session > s ); - void push_event( std::optional< std::string > transaction_id, protocol::event_data&& ev ); - void push_log( const std::string& message ); - const std::vector< event_bundle >& events(); - const std::vector< std::string >& logs(); + void set_session( std::shared_ptr< abstract_chronicler_session > s ); + void push_event( std::optional< std::string > transaction_id, protocol::event_data&& ev ); + void push_log( const std::string& message ); + const std::vector< event_bundle >& events(); + const std::vector< std::string >& logs(); + private: - std::weak_ptr< abstract_chronicler_session > _session; - std::vector< event_bundle > _events; - std::vector< std::string > _logs; - uint32_t _seq_no = 0; + std::weak_ptr< abstract_chronicler_session > _session; + std::vector< event_bundle > _events; + std::vector< std::string > _logs; + uint32_t _seq_no = 0; }; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/constants.hpp b/include/koinos/chain/constants.hpp index c9458d90..f856cb37 100644 --- a/include/koinos/chain/constants.hpp +++ b/include/koinos/chain/constants.hpp @@ -9,4 +9,4 @@ constexpr uint64_t default_irreversible_threshold = 60; constexpr uint32_t authorize_entrypoint = 0x4a2dbd90; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/controller.hpp b/include/koinos/chain/controller.hpp index 1df0a156..c9a7911a 100644 --- a/include/koinos/chain/controller.hpp +++ b/include/koinos/chain/controller.hpp @@ -14,42 +14,44 @@ namespace koinos::chain { -namespace detail { class controller_impl; } +namespace detail { +class controller_impl; +} // namespace detail enum class fork_resolution_algorithm { - fifo, - block_time, - pob + fifo, + block_time, + pob }; class controller final { - public: - controller( uint64_t read_compute_bandwith_limit = 0, uint32_t syscall_bufsize = 0 ); - ~controller(); - - void open( const std::filesystem::path& p, const chain::genesis_data& data, fork_resolution_algorithm algo, bool reset ); - void close(); - void set_client( std::shared_ptr< mq::client > c ); - - rpc::chain::submit_block_response submit_block( - const rpc::chain::submit_block_request&, - uint64_t index_to = 0, - std::chrono::system_clock::time_point now = std::chrono::system_clock::now() - ); - rpc::chain::submit_transaction_response submit_transaction( const rpc::chain::submit_transaction_request& ); - rpc::chain::get_head_info_response get_head_info( const rpc::chain::get_head_info_request& = {} ); - rpc::chain::get_chain_id_response get_chain_id( const rpc::chain::get_chain_id_request& = {} ); - rpc::chain::get_fork_heads_response get_fork_heads( const rpc::chain::get_fork_heads_request& = {} ); - rpc::chain::read_contract_response read_contract( const rpc::chain::read_contract_request& ); - rpc::chain::get_account_nonce_response get_account_nonce( const rpc::chain::get_account_nonce_request& ); - rpc::chain::get_account_rc_response get_account_rc( const rpc::chain::get_account_rc_request& ); - rpc::chain::get_resource_limits_response get_resource_limits( const rpc::chain::get_resource_limits_request& ); - rpc::chain::invoke_system_call_response invoke_system_call( const rpc::chain::invoke_system_call_request& ); - - private: - std::unique_ptr< detail::controller_impl > _my; +public: + controller( uint64_t read_compute_bandwith_limit = 0, uint32_t syscall_bufsize = 0 ); + ~controller(); + + void + open( const std::filesystem::path& p, const chain::genesis_data& data, fork_resolution_algorithm algo, bool reset ); + void close(); + void set_client( std::shared_ptr< mq::client > c ); + + rpc::chain::submit_block_response + submit_block( const rpc::chain::submit_block_request&, + uint64_t index_to = 0, + std::chrono::system_clock::time_point now = std::chrono::system_clock::now() ); + rpc::chain::submit_transaction_response submit_transaction( const rpc::chain::submit_transaction_request& ); + rpc::chain::get_head_info_response get_head_info( const rpc::chain::get_head_info_request& = {} ); + rpc::chain::get_chain_id_response get_chain_id( const rpc::chain::get_chain_id_request& = {} ); + rpc::chain::get_fork_heads_response get_fork_heads( const rpc::chain::get_fork_heads_request& = {} ); + rpc::chain::read_contract_response read_contract( const rpc::chain::read_contract_request& ); + rpc::chain::get_account_nonce_response get_account_nonce( const rpc::chain::get_account_nonce_request& ); + rpc::chain::get_account_rc_response get_account_rc( const rpc::chain::get_account_rc_request& ); + rpc::chain::get_resource_limits_response get_resource_limits( const rpc::chain::get_resource_limits_request& ); + rpc::chain::invoke_system_call_response invoke_system_call( const rpc::chain::invoke_system_call_request& ); + +private: + std::unique_ptr< detail::controller_impl > _my; }; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/exceptions.hpp b/include/koinos/chain/exceptions.hpp index 5c02464d..6c593655 100644 --- a/include/koinos/chain/exceptions.hpp +++ b/include/koinos/chain/exceptions.hpp @@ -1,14 +1,20 @@ #pragma once -#include #include +#include namespace koinos::chain { -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( system_authorization_failure_exception, reversion_exception, system_authorization_failure ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( system_authorization_failure_exception, + reversion_exception, + system_authorization_failure ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( invalid_contract_exception, reversion_exception, invalid_contract ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( insufficient_privileges_exception, reversion_exception, insufficient_privileges ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( insufficient_privileges_exception, + reversion_exception, + insufficient_privileges ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( insufficient_rc_exception, reversion_exception, insufficient_rc ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( insufficient_return_buffer_exception, reversion_exception, insufficient_return_buffer ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( insufficient_return_buffer_exception, + reversion_exception, + insufficient_return_buffer ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( unknown_thunk_exception, reversion_exception, unknown_thunk ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( unknown_operation_exception, reversion_exception, unknown_operation ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( read_only_context_exception, reversion_exception, read_only_context ); @@ -24,24 +30,40 @@ KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( invalid_nonce_exception, failure_exc KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( invalid_signature_exception, failure_exception, invalid_signature ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( malformed_block_exception, failure_exception, malformed_block ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( malformed_transaction_exception, failure_exception, malformed_transaction ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( block_resource_failure_exception, failure_exception, block_resource_failure ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( block_resource_failure_exception, + failure_exception, + block_resource_failure ); // Framework failures KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( unknown_backend_exception, failure_exception, unknown_backend ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( unexpected_state_exception, failure_exception, unexpected_state ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( missing_required_arguments_exception, failure_exception, missing_required_arguments ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( unknown_previous_block_exception, failure_exception, unknown_previous_block ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( missing_required_arguments_exception, + failure_exception, + missing_required_arguments ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( unknown_previous_block_exception, + failure_exception, + unknown_previous_block ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( unexpected_height_exception, failure_exception, unexpected_height ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( block_state_error_exception, failure_exception, block_state_error ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( state_merkle_mismatch_exception, failure_exception, state_merkle_mismatch ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( unexpected_receipt_exception, failure_exception, unexpected_receipt ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( rpc_failure_exception, failure_exception, rpc_failure ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( pending_state_error_exception, failure_exception, pending_state_error ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( timestamp_out_of_bounds_exception, failure_exception, timestamp_out_of_bounds ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( timestamp_out_of_bounds_exception, + failure_exception, + timestamp_out_of_bounds ); KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( indexer_failure_exception, failure_exception, indexer_failure ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( network_bandwidth_limit_exceeded_exception, failure_exception, network_bandwidth_limit_exceeded ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( compute_bandwidth_limit_exceeded_exception, failure_exception, compute_bandwidth_limit_exceeded ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( disk_storage_limit_exceeded_exception, failure_exception, disk_storage_limit_exceeded ); -KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( pre_irreversibility_block_exception, failure_exception, pre_irreversibility_block ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( network_bandwidth_limit_exceeded_exception, + failure_exception, + network_bandwidth_limit_exceeded ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( compute_bandwidth_limit_exceeded_exception, + failure_exception, + compute_bandwidth_limit_exceeded ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( disk_storage_limit_exceeded_exception, + failure_exception, + disk_storage_limit_exceeded ); +KOINOS_DECLARE_DERIVED_EXCEPTION_WITH_CODE( pre_irreversibility_block_exception, + failure_exception, + pre_irreversibility_block ); -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/execution_context.hpp b/include/koinos/chain/execution_context.hpp index 014528d1..e9c92fe2 100644 --- a/include/koinos/chain/execution_context.hpp +++ b/include/koinos/chain/execution_context.hpp @@ -25,210 +25,210 @@ namespace koinos::chain { namespace constants { - const std::string system = std::string{}; -} +const std::string system = std::string{}; +} // namespace constants -using koinos::state_db::state_node_ptr; -using koinos::state_db::anonymous_state_node_ptr; using koinos::state_db::abstract_state_node; +using koinos::state_db::anonymous_state_node_ptr; +using koinos::state_db::state_node_ptr; using abstract_state_node_ptr = std::shared_ptr< abstract_state_node >; using receipt = std::variant< std::monostate, protocol::block_receipt, protocol::transaction_receipt >; struct stack_frame { - std::string contract_id; - uint32_t sid = 0; - privilege call_privilege; - std::string call_args; - uint32_t entry_point = 0; + std::string contract_id; + uint32_t sid = 0; + privilege call_privilege; + std::string call_args; + uint32_t entry_point = 0; }; struct execution_result { - int32_t code = 0; - result res; + int32_t code = 0; + result res; }; enum class intent : uint64_t { - read_only, - block_application, - transaction_application + read_only, + block_application, + transaction_application }; struct system_call_cache_bundle { - std::string contract_id; - std::string contract_bytecode; - uint32_t entry_point; - chain::contract_metadata_object contract_metadata; + std::string contract_id; + std::string contract_bytecode; + uint32_t entry_point; + chain::contract_metadata_object contract_metadata; }; struct thunk_cache_bundle { - uint32_t thunk_id; - bool is_override; + uint32_t thunk_id; + bool is_override; }; struct execution_context_cache { - std::optional< std::map< std::string, uint64_t > > compute_bandwidth; - std::optional< google::protobuf::DescriptorPool > descriptor_pool; - std::map< uint32_t, std::variant< system_call_cache_bundle, thunk_cache_bundle > > system_call_table; - std::optional< crypto::multicodec > block_hash_code; + std::optional< std::map< std::string, uint64_t > > compute_bandwidth; + std::optional< google::protobuf::DescriptorPool > descriptor_pool; + std::map< uint32_t, std::variant< system_call_cache_bundle, thunk_cache_bundle > > system_call_table; + std::optional< crypto::multicodec > block_hash_code; }; class execution_context { - public: - execution_context() = delete; - execution_context( std::shared_ptr< vm_manager::vm_backend >, chain::intent i = chain::intent::read_only ); +public: + execution_context() = delete; + execution_context( std::shared_ptr< vm_manager::vm_backend >, chain::intent i = chain::intent::read_only ); - static constexpr std::size_t stack_limit = 256; + static constexpr std::size_t stack_limit = 256; - std::shared_ptr< vm_manager::vm_backend > get_backend() const; + std::shared_ptr< vm_manager::vm_backend > get_backend() const; - void set_state_node( abstract_state_node_ptr, abstract_state_node_ptr = abstract_state_node_ptr() ); - abstract_state_node_ptr get_state_node() const; - abstract_state_node_ptr get_parent_node() const; - void clear_state_node(); + void set_state_node( abstract_state_node_ptr, abstract_state_node_ptr = abstract_state_node_ptr() ); + abstract_state_node_ptr get_state_node() const; + abstract_state_node_ptr get_parent_node() const; + void clear_state_node(); - void set_block( const protocol::block& ); - const protocol::block* get_block() const; - void clear_block(); + void set_block( const protocol::block& ); + const protocol::block* get_block() const; + void clear_block(); - void set_transaction( const protocol::transaction& ); - const protocol::transaction* get_transaction() const; - void clear_transaction(); + void set_transaction( const protocol::transaction& ); + const protocol::transaction* get_transaction() const; + void clear_transaction(); - void set_operation( const protocol::operation& ); - const protocol::operation* get_operation() const; - void clear_operation(); + void set_operation( const protocol::operation& ); + const protocol::operation* get_operation() const; + void clear_operation(); - void set_contract_call_args( const std::string& args ); - const std::string& get_contract_call_args() const; + void set_contract_call_args( const std::string& args ); + const std::string& get_contract_call_args() const; - uint32_t get_contract_entry_point() const; + uint32_t get_contract_entry_point() const; - uint64_t get_compute_bandwidth( const std::string& thunk_name ); + uint64_t get_compute_bandwidth( const std::string& thunk_name ); - void push_frame( stack_frame&& frame ); - stack_frame pop_frame(); + void push_frame( stack_frame&& frame ); + stack_frame pop_frame(); - const std::string& get_caller() const; - privilege get_caller_privilege() const; - uint32_t get_caller_entry_point() const; + const std::string& get_caller() const; + privilege get_caller_privilege() const; + uint32_t get_caller_entry_point() const; - void set_privilege( privilege ); - privilege get_privilege() const; + void set_privilege( privilege ); + privilege get_privilege() const; - const std::string& get_contract_id() const; + const std::string& get_contract_id() const; - bool read_only() const; + bool read_only() const; - chain::resource_meter& resource_meter(); - chain::chronicler& chronicler(); + chain::resource_meter& resource_meter(); + chain::chronicler& chronicler(); - std::shared_ptr< session > make_session( uint64_t rc ); + std::shared_ptr< session > make_session( uint64_t rc ); - void set_intent( chain::intent i ); - chain::intent intent() const; + void set_intent( chain::intent i ); + chain::intent intent() const; - chain::receipt& receipt(); + chain::receipt& receipt(); - void reset_cache(); + void reset_cache(); - const google::protobuf::DescriptorPool& descriptor_pool(); + const google::protobuf::DescriptorPool& descriptor_pool(); - const execution_result& system_call( uint32_t id, const std::string& args ); - uint32_t thunk_translation( uint32_t id ); - bool system_call_exists( uint32_t id ); - const crypto::multicodec& block_hash_code(); + const execution_result& system_call( uint32_t id, const std::string& args ); + uint32_t thunk_translation( uint32_t id ); + bool system_call_exists( uint32_t id ); + const crypto::multicodec& block_hash_code(); - void set_result( const execution_result& r ); - void set_result( execution_result&& r ); + void set_result( const execution_result& r ); + void set_result( execution_result&& r ); - const execution_result& get_result(); + const execution_result& get_result(); - private: - void build_compute_registry_cache(); - void build_descriptor_pool(); - void cache_system_call( uint32_t ); - void build_block_hash_code_cache(); +private: + void build_compute_registry_cache(); + void build_descriptor_pool(); + void cache_system_call( uint32_t ); + void build_block_hash_code_cache(); - std::shared_ptr< vm_manager::vm_backend > _vm_backend; - std::vector< stack_frame > _stack; + std::shared_ptr< vm_manager::vm_backend > _vm_backend; + std::vector< stack_frame > _stack; - abstract_state_node_ptr _current_state_node; - abstract_state_node_ptr _parent_state_node; + abstract_state_node_ptr _current_state_node; + abstract_state_node_ptr _parent_state_node; - const protocol::block* _block = nullptr; - const protocol::transaction* _trx = nullptr; - const protocol::operation* _op = nullptr; + const protocol::block* _block = nullptr; + const protocol::transaction* _trx = nullptr; + const protocol::operation* _op = nullptr; - chain::resource_meter _resource_meter; - chain::chronicler _chronicler; + chain::resource_meter _resource_meter; + chain::chronicler _chronicler; - chain::intent _intent; - chain::receipt _receipt; + chain::intent _intent; + chain::receipt _receipt; - execution_context_cache _cache; - execution_result _result; + execution_context_cache _cache; + execution_result _result; }; namespace detail { struct frame_guard { - frame_guard( execution_context& ctx, stack_frame&& f ) : + frame_guard( execution_context& ctx, stack_frame&& f ): _ctx( ctx ) - { - _ctx.push_frame( std::move( f ) ); - } + { + _ctx.push_frame( std::move( f ) ); + } - ~frame_guard() - { - _ctx.pop_frame(); - } + ~frame_guard() + { + _ctx.pop_frame(); + } - private: - execution_context& _ctx; +private: + execution_context& _ctx; }; struct privilege_guard { - privilege_guard( execution_context& ctx, privilege p ) : + privilege_guard( execution_context& ctx, privilege p ): _ctx( ctx ) - { - _privilege = ctx.get_privilege(); - _ctx.set_privilege( p ); - } - - ~privilege_guard() - { - _ctx.set_privilege( _privilege ); - } - - private: - execution_context& _ctx; - privilege _privilege; + { + _privilege = ctx.get_privilege(); + _ctx.set_privilege( p ); + } + + ~privilege_guard() + { + _ctx.set_privilege( _privilege ); + } + +private: + execution_context& _ctx; + privilege _privilege; }; -} // detail +} // namespace detail template< typename Lambda > void with_stack_frame( execution_context& ctx, stack_frame&& f, Lambda&& l ) { - detail::frame_guard r( ctx, std::move( f ) ); - l(); + detail::frame_guard r( ctx, std::move( f ) ); + l(); } template< typename Lambda > void with_privilege( execution_context& ctx, privilege p, Lambda&& l ) { - detail::privilege_guard r( ctx, p ); - l(); + detail::privilege_guard r( ctx, p ); + l(); } -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/host_api.hpp b/include/koinos/chain/host_api.hpp index 750f8f24..37d96414 100644 --- a/include/koinos/chain/host_api.hpp +++ b/include/koinos/chain/host_api.hpp @@ -7,19 +7,30 @@ namespace koinos::chain { -class host_api final : public vm_manager::abstract_host_api +class host_api final: public vm_manager::abstract_host_api { - public: - host_api( execution_context& ctx ); - virtual ~host_api() override; +public: + host_api( execution_context& ctx ); + virtual ~host_api() override; - execution_context& _ctx; + execution_context& _ctx; - void call( uint32_t sid, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written ); - virtual int32_t invoke_thunk( uint32_t tid, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written ) override; - virtual int32_t invoke_system_call( uint32_t sid, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written ) override; - virtual int64_t get_meter_ticks() const override; - virtual void use_meter_ticks( uint64_t meter_ticks ) override; + void + call( uint32_t sid, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written ); + virtual int32_t invoke_thunk( uint32_t tid, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) override; + virtual int32_t invoke_system_call( uint32_t sid, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) override; + virtual int64_t get_meter_ticks() const override; + virtual void use_meter_ticks( uint64_t meter_ticks ) override; }; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/indexer.hpp b/include/koinos/chain/indexer.hpp index be476664..9747c8be 100644 --- a/include/koinos/chain/indexer.hpp +++ b/include/koinos/chain/indexer.hpp @@ -18,35 +18,35 @@ namespace koinos::chain { class indexer final { public: - indexer( boost::asio::io_context& ioc, controller& c, std::shared_ptr< mq::client > mc ); + indexer( boost::asio::io_context& ioc, controller& c, std::shared_ptr< mq::client > mc ); - std::future< bool > index(); + std::future< bool > index(); private: - void prepare_index(); - void send_requests( uint64_t last_height, uint64_t batch_size ); - void process_requests( uint64_t last_height, uint64_t batch_size ); - void process_block(); + void prepare_index(); + void send_requests( uint64_t last_height, uint64_t batch_size ); + void process_requests( uint64_t last_height, uint64_t batch_size ); + void process_block(); - void handle_error( const std::string& msg ); + void handle_error( const std::string& msg ); - boost::asio::io_context& _ioc; - controller& _controller; - std::shared_ptr< mq::client > _client; - boost::asio::signal_set _signals; - std::atomic_bool _stopped = false; + boost::asio::io_context& _ioc; + controller& _controller; + std::shared_ptr< mq::client > _client; + boost::asio::signal_set _signals; + std::atomic_bool _stopped = false; - boost::concurrent::sync_queue< std::shared_future< std::string > > _request_queue; - std::atomic< bool > _requests_complete = false; - std::atomic< bool > _request_processing_complete = false; + boost::concurrent::sync_queue< std::shared_future< std::string > > _request_queue; + std::atomic< bool > _requests_complete = false; + std::atomic< bool > _request_processing_complete = false; - boost::concurrent::sync_queue< protocol::block > _block_queue; + boost::concurrent::sync_queue< protocol::block > _block_queue; - block_topology _target_head; - rpc::chain::get_head_info_response _start_head_info; - const std::chrono::time_point< std::chrono::system_clock > _start_time = std::chrono::system_clock::now(); + block_topology _target_head; + rpc::chain::get_head_info_response _start_head_info; + const std::chrono::time_point< std::chrono::system_clock > _start_time = std::chrono::system_clock::now(); - std::optional< std::promise< bool > > _complete = std::promise< bool >(); + std::optional< std::promise< bool > > _complete = std::promise< bool >(); }; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/proto_utils.hpp b/include/koinos/chain/proto_utils.hpp index 5107e58e..ecc3f526 100644 --- a/include/koinos/chain/proto_utils.hpp +++ b/include/koinos/chain/proto_utils.hpp @@ -9,18 +9,18 @@ namespace koinos::chain { -value_type get_nested_field_value( execution_context& context, const google::protobuf::Message& parent_message, std::string field_name ); +value_type get_nested_field_value( execution_context& context, + const google::protobuf::Message& parent_message, + std::string field_name ); -value_type get_field_value( - const google::protobuf::Reflection* reflection, - const google::protobuf::Message& message, - const google::protobuf::FieldDescriptor* field_descriptor, - google::protobuf::FieldDescriptor::Type type ); +value_type get_field_value( const google::protobuf::Reflection* reflection, + const google::protobuf::Message& message, + const google::protobuf::FieldDescriptor* field_descriptor, + google::protobuf::FieldDescriptor::Type type ); -value_type get_repeated_field_value( - const google::protobuf::Reflection* reflection, - const google::protobuf::Message& message, - const google::protobuf::FieldDescriptor* field_descriptor, - google::protobuf::FieldDescriptor::Type type ); +value_type get_repeated_field_value( const google::protobuf::Reflection* reflection, + const google::protobuf::Message& message, + const google::protobuf::FieldDescriptor* field_descriptor, + google::protobuf::FieldDescriptor::Type type ); -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/resource_meter.hpp b/include/koinos/chain/resource_meter.hpp index d00cd8e2..b647a1b4 100644 --- a/include/koinos/chain/resource_meter.hpp +++ b/include/koinos/chain/resource_meter.hpp @@ -7,54 +7,53 @@ namespace koinos::chain { namespace compute_load { - constexpr uint64_t light = 100; - constexpr uint64_t medium = 1000; - constexpr uint64_t heavy = 10000; -} +constexpr uint64_t light = 100; +constexpr uint64_t medium = 1'000; +constexpr uint64_t heavy = 10'000; +} // namespace compute_load struct abstract_rc_session { - virtual void use_rc( int64_t rc ) = 0; - virtual uint64_t remaining_rc() = 0; - virtual uint64_t used_rc() = 0; + virtual void use_rc( int64_t rc ) = 0; + virtual uint64_t remaining_rc() = 0; + virtual uint64_t used_rc() = 0; }; class resource_meter final { public: - resource_meter(); - ~resource_meter(); + resource_meter(); + ~resource_meter(); - void set_resource_limit_data( const resource_limit_data& rld ); - const resource_limit_data& get_resource_limit_data() const; + void set_resource_limit_data( const resource_limit_data& rld ); + const resource_limit_data& get_resource_limit_data() const; - void set_session( std::shared_ptr< abstract_rc_session > s ); + void set_session( std::shared_ptr< abstract_rc_session > s ); - void use_disk_storage( int64_t bytes ); - uint64_t disk_storage_used() const; - uint64_t disk_storage_remaining() const; - uint64_t system_disk_storage_used() const; + void use_disk_storage( int64_t bytes ); + uint64_t disk_storage_used() const; + uint64_t disk_storage_remaining() const; + uint64_t system_disk_storage_used() const; - void use_network_bandwidth( int64_t bytes ); - uint64_t network_bandwidth_used() const; - uint64_t network_bandwidth_remaining() const; - uint64_t system_network_bandwidth_used() const; + void use_network_bandwidth( int64_t bytes ); + uint64_t network_bandwidth_used() const; + uint64_t network_bandwidth_remaining() const; + uint64_t system_network_bandwidth_used() const; - void use_compute_bandwidth( int64_t ticks ); - uint64_t compute_bandwidth_used() const; - uint64_t compute_bandwidth_remaining() const; - uint64_t system_compute_bandwidth_used() const; + void use_compute_bandwidth( int64_t ticks ); + uint64_t compute_bandwidth_used() const; + uint64_t compute_bandwidth_remaining() const; + uint64_t system_compute_bandwidth_used() const; private: - - uint64_t _disk_storage_remaining = 0; - int64_t _system_disk_storage_used = 0; - uint64_t _network_bandwidth_remaining = 0; - int64_t _system_network_bandwidth_used = 0; - uint64_t _compute_bandwidth_remaining = 0; - int64_t _system_compute_bandwidth_used = 0; - resource_limit_data _resource_limit_data; - std::weak_ptr< abstract_rc_session > _session; + uint64_t _disk_storage_remaining = 0; + int64_t _system_disk_storage_used = 0; + uint64_t _network_bandwidth_remaining = 0; + int64_t _system_network_bandwidth_used = 0; + uint64_t _compute_bandwidth_remaining = 0; + int64_t _system_compute_bandwidth_used = 0; + resource_limit_data _resource_limit_data; + std::weak_ptr< abstract_rc_session > _session; }; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/session.hpp b/include/koinos/chain/session.hpp index 4608d33a..6309fc89 100644 --- a/include/koinos/chain/session.hpp +++ b/include/koinos/chain/session.hpp @@ -1,33 +1,34 @@ #pragma once -#include #include +#include #include #include namespace koinos::chain { -class session final : public abstract_rc_session, public abstract_chronicler_session +class session final: public abstract_rc_session, + public abstract_chronicler_session { public: - session( int64_t begin_rc ); - ~session(); + session( int64_t begin_rc ); + ~session(); - virtual void use_rc( int64_t rc ) override; - virtual uint64_t remaining_rc() override; - virtual uint64_t used_rc() override; - virtual void push_event( const protocol::event_data& ev ) override; - virtual const std::vector< protocol::event_data >& events() override; + virtual void use_rc( int64_t rc ) override; + virtual uint64_t remaining_rc() override; + virtual uint64_t used_rc() override; + virtual void push_event( const protocol::event_data& ev ) override; + virtual const std::vector< protocol::event_data >& events() override; - virtual void push_log( const std::string& log ) override; - virtual const std::vector< std::string >& logs() override; + virtual void push_log( const std::string& log ) override; + virtual const std::vector< std::string >& logs() override; private: - int64_t _begin_rc; - int64_t _end_rc; - std::vector< protocol::event_data > _events; - std::vector< std::string > _logs; + int64_t _begin_rc; + int64_t _end_rc; + std::vector< protocol::event_data > _events; + std::vector< std::string > _logs; }; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/state.hpp b/include/koinos/chain/state.hpp index 4a0581f4..f3485a83 100644 --- a/include/koinos/chain/state.hpp +++ b/include/koinos/chain/state.hpp @@ -3,24 +3,22 @@ #include #include -#include #include +#include #include -#include #include +#include #include #include -namespace koinos::chain { - -namespace state { +namespace koinos::chain { namespace state { namespace zone { const auto kernel = std::string{}; -} // zone +} // namespace zone namespace space { @@ -30,32 +28,38 @@ const object_space system_call_dispatch(); const object_space metadata(); const object_space transaction_nonce(); -} // space +} // namespace space namespace key { -const auto head_block = util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::head_block" ) ) ); -const auto chain_id = util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::chain_id" ) ) ); -const auto genesis_key = util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::genesis_key" ) ) ); -const auto resource_limit_data = util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::resource_limit_data" ) ) ); -const auto max_account_resources = util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::max_account_resources" ) ) ); -const auto protocol_descriptor = util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::protocol_descriptor" ) ) ); -const auto compute_bandwidth_registry = util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::compute_bandwidth_registry" ) ) ); -const auto block_hash_code = util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::block_hash_code" ) ) ); - -} // key +const auto head_block = util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::head_block" ) ) ); +const auto chain_id = util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::chain_id" ) ) ); +const auto genesis_key = util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::genesis_key" ) ) ); +const auto resource_limit_data = util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::resource_limit_data" ) ) ); +const auto max_account_resources = util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::max_account_resources" ) ) ); +const auto protocol_descriptor = util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::protocol_descriptor" ) ) ); +const auto compute_bandwidth_registry = util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::compute_bandwidth_registry" ) ) ); +const auto block_hash_code = util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, std::string( "object_key::block_hash_code" ) ) ); + +} // namespace key namespace system_call_dispatch { // Size for buffer when fetching system call from database -> 1 for variant, 20 for contract_id, 4 for entry_point constexpr uint32_t max_object_size = 512; -} // system_call_dispatch +} // namespace system_call_dispatch -constexpr uint32_t max_object_size = 1024 * 1024; // 1 MB +constexpr uint32_t max_object_size = 1'024 * 1'024; // 1 MB void assert_permissions( execution_context& context, const object_space& space ); -} // state - -} // koinos::chain +}} // namespace koinos::chain::state diff --git a/include/koinos/chain/system_calls.hpp b/include/koinos/chain/system_calls.hpp index f8b4e9dc..dce443dc 100644 --- a/include/koinos/chain/system_calls.hpp +++ b/include/koinos/chain/system_calls.hpp @@ -9,8 +9,8 @@ #include #include -#include #include +#include #include #include @@ -53,7 +53,7 @@ namespace thunk { void _nop( execution_context& ); -} // thunk +} // namespace thunk // General Blockchain Management @@ -72,14 +72,21 @@ THUNK_DECLARE_VOID( get_chain_id_result, get_chain_id ); // System Helpers -THUNK_DECLARE( process_block_signature_result, process_block_signature, const std::string& digest, const protocol::block_header& header, const std::string& signature_data ); +THUNK_DECLARE( process_block_signature_result, + process_block_signature, + const std::string& digest, + const protocol::block_header& header, + const std::string& signature_data ); THUNK_DECLARE_VOID( get_transaction_result, get_transaction ); THUNK_DECLARE( get_transaction_field_result, get_transaction_field, const std::string& field ); THUNK_DECLARE_VOID( get_block_result, get_block ); THUNK_DECLARE( get_block_field_result, get_block_field, const std::string& field ); THUNK_DECLARE_VOID( get_last_irreversible_block_result, get_last_irreversible_block ); THUNK_DECLARE( get_account_nonce_result, get_account_nonce, const std::string& account ); -THUNK_DECLARE( verify_account_nonce_result, verify_account_nonce, const std::string& account, const std::string& nonce ); +THUNK_DECLARE( verify_account_nonce_result, + verify_account_nonce, + const std::string& account, + const std::string& nonce ); THUNK_DECLARE( void, set_account_nonce, const std::string& account, const std::string& nonce ); THUNK_DECLARE_VOID( check_system_authority_result, check_system_authority ); THUNK_DECLARE_VOID( get_operation_result, get_operation ); @@ -89,7 +96,11 @@ THUNK_DECLARE_VOID( get_operation_result, get_operation ); THUNK_DECLARE( get_account_rc_result, get_account_rc, const std::string& account ); THUNK_DECLARE( consume_account_rc_result, consume_account_rc, const std::string& account, uint64_t rc ); THUNK_DECLARE_VOID( get_resource_limits_result, get_resource_limits ); -THUNK_DECLARE( consume_block_resources_result, consume_block_resources, uint64_t disk, uint64_t network, uint64_t compute ); +THUNK_DECLARE( consume_block_resources_result, + consume_block_resources, + uint64_t disk, + uint64_t network, + uint64_t compute ); // Database @@ -102,15 +113,39 @@ THUNK_DECLARE( get_prev_object_result, get_prev_object, const object_space& spac // Logging THUNK_DECLARE( void, log, const std::string& msg ); -THUNK_DECLARE( void, event, const std::string& name, const std::string& data, const std::vector< std::string >& impacted ); +THUNK_DECLARE( void, + event, + const std::string& name, + const std::string& data, + const std::vector< std::string >& impacted ); // Cryptography THUNK_DECLARE( hash_result, hash, uint64_t code, const std::string& obj, uint64_t size = 0 ); -THUNK_DECLARE( recover_public_key_result, recover_public_key, dsa type, const std::string& signature_data, const std::string& digest, bool compressed ); -THUNK_DECLARE( verify_merkle_root_result, verify_merkle_root, const std::string& root, const std::vector< std::string >& hashes ); -THUNK_DECLARE( verify_signature_result, verify_signature, dsa type, const std::string& public_key, const std::string& signature, const std::string& digest, bool compressed ); -THUNK_DECLARE( verify_vrf_proof_result, verify_vrf_proof, dsa type, const std::string& public_key, const std::string& proof, const std::string& hash, const std::string& message ); +THUNK_DECLARE( recover_public_key_result, + recover_public_key, + dsa type, + const std::string& signature_data, + const std::string& digest, + bool compressed ); +THUNK_DECLARE( verify_merkle_root_result, + verify_merkle_root, + const std::string& root, + const std::vector< std::string >& hashes ); +THUNK_DECLARE( verify_signature_result, + verify_signature, + dsa type, + const std::string& public_key, + const std::string& signature, + const std::string& digest, + bool compressed ); +THUNK_DECLARE( verify_vrf_proof_result, + verify_vrf_proof, + dsa type, + const std::string& public_key, + const std::string& proof, + const std::string& hash, + const std::string& message ); // Contract Management @@ -119,13 +154,17 @@ THUNK_DECLARE( void, exit, int32_t code, result res ); THUNK_DECLARE_VOID( get_arguments_result, get_arguments ); THUNK_DECLARE_VOID( get_contract_id_result, get_contract_id ); THUNK_DECLARE_VOID( get_caller_result, get_caller ); -THUNK_DECLARE( check_authority_result, check_authority, authorization_type type, const std::string& account, const std::string& data ); +THUNK_DECLARE( check_authority_result, + check_authority, + authorization_type type, + const std::string& account, + const std::string& data ); namespace system_call { - inline bool check_authority( execution_context& context, authorization_type type, const std::string& account ) - { - return check_authority( context, type, account, "" ); - } +inline bool check_authority( execution_context& context, authorization_type type, const std::string& account ) +{ + return check_authority( context, type, account, "" ); } +} // namespace system_call -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/thunk_dispatcher.hpp b/include/koinos/chain/thunk_dispatcher.hpp index 9c5d7190..4a29d3b8 100644 --- a/include/koinos/chain/thunk_dispatcher.hpp +++ b/include/koinos/chain/thunk_dispatcher.hpp @@ -1,11 +1,11 @@ #pragma once -#include #include +#include #include -#include #include +#include #include #include @@ -15,277 +15,325 @@ namespace koinos::chain { -namespace detail +namespace detail { +template< typename T, typename Lambda > +std::enable_if_t< std::is_same_v< decltype( std::declval< Lambda >()( std::declval< int >() ) ), T >, void > +iterate_repeated_field( const google::protobuf::Message& msg, + const google::protobuf::FieldDescriptor* fd, + std::vector< T >& v, + Lambda&& l ) { - template< typename T, typename Lambda > - std::enable_if_t< std::is_same_v< decltype( std::declval< Lambda >()( std::declval< int >() ) ), T >, void > - iterate_repeated_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, std::vector< T >& v, Lambda&& l ) - { - auto ref = msg.GetReflection(); - for( int i = 0; i < ref->FieldSize( msg, fd ); i++ ) - { - v.emplace_back( l( i ) ); - } - } - - template< typename T, typename Lambda > - std::enable_if_t< !std::is_same_v< decltype( std::declval< Lambda >()( std::declval< int >() ) ), T >, void > - iterate_repeated_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, std::vector< T >& v, Lambda&& l ) {} - - template< typename T > - std::enable_if_t< std::is_base_of_v< google::protobuf::Message, T >, void > - copy_from( const google::protobuf::Message& m, T& t ) - { - t.CopyFrom( m ); - } + auto ref = msg.GetReflection(); + for( int i = 0; i < ref->FieldSize( msg, fd ); i++ ) + { + v.emplace_back( l( i ) ); + } +} + +template< typename T, typename Lambda > +std::enable_if_t< !std::is_same_v< decltype( std::declval< Lambda >()( std::declval< int >() ) ), T >, void > +iterate_repeated_field( const google::protobuf::Message& msg, + const google::protobuf::FieldDescriptor* fd, + std::vector< T >& v, + Lambda&& l ) +{} + +template< typename T > +std::enable_if_t< std::is_base_of_v< google::protobuf::Message, T >, void > +copy_from( const google::protobuf::Message& m, T& t ) +{ + t.CopyFrom( m ); +} - template< typename T > - std::enable_if_t< !std::is_base_of_v< google::protobuf::Message, T >, void > - copy_from( const google::protobuf::Message& m, T& t ) {} +template< typename T > +std::enable_if_t< !std::is_base_of_v< google::protobuf::Message, T >, void > +copy_from( const google::protobuf::Message& m, T& t ) +{} - inline std::any get_type_from_field_impl( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd ) - { - auto ref = msg.GetReflection(); - std::any field; +inline std::any get_type_from_field_impl( const google::protobuf::Message& msg, + const google::protobuf::FieldDescriptor* fd ) +{ + auto ref = msg.GetReflection(); + std::any field; + + switch( fd->cpp_type() ) + { + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT64: + field = ref->GetInt64( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT64: + field = ref->GetUInt64( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32: + field = ref->GetInt32( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT32: + field = ref->GetUInt32( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_BOOL: + field = ref->GetBool( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING: + field = ref->GetString( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_MESSAGE: + field = &ref->GetMessage( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_ENUM: + field = ref->GetEnumValue( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_FLOAT: + field = ref->GetFloat( msg, fd ); + break; + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_DOUBLE: + field = ref->GetDouble( msg, fd ); + break; + default: + assert( "Type not handled for thunk args." ); + } + + return field; +} + +// Parses through a repeated field and puts values in a vector. +template< typename T > +std::any get_type_from_repeated_field( const google::protobuf::Message& msg, + const google::protobuf::FieldDescriptor* fd ) +{ + auto ref = msg.GetReflection(); + std::any field; - switch( fd->cpp_type() ) + switch( fd->cpp_type() ) + { + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT64: { - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT64: - field = ref->GetInt64( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT64: - field = ref->GetUInt64( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32: - field = ref->GetInt32( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT32: - field = ref->GetUInt32( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_BOOL: - field = ref->GetBool( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING: - field = ref->GetString( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_MESSAGE: - field = &ref->GetMessage( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_ENUM: - field = ref->GetEnumValue( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_FLOAT: - field = ref->GetFloat( msg, fd ); - break; - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_DOUBLE: - field = ref->GetDouble( msg, fd ); - break; - default: - assert( "Type not handled for thunk args." ); + std::vector< int64_t > v; + iterate_repeated_field( msg, + fd, + v, + [ & ]( int i ) + { + return ref->GetRepeatedInt64( msg, fd, i ); + } ); + field = std::move( v ); + break; } + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT64: + { + std::vector< uint64_t > v; + iterate_repeated_field( msg, + fd, + v, + [ & ]( int i ) + { + return ref->GetRepeatedUInt64( msg, fd, i ); + } ); + field = std::move( v ); + break; + } + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32: + { + std::vector< int32_t > v; + iterate_repeated_field( msg, + fd, + v, + [ & ]( int i ) + { + return ref->GetRepeatedInt32( msg, fd, i ); + } ); + field = std::move( v ); + break; + } + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT32: + { + std::vector< uint32_t > v; + iterate_repeated_field( msg, + fd, + v, + [ & ]( int i ) + { + return ref->GetRepeatedUInt32( msg, fd, i ); + } ); + field = std::move( v ); + break; + } + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_BOOL: + { + std::vector< bool > v; + iterate_repeated_field( msg, + fd, + v, + [ & ]( int i ) + { + return ref->GetRepeatedBool( msg, fd, i ); + } ); + field = std::move( v ); + break; + } + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING: + { + std::vector< std::string > v; + iterate_repeated_field( msg, + fd, + v, + [ & ]( int i ) + { + return ref->GetRepeatedString( msg, fd, i ); + } ); + field = std::move( v ); + break; + } + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_MESSAGE: + { + std::vector< T > v; + iterate_repeated_field( msg, + fd, + v, + [ & ]( int i ) + { + T t; + copy_from( ref->GetRepeatedMessage( msg, fd, i ), t ); + return t; + } ); + field = std::move( v ); + break; + } + case google::protobuf::FieldDescriptor::CppType::CPPTYPE_ENUM: + { + std::vector< int > v; + iterate_repeated_field( msg, + fd, + v, + [ & ]( int i ) + { + return ref->GetRepeatedEnum( msg, fd, i ); + } ); + field = std::move( v ); + break; + } + default: + assert( "Type not handled for thunk args." ); + } + + return field; +} + +// Overload to capture when field is repeated (vector) +template< typename T > +void get_type_from_field( const google::protobuf::Message& msg, + const google::protobuf::FieldDescriptor* fd, + std::vector< T >& v ) +{ + v = std::any_cast< std::vector< T > >( get_type_from_repeated_field< T >( msg, fd ) ); +} - return field; - } +// Overload to capture when field is a Message +template< typename T > +std::enable_if_t< std::is_base_of_v< google::protobuf::Message, T >, void > +get_type_from_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, T& t ) +{ + auto ptr = std::any_cast< const google::protobuf::Message* >( get_type_from_field_impl( msg, fd ) ); + t.CopyFrom( *ptr ); +} + +// Overload to capture when field is an Enum +template< typename T > +std::enable_if_t< !std::is_base_of_v< google::protobuf::Message, T > && std::is_enum_v< T >, void > +get_type_from_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, T& t ) +{ + t = T( std::any_cast< std::underlying_type_t< T > >( get_type_from_field_impl( msg, fd ) ) ); +} - // Parses through a repeated field and puts values in a vector. - template< typename T > - std::any get_type_from_repeated_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd ) - { - auto ref = msg.GetReflection(); - std::any field; +// Overload to capture when field is neither +template< typename T > +std::enable_if_t< !std::is_base_of_v< google::protobuf::Message, T > && !std::is_enum_v< T >, void > +get_type_from_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, T& t ) +{ + t = std::any_cast< T >( get_type_from_field_impl( msg, fd ) ); +} + +// Variadic recusrive template to convert fields of a message in to a tuple +// Arg type information is assumed to match the fields of the corresponding Message +// Each call strips off the next argument (T), parses it with get_type_from_field, +// adds it to the tuple and recusively calls with the remaining arguments (Ts). +// The base case is when there are no more fields remaining (Ts is empty). +template< typename T, typename... Ts > +std::tuple< T, Ts... > message_to_tuple_impl( const google::protobuf::Message& msg ) +{ + // Get our type + constexpr std::size_t fields_remaining = sizeof...( Ts ); + auto desc = msg.GetDescriptor(); + auto fd = desc->FindFieldByNumber( desc->field_count() - fields_remaining ); + T t; + get_type_from_field( msg, fd, t ); + + if constexpr( fields_remaining > 0 ) + return std::tuple_cat( std::tuple< T >( std::move( t ) ), message_to_tuple_impl< Ts... >( msg ) ); + else + return std::tuple< T >( std::move( t ) ); +} + +template< typename... Ts > +std::tuple< std::decay_t< Ts >... > message_to_tuple( const google::protobuf::Message& msg ) +{ + return message_to_tuple_impl< std::decay_t< Ts >... >( msg ); +} - switch( fd->cpp_type() ) - { - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT64: - { - std::vector< int64_t > v; - iterate_repeated_field( msg, fd, v, [&]( int i ) - { - return ref->GetRepeatedInt64( msg, fd, i ); - } ); - field = std::move( v ); - break; - } - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT64: - { - std::vector< uint64_t > v; - iterate_repeated_field( msg, fd, v, [&]( int i ) - { - return ref->GetRepeatedUInt64( msg, fd, i ); - } ); - field = std::move( v ); - break; - } - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32: - { - std::vector< int32_t > v; - iterate_repeated_field( msg, fd, v, [&]( int i ) - { - return ref->GetRepeatedInt32( msg, fd, i ); - } ); - field = std::move( v ); - break; - } - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT32: - { - std::vector< uint32_t > v; - iterate_repeated_field( msg, fd, v, [&]( int i ) - { - return ref->GetRepeatedUInt32( msg, fd, i ); - } ); - field = std::move( v ); - break; - } - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_BOOL: - { - std::vector< bool > v; - iterate_repeated_field( msg, fd, v, [&]( int i ) - { - return ref->GetRepeatedBool( msg, fd, i ); - } ); - field = std::move( v ); - break; - } - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING: - { - std::vector< std::string > v; - iterate_repeated_field( msg, fd, v, [&]( int i ) - { - return ref->GetRepeatedString( msg, fd, i ); - } ); - field = std::move( v ); - break; - } - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_MESSAGE: - { - std::vector< T > v; - iterate_repeated_field( msg, fd, v, [&]( int i ) - { - T t; - copy_from( ref->GetRepeatedMessage( msg, fd, i ), t ); - return t; - } ); - field = std::move( v ); - break; - } - case google::protobuf::FieldDescriptor::CppType::CPPTYPE_ENUM: - { - std::vector< int > v; - iterate_repeated_field( msg, fd, v, [&]( int i ) - { - return ref->GetRepeatedEnum( msg, fd, i ); - } ); - field = std::move( v ); - break; - } - default: - assert( "Type not handled for thunk args." ); - } +template<> +inline std::tuple<> message_to_tuple<>( const google::protobuf::Message& ) +{ + return std::tuple<>(); +} + +/* + * std::apply takes a function and a tuple and calls the function with the contents of the tuple + * as the arguments. The only "trick" here is converting a reflected object in to an equivalent + * tuple. That is handled as part of the reflection macro to generate the needed code. We cat a + * tuple containing just the apply context as the first argument and then call in to the thunk. + * + * Two versions exist of the function, one that serializes the return value and one that does not. + */ +template< typename ArgStruct, typename RetStruct, typename ThunkReturn, typename... ThunkArgs > +typename std::enable_if< std::is_same< ThunkReturn, void >::value, void >::type +call_thunk_impl( const std::function< ThunkReturn( execution_context&, ThunkArgs... ) >& thunk, + execution_context& ctx, + char* ret_ptr, + uint32_t ret_len, + ArgStruct& arg, + uint32_t* bytes_written ) +{ + auto thunk_args = std::tuple_cat( std::tuple< execution_context& >( ctx ), message_to_tuple< ThunkArgs... >( arg ) ); + *bytes_written = 0; + + std::apply( thunk, thunk_args ); +} + +template< typename ArgStruct, typename RetStruct, typename ThunkReturn, typename... ThunkArgs > +typename std::enable_if< !std::is_same< ThunkReturn, void >::value, void >::type +call_thunk_impl( const std::function< ThunkReturn( execution_context&, ThunkArgs... ) >& thunk, + execution_context& ctx, + char* ret_ptr, + uint32_t ret_len, + ArgStruct& arg, + uint32_t* bytes_written ) +{ + static_assert( std::is_same< RetStruct, ThunkReturn >::value, + "thunk return does not match defined return in koinos-proto" ); + auto thunk_args = std::tuple_cat( std::tuple< execution_context& >( ctx ), message_to_tuple< ThunkArgs... >( arg ) ); + ThunkReturn ret; + + ret = std::apply( thunk, thunk_args ); + + std::size_t byte_size = ret.ByteSizeLong(); + KOINOS_ASSERT( byte_size <= ret_len, + insufficient_return_buffer_exception, + "return buffer is not large enough for the return value" ); - return field; - } - - // Overload to capture when field is repeated (vector) - template< typename T > - void get_type_from_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, std::vector< T >& v ) - { - v = std::any_cast< std::vector< T > >( get_type_from_repeated_field< T >( msg, fd ) ); - } - - // Overload to capture when field is a Message - template< typename T > - std::enable_if_t< std::is_base_of_v< google::protobuf::Message, T >, void > - get_type_from_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, T& t ) - { - auto ptr = std::any_cast< const google::protobuf::Message* >( get_type_from_field_impl( msg, fd ) ); - t.CopyFrom( *ptr ); - } - - // Overload to capture when field is an Enum - template< typename T > - std::enable_if_t< !std::is_base_of_v< google::protobuf::Message, T > && std::is_enum_v< T >, void > - get_type_from_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, T& t ) - { - t = T( std::any_cast< std::underlying_type_t< T > >( get_type_from_field_impl( msg, fd ) ) ); - } - - // Overload to capture when field is neither - template< typename T > - std::enable_if_t< !std::is_base_of_v< google::protobuf::Message, T > && !std::is_enum_v< T >, void > - get_type_from_field( const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, T& t ) - { - t = std::any_cast< T >( get_type_from_field_impl( msg, fd ) ); - } - - // Variadic recusrive template to convert fields of a message in to a tuple - // Arg type information is assumed to match the fields of the corresponding Message - // Each call strips off the next argument (T), parses it with get_type_from_field, - // adds it to the tuple and recusively calls with the remaining arguments (Ts). - // The base case is when there are no more fields remaining (Ts is empty). - template< typename T, typename... Ts > - std::tuple< T, Ts... > message_to_tuple_impl( const google::protobuf::Message& msg ) - { - // Get our type - constexpr std::size_t fields_remaining = sizeof...( Ts ); - auto desc = msg.GetDescriptor(); - auto fd = desc->FindFieldByNumber( desc->field_count() - fields_remaining ); - T t; - get_type_from_field( msg, fd, t ); - - if constexpr ( fields_remaining > 0 ) - return std::tuple_cat( std::tuple< T >( std::move( t ) ), message_to_tuple_impl< Ts... >( msg ) ); - else - return std::tuple< T >( std::move( t ) ); - } - - template< typename... Ts > - std::tuple< std::decay_t< Ts >... > message_to_tuple( const google::protobuf::Message& msg ) - { - return message_to_tuple_impl< std::decay_t< Ts >... >( msg ); - } - - template<> - inline std::tuple<> message_to_tuple<>( const google::protobuf::Message& ) - { - return std::tuple<>(); - } - - /* - * std::apply takes a function and a tuple and calls the function with the contents of the tuple - * as the arguments. The only "trick" here is converting a reflected object in to an equivalent - * tuple. That is handled as part of the reflection macro to generate the needed code. We cat a - * tuple containing just the apply context as the first argument and then call in to the thunk. - * - * Two versions exist of the function, one that serializes the return value and one that does not. - */ - template< typename ArgStruct, typename RetStruct, typename ThunkReturn, typename... ThunkArgs > - typename std::enable_if< std::is_same< ThunkReturn, void >::value, void >::type - call_thunk_impl( const std::function< ThunkReturn(execution_context&, ThunkArgs...) >& thunk, execution_context& ctx, char* ret_ptr, uint32_t ret_len, ArgStruct& arg, uint32_t* bytes_written ) - { - auto thunk_args = std::tuple_cat( std::tuple< execution_context& >( ctx ), message_to_tuple< ThunkArgs... >( arg ) ); - *bytes_written = 0; - - std::apply( thunk, thunk_args ); - } - - template< typename ArgStruct, typename RetStruct, typename ThunkReturn, typename... ThunkArgs > - typename std::enable_if< !std::is_same< ThunkReturn, void >::value, void >::type - call_thunk_impl( const std::function< ThunkReturn(execution_context&, ThunkArgs...) >& thunk, execution_context& ctx, char* ret_ptr, uint32_t ret_len, ArgStruct& arg, uint32_t* bytes_written ) - { - static_assert( std::is_same< RetStruct, ThunkReturn >::value, "thunk return does not match defined return in koinos-proto" ); - auto thunk_args = std::tuple_cat( std::tuple< execution_context& >( ctx ), message_to_tuple< ThunkArgs... >( arg ) ); - ThunkReturn ret; - - ret = std::apply( thunk, thunk_args ); - - std::size_t byte_size = ret.ByteSizeLong(); - KOINOS_ASSERT( byte_size <= ret_len, insufficient_return_buffer_exception, "return buffer is not large enough for the return value" ); - - ret.SerializeToArray( ret_ptr, uint32_t( byte_size ) ); - *bytes_written = uint32_t( byte_size ); - } - -} // detail + ret.SerializeToArray( ret_ptr, uint32_t( byte_size ) ); + *bytes_written = uint32_t( byte_size ); +} + +} // namespace detail /** * A registry for thunks. @@ -305,50 +353,71 @@ namespace detail */ class thunk_dispatcher { - public: - void call_thunk( uint32_t id, execution_context& ctx, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written )const; - - template< typename ThunkReturn, typename... ThunkArgs > - auto call_thunk( uint32_t id, execution_context& ctx, ThunkArgs&... args ) const +public: + void call_thunk( uint32_t id, + execution_context& ctx, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) const; + + template< typename ThunkReturn, typename... ThunkArgs > + auto call_thunk( uint32_t id, execution_context& ctx, ThunkArgs&... args ) const + { + auto it = _pass_through_map.find( id ); + KOINOS_ASSERT( it != _pass_through_map.end(), unknown_thunk_exception, "thunk ${id} not found", ( "id", id ) ); + return std::any_cast< std::function< ThunkReturn( execution_context&, ThunkArgs... ) > >( it->second )( ctx, + args... ); + } + + template< typename ArgStruct, typename RetStruct, typename ThunkReturn, typename... ThunkArgs > + void register_thunk( uint32_t id, ThunkReturn ( *thunk_ptr )( execution_context&, ThunkArgs... ) ) + { + std::function< ThunkReturn( execution_context&, ThunkArgs... ) > thunk = thunk_ptr; + _dispatch_map.insert_or_assign( + id, + [ thunk ]( execution_context& ctx, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) { - auto it = _pass_through_map.find( id ); - KOINOS_ASSERT( it != _pass_through_map.end(), unknown_thunk_exception, "thunk ${id} not found", ("id", id ) ); - return std::any_cast< std::function >(it->second)( ctx, args... ); - } - - template< typename ArgStruct, typename RetStruct, typename ThunkReturn, typename... ThunkArgs > - void register_thunk( uint32_t id, ThunkReturn (*thunk_ptr)(execution_context&, ThunkArgs...) ) - { - std::function thunk = thunk_ptr; - _dispatch_map.insert_or_assign( id, [thunk]( execution_context& ctx, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written ) - { - ArgStruct args; - ctx.resource_meter().use_compute_bandwidth( ctx.get_compute_bandwidth( "deserialize_message_per_byte" ) * arg_len ); - args.ParseFromArray( arg_ptr, arg_len ); - detail::call_thunk_impl< ArgStruct, RetStruct >( thunk, ctx, ret_ptr, ret_len, args, bytes_written ); - }); - _pass_through_map.insert_or_assign( id, thunk ); - } - - template< typename ArgStruct, typename RetStruct, typename ThunkReturn, typename... ThunkArgs > - void register_genesis_thunk( uint32_t id, ThunkReturn (*thunk_ptr)(execution_context&, ThunkArgs...) ) - { - register_thunk< ArgStruct, RetStruct, ThunkReturn, ThunkArgs... >( id, thunk_ptr ); - _genesis_thunks.insert( id ); - } - - bool thunk_exists( uint32_t id ) const; - bool thunk_is_genesis( uint32_t ) const; - static const thunk_dispatcher& instance(); - - private: - thunk_dispatcher(); - - typedef std::function< void(execution_context&, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written) > generic_thunk_handler; - - std::map< int32_t, generic_thunk_handler > _dispatch_map; - std::map< int32_t, std::any > _pass_through_map; - std::set< uint32_t > _genesis_thunks; + ArgStruct args; + ctx.resource_meter().use_compute_bandwidth( ctx.get_compute_bandwidth( "deserialize_message_per_byte" ) + * arg_len ); + args.ParseFromArray( arg_ptr, arg_len ); + detail::call_thunk_impl< ArgStruct, RetStruct >( thunk, ctx, ret_ptr, ret_len, args, bytes_written ); + } ); + _pass_through_map.insert_or_assign( id, thunk ); + } + + template< typename ArgStruct, typename RetStruct, typename ThunkReturn, typename... ThunkArgs > + void register_genesis_thunk( uint32_t id, ThunkReturn ( *thunk_ptr )( execution_context&, ThunkArgs... ) ) + { + register_thunk< ArgStruct, RetStruct, ThunkReturn, ThunkArgs... >( id, thunk_ptr ); + _genesis_thunks.insert( id ); + } + + bool thunk_exists( uint32_t id ) const; + bool thunk_is_genesis( uint32_t ) const; + static const thunk_dispatcher& instance(); + +private: + thunk_dispatcher(); + + typedef std::function< void( execution_context&, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) > + generic_thunk_handler; + + std::map< int32_t, generic_thunk_handler > _dispatch_map; + std::map< int32_t, std::any > _pass_through_map; + std::set< uint32_t > _genesis_thunks; }; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/chain/thunk_utils.hpp b/include/koinos/chain/thunk_utils.hpp index 0ca1e7c2..f9709ee5 100644 --- a/include/koinos/chain/thunk_utils.hpp +++ b/include/koinos/chain/thunk_utils.hpp @@ -21,294 +21,297 @@ #define _THUNK_ARGS_SUFFIX _arguments #define _THUNK_RET_SUFFIX _result -#define _THUNK_REGISTRATION_GENESIS( r, data, i, elem ) \ -data.register_genesis_thunk( chain::system_call_id::elem, thunk::BOOST_PP_CAT(_, elem) ); - -#define THUNK_REGISTER_GENESIS( dispatcher, args ) \ - BOOST_PP_SEQ_FOR_EACH_I( _THUNK_REGISTRATION_GENESIS, dispatcher, args ) - -#define _THUNK_REGISTRATION( r, data, i, elem ) \ -data.register_thunk( chain::system_call_id::elem, thunk::BOOST_PP_CAT(_, elem) ); - -#define THUNK_REGISTER( dispatcher, args ) \ - BOOST_PP_SEQ_FOR_EACH_I( _THUNK_REGISTRATION, dispatcher, args ) - -#define VA_ARGS(...) , ##__VA_ARGS__ - -#define THUNK_DECLARE(return_type, name, ...) \ - namespace thunk { return_type BOOST_PP_CAT(_, name)( execution_context& VA_ARGS(__VA_ARGS__) ); } \ - namespace system_call { \ - BOOST_PP_IF( \ - _THUNK_IS_VOID(return_type), \ - void, \ - std::remove_reference_t< decltype( std::declval< return_type >().value() ) > \ - ) name( execution_context& VA_ARGS(__VA_ARGS__) ); } - -#define THUNK_DECLARE_VOID(return_type, name) \ - namespace thunk { return_type BOOST_PP_CAT(_, name)( execution_context& ); } \ - namespace system_call { \ - BOOST_PP_IF( \ - _THUNK_IS_VOID(return_type), \ - void, \ - std::remove_reference_t< decltype( std::declval().value() ) > \ - ) name( execution_context& ); } +#define _THUNK_REGISTRATION_GENESIS( r, data, i, elem ) \ + data.register_genesis_thunk< BOOST_PP_CAT( elem, _THUNK_ARGS_SUFFIX ), BOOST_PP_CAT( elem, _THUNK_RET_SUFFIX ) >( \ + chain::system_call_id::elem, \ + thunk::BOOST_PP_CAT( _, elem ) ); + +#define THUNK_REGISTER_GENESIS( dispatcher, args ) \ + BOOST_PP_SEQ_FOR_EACH_I( _THUNK_REGISTRATION_GENESIS, dispatcher, args ) + +#define _THUNK_REGISTRATION( r, data, i, elem ) \ + data.register_thunk< BOOST_PP_CAT( elem, _THUNK_ARGS_SUFFIX ), BOOST_PP_CAT( elem, _THUNK_RET_SUFFIX ) >( \ + chain::system_call_id::elem, \ + thunk::BOOST_PP_CAT( _, elem ) ); + +#define THUNK_REGISTER( dispatcher, args ) BOOST_PP_SEQ_FOR_EACH_I( _THUNK_REGISTRATION, dispatcher, args ) + +#define VA_ARGS( ... ) , ##__VA_ARGS__ + +#define THUNK_DECLARE( return_type, name, ... ) \ + namespace thunk { \ + return_type BOOST_PP_CAT( _, name )( execution_context & VA_ARGS( __VA_ARGS__ ) ); \ + } \ + namespace system_call { \ + BOOST_PP_IF( _THUNK_IS_VOID( return_type ), \ + void, \ + std::remove_reference_t< decltype( std::declval< return_type >().value() ) > ) \ + name( execution_context& VA_ARGS( __VA_ARGS__ ) ); \ + } + +#define THUNK_DECLARE_VOID( return_type, name ) \ + namespace thunk { \ + return_type BOOST_PP_CAT( _, name )( execution_context& ); \ + } \ + namespace system_call { \ + BOOST_PP_IF( _THUNK_IS_VOID( return_type ), \ + void, \ + std::remove_reference_t< decltype( std::declval< return_type >().value() ) > ) \ + name( execution_context& ); \ + } #define _THUNK_RET_TYPE_void 1)(1 -#define _THUNK_IS_VOID(type) BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE((BOOST_PP_CAT(_THUNK_RET_TYPE_,type))),2) +#define _THUNK_IS_VOID( type ) BOOST_PP_EQUAL( BOOST_PP_SEQ_SIZE( ( BOOST_PP_CAT( _THUNK_RET_TYPE_, type ) ) ), 2 ) -#define _THUNK_REM(...) __VA_ARGS__ -#define _THUNK_EAT(...) +#define _THUNK_REM( ... ) __VA_ARGS__ +#define _THUNK_EAT( ... ) // Strip off the type -#define _THUNK_STRIP(x) _THUNK_EAT x +#define _THUNK_STRIP( x ) _THUNK_EAT x // Show the type without parenthesis -#define _THUNK_PAIR(x) _THUNK_REM x +#define _THUNK_PAIR( x ) _THUNK_REM x // Strip off the variable -#define _THUNK_TYPE(x) BOOST_PP_SEQ_ELEM(0, x) +#define _THUNK_TYPE( x ) BOOST_PP_SEQ_ELEM( 0, x ) -#define _THUNK_DETAIL_DEFINE_ARGS_EACH(r, data, i, x) BOOST_PP_COMMA_IF(i) _THUNK_PAIR(x) -#define _THUNK_DETAIL_DEFINE_FORWARD_EACH(r, data, i, x) BOOST_PP_COMMA_IF(i) _THUNK_STRIP(x) -#define _THUNK_DETAIL_DEFINE_TYPES_EACH(r, data, i, x) BOOST_PP_COMMA_IF(i) _THUNK_TYPE(x) +#define _THUNK_DETAIL_DEFINE_ARGS_EACH( r, data, i, x ) BOOST_PP_COMMA_IF( i ) _THUNK_PAIR( x ) +#define _THUNK_DETAIL_DEFINE_FORWARD_EACH( r, data, i, x ) BOOST_PP_COMMA_IF( i ) _THUNK_STRIP( x ) +#define _THUNK_DETAIL_DEFINE_TYPES_EACH( r, data, i, x ) BOOST_PP_COMMA_IF( i ) _THUNK_TYPE( x ) -#define _THUNK_DETAIL_DEFINE_ARGS(args) BOOST_PP_SEQ_FOR_EACH_I(_THUNK_DETAIL_DEFINE_ARGS_EACH, data, BOOST_PP_VARIADIC_TO_SEQ args) -#define _THUNK_DETAIL_DEFINE_FORWARD(args) BOOST_PP_SEQ_FOR_EACH_I(_THUNK_DETAIL_DEFINE_FORWARD_EACH, data, BOOST_PP_VARIADIC_TO_SEQ args) -#define _THUNK_DETAIL_DEFINE_TYPES(args) BOOST_PP_SEQ_FOR_EACH_I(_THUNK_DETAIL_DEFINE_TYPES_EACH, data, BOOST_PP_VARIADIC_TO_SEQ args) +#define _THUNK_DETAIL_DEFINE_ARGS( args ) \ + BOOST_PP_SEQ_FOR_EACH_I( _THUNK_DETAIL_DEFINE_ARGS_EACH, data, BOOST_PP_VARIADIC_TO_SEQ args ) +#define _THUNK_DETAIL_DEFINE_FORWARD( args ) \ + BOOST_PP_SEQ_FOR_EACH_I( _THUNK_DETAIL_DEFINE_FORWARD_EACH, data, BOOST_PP_VARIADIC_TO_SEQ args ) +#define _THUNK_DETAIL_DEFINE_TYPES( args ) \ + BOOST_PP_SEQ_FOR_EACH_I( _THUNK_DETAIL_DEFINE_TYPES_EACH, data, BOOST_PP_VARIADIC_TO_SEQ args ) namespace koinos::chain::detail { - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, int64_t value ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - if ( fd->type() == google::protobuf::FieldDescriptor::Type::TYPE_ENUM ) - ref->SetEnumValue( &msg, fd, (int)value ); - else - ref->SetInt64( &msg, fd, value ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, uint64_t value ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - ref->SetUInt64( &msg, fd, value ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, int32_t value ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - if ( fd->type() == google::protobuf::FieldDescriptor::Type::TYPE_ENUM ) - ref->SetEnumValue( &msg, fd, (int)value ); - else - ref->SetInt32( &msg, fd, value ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, uint32_t value ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - ref->SetUInt32( &msg, fd, value ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, bool value ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - ref->SetBool( &msg, fd, value ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::string& value ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - ref->SetString( &msg, fd, value ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const google::protobuf::Message& value ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - auto m = ref->MutableMessage( &msg, fd ); - m->CopyFrom( value ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< uint64_t >& values ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - assert( fd->is_repeated() ); - for( const auto& v : values ) - ref->AddUInt64( &msg, fd, v ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< int64_t >& values ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - assert( fd->is_repeated() ); - for( const auto& v : values ) - ref->AddInt64( &msg, fd, v ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< uint32_t >& values ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - assert( fd->is_repeated() ); - for( const auto& v : values ) - ref->AddUInt32( &msg, fd, v ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< int32_t >& values ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - assert( fd->is_repeated() ); - for( const auto& v : values ) - { - if ( fd->type() == google::protobuf::FieldDescriptor::Type::TYPE_ENUM ) - ref->AddEnumValue( &msg, fd, (int)v ); - else - ref->AddInt32( &msg, fd, v ); - } - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< bool >& values ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - assert( fd->is_repeated() ); - for( const auto& v : values ) - ref->AddBool( &msg, fd, v ); - } - - inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< std::string >& values ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - assert( fd->is_repeated() ); - for( const auto& v : values ) - ref->AddString( &msg, fd, v ); - } - - template< typename T > - std::enable_if_t< std::is_base_of_v< google::protobuf::Message, T >, void > - inline set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< T >& values ) - { - auto desc = msg.GetDescriptor(); - auto ref = msg.GetReflection(); - auto fd = desc->FindFieldByNumber( index ); - assert( fd ); - assert( fd->is_repeated() ); - for( const auto& v : values ) - { - auto m = ref->AddMessage( &msg, fd ); - m->CopyFrom( v ); - } - } +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, int64_t value ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + if( fd->type() == google::protobuf::FieldDescriptor::Type::TYPE_ENUM ) + ref->SetEnumValue( &msg, fd, (int)value ); + else + ref->SetInt64( &msg, fd, value ); } -#define _THUNK_DETAIL_ARG_PACK(r, msg, i, elem) koinos::chain::detail::set_message_field( msg, i + 1, elem ); -#define _THUNK_ARG_PACK( FIRST, ... ) BOOST_PP_LIST_FOR_EACH_I(_THUNK_DETAIL_ARG_PACK, _args, BOOST_PP_TUPLE_TO_LIST((__VA_ARGS__))) - -#define _THUNK_DETAIL_DEFINE( RETURN_TYPE, SYSCALL, ARGS, TYPES, FWD ) \ - } \ - namespace system_call { \ - auto SYSCALL( execution_context& context ARGS ) -> \ - BOOST_PP_IF( \ - _THUNK_IS_VOID(RETURN_TYPE), \ - void, \ - std::remove_reference_t< decltype( std::declval().value() ) > \ - ) \ - { \ - \ - uint32_t _sid = static_cast< uint32_t >( chain::system_call_id::SYSCALL ); \ - \ - BOOST_PP_IF(_THUNK_IS_VOID(RETURN_TYPE),,RETURN_TYPE _ret;) \ - \ - with_stack_frame ( \ - context, \ - stack_frame { \ - .sid = _sid, \ - .call_privilege = privilege::kernel_mode \ - }, \ - [&]() { \ - if ( context.system_call_exists( _sid ) ) \ - { \ - BOOST_PP_CAT( SYSCALL, _THUNK_ARGS_SUFFIX ) _args; \ - BOOST_PP_IF(BOOST_VMD_IS_EMPTY(FWD),,_THUNK_ARG_PACK(FWD)); \ - std::string _arg_str; \ - _args.SerializeToString( &_arg_str ); \ - const auto& _res = context.system_call( _sid, _arg_str ); \ - if ( _res.code ) \ - { \ - if ( _res.code >= chain::reversion ) \ - throw chain::reversion_exception( _res.code, _res.res.error() ); \ - else if ( _res.code <= chain::failure ) \ - throw chain::failure_exception( _res.code, _res.res.error() ); \ - } \ - else if ( _sid == system_call_id::exit ) \ - throw chain::success_exception( _res.code ); \ - BOOST_PP_IF(_THUNK_IS_VOID(RETURN_TYPE),,_ret.ParseFromString( _res.res.object() );) \ - } \ - else \ - { \ - auto _thunk_id = context.thunk_translation( _sid ); \ - auto _desc = chain::system_call_id_descriptor(); \ - auto _enum_value = _desc->FindValueByNumber( _thunk_id ); \ - KOINOS_ASSERT( _enum_value, unknown_thunk_exception, "unrecognized thunk id ${id}", ("id", _thunk_id) ); \ - auto _compute = context.get_compute_bandwidth( _enum_value->name() ); \ - context.resource_meter().use_compute_bandwidth( _compute ); \ - BOOST_PP_IF(_THUNK_IS_VOID(RETURN_TYPE),,_ret =) \ - thunk_dispatcher::instance().call_thunk< \ - RETURN_TYPE \ - TYPES >( \ - _thunk_id, \ - context \ - FWD ); \ - } \ - } \ - ); \ - \ - BOOST_PP_IF(_THUNK_IS_VOID(RETURN_TYPE),,return _ret.value();) \ - } \ - } \ - namespace thunk { \ - RETURN_TYPE BOOST_PP_CAT(_, SYSCALL)( execution_context& context ARGS ) - -#define THUNK_DEFINE( RETURN_TYPE, SYSCALL, ... ) \ - _THUNK_DETAIL_DEFINE( RETURN_TYPE, SYSCALL, \ - VA_ARGS(_THUNK_DETAIL_DEFINE_ARGS(__VA_ARGS__)), \ - VA_ARGS(_THUNK_DETAIL_DEFINE_TYPES(__VA_ARGS__)), \ - VA_ARGS(_THUNK_DETAIL_DEFINE_FORWARD(__VA_ARGS__))) \ - -#define THUNK_DEFINE_VOID( RETURN_TYPE, SYSCALL ) \ - _THUNK_DETAIL_DEFINE( RETURN_TYPE, SYSCALL, , , ) +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, uint64_t value ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + ref->SetUInt64( &msg, fd, value ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, int32_t value ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + if( fd->type() == google::protobuf::FieldDescriptor::Type::TYPE_ENUM ) + ref->SetEnumValue( &msg, fd, (int)value ); + else + ref->SetInt32( &msg, fd, value ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, uint32_t value ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + ref->SetUInt32( &msg, fd, value ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, bool value ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + ref->SetBool( &msg, fd, value ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::string& value ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + ref->SetString( &msg, fd, value ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const google::protobuf::Message& value ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + auto m = ref->MutableMessage( &msg, fd ); + m->CopyFrom( value ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< uint64_t >& values ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + assert( fd->is_repeated() ); + for( const auto& v: values ) + ref->AddUInt64( &msg, fd, v ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< int64_t >& values ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + assert( fd->is_repeated() ); + for( const auto& v: values ) + ref->AddInt64( &msg, fd, v ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< uint32_t >& values ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + assert( fd->is_repeated() ); + for( const auto& v: values ) + ref->AddUInt32( &msg, fd, v ); +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< int32_t >& values ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + assert( fd->is_repeated() ); + for( const auto& v: values ) + { + if( fd->type() == google::protobuf::FieldDescriptor::Type::TYPE_ENUM ) + ref->AddEnumValue( &msg, fd, (int)v ); + else + ref->AddInt32( &msg, fd, v ); + } +} + +inline void set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< bool >& values ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + assert( fd->is_repeated() ); + for( const auto& v: values ) + ref->AddBool( &msg, fd, v ); +} + +inline void +set_message_field( google::protobuf::Message& msg, uint32_t index, const std::vector< std::string >& values ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + assert( fd->is_repeated() ); + for( const auto& v: values ) + ref->AddString( &msg, fd, v ); +} + +template< typename T > +std::enable_if_t< std::is_base_of_v< google::protobuf::Message, T >, void > inline set_message_field( + google::protobuf::Message& msg, + uint32_t index, + const std::vector< T >& values ) +{ + auto desc = msg.GetDescriptor(); + auto ref = msg.GetReflection(); + auto fd = desc->FindFieldByNumber( index ); + assert( fd ); + assert( fd->is_repeated() ); + for( const auto& v: values ) + { + auto m = ref->AddMessage( &msg, fd ); + m->CopyFrom( v ); + } +} +} // namespace koinos::chain::detail + +#define _THUNK_DETAIL_ARG_PACK( r, msg, i, elem ) koinos::chain::detail::set_message_field( msg, i + 1, elem ); +#define _THUNK_ARG_PACK( FIRST, ... ) \ + BOOST_PP_LIST_FOR_EACH_I( _THUNK_DETAIL_ARG_PACK, _args, BOOST_PP_TUPLE_TO_LIST( ( __VA_ARGS__ ) ) ) + +#define _THUNK_DETAIL_DEFINE( RETURN_TYPE, SYSCALL, ARGS, TYPES, FWD ) \ + } \ + namespace system_call { \ + auto SYSCALL( execution_context& context ARGS ) \ + -> BOOST_PP_IF( _THUNK_IS_VOID( RETURN_TYPE ), \ + void, \ + std::remove_reference_t< decltype( std::declval< RETURN_TYPE >().value() ) > ) \ + { \ + uint32_t _sid = static_cast< uint32_t >( chain::system_call_id::SYSCALL ); \ + \ + BOOST_PP_IF( _THUNK_IS_VOID( RETURN_TYPE ), , RETURN_TYPE _ret; ) \ + \ + with_stack_frame( \ + context, \ + stack_frame{ .sid = _sid, .call_privilege = privilege::kernel_mode }, \ + [ & ]() \ + { \ + if( context.system_call_exists( _sid ) ) \ + { \ + BOOST_PP_CAT( SYSCALL, _THUNK_ARGS_SUFFIX ) _args; \ + BOOST_PP_IF( BOOST_VMD_IS_EMPTY( FWD ), , _THUNK_ARG_PACK( FWD ) ); \ + std::string _arg_str; \ + _args.SerializeToString( &_arg_str ); \ + const auto& _res = context.system_call( _sid, _arg_str ); \ + if( _res.code ) \ + { \ + if( _res.code >= chain::reversion ) \ + throw chain::reversion_exception( _res.code, _res.res.error() ); \ + else if( _res.code <= chain::failure ) \ + throw chain::failure_exception( _res.code, _res.res.error() ); \ + } \ + else if( _sid == system_call_id::exit ) \ + throw chain::success_exception( _res.code ); \ + BOOST_PP_IF( _THUNK_IS_VOID( RETURN_TYPE ), , _ret.ParseFromString( _res.res.object() ); ) \ + } \ + else \ + { \ + auto _thunk_id = context.thunk_translation( _sid ); \ + auto _desc = chain::system_call_id_descriptor(); \ + auto _enum_value = _desc->FindValueByNumber( _thunk_id ); \ + KOINOS_ASSERT( _enum_value, unknown_thunk_exception, "unrecognized thunk id ${id}", ( "id", _thunk_id ) ); \ + auto _compute = context.get_compute_bandwidth( _enum_value->name() ); \ + context.resource_meter().use_compute_bandwidth( _compute ); \ + BOOST_PP_IF( _THUNK_IS_VOID( RETURN_TYPE ), , _ret = ) \ + thunk_dispatcher::instance().call_thunk< RETURN_TYPE TYPES >( _thunk_id, context FWD ); \ + } \ + } ); \ + \ + BOOST_PP_IF( _THUNK_IS_VOID( RETURN_TYPE ), , return _ret.value(); ) \ + } \ + } \ + namespace thunk { \ + RETURN_TYPE BOOST_PP_CAT( _, SYSCALL )( execution_context & context ARGS ) + +#define THUNK_DEFINE( RETURN_TYPE, SYSCALL, ... ) \ + _THUNK_DETAIL_DEFINE( RETURN_TYPE, \ + SYSCALL, \ + VA_ARGS( _THUNK_DETAIL_DEFINE_ARGS( __VA_ARGS__ ) ), \ + VA_ARGS( _THUNK_DETAIL_DEFINE_TYPES( __VA_ARGS__ ) ), \ + VA_ARGS( _THUNK_DETAIL_DEFINE_FORWARD( __VA_ARGS__ ) ) ) + +#define THUNK_DEFINE_VOID( RETURN_TYPE, SYSCALL ) _THUNK_DETAIL_DEFINE( RETURN_TYPE, SYSCALL, , , ) #define THUNK_DEFINE_BEGIN() namespace thunk { #define THUNK_DEFINE_END() } diff --git a/include/koinos/chain/types.hpp b/include/koinos/chain/types.hpp index bb19a432..0ba4b3cf 100644 --- a/include/koinos/chain/types.hpp +++ b/include/koinos/chain/types.hpp @@ -8,10 +8,10 @@ namespace koinos::chain { - using std::map; - using std::vector; - using std::string; - using std::pair; - using std::make_pair; +using std::make_pair; +using std::map; +using std::pair; +using std::string; +using std::vector; -} // koinos::chain +} // namespace koinos::chain diff --git a/include/koinos/vm_manager/fizzy/exceptions.hpp b/include/koinos/vm_manager/fizzy/exceptions.hpp index 480970c2..ffc0be79 100644 --- a/include/koinos/vm_manager/fizzy/exceptions.hpp +++ b/include/koinos/vm_manager/fizzy/exceptions.hpp @@ -23,4 +23,4 @@ KOINOS_DECLARE_DERIVED_EXCEPTION( fizzy_returned_null_exception, fizzy_vm_except KOINOS_DECLARE_DERIVED_EXCEPTION( null_argument_exception, fizzy_vm_exception ); KOINOS_DECLARE_DERIVED_EXCEPTION( runner_state_exception, fizzy_vm_exception ); -} // koinos::vm_manager::fizzy +} // namespace koinos::vm_manager::fizzy diff --git a/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp b/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp index 1b8efdb3..81bf6803 100644 --- a/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp +++ b/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp @@ -12,19 +12,19 @@ namespace koinos::vm_manager::fizzy { /** * Implementation of vm_backend for Fizzy. */ -class fizzy_vm_backend : public vm_backend +class fizzy_vm_backend: public vm_backend { - public: - fizzy_vm_backend(); - virtual ~fizzy_vm_backend(); +public: + fizzy_vm_backend(); + virtual ~fizzy_vm_backend(); - virtual std::string backend_name(); - virtual void initialize(); + virtual std::string backend_name(); + virtual void initialize(); - virtual void run( abstract_host_api& hapi, const std::string& bytecode, const std::string& id = std::string() ); + virtual void run( abstract_host_api& hapi, const std::string& bytecode, const std::string& id = std::string() ); - private: - module_cache _cache; +private: + module_cache _cache; }; -} // koinos::vm_manager::fizzy +} // namespace koinos::vm_manager::fizzy diff --git a/include/koinos/vm_manager/fizzy/module_cache.hpp b/include/koinos/vm_manager/fizzy/module_cache.hpp index 515c7bd7..6b723889 100644 --- a/include/koinos/vm_manager/fizzy/module_cache.hpp +++ b/include/koinos/vm_manager/fizzy/module_cache.hpp @@ -8,44 +8,47 @@ namespace koinos::vm_manager::fizzy { -class module_guard { - private: - const FizzyModule* _module; - - public: - module_guard( const FizzyModule* m ) : _module(m) {} - ~module_guard() { fizzy_free_module( _module ); } - - const FizzyModule* get() const { return _module; } +class module_guard +{ +private: + const FizzyModule* _module; + +public: + module_guard( const FizzyModule* m ): + _module( m ) + {} + + ~module_guard() + { + fizzy_free_module( _module ); + } + + const FizzyModule* get() const + { + return _module; + } }; using module_ptr = std::shared_ptr< const module_guard >; class module_cache { - private: - using lru_list_type = std::list< std::string >; - - using module_map_type = - std::map< - std::string, - std::pair< - module_ptr, - typename lru_list_type::iterator - > - >; - - lru_list_type _lru_list; - module_map_type _module_map; - std::mutex _mutex; - const std::size_t _cache_size; - - public: - module_cache( std::size_t size ); - ~module_cache(); - - module_ptr get_module( const std::string& id ); - void put_module( const std::string& id, module_ptr module ); +private: + using lru_list_type = std::list< std::string >; + + using module_map_type = std::map< std::string, std::pair< module_ptr, typename lru_list_type::iterator > >; + + lru_list_type _lru_list; + module_map_type _module_map; + std::mutex _mutex; + const std::size_t _cache_size; + +public: + module_cache( std::size_t size ); + ~module_cache(); + + module_ptr get_module( const std::string& id ); + void put_module( const std::string& id, module_ptr module ); }; -} // koinos::vm_manager::fizzy +} // namespace koinos::vm_manager::fizzy diff --git a/src/koinos/chain/chronicler.cpp b/src/koinos/chain/chronicler.cpp index e1619af1..5ba02ad8 100644 --- a/src/koinos/chain/chronicler.cpp +++ b/src/koinos/chain/chronicler.cpp @@ -4,36 +4,36 @@ namespace koinos::chain { void chronicler::set_session( std::shared_ptr< abstract_chronicler_session > s ) { - _session = s; + _session = s; } void chronicler::push_event( std::optional< std::string > transaction_id, protocol::event_data&& ev ) { - ev.set_sequence( _seq_no ); + ev.set_sequence( _seq_no ); - if ( auto session = _session.lock() ) - session->push_event( ev ); + if( auto session = _session.lock() ) + session->push_event( ev ); - _events.emplace_back( std::make_pair( transaction_id, std::move( ev ) ) ); - _seq_no++; + _events.emplace_back( std::make_pair( transaction_id, std::move( ev ) ) ); + _seq_no++; } void chronicler::push_log( const std::string& message ) { - if ( auto session = _session.lock() ) - session->push_log( message ); - else - _logs.push_back( message ); + if( auto session = _session.lock() ) + session->push_log( message ); + else + _logs.push_back( message ); } const std::vector< event_bundle >& chronicler::events() { - return _events; + return _events; } const std::vector< std::string >& chronicler::logs() { - return _logs; + return _logs; } -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/controller.cpp b/src/koinos/chain/controller.cpp index c8b2c99c..908c49a5 100644 --- a/src/koinos/chain/controller.cpp +++ b/src/koinos/chain/controller.cpp @@ -1,10 +1,10 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -48,926 +48,1011 @@ namespace detail { std::string format_time( int64_t time ) { - std::stringstream ss; - - auto seconds = time % 60; - time /= 60; - auto minutes = time % 60; - time /= 60; - auto hours = time % 24; - time /= 24; - auto days = time % 365; - auto years = time / 365; - - if ( years ) - { - ss << years << "y, " << days << "d, "; - } - else if ( days ) - { - ss << days << "d, "; - } - - ss << std::setw(2) << std::setfill('0') << hours; - ss << std::setw(1) << "h, "; - ss << std::setw(2) << std::setfill('0') << minutes; - ss << std::setw(1) << "m, "; - ss << std::setw(2) << std::setfill('0') << seconds; - ss << std::setw(1) << "s"; - return ss.str(); + std::stringstream ss; + + auto seconds = time % 60; + time /= 60; + auto minutes = time % 60; + time /= 60; + auto hours = time % 24; + time /= 24; + auto days = time % 365; + auto years = time / 365; + + if( years ) + { + ss << years << "y, " << days << "d, "; + } + else if( days ) + { + ss << days << "d, "; + } + + ss << std::setw( 2 ) << std::setfill( '0' ) << hours; + ss << std::setw( 1 ) << "h, "; + ss << std::setw( 2 ) << std::setfill( '0' ) << minutes; + ss << std::setw( 1 ) << "m, "; + ss << std::setw( 2 ) << std::setfill( '0' ) << seconds; + ss << std::setw( 1 ) << "s"; + return ss.str(); } class controller_impl final { - public: - controller_impl( uint64_t read_compute_bandwith_limit, uint32_t syscall_bufsize ); - ~controller_impl(); - - void open( const std::filesystem::path& p, const genesis_data& data, fork_resolution_algorithm algo, bool reset ); - void close(); - void set_client( std::shared_ptr< mq::client > c ); - - rpc::chain::submit_block_response submit_block( - const rpc::chain::submit_block_request&, - uint64_t index_to, - std::chrono::system_clock::time_point now - ); - - rpc::chain::submit_transaction_response submit_transaction( const rpc::chain::submit_transaction_request& ); - rpc::chain::get_head_info_response get_head_info( const rpc::chain::get_head_info_request& ); - rpc::chain::get_chain_id_response get_chain_id( const rpc::chain::get_chain_id_request& ); - rpc::chain::get_fork_heads_response get_fork_heads( const rpc::chain::get_fork_heads_request& ); - rpc::chain::read_contract_response read_contract( const rpc::chain::read_contract_request& ); - rpc::chain::get_account_nonce_response get_account_nonce( const rpc::chain::get_account_nonce_request& ); - rpc::chain::get_account_rc_response get_account_rc( const rpc::chain::get_account_rc_request& ); - rpc::chain::get_resource_limits_response get_resource_limits( const rpc::chain::get_resource_limits_request& ); - rpc::chain::invoke_system_call_response invoke_system_call( const rpc::chain::invoke_system_call_request& ); - - - private: - state_db::database _db; - std::shared_ptr< vm_manager::vm_backend > _vm_backend; - std::shared_ptr< mq::client > _client; - uint64_t _read_compute_bandwidth_limit; - uint32_t _syscall_bufsize; - std::shared_mutex _cached_head_block_mutex; - std::shared_ptr< const protocol::block > _cached_head_block; - - void validate_block( const protocol::block& b ); - void validate_transaction( const protocol::transaction& t ); - - fork_data get_fork_data( state_db::shared_lock_ptr db_lock ); +public: + controller_impl( uint64_t read_compute_bandwith_limit, uint32_t syscall_bufsize ); + ~controller_impl(); + + void open( const std::filesystem::path& p, const genesis_data& data, fork_resolution_algorithm algo, bool reset ); + void close(); + void set_client( std::shared_ptr< mq::client > c ); + + rpc::chain::submit_block_response + submit_block( const rpc::chain::submit_block_request&, uint64_t index_to, std::chrono::system_clock::time_point now ); + + rpc::chain::submit_transaction_response submit_transaction( const rpc::chain::submit_transaction_request& ); + rpc::chain::get_head_info_response get_head_info( const rpc::chain::get_head_info_request& ); + rpc::chain::get_chain_id_response get_chain_id( const rpc::chain::get_chain_id_request& ); + rpc::chain::get_fork_heads_response get_fork_heads( const rpc::chain::get_fork_heads_request& ); + rpc::chain::read_contract_response read_contract( const rpc::chain::read_contract_request& ); + rpc::chain::get_account_nonce_response get_account_nonce( const rpc::chain::get_account_nonce_request& ); + rpc::chain::get_account_rc_response get_account_rc( const rpc::chain::get_account_rc_request& ); + rpc::chain::get_resource_limits_response get_resource_limits( const rpc::chain::get_resource_limits_request& ); + rpc::chain::invoke_system_call_response invoke_system_call( const rpc::chain::invoke_system_call_request& ); + +private: + state_db::database _db; + std::shared_ptr< vm_manager::vm_backend > _vm_backend; + std::shared_ptr< mq::client > _client; + uint64_t _read_compute_bandwidth_limit; + uint32_t _syscall_bufsize; + std::shared_mutex _cached_head_block_mutex; + std::shared_ptr< const protocol::block > _cached_head_block; + + void validate_block( const protocol::block& b ); + void validate_transaction( const protocol::transaction& t ); + + fork_data get_fork_data( state_db::shared_lock_ptr db_lock ); }; -controller_impl::controller_impl( uint64_t read_compute_bandwidth_limit, uint32_t syscall_bufsize ) : - _read_compute_bandwidth_limit( read_compute_bandwidth_limit ), - _syscall_bufsize( syscall_bufsize ) +controller_impl::controller_impl( uint64_t read_compute_bandwidth_limit, uint32_t syscall_bufsize ): + _read_compute_bandwidth_limit( read_compute_bandwidth_limit ), + _syscall_bufsize( syscall_bufsize ) { - _vm_backend = vm_manager::get_vm_backend(); // Default is fizzy - KOINOS_ASSERT( _vm_backend, unknown_backend_exception, "could not get vm backend" ); + _vm_backend = vm_manager::get_vm_backend(); // Default is fizzy + KOINOS_ASSERT( _vm_backend, unknown_backend_exception, "could not get vm backend" ); - _cached_head_block = std::make_shared< const protocol::block >( protocol::block() ); + _cached_head_block = std::make_shared< const protocol::block >( protocol::block() ); - _vm_backend->initialize(); - LOG(info) << "Initialized " << _vm_backend->backend_name() << " VM backend"; + _vm_backend->initialize(); + LOG( info ) << "Initialized " << _vm_backend->backend_name() << " VM backend"; } controller_impl::~controller_impl() { - close(); + close(); } -void controller_impl::open( const std::filesystem::path& p, const chain::genesis_data& data, fork_resolution_algorithm algo, bool reset ) +void controller_impl::open( const std::filesystem::path& p, + const chain::genesis_data& data, + fork_resolution_algorithm algo, + bool reset ) { - state_db::state_node_comparator_function comp; - - switch( algo ) - { - case fork_resolution_algorithm::block_time: - comp = &state_db::block_time_comparator; - break; - case fork_resolution_algorithm::pob: - comp = &state_db::pob_comparator; - break; - case fork_resolution_algorithm::fifo: - [[fallthrough]]; - default: - comp = &state_db::fifo_comparator; - } - - _db.open( p, [&]( state_db::state_node_ptr root ) - { + state_db::state_node_comparator_function comp; + + switch( algo ) + { + case fork_resolution_algorithm::block_time: + comp = &state_db::block_time_comparator; + break; + case fork_resolution_algorithm::pob: + comp = &state_db::pob_comparator; + break; + case fork_resolution_algorithm::fifo: + [[fallthrough]]; + default: + comp = &state_db::fifo_comparator; + } + + _db.open( + p, + [ & ]( state_db::state_node_ptr root ) + { // Write genesis objects into the database - for ( const auto& entry : data.entries() ) + for( const auto& entry: data.entries() ) { - KOINOS_ASSERT( - !root->get_object( entry.space(), entry.key() ), - unexpected_state_exception, - "encountered unexpected object in initial state" - ); + KOINOS_ASSERT( !root->get_object( entry.space(), entry.key() ), + unexpected_state_exception, + "encountered unexpected object in initial state" ); - root->put_object( entry.space(), entry.key(), &entry.value() ); + root->put_object( entry.space(), entry.key(), &entry.value() ); } - LOG(info) << "Wrote " << data.entries().size() << " genesis objects into new database"; + LOG( info ) << "Wrote " << data.entries().size() << " genesis objects into new database"; // Read genesis public key from the database, assert its existence at the correct location - KOINOS_ASSERT( - root->get_object( state::space::metadata(), state::key::genesis_key ), - unexpected_state_exception, - "could not find genesis public key in database" - ); + KOINOS_ASSERT( root->get_object( state::space::metadata(), state::key::genesis_key ), + unexpected_state_exception, + "could not find genesis public key in database" ); // Calculate and write the chain ID into the database auto chain_id = crypto::hash( koinos::crypto::multicodec::sha2_256, data ); - LOG(info) << "Calculated chain ID: " << chain_id; + LOG( info ) << "Calculated chain ID: " << chain_id; auto chain_id_str = util::converter::as< std::string >( chain_id ); - KOINOS_ASSERT( - !root->get_object( chain::state::space::metadata(), chain::state::key::chain_id ), - unexpected_state_exception, - "encountered unexpected chain id in initial state" - ); + KOINOS_ASSERT( !root->get_object( chain::state::space::metadata(), chain::state::key::chain_id ), + unexpected_state_exception, + "encountered unexpected chain id in initial state" ); root->put_object( chain::state::space::metadata(), chain::state::key::chain_id, &chain_id_str ); - LOG(info) << "Wrote chain ID into new database"; - }, comp, _db.get_unique_lock() ); - - if ( reset ) - { - LOG(info) << "Resetting database..."; - _db.reset( _db.get_unique_lock() ); - } - - auto head = _db.get_head( _db.get_shared_lock() ); - LOG(info) << "Opened database at block - Height: " << head->revision() << ", ID: " << head->id(); + LOG( info ) << "Wrote chain ID into new database"; + }, + comp, + _db.get_unique_lock() ); + + if( reset ) + { + LOG( info ) << "Resetting database..."; + _db.reset( _db.get_unique_lock() ); + } + + auto head = _db.get_head( _db.get_shared_lock() ); + LOG( info ) << "Opened database at block - Height: " << head->revision() << ", ID: " << head->id(); } void controller_impl::close() { - _db.close( _db.get_unique_lock() ); + _db.close( _db.get_unique_lock() ); } void controller_impl::set_client( std::shared_ptr< mq::client > c ) { - _client = c; + _client = c; } void controller_impl::validate_block( const protocol::block& b ) { - KOINOS_ASSERT( b.id().size(), missing_required_arguments_exception, "missing expected field in block: ${field}", ("field", "id") ); - KOINOS_ASSERT( b.has_header(), missing_required_arguments_exception, "missing expected field in block: ${field}", ("field", "header")("block_id", util::to_hex( b.id() )) ); - KOINOS_ASSERT( b.header().previous().size(), missing_required_arguments_exception, "missing expected field in block header: ${field}", ("field", "previous")("block_id", util::to_hex( b.id() )) ); - KOINOS_ASSERT( b.header().height(), missing_required_arguments_exception, "missing expected field in block header: ${field}", ("field", "height")("block_id", util::to_hex( b.id() )) ); - KOINOS_ASSERT( b.header().timestamp(), missing_required_arguments_exception, "missing expected field in block header: ${field}", ("field", "timestamp")("block_id", util::to_hex( b.id() )) ); - KOINOS_ASSERT( b.header().previous_state_merkle_root().size(), missing_required_arguments_exception, "missing expected field in block header: ${field}", ("field", "previous_state_merkle_root")("block_id", util::to_hex( b.id() )) ); - KOINOS_ASSERT( b.header().transaction_merkle_root().size(), missing_required_arguments_exception, "missing expected field in block header: ${field}", ("field", "transaction_merkle_root")("block_id", util::to_hex( b.id() )) ); - KOINOS_ASSERT( b.signature().size(), missing_required_arguments_exception, "missing expected field in block: ${field}", ("field", "signature_data")("block_id", util::to_hex( b.id() )) ); - - for ( const auto& t : b.transactions() ) - validate_transaction( t ); + KOINOS_ASSERT( b.id().size(), + missing_required_arguments_exception, + "missing expected field in block: ${field}", + ( "field", "id" ) ); + KOINOS_ASSERT( b.has_header(), + missing_required_arguments_exception, + "missing expected field in block: ${field}", + ( "field", "header" )( "block_id", util::to_hex( b.id() ) ) ); + KOINOS_ASSERT( b.header().previous().size(), + missing_required_arguments_exception, + "missing expected field in block header: ${field}", + ( "field", "previous" )( "block_id", util::to_hex( b.id() ) ) ); + KOINOS_ASSERT( b.header().height(), + missing_required_arguments_exception, + "missing expected field in block header: ${field}", + ( "field", "height" )( "block_id", util::to_hex( b.id() ) ) ); + KOINOS_ASSERT( b.header().timestamp(), + missing_required_arguments_exception, + "missing expected field in block header: ${field}", + ( "field", "timestamp" )( "block_id", util::to_hex( b.id() ) ) ); + KOINOS_ASSERT( b.header().previous_state_merkle_root().size(), + missing_required_arguments_exception, + "missing expected field in block header: ${field}", + ( "field", "previous_state_merkle_root" )( "block_id", util::to_hex( b.id() ) ) ); + KOINOS_ASSERT( b.header().transaction_merkle_root().size(), + missing_required_arguments_exception, + "missing expected field in block header: ${field}", + ( "field", "transaction_merkle_root" )( "block_id", util::to_hex( b.id() ) ) ); + KOINOS_ASSERT( b.signature().size(), + missing_required_arguments_exception, + "missing expected field in block: ${field}", + ( "field", "signature_data" )( "block_id", util::to_hex( b.id() ) ) ); + + for( const auto& t: b.transactions() ) + validate_transaction( t ); } void controller_impl::validate_transaction( const protocol::transaction& t ) { - KOINOS_ASSERT( t.id().size(), missing_required_arguments_exception, "missing expected field in transaction: ${field}", ("field", "id") ); - KOINOS_ASSERT( t.has_header(), missing_required_arguments_exception, "missing expected field in transaction: ${field}", ("field", "header")("transaction_id", util::to_hex( t.id() )) ); - KOINOS_ASSERT( t.header().rc_limit(), missing_required_arguments_exception, "missing expected field in transaction header: ${field}", ("field", "rc_limit")("transaction_id", util::to_hex( t.id() )) ); - KOINOS_ASSERT( t.header().operation_merkle_root().size(), missing_required_arguments_exception, "missing expected field in transaction header: ${field}", ("field", "operation_merkle_root")("transaction_id", util::to_hex( t.id() )) ); - KOINOS_ASSERT( t.signatures().size(), missing_required_arguments_exception, "missing expected field in transaction: ${field}", ("field", "signature_data")("transaction_id", util::to_hex( t.id() )) ); + KOINOS_ASSERT( t.id().size(), + missing_required_arguments_exception, + "missing expected field in transaction: ${field}", + ( "field", "id" ) ); + KOINOS_ASSERT( t.has_header(), + missing_required_arguments_exception, + "missing expected field in transaction: ${field}", + ( "field", "header" )( "transaction_id", util::to_hex( t.id() ) ) ); + KOINOS_ASSERT( t.header().rc_limit(), + missing_required_arguments_exception, + "missing expected field in transaction header: ${field}", + ( "field", "rc_limit" )( "transaction_id", util::to_hex( t.id() ) ) ); + KOINOS_ASSERT( t.header().operation_merkle_root().size(), + missing_required_arguments_exception, + "missing expected field in transaction header: ${field}", + ( "field", "operation_merkle_root" )( "transaction_id", util::to_hex( t.id() ) ) ); + KOINOS_ASSERT( t.signatures().size(), + missing_required_arguments_exception, + "missing expected field in transaction: ${field}", + ( "field", "signature_data" )( "transaction_id", util::to_hex( t.id() ) ) ); } -rpc::chain::submit_block_response controller_impl::submit_block( - const rpc::chain::submit_block_request& request, - uint64_t index_to, - std::chrono::system_clock::time_point now ) +rpc::chain::submit_block_response controller_impl::submit_block( const rpc::chain::submit_block_request& request, + uint64_t index_to, + std::chrono::system_clock::time_point now ) { - validate_block( request.block() ); - - rpc::chain::submit_block_response resp; - - static constexpr uint64_t index_message_interval = 1000; - static constexpr std::chrono::seconds time_delta = std::chrono::seconds( 5 ); - static constexpr std::chrono::seconds live_delta = std::chrono::seconds( 60 ); - - auto time_lower_bound = uint64_t( 0 ); - auto time_upper_bound = std::chrono::duration_cast< std::chrono::milliseconds >( ( now + time_delta ).time_since_epoch() ).count(); - uint64_t parent_height = 0; - - auto db_lock = _db.get_shared_lock(); - - const auto& block = request.block(); - auto block_id = util::converter::to< crypto::multihash >( block.id() ); - auto block_height = block.header().height(); - auto parent_id = util::converter::to< crypto::multihash >( block.header().previous() ); - auto block_node = _db.get_node( block_id, db_lock ); - auto parent_node = _db.get_node( parent_id, db_lock ); - - bool new_head = false; - - if ( block_node ) return {}; // Block has been applied - - // This prevents returning "unknown previous block" when the pushed block is the LIB - if ( !parent_node ) - { - auto root = _db.get_root( db_lock ); - KOINOS_ASSERT( block_height >= root->revision(), pre_irreversibility_block_exception, "block is prior to irreversibility" ); - KOINOS_ASSERT( block_id == root->id(), unknown_previous_block_exception, "unknown previous block" ); - return {}; // Block is current LIB - } - - bool live = block.header().timestamp() > std::chrono::duration_cast< std::chrono::milliseconds >( ( now - live_delta ).time_since_epoch() ).count(); - - if ( !index_to && live ) - { - LOG(debug) << "Pushing block - Height: " << block_height << ", ID: " << block_id; - } - - block_node = _db.create_writable_node( parent_id, block_id, block.header(), db_lock ); - - // If this is not the genesis case, we must ensure that the proposed block timestamp is greater - // than the parent block timestamp. - if ( block_node && !parent_id.is_zero() ) - { - execution_context parent_ctx( _vm_backend, intent::read_only ); - - parent_ctx.push_frame( stack_frame { - .call_privilege = privilege::kernel_mode - } ); - - parent_ctx.set_state_node( parent_node ); - parent_ctx.reset_cache(); - auto head_info = system_call::get_head_info( parent_ctx ); - parent_height = head_info.head_topology().height(); - time_lower_bound = head_info.head_block_time(); - } - - execution_context ctx( _vm_backend, intent::block_application ); - - try - { - // Genesis case, when the first block is submitted the previous must be the zero hash - if ( parent_id.is_zero() ) + validate_block( request.block() ); + + rpc::chain::submit_block_response resp; + + static constexpr uint64_t index_message_interval = 1'000; + static constexpr std::chrono::seconds time_delta = std::chrono::seconds( 5 ); + static constexpr std::chrono::seconds live_delta = std::chrono::seconds( 60 ); + + auto time_lower_bound = uint64_t( 0 ); + auto time_upper_bound = + std::chrono::duration_cast< std::chrono::milliseconds >( ( now + time_delta ).time_since_epoch() ).count(); + uint64_t parent_height = 0; + + auto db_lock = _db.get_shared_lock(); + + const auto& block = request.block(); + auto block_id = util::converter::to< crypto::multihash >( block.id() ); + auto block_height = block.header().height(); + auto parent_id = util::converter::to< crypto::multihash >( block.header().previous() ); + auto block_node = _db.get_node( block_id, db_lock ); + auto parent_node = _db.get_node( parent_id, db_lock ); + + bool new_head = false; + + if( block_node ) + return {}; // Block has been applied + + // This prevents returning "unknown previous block" when the pushed block is the LIB + if( !parent_node ) + { + auto root = _db.get_root( db_lock ); + KOINOS_ASSERT( block_height >= root->revision(), + pre_irreversibility_block_exception, + "block is prior to irreversibility" ); + KOINOS_ASSERT( block_id == root->id(), unknown_previous_block_exception, "unknown previous block" ); + return {}; // Block is current LIB + } + + bool live = + block.header().timestamp() + > std::chrono::duration_cast< std::chrono::milliseconds >( ( now - live_delta ).time_since_epoch() ).count(); + + if( !index_to && live ) + { + LOG( debug ) << "Pushing block - Height: " << block_height << ", ID: " << block_id; + } + + block_node = _db.create_writable_node( parent_id, block_id, block.header(), db_lock ); + + // If this is not the genesis case, we must ensure that the proposed block timestamp is greater + // than the parent block timestamp. + if( block_node && !parent_id.is_zero() ) + { + execution_context parent_ctx( _vm_backend, intent::read_only ); + + parent_ctx.push_frame( stack_frame{ .call_privilege = privilege::kernel_mode } ); + + parent_ctx.set_state_node( parent_node ); + parent_ctx.reset_cache(); + auto head_info = system_call::get_head_info( parent_ctx ); + parent_height = head_info.head_topology().height(); + time_lower_bound = head_info.head_block_time(); + } + + execution_context ctx( _vm_backend, intent::block_application ); + + try + { + // Genesis case, when the first block is submitted the previous must be the zero hash + if( parent_id.is_zero() ) + { + KOINOS_ASSERT( block_height == 1, unexpected_height_exception, "first block must have height of 1" ); + } + + KOINOS_ASSERT( block_node, block_state_error_exception, "could not create new block state node" ); + + KOINOS_ASSERT( block_height == parent_height + 1, + unexpected_height_exception, + "expected block height of ${a}, was ${b}", + ( "a", parent_height + 1 )( "b", block_height ) ); + + KOINOS_ASSERT( block.header().timestamp() <= time_upper_bound, + timestamp_out_of_bounds_exception, + "block timestamp is too far in the future" ); + KOINOS_ASSERT( block.header().timestamp() > time_lower_bound, + timestamp_out_of_bounds_exception, + "block timestamp is too old" ); + + KOINOS_ASSERT( block.header().previous_state_merkle_root() + == util::converter::as< std::string >( parent_node->merkle_root() ), + state_merkle_mismatch_exception, + "block previous state merkle mismatch" ); + + ctx.push_frame( stack_frame{ .call_privilege = privilege::kernel_mode } ); + + ctx.set_state_node( block_node ); + ctx.reset_cache(); + + system_call::apply_block( ctx, block ); + + KOINOS_ASSERT( std::holds_alternative< protocol::block_receipt >( ctx.receipt() ), + unexpected_receipt_exception, + "expected block receipt" ); + *resp.mutable_receipt() = std::get< protocol::block_receipt >( ctx.receipt() ); + + if( _client ) + { + rpc::block_store::block_store_request req; + req.mutable_add_block()->mutable_block_to_add()->CopyFrom( block ); + req.mutable_add_block()->mutable_receipt_to_add()->CopyFrom( + std::get< protocol::block_receipt >( ctx.receipt() ) ); + + auto future = _client->rpc( util::service::block_store, + util::converter::as< std::string >( req ), + 1'500ms, + mq::retry_policy::none ); + + rpc::block_store::block_store_response resp; + resp.ParseFromString( future.get() ); + + KOINOS_ASSERT( !resp.has_error(), + rpc_failure_exception, + "received error from block store: ${e}", + ( "e", resp.error() ) ); + KOINOS_ASSERT( resp.has_add_block(), + rpc_failure_exception, + "unexpected response when submitting block: ${r}", + ( "r", resp ) ); + } + + if( !index_to && live ) + { + auto num_transactions = block.transactions_size(); + + LOG( info ) << "Block applied - Height: " << block_height << ", ID: " << block_id << " (" << num_transactions + << ( num_transactions == 1 ? " transaction)" : " transactions)" ); + } + else if( block_height % index_message_interval == 0 ) + { + if( index_to ) { - KOINOS_ASSERT( block_height == 1, unexpected_height_exception, "first block must have height of 1" ); + auto progress = block_height / static_cast< double >( index_to ) * 100; + LOG( info ) << "Indexing chain (" << progress << "%) - Height: " << block_height << ", ID: " << block_id; } - - KOINOS_ASSERT( block_node, block_state_error_exception, "could not create new block state node" ); - - KOINOS_ASSERT( - block_height == parent_height + 1, - unexpected_height_exception, - "expected block height of ${a}, was ${b}", ("a", parent_height + 1)("b", block_height) - ); - - KOINOS_ASSERT( block.header().timestamp() <= time_upper_bound, timestamp_out_of_bounds_exception, "block timestamp is too far in the future" ); - KOINOS_ASSERT( block.header().timestamp() > time_lower_bound, timestamp_out_of_bounds_exception, "block timestamp is too old" ); - - KOINOS_ASSERT( - block.header().previous_state_merkle_root() == util::converter::as< std::string >( parent_node->merkle_root() ), - state_merkle_mismatch_exception, - "block previous state merkle mismatch" - ); - - ctx.push_frame( stack_frame { - .call_privilege = privilege::kernel_mode - } ); - - ctx.set_state_node( block_node ); - ctx.reset_cache(); - - system_call::apply_block( ctx, block ); - - KOINOS_ASSERT( std::holds_alternative< protocol::block_receipt >( ctx.receipt() ), unexpected_receipt_exception, "expected block receipt" ); - *resp.mutable_receipt() = std::get< protocol::block_receipt >( ctx.receipt() ); - - if ( _client ) + else { - rpc::block_store::block_store_request req; - req.mutable_add_block()->mutable_block_to_add()->CopyFrom( block ); - req.mutable_add_block()->mutable_receipt_to_add()->CopyFrom( std::get< protocol::block_receipt >( ctx.receipt() ) ); + auto to_go = std::chrono::duration_cast< std::chrono::seconds >( + now.time_since_epoch() - std::chrono::milliseconds( block.header().timestamp() ) ) + .count(); + LOG( info ) << "Sync progress - Height: " << block_height << ", ID: " << block_id << " (" + << format_time( to_go ) << " block time remaining)"; + } + } - auto future = _client->rpc( util::service::block_store, util::converter::as< std::string >( req ), 1500ms, mq::retry_policy::none ); + auto lib = system_call::get_last_irreversible_block( ctx ); - rpc::block_store::block_store_response resp; - resp.ParseFromString( future.get() ); + try + { + // We need to finalize our node, checking if it is the new head block, update the cached head block, + // and advancing LIB as an atomic action or else we risk _db.get_head(), _cached_head_block, and + // LIB desyncing from each other + db_lock.reset(); + block_node.reset(); + parent_node.reset(); + ctx.clear_state_node(); - KOINOS_ASSERT( !resp.has_error(), rpc_failure_exception, "received error from block store: ${e}", ("e", resp.error()) ); - KOINOS_ASSERT( resp.has_add_block(), rpc_failure_exception, "unexpected response when submitting block: ${r}", ("r", resp) ); - } + auto unique_db_lock = _db.get_unique_lock(); + _db.finalize_node( block_id, unique_db_lock ); - if ( !index_to && live ) - { - auto num_transactions = block.transactions_size(); + resp.mutable_receipt()->set_state_merkle_root( + util::converter::as< std::string >( _db.get_node( block_id, unique_db_lock )->merkle_root() ) ); - LOG(info) << "Block applied - Height: " << block_height << ", ID: " << block_id << " (" << num_transactions << ( num_transactions == 1 ? " transaction)" : " transactions)" ); - } - else if ( block_height % index_message_interval == 0 ) + if( block_id == _db.get_head( unique_db_lock )->id() ) { - if ( index_to ) - { - auto progress = block_height / static_cast< double >( index_to ) * 100; - LOG(info) << "Indexing chain (" << progress << "%) - Height: " << block_height << ", ID: " << block_id; - } - else - { - auto to_go = std::chrono::duration_cast< std::chrono::seconds >( now.time_since_epoch() - std::chrono::milliseconds( block.header().timestamp() ) ).count(); - LOG(info) << "Sync progress - Height: " << block_height << ", ID: " << block_id << " (" << format_time( to_go ) << " block time remaining)"; - } + std::unique_lock< std::shared_mutex > head_lock( _cached_head_block_mutex ); + new_head = true; + _cached_head_block = std::make_shared< protocol::block >( block ); } - auto lib = system_call::get_last_irreversible_block( ctx ); - - try { - // We need to finalize our node, checking if it is the new head block, update the cached head block, - // and advancing LIB as an atomic action or else we risk _db.get_head(), _cached_head_block, and - // LIB desyncing from each other - db_lock.reset(); - block_node.reset(); - parent_node.reset(); - ctx.clear_state_node(); - - auto unique_db_lock = _db.get_unique_lock(); - _db.finalize_node( block_id, unique_db_lock ); - - resp.mutable_receipt()->set_state_merkle_root( util::converter::as< std::string >( _db.get_node( block_id, unique_db_lock )->merkle_root() ) ); - - if ( block_id == _db.get_head( unique_db_lock )->id() ) - { - std::unique_lock< std::shared_mutex > head_lock( _cached_head_block_mutex ); - new_head = true; - _cached_head_block = std::make_shared< protocol::block >( block ); - } - - if ( lib > _db.get_root( unique_db_lock )->revision() ) - { - auto lib_id = _db.get_node_at_revision( lib, block_id, unique_db_lock )->id(); - _db.commit_node( lib_id, unique_db_lock ); - } - - unique_db_lock.reset(); - db_lock = _db.get_shared_lock(); - block_node = _db.get_node( block_id, db_lock ); - ctx.set_state_node( block_node ); - } - catch ( ... ) + if( lib > _db.get_root( unique_db_lock )->revision() ) { - // If any exception is thrown, reset to the expected local state and then rethrow. - db_lock = _db.get_shared_lock(); - block_node = _db.get_node( block_id, db_lock ); - ctx.set_state_node( block_node ); - throw; + auto lib_id = _db.get_node_at_revision( lib, block_id, unique_db_lock )->id(); + _db.commit_node( lib_id, unique_db_lock ); } - // It is NOT safe to use block_node after this point without checking it against null - - if ( _client ) - { - const auto [ fork_heads, last_irreversible_block ] = get_fork_data( db_lock ); - - broadcast::block_irreversible bc; - bc.mutable_topology()->CopyFrom( last_irreversible_block ); - - _client->broadcast( "koinos.block.irreversible", util::converter::as< std::string >( bc ) ); + unique_db_lock.reset(); + db_lock = _db.get_shared_lock(); + block_node = _db.get_node( block_id, db_lock ); + ctx.set_state_node( block_node ); + } + catch( ... ) + { + // If any exception is thrown, reset to the expected local state and then rethrow. + db_lock = _db.get_shared_lock(); + block_node = _db.get_node( block_id, db_lock ); + ctx.set_state_node( block_node ); + throw; + } - broadcast::block_accepted ba; - *ba.mutable_block() = block; - *ba.mutable_receipt() = std::get< protocol::block_receipt >( ctx.receipt() ); - ba.set_live( live ); - ba.set_head( new_head ); + // It is NOT safe to use block_node after this point without checking it against null - _client->broadcast( "koinos.block.accept", util::converter::as< std::string >( ba ) ); + if( _client ) + { + const auto [ fork_heads, last_irreversible_block ] = get_fork_data( db_lock ); - broadcast::fork_heads fh; - fh.set_allocated_last_irreversible_block( bc.release_topology() ); + broadcast::block_irreversible bc; + bc.mutable_topology()->CopyFrom( last_irreversible_block ); - for ( const auto& fork_head : fork_heads ) - { - auto* head = fh.add_heads(); - *head = fork_head; - } + _client->broadcast( "koinos.block.irreversible", util::converter::as< std::string >( bc ) ); - _client->broadcast( "koinos.block.forks", util::converter::as< std::string >( fh ) ); + broadcast::block_accepted ba; + *ba.mutable_block() = block; + *ba.mutable_receipt() = std::get< protocol::block_receipt >( ctx.receipt() ); + ba.set_live( live ); + ba.set_head( new_head ); - for ( const auto& [ transaction_id, event ] : ctx.chronicler().events() ) - { - broadcast::event_parcel ep; - ep.set_block_id( block.id() ); - ep.set_height( block.header().height() ); - *ep.mutable_event() = event; + _client->broadcast( "koinos.block.accept", util::converter::as< std::string >( ba ) ); - if ( transaction_id ) - ep.set_transaction_id( *transaction_id ); + broadcast::fork_heads fh; + fh.set_allocated_last_irreversible_block( bc.release_topology() ); - _client->broadcast( "koinos.event." + util::to_base58( event.source() ) + "." + event.name(), ep.SerializeAsString() ); - } - } - } - catch ( const block_state_error_exception& e ) - { - LOG(warning) << "Block application failed - Height: " << block_height << " ID: " << block_id << ", with reason: " << e.what(); - throw; - } - catch ( koinos::exception& e ) - { - if ( block_node && !block_node->is_finalized() ) - { - _db.discard_node( block_node->id(), db_lock ); - LOG(warning) << "Block application failed - Height: " << block_height << " ID: " << block_id << ", with reason: " << e.what(); - } - else + for( const auto& fork_head: fork_heads ) { - LOG(error) << "Block application failed after finalization - Height: " << block_height << " ID: " << block_id << ", with reason: " << e.what(); + auto* head = fh.add_heads(); + *head = fork_head; } - if ( _client ) + _client->broadcast( "koinos.block.forks", util::converter::as< std::string >( fh ) ); + + for( const auto& [ transaction_id, event ]: ctx.chronicler().events() ) { - const auto& exception_data = e.get_json(); - - if ( exception_data.count( "transaction_id" ) ) - { - broadcast::transaction_failed ptf; - ptf.set_id( util::from_hex< std::string >( exception_data[ "transaction_id" ] ) ); - _client->broadcast( "koinos.transaction.fail", util::converter::as< std::string >( ptf ) ); - } - } + broadcast::event_parcel ep; + ep.set_block_id( block.id() ); + ep.set_height( block.header().height() ); + *ep.mutable_event() = event; - if ( std::holds_alternative< protocol::block_receipt >( ctx.receipt() ) ) - e.add_json( "logs", std::get< protocol::block_receipt >( ctx.receipt() ).logs() ); + if( transaction_id ) + ep.set_transaction_id( *transaction_id ); - throw; - } - catch ( ... ) - { - if ( block_node && !block_node->is_finalized() ) - { - _db.discard_node( block_node->id(), db_lock ); - LOG(warning) << "Block application failed - Height: " << block_height << ", ID: " << block_id << ", for an unknown reason"; + _client->broadcast( "koinos.event." + util::to_base58( event.source() ) + "." + event.name(), + ep.SerializeAsString() ); } - else + } + } + catch( const block_state_error_exception& e ) + { + LOG( warning ) << "Block application failed - Height: " << block_height << " ID: " << block_id + << ", with reason: " << e.what(); + throw; + } + catch( koinos::exception& e ) + { + if( block_node && !block_node->is_finalized() ) + { + _db.discard_node( block_node->id(), db_lock ); + LOG( warning ) << "Block application failed - Height: " << block_height << " ID: " << block_id + << ", with reason: " << e.what(); + } + else + { + LOG( error ) << "Block application failed after finalization - Height: " << block_height << " ID: " << block_id + << ", with reason: " << e.what(); + } + + if( _client ) + { + const auto& exception_data = e.get_json(); + + if( exception_data.count( "transaction_id" ) ) { - LOG(error) << "Block application failed after finalization - Height: " << block_height << ", ID: " << block_id << ", for an unknown reason"; + broadcast::transaction_failed ptf; + ptf.set_id( util::from_hex< std::string >( exception_data[ "transaction_id" ] ) ); + _client->broadcast( "koinos.transaction.fail", util::converter::as< std::string >( ptf ) ); } - - throw; - } - - return resp; + } + + if( std::holds_alternative< protocol::block_receipt >( ctx.receipt() ) ) + e.add_json( "logs", std::get< protocol::block_receipt >( ctx.receipt() ).logs() ); + + throw; + } + catch( ... ) + { + if( block_node && !block_node->is_finalized() ) + { + _db.discard_node( block_node->id(), db_lock ); + LOG( warning ) << "Block application failed - Height: " << block_height << ", ID: " << block_id + << ", for an unknown reason"; + } + else + { + LOG( error ) << "Block application failed after finalization - Height: " << block_height << ", ID: " << block_id + << ", for an unknown reason"; + } + + throw; + } + + return resp; } -rpc::chain::submit_transaction_response controller_impl::submit_transaction( const rpc::chain::submit_transaction_request& request ) +rpc::chain::submit_transaction_response +controller_impl::submit_transaction( const rpc::chain::submit_transaction_request& request ) { - validate_transaction( request.transaction() ); - - rpc::chain::submit_transaction_response resp; - - std::string payer; - uint64_t max_payer_rc; - uint64_t trx_rc_limit; - - auto transaction = request.transaction(); - auto transaction_id = util::to_hex( transaction.id() ); - - LOG(debug) << "Pushing transaction - ID: " << transaction_id; - - auto db_lock = _db.get_shared_lock(); - state_node_ptr head; - execution_context ctx( _vm_backend, intent::transaction_application ); - std::shared_ptr< const protocol::block > head_block_ptr; - - { - std::shared_lock< std::shared_mutex > head_lock( _cached_head_block_mutex ); - head_block_ptr = _cached_head_block; - KOINOS_ASSERT( head_block_ptr, internal_error_exception, "error retrieving head block" ); - - head = _db.get_head( db_lock ); - } - - ctx.set_block( *head_block_ptr ); - ctx.set_state_node( head->create_anonymous_node() ); - - ctx.push_frame( stack_frame { - .call_privilege = privilege::kernel_mode - } ); - - try - { - ctx.reset_cache(); - - payer = transaction.header().payer(); - max_payer_rc = system_call::get_account_rc( ctx, payer ); - trx_rc_limit = transaction.header().rc_limit(); - - if ( request.broadcast() && _client ) - { - rpc::mempool::mempool_request req; - auto* check_pending = req.mutable_check_pending_account_resources(); - - check_pending->set_payer( payer ); - check_pending->set_max_payer_rc( max_payer_rc ); - check_pending->set_rc_limit( trx_rc_limit ); - - auto future = _client->rpc( util::service::mempool, util::converter::as< std::string >( req ), 750ms, mq::retry_policy::none ); - - rpc::mempool::mempool_response resp; - resp.ParseFromString( future.get() ); - - KOINOS_ASSERT( !resp.has_error(), rpc_failure_exception, "received error from mempool: ${e}", ("e", resp.error()) ); - KOINOS_ASSERT( resp.has_check_pending_account_resources(), rpc_failure_exception, "received unexpected response from mempool" ); - KOINOS_ASSERT( resp.check_pending_account_resources().success(), insufficient_rc_exception, "insufficient pending account resources" ); - } - - ctx.resource_meter().set_resource_limit_data( system_call::get_resource_limits( ctx ) ); - system_call::apply_transaction( ctx, transaction ); - - LOG(debug) << "Transaction applied - ID: " << transaction_id; - - KOINOS_ASSERT( std::holds_alternative< protocol::transaction_receipt >( ctx.receipt() ), unexpected_receipt_exception, "expected transaction receipt" ); - *resp.mutable_receipt() = std::get< protocol::transaction_receipt >( ctx.receipt() ); - - if ( request.broadcast() && _client ) - { - broadcast::transaction_accepted ta; - *ta.mutable_transaction() = transaction; - *ta.mutable_receipt() = std::get< protocol::transaction_receipt >( ctx.receipt() ); - ta.set_height( ctx.get_state_node()->revision() ); - - _client->broadcast( "koinos.transaction.accept", util::converter::as< std::string >( ta ) ); - } - } - catch ( koinos::exception& e ) - { - LOG(debug) << "Transaction application failed - ID: " << transaction_id << ", with reason: " << e.what(); - - if ( std::holds_alternative< protocol::transaction_receipt >( ctx.receipt() ) ) - e.add_json( "logs", std::get< protocol::transaction_receipt >( ctx.receipt() ).logs() ); - - throw; - } - catch ( ... ) - { - LOG(debug) << "Transaction application failed - ID: " << transaction_id << ", for an unknown reason"; - throw; - } - - return resp; + validate_transaction( request.transaction() ); + + rpc::chain::submit_transaction_response resp; + + std::string payer; + uint64_t max_payer_rc; + uint64_t trx_rc_limit; + + auto transaction = request.transaction(); + auto transaction_id = util::to_hex( transaction.id() ); + + LOG( debug ) << "Pushing transaction - ID: " << transaction_id; + + auto db_lock = _db.get_shared_lock(); + state_node_ptr head; + execution_context ctx( _vm_backend, intent::transaction_application ); + std::shared_ptr< const protocol::block > head_block_ptr; + + { + std::shared_lock< std::shared_mutex > head_lock( _cached_head_block_mutex ); + head_block_ptr = _cached_head_block; + KOINOS_ASSERT( head_block_ptr, internal_error_exception, "error retrieving head block" ); + + head = _db.get_head( db_lock ); + } + + ctx.set_block( *head_block_ptr ); + ctx.set_state_node( head->create_anonymous_node() ); + + ctx.push_frame( stack_frame{ .call_privilege = privilege::kernel_mode } ); + + try + { + ctx.reset_cache(); + + payer = transaction.header().payer(); + max_payer_rc = system_call::get_account_rc( ctx, payer ); + trx_rc_limit = transaction.header().rc_limit(); + + if( request.broadcast() && _client ) + { + rpc::mempool::mempool_request req; + auto* check_pending = req.mutable_check_pending_account_resources(); + + check_pending->set_payer( payer ); + check_pending->set_max_payer_rc( max_payer_rc ); + check_pending->set_rc_limit( trx_rc_limit ); + + auto future = _client->rpc( util::service::mempool, + util::converter::as< std::string >( req ), + 750ms, + mq::retry_policy::none ); + + rpc::mempool::mempool_response resp; + resp.ParseFromString( future.get() ); + + KOINOS_ASSERT( !resp.has_error(), + rpc_failure_exception, + "received error from mempool: ${e}", + ( "e", resp.error() ) ); + KOINOS_ASSERT( resp.has_check_pending_account_resources(), + rpc_failure_exception, + "received unexpected response from mempool" ); + KOINOS_ASSERT( resp.check_pending_account_resources().success(), + insufficient_rc_exception, + "insufficient pending account resources" ); + } + + ctx.resource_meter().set_resource_limit_data( system_call::get_resource_limits( ctx ) ); + system_call::apply_transaction( ctx, transaction ); + + LOG( debug ) << "Transaction applied - ID: " << transaction_id; + + KOINOS_ASSERT( std::holds_alternative< protocol::transaction_receipt >( ctx.receipt() ), + unexpected_receipt_exception, + "expected transaction receipt" ); + *resp.mutable_receipt() = std::get< protocol::transaction_receipt >( ctx.receipt() ); + + if( request.broadcast() && _client ) + { + broadcast::transaction_accepted ta; + *ta.mutable_transaction() = transaction; + *ta.mutable_receipt() = std::get< protocol::transaction_receipt >( ctx.receipt() ); + ta.set_height( ctx.get_state_node()->revision() ); + + _client->broadcast( "koinos.transaction.accept", util::converter::as< std::string >( ta ) ); + } + } + catch( koinos::exception& e ) + { + LOG( debug ) << "Transaction application failed - ID: " << transaction_id << ", with reason: " << e.what(); + + if( std::holds_alternative< protocol::transaction_receipt >( ctx.receipt() ) ) + e.add_json( "logs", std::get< protocol::transaction_receipt >( ctx.receipt() ).logs() ); + + throw; + } + catch( ... ) + { + LOG( debug ) << "Transaction application failed - ID: " << transaction_id << ", for an unknown reason"; + throw; + } + + return resp; } rpc::chain::get_head_info_response controller_impl::get_head_info( const rpc::chain::get_head_info_request& ) { - execution_context ctx( _vm_backend ); - ctx.push_frame( stack_frame { - .call_privilege = privilege::kernel_mode - } ); + execution_context ctx( _vm_backend ); + ctx.push_frame( stack_frame{ .call_privilege = privilege::kernel_mode } ); - auto db_lock = _db.get_shared_lock(); - state_node_ptr head; - std::shared_ptr< const protocol::block > head_block_ptr; + auto db_lock = _db.get_shared_lock(); + state_node_ptr head; + std::shared_ptr< const protocol::block > head_block_ptr; - { - std::shared_lock< std::shared_mutex > head_lock( _cached_head_block_mutex ); - head_block_ptr = _cached_head_block; + { + std::shared_lock< std::shared_mutex > head_lock( _cached_head_block_mutex ); + head_block_ptr = _cached_head_block; - KOINOS_ASSERT( head_block_ptr, internal_error_exception, "error retrieving head block" ); + KOINOS_ASSERT( head_block_ptr, internal_error_exception, "error retrieving head block" ); - head = _db.get_head( db_lock ); - } + head = _db.get_head( db_lock ); + } - ctx.set_state_node( head->create_anonymous_node() ); + ctx.set_state_node( head->create_anonymous_node() ); - KOINOS_ASSERT( head_block_ptr, internal_error_exception, "error retrieving head block" ); + KOINOS_ASSERT( head_block_ptr, internal_error_exception, "error retrieving head block" ); - ctx.set_block( *head_block_ptr ); - ctx.reset_cache(); + ctx.set_block( *head_block_ptr ); + ctx.reset_cache(); - auto head_info = system_call::get_head_info( ctx ); - block_topology topo = head_info.head_topology(); + auto head_info = system_call::get_head_info( ctx ); + block_topology topo = head_info.head_topology(); - rpc::chain::get_head_info_response resp; - *resp.mutable_head_topology() = topo; - resp.set_last_irreversible_block( head_info.last_irreversible_block() ); - resp.set_head_state_merkle_root( util::converter::as< std::string >( head->merkle_root() ) ); - resp.set_head_block_time( head_info.head_block_time() ); + rpc::chain::get_head_info_response resp; + *resp.mutable_head_topology() = topo; + resp.set_last_irreversible_block( head_info.last_irreversible_block() ); + resp.set_head_state_merkle_root( util::converter::as< std::string >( head->merkle_root() ) ); + resp.set_head_block_time( head_info.head_block_time() ); - return resp; + return resp; } rpc::chain::get_chain_id_response controller_impl::get_chain_id( const rpc::chain::get_chain_id_request& ) { - execution_context ctx( _vm_backend ); - ctx.push_frame( stack_frame { - .call_privilege = privilege::kernel_mode - } ); + execution_context ctx( _vm_backend ); + ctx.push_frame( stack_frame{ .call_privilege = privilege::kernel_mode } ); - ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); - ctx.reset_cache(); + ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); + ctx.reset_cache(); - rpc::chain::get_chain_id_response resp; - resp.set_chain_id( system_call::get_chain_id( ctx ) ); + rpc::chain::get_chain_id_response resp; + resp.set_chain_id( system_call::get_chain_id( ctx ) ); - return resp; + return resp; } fork_data controller_impl::get_fork_data( state_db::shared_lock_ptr db_lock ) { - fork_data fdata; - execution_context ctx( _vm_backend ); - - ctx.push_frame( koinos::chain::stack_frame { - .call_privilege = privilege::kernel_mode - } ); - - std::vector< state_db::state_node_ptr > fork_heads; - - ctx.set_state_node( _db.get_root( db_lock )->create_anonymous_node() ); - ctx.reset_cache(); - fork_heads = _db.get_fork_heads( db_lock ); - - auto head_info = system_call::get_head_info( ctx ); - fdata.second = head_info.head_topology(); - - for ( auto& fork : fork_heads ) - { - ctx.set_state_node( fork->create_anonymous_node() ); - ctx.reset_cache(); - auto head_info = system_call::get_head_info( ctx ); - fdata.first.emplace_back( std::move( head_info.head_topology() ) ); - } - - // Sort all fork heads by height - std::sort( fdata.first.begin(), fdata.first.end(), []( const block_topology& a, const block_topology& b ) - { - return a.height() > b.height(); - } ); - - // If there is a tie for highest block, ensure the head block is first - auto fork_itr = fdata.first.begin(); - while ( fork_itr != fdata.first.begin() && fork_itr->id() != head_info.head_topology().id() ) - { - ++fork_itr; - } - - if ( fork_itr != fdata.first.begin() ) - { - std::iter_swap( fork_itr, fdata.first.begin() ); - } - - return fdata; + fork_data fdata; + execution_context ctx( _vm_backend ); + + ctx.push_frame( koinos::chain::stack_frame{ .call_privilege = privilege::kernel_mode } ); + + std::vector< state_db::state_node_ptr > fork_heads; + + ctx.set_state_node( _db.get_root( db_lock )->create_anonymous_node() ); + ctx.reset_cache(); + fork_heads = _db.get_fork_heads( db_lock ); + + auto head_info = system_call::get_head_info( ctx ); + fdata.second = head_info.head_topology(); + + for( auto& fork: fork_heads ) + { + ctx.set_state_node( fork->create_anonymous_node() ); + ctx.reset_cache(); + auto head_info = system_call::get_head_info( ctx ); + fdata.first.emplace_back( std::move( head_info.head_topology() ) ); + } + + // Sort all fork heads by height + std::sort( fdata.first.begin(), + fdata.first.end(), + []( const block_topology& a, const block_topology& b ) + { + return a.height() > b.height(); + } ); + + // If there is a tie for highest block, ensure the head block is first + auto fork_itr = fdata.first.begin(); + while( fork_itr != fdata.first.begin() && fork_itr->id() != head_info.head_topology().id() ) + { + ++fork_itr; + } + + if( fork_itr != fdata.first.begin() ) + { + std::iter_swap( fork_itr, fdata.first.begin() ); + } + + return fdata; } -rpc::chain::get_resource_limits_response controller_impl::get_resource_limits( const rpc::chain::get_resource_limits_request& ) +rpc::chain::get_resource_limits_response +controller_impl::get_resource_limits( const rpc::chain::get_resource_limits_request& ) { - execution_context ctx( _vm_backend ); - ctx.push_frame( stack_frame { - .call_privilege = privilege::kernel_mode - } ); + execution_context ctx( _vm_backend ); + ctx.push_frame( stack_frame{ .call_privilege = privilege::kernel_mode } ); - ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); - ctx.reset_cache(); + ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); + ctx.reset_cache(); - auto value = system_call::get_resource_limits( ctx ); + auto value = system_call::get_resource_limits( ctx ); - rpc::chain::get_resource_limits_response resp; - *resp.mutable_resource_limit_data() = value; + rpc::chain::get_resource_limits_response resp; + *resp.mutable_resource_limit_data() = value; - return resp; + return resp; } rpc::chain::get_account_rc_response controller_impl::get_account_rc( const rpc::chain::get_account_rc_request& request ) { - KOINOS_ASSERT( request.account().size(), missing_required_arguments_exception, "missing expected field: ${f}", ("f", "payer") ); + KOINOS_ASSERT( request.account().size(), + missing_required_arguments_exception, + "missing expected field: ${f}", + ( "f", "payer" ) ); - execution_context ctx( _vm_backend ); - ctx.push_frame( stack_frame { - .call_privilege = privilege::kernel_mode - } ); + execution_context ctx( _vm_backend ); + ctx.push_frame( stack_frame{ .call_privilege = privilege::kernel_mode } ); - ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); - ctx.reset_cache(); + ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); + ctx.reset_cache(); - auto value = system_call::get_account_rc( ctx, request.account() ); + auto value = system_call::get_account_rc( ctx, request.account() ); - rpc::chain::get_account_rc_response resp; - resp.set_rc( value ); + rpc::chain::get_account_rc_response resp; + resp.set_rc( value ); - return resp; + return resp; } rpc::chain::get_fork_heads_response controller_impl::get_fork_heads( const rpc::chain::get_fork_heads_request& ) { - rpc::chain::get_fork_heads_response resp; + rpc::chain::get_fork_heads_response resp; - const auto [ fork_heads, last_irreversible_block ] = get_fork_data( _db.get_shared_lock() ); - auto topo = resp.mutable_last_irreversible_block(); - *topo = std::move( last_irreversible_block ); + const auto [ fork_heads, last_irreversible_block ] = get_fork_data( _db.get_shared_lock() ); + auto topo = resp.mutable_last_irreversible_block(); + *topo = std::move( last_irreversible_block ); - for ( const auto& fork_head : fork_heads ) - { - auto* head = resp.add_fork_heads(); - *head = fork_head; - } + for( const auto& fork_head: fork_heads ) + { + auto* head = resp.add_fork_heads(); + *head = fork_head; + } - return resp; + return resp; } rpc::chain::read_contract_response controller_impl::read_contract( const rpc::chain::read_contract_request& request ) { - KOINOS_ASSERT( request.contract_id().size(), missing_required_arguments_exception, "missing expected field: ${f}", ("f", "contract_id") ); - - auto db_lock = _db.get_shared_lock(); + KOINOS_ASSERT( request.contract_id().size(), + missing_required_arguments_exception, + "missing expected field: ${f}", + ( "f", "contract_id" ) ); - execution_context ctx( _vm_backend, intent::read_only ); - ctx.push_frame( stack_frame { - .call_privilege = privilege::user_mode, - } ); + auto db_lock = _db.get_shared_lock(); - std::shared_ptr< const protocol::block > head_block_ptr; + execution_context ctx( _vm_backend, intent::read_only ); + ctx.push_frame( stack_frame{ + .call_privilege = privilege::user_mode, + } ); - { - std::shared_lock< std::shared_mutex > head_lock( _cached_head_block_mutex ); - head_block_ptr = _cached_head_block; - KOINOS_ASSERT( head_block_ptr, internal_error_exception, "error retrieving head block" ); + std::shared_ptr< const protocol::block > head_block_ptr; - ctx.set_state_node( _db.get_head( db_lock )->create_anonymous_node() ); - } + { + std::shared_lock< std::shared_mutex > head_lock( _cached_head_block_mutex ); + head_block_ptr = _cached_head_block; + KOINOS_ASSERT( head_block_ptr, internal_error_exception, "error retrieving head block" ); - ctx.set_block( *head_block_ptr ); - ctx.reset_cache(); + ctx.set_state_node( _db.get_head( db_lock )->create_anonymous_node() ); + } - resource_limit_data rl; - rl.set_compute_bandwidth_limit( _read_compute_bandwidth_limit ); + ctx.set_block( *head_block_ptr ); + ctx.reset_cache(); - ctx.resource_meter().set_resource_limit_data( rl ); + resource_limit_data rl; + rl.set_compute_bandwidth_limit( _read_compute_bandwidth_limit ); - rpc::chain::read_contract_response resp; + ctx.resource_meter().set_resource_limit_data( rl ); - try - { - resp.set_result( system_call::call( ctx, request.contract_id(), request.entry_point(), request.args() ) ); - } - catch ( koinos::exception& e ) - { - e.add_json( "logs", ctx.chronicler().logs() ); - throw e; - } + rpc::chain::read_contract_response resp; + try + { + resp.set_result( system_call::call( ctx, request.contract_id(), request.entry_point(), request.args() ) ); + } + catch( koinos::exception& e ) + { + e.add_json( "logs", ctx.chronicler().logs() ); + throw e; + } - for ( const auto& message : ctx.chronicler().logs() ) - *resp.add_logs() = message; + for( const auto& message: ctx.chronicler().logs() ) + *resp.add_logs() = message; - return resp; + return resp; } -rpc::chain::get_account_nonce_response controller_impl::get_account_nonce( const rpc::chain::get_account_nonce_request& request ) +rpc::chain::get_account_nonce_response +controller_impl::get_account_nonce( const rpc::chain::get_account_nonce_request& request ) { - KOINOS_ASSERT( request.account().size(), missing_required_arguments_exception, "missing expected field: ${f}", ("f", "account") ); + KOINOS_ASSERT( request.account().size(), + missing_required_arguments_exception, + "missing expected field: ${f}", + ( "f", "account" ) ); - execution_context ctx( _vm_backend ); + execution_context ctx( _vm_backend ); - ctx.push_frame( koinos::chain::stack_frame { - .call_privilege = privilege::kernel_mode - } ); + ctx.push_frame( koinos::chain::stack_frame{ .call_privilege = privilege::kernel_mode } ); - ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); - ctx.reset_cache(); + ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); + ctx.reset_cache(); - auto nonce = system_call::get_account_nonce( ctx, request.account() ); + auto nonce = system_call::get_account_nonce( ctx, request.account() ); - rpc::chain::get_account_nonce_response resp; - resp.set_nonce( nonce ); + rpc::chain::get_account_nonce_response resp; + resp.set_nonce( nonce ); - return resp; + return resp; } -rpc::chain::invoke_system_call_response controller_impl::invoke_system_call( const rpc::chain::invoke_system_call_request& request ) +rpc::chain::invoke_system_call_response +controller_impl::invoke_system_call( const rpc::chain::invoke_system_call_request& request ) { - KOINOS_ASSERT( - request.has_id() || request.has_name(), - missing_required_arguments_exception, - "missing expected field: ${f1} or ${f2}", ("f1", "id")("f2", "name") - ); + KOINOS_ASSERT( request.has_id() || request.has_name(), + missing_required_arguments_exception, + "missing expected field: ${f1} or ${f2}", + ( "f1", "id" )( "f2", "name" ) ); - execution_context ctx( _vm_backend, intent::read_only ); + execution_context ctx( _vm_backend, intent::read_only ); - stack_frame sframe; + stack_frame sframe; - if ( request.has_caller_data() ) - { - sframe.contract_id = request.caller_data().caller(); - sframe.call_privilege = request.caller_data().caller_privilege(); - } - else - { - sframe.call_privilege = privilege::kernel_mode; - } + if( request.has_caller_data() ) + { + sframe.contract_id = request.caller_data().caller(); + sframe.call_privilege = request.caller_data().caller_privilege(); + } + else + { + sframe.call_privilege = privilege::kernel_mode; + } - ctx.push_frame( std::move( sframe ) ); + ctx.push_frame( std::move( sframe ) ); - ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); - ctx.reset_cache(); + ctx.set_state_node( _db.get_head( _db.get_shared_lock() )->create_anonymous_node() ); + ctx.reset_cache(); - resource_limit_data rl; - rl.set_compute_bandwidth_limit( _read_compute_bandwidth_limit ); + resource_limit_data rl; + rl.set_compute_bandwidth_limit( _read_compute_bandwidth_limit ); - ctx.resource_meter().set_resource_limit_data( rl ); + ctx.resource_meter().set_resource_limit_data( rl ); - system_call_id syscall_id; + system_call_id syscall_id; - if ( request.has_id() ) - { - syscall_id = system_call_id( request.id() ); - } - else - { - if ( !system_call_id_Parse( request.name(), &syscall_id ) ) - KOINOS_THROW( unknown_system_call_exception, "unknown system call name" ); - } + if( request.has_id() ) + { + syscall_id = system_call_id( request.id() ); + } + else + { + if( !system_call_id_Parse( request.name(), &syscall_id ) ) + KOINOS_THROW( unknown_system_call_exception, "unknown system call name" ); + } - koinos::chain::host_api hapi( ctx ); + koinos::chain::host_api hapi( ctx ); - std::vector< char > buffer( _syscall_bufsize, 0 ); - uint32_t bytes_written; - rpc::chain::invoke_system_call_response resp; + std::vector< char > buffer( _syscall_bufsize, 0 ); + uint32_t bytes_written; + rpc::chain::invoke_system_call_response resp; - hapi.call( syscall_id, &buffer[0], _syscall_bufsize, request.args().c_str(), uint32_t( request.args().size() ), &bytes_written ); + hapi.call( syscall_id, + &buffer[ 0 ], + _syscall_bufsize, + request.args().c_str(), + uint32_t( request.args().size() ), + &bytes_written ); - resp.set_value( std::string( &buffer[0], bytes_written ) ); + resp.set_value( std::string( &buffer[ 0 ], bytes_written ) ); - return resp; + return resp; } -} // detail +} // namespace detail -controller::controller( uint64_t read_compute_bandwith_limit, uint32_t syscall_bufsize ) : - _my( std::make_unique< detail::controller_impl >( read_compute_bandwith_limit, syscall_bufsize ) ) {} +controller::controller( uint64_t read_compute_bandwith_limit, uint32_t syscall_bufsize ): + _my( std::make_unique< detail::controller_impl >( read_compute_bandwith_limit, syscall_bufsize ) ) +{} controller::~controller() = default; -void controller::open( const std::filesystem::path& p, const chain::genesis_data& data, fork_resolution_algorithm algo, bool reset ) +void controller::open( const std::filesystem::path& p, + const chain::genesis_data& data, + fork_resolution_algorithm algo, + bool reset ) { - _my->open( p, data, algo, reset ); + _my->open( p, data, algo, reset ); } void controller::close() { - _my->close(); + _my->close(); } void controller::set_client( std::shared_ptr< mq::client > c ) { - _my->set_client( c ); + _my->set_client( c ); } -rpc::chain::submit_block_response controller::submit_block( - const rpc::chain::submit_block_request& request, - uint64_t index_to, - std::chrono::system_clock::time_point now ) +rpc::chain::submit_block_response controller::submit_block( const rpc::chain::submit_block_request& request, + uint64_t index_to, + std::chrono::system_clock::time_point now ) { - return _my->submit_block( request, index_to, now ); + return _my->submit_block( request, index_to, now ); } -rpc::chain::submit_transaction_response controller::submit_transaction( const rpc::chain::submit_transaction_request& request ) +rpc::chain::submit_transaction_response +controller::submit_transaction( const rpc::chain::submit_transaction_request& request ) { - return _my->submit_transaction( request ); + return _my->submit_transaction( request ); } rpc::chain::get_head_info_response controller::get_head_info( const rpc::chain::get_head_info_request& request ) { - return _my->get_head_info( request ); + return _my->get_head_info( request ); } rpc::chain::get_chain_id_response controller::get_chain_id( const rpc::chain::get_chain_id_request& request ) { - return _my->get_chain_id( request ); + return _my->get_chain_id( request ); } rpc::chain::get_fork_heads_response controller::get_fork_heads( const rpc::chain::get_fork_heads_request& request ) { - return _my->get_fork_heads( request ); + return _my->get_fork_heads( request ); } rpc::chain::read_contract_response controller::read_contract( const rpc::chain::read_contract_request& request ) { - return _my->read_contract( request ); + return _my->read_contract( request ); } -rpc::chain::get_account_nonce_response controller::get_account_nonce( const rpc::chain::get_account_nonce_request& request ) +rpc::chain::get_account_nonce_response +controller::get_account_nonce( const rpc::chain::get_account_nonce_request& request ) { - return _my->get_account_nonce( request ); + return _my->get_account_nonce( request ); } rpc::chain::get_account_rc_response controller::get_account_rc( const rpc::chain::get_account_rc_request& request ) { - return _my->get_account_rc( request ); + return _my->get_account_rc( request ); } -rpc::chain::get_resource_limits_response controller::get_resource_limits( const rpc::chain::get_resource_limits_request& request ) +rpc::chain::get_resource_limits_response +controller::get_resource_limits( const rpc::chain::get_resource_limits_request& request ) { - return _my->get_resource_limits( request ); + return _my->get_resource_limits( request ); } -rpc::chain::invoke_system_call_response controller::invoke_system_call( const rpc::chain::invoke_system_call_request& request ) +rpc::chain::invoke_system_call_response +controller::invoke_system_call( const rpc::chain::invoke_system_call_request& request ) { - return _my->invoke_system_call( request ); + return _my->invoke_system_call( request ); } - -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/execution_context.cpp b/src/koinos/chain/execution_context.cpp index 0d2809ea..bd5f4e9e 100644 --- a/src/koinos/chain/execution_context.cpp +++ b/src/koinos/chain/execution_context.cpp @@ -1,408 +1,442 @@ +#include #include #include #include #include -#include #include namespace koinos::chain { -execution_context::execution_context( std::shared_ptr< vm_manager::vm_backend > vm_backend, chain::intent i ) : - _vm_backend( vm_backend ) +execution_context::execution_context( std::shared_ptr< vm_manager::vm_backend > vm_backend, chain::intent i ): + _vm_backend( vm_backend ) { - set_intent( i ); + set_intent( i ); } std::shared_ptr< vm_manager::vm_backend > execution_context::get_backend() const { - return _vm_backend; + return _vm_backend; } void execution_context::set_state_node( abstract_state_node_ptr node, abstract_state_node_ptr parent ) { - _current_state_node = node; - if ( parent ) - _parent_state_node = parent; - else if ( _current_state_node ) - _parent_state_node = node->parent(); - else - _parent_state_node.reset(); + _current_state_node = node; + if( parent ) + _parent_state_node = parent; + else if( _current_state_node ) + _parent_state_node = node->parent(); + else + _parent_state_node.reset(); } abstract_state_node_ptr execution_context::get_state_node() const { - return _current_state_node; + return _current_state_node; } abstract_state_node_ptr execution_context::get_parent_node() const { - // This handles the genesis case - return _parent_state_node ? _parent_state_node : _current_state_node; + // This handles the genesis case + return _parent_state_node ? _parent_state_node : _current_state_node; } void execution_context::clear_state_node() { - _current_state_node.reset(); - _parent_state_node.reset(); + _current_state_node.reset(); + _parent_state_node.reset(); } void execution_context::set_block( const protocol::block& block ) { - _block = █ + _block = █ } const protocol::block* execution_context::get_block() const { - return _block; + return _block; } void execution_context::clear_block() { - _block = nullptr; + _block = nullptr; } void execution_context::set_transaction( const protocol::transaction& trx ) { - _trx = &trx; + _trx = &trx; } const protocol::transaction* execution_context::get_transaction() const { - return _trx; + return _trx; } void execution_context::clear_transaction() { - _trx = nullptr; + _trx = nullptr; } void execution_context::set_operation( const protocol::operation& op ) { - _op = &op; + _op = &op; } const protocol::operation* execution_context::get_operation() const { - return _op; + return _op; } void execution_context::clear_operation() { - _op = nullptr; + _op = nullptr; } const std::string& execution_context::get_contract_call_args() const { - KOINOS_ASSERT( _stack.size() > 1, chain::internal_error_exception, "stack is empty" ); - return _stack[ _stack.size() - 2 ].call_args; + KOINOS_ASSERT( _stack.size() > 1, chain::internal_error_exception, "stack is empty" ); + return _stack[ _stack.size() - 2 ].call_args; } uint32_t execution_context::get_contract_entry_point() const { - KOINOS_ASSERT( _stack.size() > 1, chain::internal_error_exception, "stack is empty" ); - return _stack[ _stack.size() - 2 ].entry_point; + KOINOS_ASSERT( _stack.size() > 1, chain::internal_error_exception, "stack is empty" ); + return _stack[ _stack.size() - 2 ].entry_point; } void execution_context::push_frame( stack_frame&& frame ) { - KOINOS_ASSERT( _stack.size() < execution_context::stack_limit, chain::reversion_exception, "apply context stack overflow" ); - _stack.emplace_back( std::move(frame) ); + KOINOS_ASSERT( _stack.size() < execution_context::stack_limit, + chain::reversion_exception, + "apply context stack overflow" ); + _stack.emplace_back( std::move( frame ) ); } stack_frame execution_context::pop_frame() { - KOINOS_ASSERT( _stack.size(), chain::internal_error_exception, "stack is empty" ); - auto frame = _stack[ _stack.size() - 1 ]; - _stack.pop_back(); - return frame; + KOINOS_ASSERT( _stack.size(), chain::internal_error_exception, "stack is empty" ); + auto frame = _stack[ _stack.size() - 1 ]; + _stack.pop_back(); + return frame; } const std::string& execution_context::get_caller() const { - if ( _stack.size() > 1 ) - return _stack[ _stack.size() - 2 ].contract_id; + if( _stack.size() > 1 ) + return _stack[ _stack.size() - 2 ].contract_id; - return constants::system; + return constants::system; } privilege execution_context::get_caller_privilege() const { - if ( _stack.size() > 1 ) - return _stack[ _stack.size() - 2 ].call_privilege; + if( _stack.size() > 1 ) + return _stack[ _stack.size() - 2 ].call_privilege; - return privilege::kernel_mode; + return privilege::kernel_mode; } uint32_t execution_context::get_caller_entry_point() const { - if ( _stack.size() > 1 ) - return _stack[ _stack.size() - 2 ].entry_point; + if( _stack.size() > 1 ) + return _stack[ _stack.size() - 2 ].entry_point; - return 0; + return 0; } void execution_context::set_privilege( privilege p ) { - KOINOS_ASSERT( _stack.size(), internal_error_exception, "stack empty" ); - _stack[ _stack.size() - 1 ].call_privilege = p; + KOINOS_ASSERT( _stack.size(), internal_error_exception, "stack empty" ); + _stack[ _stack.size() - 1 ].call_privilege = p; } privilege execution_context::get_privilege() const { - KOINOS_ASSERT( _stack.size(), internal_error_exception, "stack empty" ); - return _stack[ _stack.size() - 1 ].call_privilege; + KOINOS_ASSERT( _stack.size(), internal_error_exception, "stack empty" ); + return _stack[ _stack.size() - 1 ].call_privilege; } const std::string& execution_context::get_contract_id() const { - for ( auto i = _stack.size(); i-- > 0; ) - { - if ( _stack[ i ].contract_id.size() ) - return _stack[ i ].contract_id; - } + for( auto i = _stack.size(); i-- > 0; ) + { + if( _stack[ i ].contract_id.size() ) + return _stack[ i ].contract_id; + } - return constants::system; + return constants::system; } bool execution_context::read_only() const { - return _intent == intent::read_only; + return _intent == intent::read_only; } resource_meter& execution_context::resource_meter() { - return _resource_meter; + return _resource_meter; } chronicler& execution_context::chronicler() { - return _chronicler; + return _chronicler; } std::shared_ptr< session > execution_context::make_session( uint64_t rc ) { - auto session = std::make_shared< chain::session >( rc ); - resource_meter().set_session( session ); - chronicler().set_session( session ); - return session; + auto session = std::make_shared< chain::session >( rc ); + resource_meter().set_session( session ); + chronicler().set_session( session ); + return session; } chain::receipt& execution_context::receipt() { - return _receipt; + return _receipt; } void execution_context::set_intent( chain::intent i ) { - _intent = i; + _intent = i; } chain::intent execution_context::intent() const { - return _intent; + return _intent; } void execution_context::build_compute_registry_cache() { - auto parent_state_node = get_parent_node(); - KOINOS_ASSERT( parent_state_node, chain::reversion_exception, "cannot build execution context cache without a state node" ); + auto parent_state_node = get_parent_node(); + KOINOS_ASSERT( parent_state_node, + chain::reversion_exception, + "cannot build execution context cache without a state node" ); - auto obj = parent_state_node->get_object( state::space::metadata(), state::key::compute_bandwidth_registry ); - KOINOS_ASSERT( obj, chain::reversion_exception, "compute bandwidth registry does not exist" ); - auto compute_registry = util::converter::to< compute_bandwidth_registry >( *obj ); + auto obj = parent_state_node->get_object( state::space::metadata(), state::key::compute_bandwidth_registry ); + KOINOS_ASSERT( obj, chain::reversion_exception, "compute bandwidth registry does not exist" ); + auto compute_registry = util::converter::to< compute_bandwidth_registry >( *obj ); - _cache.compute_bandwidth.emplace(); - for ( const auto& entry : compute_registry.entries() ) - ( *_cache.compute_bandwidth )[ entry.name() ] = entry.compute(); + _cache.compute_bandwidth.emplace(); + for( const auto& entry: compute_registry.entries() ) + ( *_cache.compute_bandwidth )[ entry.name() ] = entry.compute(); } void execution_context::build_descriptor_pool() { - auto parent_state_node = get_parent_node(); - KOINOS_ASSERT( parent_state_node, chain::reversion_exception, "cannot build execution context cache without a state node" ); + auto parent_state_node = get_parent_node(); + KOINOS_ASSERT( parent_state_node, + chain::reversion_exception, + "cannot build execution context cache without a state node" ); - auto pdesc = parent_state_node->get_object( state::space::metadata(), state::key::protocol_descriptor ); - KOINOS_ASSERT( pdesc, chain::reversion_exception, "file descriptor set does not exist" ); + auto pdesc = parent_state_node->get_object( state::space::metadata(), state::key::protocol_descriptor ); + KOINOS_ASSERT( pdesc, chain::reversion_exception, "file descriptor set does not exist" ); - google::protobuf::FileDescriptorSet fdesc; - KOINOS_ASSERT( fdesc.ParseFromString( *pdesc ), chain::reversion_exception, "file descriptor set is malformed" ); + google::protobuf::FileDescriptorSet fdesc; + KOINOS_ASSERT( fdesc.ParseFromString( *pdesc ), chain::reversion_exception, "file descriptor set is malformed" ); - _cache.descriptor_pool.emplace(); - for ( const auto& fd : fdesc.file() ) - _cache.descriptor_pool->BuildFile( fd ); + _cache.descriptor_pool.emplace(); + for( const auto& fd: fdesc.file() ) + _cache.descriptor_pool->BuildFile( fd ); } void execution_context::cache_system_call( uint32_t id ) { - auto parent_state_node = get_parent_node(); - KOINOS_ASSERT( parent_state_node, chain::reversion_exception, "cannot build execution context cache without a state node" ); - - if ( _cache.system_call_table.find( id ) != _cache.system_call_table.end() ) - return; - - auto obj = parent_state_node->get_object( state::space::system_call_dispatch(), util::converter::as< std::string >( id ) ); - - if ( obj != nullptr ) - { - auto system_call_target = util::converter::to< protocol::system_call_target >( *obj ); - - if ( system_call_target.has_system_call_bundle() ) - { - const auto& contract_id = system_call_target.system_call_bundle().contract_id(); - auto entry_point = system_call_target.system_call_bundle().entry_point(); - auto contract_meta = parent_state_node->get_object( state::space::contract_metadata(), util::converter::as< std::string >( contract_id ) ); - auto contract_bytecode = parent_state_node->get_object( state::space::contract_bytecode(), util::converter::as< std::string >( contract_id ) ); - - KOINOS_ASSERT( contract_meta, invalid_contract_exception, "contract metadata for call id ${id} not found", ("id", id) ); - KOINOS_ASSERT( contract_bytecode, invalid_contract_exception, "contract bytecode for call id ${id} not found", ("id", id) ); - - auto success = _cache.system_call_table.emplace( - id, - system_call_cache_bundle { - contract_id, - *contract_bytecode, - entry_point, - util::converter::to< chain::contract_metadata_object >( *contract_meta ) - } - ).second; - KOINOS_ASSERT( success, internal_error_exception, "caching system call ${id} failed", ("id", id) ); - } - else - { - auto success = _cache.system_call_table.emplace( id, thunk_cache_bundle { system_call_target.thunk_id(), true } ).second; - KOINOS_ASSERT( success, internal_error_exception, "caching system call ${id} failed", ("id", id) ); - } - } - else - { - auto success = _cache.system_call_table.emplace( id, thunk_cache_bundle { id, false } ).second; - KOINOS_ASSERT( success, internal_error_exception, "caching system call ${id} failed", ("id", id) ); - } + auto parent_state_node = get_parent_node(); + KOINOS_ASSERT( parent_state_node, + chain::reversion_exception, + "cannot build execution context cache without a state node" ); + + if( _cache.system_call_table.find( id ) != _cache.system_call_table.end() ) + return; + + auto obj = + parent_state_node->get_object( state::space::system_call_dispatch(), util::converter::as< std::string >( id ) ); + + if( obj != nullptr ) + { + auto system_call_target = util::converter::to< protocol::system_call_target >( *obj ); + + if( system_call_target.has_system_call_bundle() ) + { + const auto& contract_id = system_call_target.system_call_bundle().contract_id(); + auto entry_point = system_call_target.system_call_bundle().entry_point(); + auto contract_meta = parent_state_node->get_object( state::space::contract_metadata(), + util::converter::as< std::string >( contract_id ) ); + auto contract_bytecode = parent_state_node->get_object( state::space::contract_bytecode(), + util::converter::as< std::string >( contract_id ) ); + + KOINOS_ASSERT( contract_meta, + invalid_contract_exception, + "contract metadata for call id ${id} not found", + ( "id", id ) ); + KOINOS_ASSERT( contract_bytecode, + invalid_contract_exception, + "contract bytecode for call id ${id} not found", + ( "id", id ) ); + + auto success = _cache.system_call_table + .emplace( id, + system_call_cache_bundle{ + contract_id, + *contract_bytecode, + entry_point, + util::converter::to< chain::contract_metadata_object >( *contract_meta ) } ) + .second; + KOINOS_ASSERT( success, internal_error_exception, "caching system call ${id} failed", ( "id", id ) ); + } + else + { + auto success = + _cache.system_call_table.emplace( id, thunk_cache_bundle{ system_call_target.thunk_id(), true } ).second; + KOINOS_ASSERT( success, internal_error_exception, "caching system call ${id} failed", ( "id", id ) ); + } + } + else + { + auto success = _cache.system_call_table.emplace( id, thunk_cache_bundle{ id, false } ).second; + KOINOS_ASSERT( success, internal_error_exception, "caching system call ${id} failed", ( "id", id ) ); + } } void execution_context::build_block_hash_code_cache() { - auto parent_state_node = get_parent_node(); - KOINOS_ASSERT( parent_state_node, reversion_exception, "cannot build execution context cache without a state node" ); + auto parent_state_node = get_parent_node(); + KOINOS_ASSERT( parent_state_node, reversion_exception, "cannot build execution context cache without a state node" ); - auto bhash = parent_state_node->get_object( state::space::metadata(), state::key::block_hash_code ); - KOINOS_ASSERT( bhash, invalid_contract_exception, "block hash code does not exist" ); + auto bhash = parent_state_node->get_object( state::space::metadata(), state::key::block_hash_code ); + KOINOS_ASSERT( bhash, invalid_contract_exception, "block hash code does not exist" ); - _cache.block_hash_code.emplace( crypto::multicodec( util::converter::to< unsigned_varint >( *bhash ).value ) ); + _cache.block_hash_code.emplace( crypto::multicodec( util::converter::to< unsigned_varint >( *bhash ).value ) ); } void execution_context::reset_cache() { - _cache.compute_bandwidth.reset(); - _cache.descriptor_pool.reset(); - _cache.system_call_table.clear(); - _cache.block_hash_code.reset(); + _cache.compute_bandwidth.reset(); + _cache.descriptor_pool.reset(); + _cache.system_call_table.clear(); + _cache.block_hash_code.reset(); } uint64_t execution_context::get_compute_bandwidth( const std::string& thunk_name ) { - if ( !_cache.compute_bandwidth ) - build_compute_registry_cache(); + if( !_cache.compute_bandwidth ) + build_compute_registry_cache(); - auto itr = _cache.compute_bandwidth->find( thunk_name ); + auto itr = _cache.compute_bandwidth->find( thunk_name ); - KOINOS_ASSERT( itr != _cache.compute_bandwidth->end(), reversion_exception, "unable to find compute bandwidth for ${t}", ("t", thunk_name) ); + KOINOS_ASSERT( itr != _cache.compute_bandwidth->end(), + reversion_exception, + "unable to find compute bandwidth for ${t}", + ( "t", thunk_name ) ); - return itr->second; + return itr->second; } const google::protobuf::DescriptorPool& execution_context::descriptor_pool() { - if ( !_cache.descriptor_pool ) - build_descriptor_pool(); + if( !_cache.descriptor_pool ) + build_descriptor_pool(); - return *_cache.descriptor_pool; + return *_cache.descriptor_pool; } const execution_result& execution_context::system_call( uint32_t id, const std::string& args ) { - try - { - cache_system_call( id ); - - auto itr = _cache.system_call_table.find( id ); - KOINOS_ASSERT( itr != _cache.system_call_table.end(), reversion_exception, "unable to find call id ${id} in system call cache", ("id", id) ); - - const auto* call_bundle = std::get_if< system_call_cache_bundle >( &itr->second ); - KOINOS_ASSERT( call_bundle, reversion_exception, "system call ${id} is implemented via thunk", ("id", id) ); - - with_stack_frame( - *this, - stack_frame { - .contract_id = call_bundle->contract_id, - .call_privilege = call_bundle->contract_metadata.system() ? privilege::kernel_mode : privilege::user_mode, - .call_args = args, - .entry_point = call_bundle->entry_point - }, - [&] - { - chain::host_api hapi( *this ); - get_backend()->run( hapi, call_bundle->contract_bytecode, call_bundle->contract_metadata.hash() ); - } - ); - } - catch ( const success_exception& ) {} + try + { + cache_system_call( id ); + + auto itr = _cache.system_call_table.find( id ); + KOINOS_ASSERT( itr != _cache.system_call_table.end(), + reversion_exception, + "unable to find call id ${id} in system call cache", + ( "id", id ) ); + + const auto* call_bundle = std::get_if< system_call_cache_bundle >( &itr->second ); + KOINOS_ASSERT( call_bundle, reversion_exception, "system call ${id} is implemented via thunk", ( "id", id ) ); + + with_stack_frame( + *this, + stack_frame{ .contract_id = call_bundle->contract_id, + .call_privilege = + call_bundle->contract_metadata.system() ? privilege::kernel_mode : privilege::user_mode, + .call_args = args, + .entry_point = call_bundle->entry_point }, + [ & ] + { + chain::host_api hapi( *this ); + get_backend()->run( hapi, call_bundle->contract_bytecode, call_bundle->contract_metadata.hash() ); + } ); + } + catch( const success_exception& ) + {} - return get_result(); + return get_result(); } bool execution_context::system_call_exists( uint32_t id ) { - cache_system_call( id ); + cache_system_call( id ); - auto itr = _cache.system_call_table.find( id ); - if ( itr == _cache.system_call_table.end() ) - return false; + auto itr = _cache.system_call_table.find( id ); + if( itr == _cache.system_call_table.end() ) + return false; - return std::get_if< system_call_cache_bundle >( &itr->second ) != nullptr; + return std::get_if< system_call_cache_bundle >( &itr->second ) != nullptr; } uint32_t execution_context::thunk_translation( uint32_t id ) { - cache_system_call( id ); + cache_system_call( id ); - auto itr = _cache.system_call_table.find( id ); - KOINOS_ASSERT( itr != _cache.system_call_table.end(), reversion_exception, "unable to find call id ${id} in system call cache", ("id", id) ); + auto itr = _cache.system_call_table.find( id ); + KOINOS_ASSERT( itr != _cache.system_call_table.end(), + reversion_exception, + "unable to find call id ${id} in system call cache", + ( "id", id ) ); - const auto* thunk_bundle = std::get_if< thunk_cache_bundle >( &itr->second ); - KOINOS_ASSERT( thunk_bundle, reversion_exception, "system call ${id} is implemented via contract override", ("id", id) ); + const auto* thunk_bundle = std::get_if< thunk_cache_bundle >( &itr->second ); + KOINOS_ASSERT( thunk_bundle, + reversion_exception, + "system call ${id} is implemented via contract override", + ( "id", id ) ); - if ( thunk_bundle->is_override ) - { - return thunk_bundle->thunk_id; - } + if( thunk_bundle->is_override ) + { + return thunk_bundle->thunk_id; + } - KOINOS_ASSERT( thunk_bundle->thunk_id == id, internal_error_exception, "non-override cached thunk id ${cached} does not match id ${id}", ("cached", thunk_bundle->thunk_id)("id", id) ); - KOINOS_ASSERT( thunk_dispatcher::instance().thunk_is_genesis( id ), unknown_thunk_exception, "thunk ${id} is not enabled", ("id", id) ); - return id; + KOINOS_ASSERT( thunk_bundle->thunk_id == id, + internal_error_exception, + "non-override cached thunk id ${cached} does not match id ${id}", + ( "cached", thunk_bundle->thunk_id )( "id", id ) ); + KOINOS_ASSERT( thunk_dispatcher::instance().thunk_is_genesis( id ), + unknown_thunk_exception, + "thunk ${id} is not enabled", + ( "id", id ) ); + return id; } const crypto::multicodec& execution_context::block_hash_code() { - if ( !_cache.block_hash_code ) - build_block_hash_code_cache(); + if( !_cache.block_hash_code ) + build_block_hash_code_cache(); - return *_cache.block_hash_code; + return *_cache.block_hash_code; } void execution_context::set_result( const execution_result& r ) { - _result = r; + _result = r; } void execution_context::set_result( execution_result&& r ) { - _result = std::move( r ); + _result = std::move( r ); } const execution_result& execution_context::get_result() { - return _result; + return _result; } -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/host_api.cpp b/src/koinos/chain/host_api.cpp index 955cd5de..3ce8e9ab 100644 --- a/src/koinos/chain/host_api.cpp +++ b/src/koinos/chain/host_api.cpp @@ -1,10 +1,10 @@ #include #include -#include #include -#include #include +#include +#include #include #include @@ -13,166 +13,188 @@ using namespace std::string_literals; namespace koinos::chain { -host_api::host_api( execution_context& ctx ) : _ctx( ctx ) {} -host_api::~host_api() {} - -int32_t host_api::invoke_thunk( uint32_t tid, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written ) -{ - KOINOS_ASSERT( _ctx.get_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "'invoke_thunk' must be called from a system context" ); - - int32_t code = 0; - error_data error; - - try - { - thunk_dispatcher::instance().call_thunk( tid, _ctx, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); - } - catch ( koinos::exception& e ) - { - code = e.get_code(); - error = e.get_data(); - } - - if ( tid == system_call_id::exit ) - { - if ( code >= chain::reversion ) - throw reversion_exception( code, error ); - if ( code <= chain::failure ) - throw failure_exception( code, error ); - - throw success_exception( code ); - } - - if ( code != chain::success ) - { - auto error_bytes = util::converter::as< std::string >( error ); - - auto msg_len = error_bytes.size(); - if ( msg_len <= ret_len ) - { - std::memcpy( ret_ptr, error_bytes.data(), msg_len ); - *bytes_written = uint32_t( msg_len ); - } - else - { - code = chain::insufficient_return_buffer; - *bytes_written = 0; - } - } +host_api::host_api( execution_context& ctx ): + _ctx( ctx ) +{} - return code; -} +host_api::~host_api() {} -void host_api::call( uint32_t sid, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written ) +int32_t host_api::invoke_thunk( uint32_t tid, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) { - *bytes_written = 0; - - with_stack_frame( - _ctx, - stack_frame { - .sid = sid, - .call_privilege = privilege::kernel_mode - }, - [&]() { - if ( _ctx.system_call_exists( sid ) ) - { - std::string args( arg_ptr, arg_len ); - auto exec_res = _ctx.system_call( sid, args ); - - if ( exec_res.res.has_object() ) - { - auto obj_len = exec_res.res.object().size(); - KOINOS_ASSERT( obj_len <= ret_len, insufficient_return_buffer_exception, "return buffer is not large enough for the return value" ); - memcpy( ret_ptr, exec_res.res.object().data(), obj_len ); - *bytes_written = uint32_t( obj_len ); - } - } - else - { - auto thunk_id = _ctx.thunk_translation( sid ); - KOINOS_ASSERT( thunk_dispatcher::instance().thunk_exists( thunk_id ), unknown_thunk_exception, "thunk ${tid} does not exist", ("tid", thunk_id) ); - auto desc = chain::system_call_id_descriptor(); - auto enum_value = desc->FindValueByNumber( thunk_id ); - KOINOS_ASSERT( enum_value, unknown_thunk_exception, "unrecognized thunk id ${id}", ("id", thunk_id) ); - auto compute = _ctx.get_compute_bandwidth( enum_value->name() ); - _ctx.resource_meter().use_compute_bandwidth( compute ); - thunk_dispatcher::instance().call_thunk( thunk_id, _ctx, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); - } - } - ); + KOINOS_ASSERT( _ctx.get_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "'invoke_thunk' must be called from a system context" ); + + int32_t code = 0; + error_data error; + + try + { + thunk_dispatcher::instance().call_thunk( tid, _ctx, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); + } + catch( koinos::exception& e ) + { + code = e.get_code(); + error = e.get_data(); + } + + if( tid == system_call_id::exit ) + { + if( code >= chain::reversion ) + throw reversion_exception( code, error ); + if( code <= chain::failure ) + throw failure_exception( code, error ); + + throw success_exception( code ); + } + + if( code != chain::success ) + { + auto error_bytes = util::converter::as< std::string >( error ); + + auto msg_len = error_bytes.size(); + if( msg_len <= ret_len ) + { + std::memcpy( ret_ptr, error_bytes.data(), msg_len ); + *bytes_written = uint32_t( msg_len ); + } + else + { + code = chain::insufficient_return_buffer; + *bytes_written = 0; + } + } + + return code; } -int32_t host_api::invoke_system_call( uint32_t sid, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written ) +void host_api::call( uint32_t sid, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) { - int32_t code = 0; - error_data error; - - try - { - call( sid, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); - } - catch ( const koinos::exception& e ) - { - error = e.get_data(); - code = e.get_code(); - } - - if ( _ctx.get_privilege() == privilege::user_mode && code >= reversion ) - throw reversion_exception( code, error ); - - if ( sid == system_call_id::exit ) - { - if ( code >= reversion ) - throw reversion_exception( code, error ); - if ( code <= failure ) - throw failure_exception( code, error ); - - throw success_exception(); - } - - if ( code != chain::success ) - { - auto error_bytes = util::converter::as< std::string >( error ); - - auto msg_len = error_bytes.size(); - if ( msg_len <= ret_len ) + *bytes_written = 0; + + with_stack_frame( + _ctx, + stack_frame{ .sid = sid, .call_privilege = privilege::kernel_mode }, + [ & ]() + { + if( _ctx.system_call_exists( sid ) ) { - std::memcpy( ret_ptr, error_bytes.data(), msg_len ); - *bytes_written = uint32_t( msg_len ); + std::string args( arg_ptr, arg_len ); + auto exec_res = _ctx.system_call( sid, args ); + + if( exec_res.res.has_object() ) + { + auto obj_len = exec_res.res.object().size(); + KOINOS_ASSERT( obj_len <= ret_len, + insufficient_return_buffer_exception, + "return buffer is not large enough for the return value" ); + memcpy( ret_ptr, exec_res.res.object().data(), obj_len ); + *bytes_written = uint32_t( obj_len ); + } } else { - code = chain::insufficient_return_buffer; - *bytes_written = 0; + auto thunk_id = _ctx.thunk_translation( sid ); + KOINOS_ASSERT( thunk_dispatcher::instance().thunk_exists( thunk_id ), + unknown_thunk_exception, + "thunk ${tid} does not exist", + ( "tid", thunk_id ) ); + auto desc = chain::system_call_id_descriptor(); + auto enum_value = desc->FindValueByNumber( thunk_id ); + KOINOS_ASSERT( enum_value, unknown_thunk_exception, "unrecognized thunk id ${id}", ( "id", thunk_id ) ); + auto compute = _ctx.get_compute_bandwidth( enum_value->name() ); + _ctx.resource_meter().use_compute_bandwidth( compute ); + thunk_dispatcher::instance().call_thunk( thunk_id, _ctx, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); } - } + } ); +} - return code; +int32_t host_api::invoke_system_call( uint32_t sid, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) +{ + int32_t code = 0; + error_data error; + + try + { + call( sid, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); + } + catch( const koinos::exception& e ) + { + error = e.get_data(); + code = e.get_code(); + } + + if( _ctx.get_privilege() == privilege::user_mode && code >= reversion ) + throw reversion_exception( code, error ); + + if( sid == system_call_id::exit ) + { + if( code >= reversion ) + throw reversion_exception( code, error ); + if( code <= failure ) + throw failure_exception( code, error ); + + throw success_exception(); + } + + if( code != chain::success ) + { + auto error_bytes = util::converter::as< std::string >( error ); + + auto msg_len = error_bytes.size(); + if( msg_len <= ret_len ) + { + std::memcpy( ret_ptr, error_bytes.data(), msg_len ); + *bytes_written = uint32_t( msg_len ); + } + else + { + code = chain::insufficient_return_buffer; + *bytes_written = 0; + } + } + + return code; } int64_t host_api::get_meter_ticks() const { - auto compute_bandwidth_remaining = _ctx.resource_meter().compute_bandwidth_remaining(); + auto compute_bandwidth_remaining = _ctx.resource_meter().compute_bandwidth_remaining(); - // If we have more ticks than fizzy can accept - if ( compute_bandwidth_remaining > std::numeric_limits< int64_t >::max() ) - compute_bandwidth_remaining = std::numeric_limits< int64_t >::max(); + // If we have more ticks than fizzy can accept + if( compute_bandwidth_remaining > std::numeric_limits< int64_t >::max() ) + compute_bandwidth_remaining = std::numeric_limits< int64_t >::max(); - int64_t ticks = compute_bandwidth_remaining; - return ticks; + int64_t ticks = compute_bandwidth_remaining; + return ticks; } void host_api::use_meter_ticks( uint64_t meter_ticks ) { - if ( meter_ticks > _ctx.resource_meter().compute_bandwidth_remaining() ) - { - _ctx.resource_meter().use_compute_bandwidth( _ctx.resource_meter().compute_bandwidth_remaining() ); - _ctx.resource_meter().use_compute_bandwidth( 1 ); - } - else - { - _ctx.resource_meter().use_compute_bandwidth( meter_ticks ); - } + if( meter_ticks > _ctx.resource_meter().compute_bandwidth_remaining() ) + { + _ctx.resource_meter().use_compute_bandwidth( _ctx.resource_meter().compute_bandwidth_remaining() ); + _ctx.resource_meter().use_compute_bandwidth( 1 ); + } + else + { + _ctx.resource_meter().use_compute_bandwidth( meter_ticks ); + } } -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/indexer.cpp b/src/koinos/chain/indexer.cpp index 660bbe4d..cb66a5c2 100644 --- a/src/koinos/chain/indexer.cpp +++ b/src/koinos/chain/indexer.cpp @@ -9,233 +9,239 @@ namespace koinos::chain { -indexer::indexer( boost::asio::io_context& ioc, controller& c, std::shared_ptr< mq::client > mc ) : - _ioc( ioc ), - _controller( c ), - _client( mc ), - _signals( ioc ) +indexer::indexer( boost::asio::io_context& ioc, controller& c, std::shared_ptr< mq::client > mc ): + _ioc( ioc ), + _controller( c ), + _client( mc ), + _signals( ioc ) { - _signals.add( SIGINT ); - _signals.add( SIGTERM ); -#if defined(SIGQUIT) - _signals.add( SIGQUIT ); + _signals.add( SIGINT ); + _signals.add( SIGTERM ); +#if defined( SIGQUIT ) + _signals.add( SIGQUIT ); #endif // defined(SIGQUIT) - _signals.async_wait( [&]( const boost::system::error_code& err, int num ) - { + _signals.async_wait( + [ & ]( const boost::system::error_code& err, int num ) + { _stopped = true; - if ( _complete.has_value() ) + if( _complete.has_value() ) { - _complete->set_value( false ); - _complete.reset(); + _complete->set_value( false ); + _complete.reset(); } _request_queue.close(); _block_queue.close(); - } ); + } ); } void indexer::handle_error( const std::string& msg ) { - _stopped = true; + _stopped = true; - if ( _complete.has_value() ) - { - _complete->set_exception( std::make_exception_ptr( indexer_failure_exception( msg ) ) ); - _complete.reset(); - } + if( _complete.has_value() ) + { + _complete->set_exception( std::make_exception_ptr( indexer_failure_exception( msg ) ) ); + _complete.reset(); + } - _request_queue.close(); - _block_queue.close(); + _request_queue.close(); + _block_queue.close(); } std::future< bool > indexer::index() { - boost::asio::post( std::bind( &indexer::prepare_index, this ) ); - return _complete->get_future(); + boost::asio::post( std::bind( &indexer::prepare_index, this ) ); + return _complete->get_future(); } void indexer::prepare_index() { - try - { - if ( _stopped ) - return; + try + { + if( _stopped ) + return; - LOG(info) << "Retrieving highest block from block store"; - rpc::block_store::block_store_request req; - req.mutable_get_highest_block(); + LOG( info ) << "Retrieving highest block from block store"; + rpc::block_store::block_store_request req; + req.mutable_get_highest_block(); - std::shared_future< std::string > data; + std::shared_future< std::string > data; - rpc::block_store::block_store_response resp; + rpc::block_store::block_store_response resp; - data = _client->rpc( util::service::block_store, req.SerializeAsString() ); + data = _client->rpc( util::service::block_store, req.SerializeAsString() ); - if ( !resp.ParseFromString( data.get() ) ) - return handle_error( "could not get highest block from block store" ); + if( !resp.ParseFromString( data.get() ) ) + return handle_error( "could not get highest block from block store" ); - if ( resp.has_error() ) - return handle_error( resp.error().message() ); + if( resp.has_error() ) + return handle_error( resp.error().message() ); - if ( !resp.has_get_highest_block() ) - return handle_error( "unexpected block store response" ); + if( !resp.has_get_highest_block() ) + return handle_error( "unexpected block store response" ); - _target_head = resp.get_highest_block().topology(); + _target_head = resp.get_highest_block().topology(); - _start_head_info = _controller.get_head_info(); + _start_head_info = _controller.get_head_info(); - if ( _start_head_info.head_topology().height() < _target_head.height() ) - { - LOG(info) << "Indexing to target block - Height: " << _target_head.height() << ", ID: " << util::to_hex( _target_head.id() ); - boost::asio::post( std::bind( &indexer::send_requests, this, _start_head_info.head_topology().height(), 50 ) ); - boost::asio::post( std::bind( &indexer::process_block, this ) ); - } - else - { - LOG(info) << "Chain state is synchronized with block store"; - _complete->set_value( true ); - _complete.reset(); - } - } - catch ( const std::exception& e ) - { - return handle_error( e.what() ); - } - catch ( const boost::exception& e ) - { - return handle_error( boost::diagnostic_information( e ) ); - } + if( _start_head_info.head_topology().height() < _target_head.height() ) + { + LOG( info ) << "Indexing to target block - Height: " << _target_head.height() + << ", ID: " << util::to_hex( _target_head.id() ); + boost::asio::post( std::bind( &indexer::send_requests, this, _start_head_info.head_topology().height(), 50 ) ); + boost::asio::post( std::bind( &indexer::process_block, this ) ); + } + else + { + LOG( info ) << "Chain state is synchronized with block store"; + _complete->set_value( true ); + _complete.reset(); + } + } + catch( const std::exception& e ) + { + return handle_error( e.what() ); + } + catch( const boost::exception& e ) + { + return handle_error( boost::diagnostic_information( e ) ); + } } void indexer::send_requests( uint64_t last_height, uint64_t batch_size ) { - try - { - if ( _stopped ) - return; - - if ( last_height <= _target_head.height() ) - { - rpc::block_store::block_store_request req; - auto* by_height_req = req.mutable_get_blocks_by_height(); - by_height_req->set_head_block_id( _target_head.id() ); - by_height_req->set_ancestor_start_height( last_height + 1 ); - by_height_req->set_num_blocks( uint32_t( batch_size ) ); - by_height_req->set_return_block( true ); - by_height_req->set_return_receipt( false ); - - std::shared_future< std::string > data; + try + { + if( _stopped ) + return; - data = _client->rpc( util::service::block_store, req.SerializeAsString(), std::chrono::milliseconds( 5000 ) ); + if( last_height <= _target_head.height() ) + { + rpc::block_store::block_store_request req; + auto* by_height_req = req.mutable_get_blocks_by_height(); + by_height_req->set_head_block_id( _target_head.id() ); + by_height_req->set_ancestor_start_height( last_height + 1 ); + by_height_req->set_num_blocks( uint32_t( batch_size ) ); + by_height_req->set_return_block( true ); + by_height_req->set_return_receipt( false ); - _request_queue.push( std::move( data ) ); - } - else - { - _requests_complete = true; - } + std::shared_future< std::string > data; - boost::asio::dispatch( std::bind( &indexer::process_requests, this, last_height, batch_size ) ); - } - catch ( boost::sync_queue_is_closed& ) - { - LOG(warning) << "Indexer synchronized queue has been closed"; - } - catch ( const std::exception& e ) - { - return handle_error( e.what() ); - } - catch ( const boost::exception& e ) - { - return handle_error( boost::diagnostic_information( e ) ); - } + data = _client->rpc( util::service::block_store, req.SerializeAsString(), std::chrono::milliseconds( 5'000 ) ); + + _request_queue.push( std::move( data ) ); + } + else + { + _requests_complete = true; + } + + boost::asio::dispatch( std::bind( &indexer::process_requests, this, last_height, batch_size ) ); + } + catch( boost::sync_queue_is_closed& ) + { + LOG( warning ) << "Indexer synchronized queue has been closed"; + } + catch( const std::exception& e ) + { + return handle_error( e.what() ); + } + catch( const boost::exception& e ) + { + return handle_error( boost::diagnostic_information( e ) ); + } } void indexer::process_requests( uint64_t last_height, uint64_t batch_size ) { - try - { - if ( _stopped ) - return; - - if ( _requests_complete && _request_queue.empty() ) - { - _request_processing_complete = true; - return; - } - - auto fut = _request_queue.pull(); - - rpc::block_store::block_store_response resp; - rpc::block_store::get_blocks_by_height_response by_height_resp; - - if ( !resp.ParseFromString( fut.get() ) ) - return handle_error( "could not parse block store response" ); - - if ( resp.has_error() ) - return handle_error( resp.error().message() ); - - if ( !resp.has_get_blocks_by_height() ) - return handle_error( "unexpected block store response" ); - - for ( auto& block_item : *resp.mutable_get_blocks_by_height()->mutable_block_items() ) - _block_queue.push( std::move( *block_item.mutable_block() ) ); - - boost::asio::post( std::bind( &indexer::send_requests, this, last_height + batch_size, std::min( batch_size * 2, uint64_t( 1000 ) ) ) ); - } - catch ( boost::sync_queue_is_closed& ) - { - LOG(warning) << "Indexer synchronized queue has been closed"; - } - catch ( const std::exception& e ) - { - return handle_error( e.what() ); - } - catch ( const boost::exception& e ) - { - return handle_error( boost::diagnostic_information( e ) ); - } + try + { + if( _stopped ) + return; + + if( _requests_complete && _request_queue.empty() ) + { + _request_processing_complete = true; + return; + } + + auto fut = _request_queue.pull(); + + rpc::block_store::block_store_response resp; + rpc::block_store::get_blocks_by_height_response by_height_resp; + + if( !resp.ParseFromString( fut.get() ) ) + return handle_error( "could not parse block store response" ); + + if( resp.has_error() ) + return handle_error( resp.error().message() ); + + if( !resp.has_get_blocks_by_height() ) + return handle_error( "unexpected block store response" ); + + for( auto& block_item: *resp.mutable_get_blocks_by_height()->mutable_block_items() ) + _block_queue.push( std::move( *block_item.mutable_block() ) ); + + boost::asio::post( std::bind( &indexer::send_requests, + this, + last_height + batch_size, + std::min( batch_size * 2, uint64_t( 1'000 ) ) ) ); + } + catch( boost::sync_queue_is_closed& ) + { + LOG( warning ) << "Indexer synchronized queue has been closed"; + } + catch( const std::exception& e ) + { + return handle_error( e.what() ); + } + catch( const boost::exception& e ) + { + return handle_error( boost::diagnostic_information( e ) ); + } } void indexer::process_block() { - try - { - if ( _stopped ) - return; - - if ( _request_processing_complete && _block_queue.empty() ) - { - const auto new_head_info = _controller.get_head_info(); - const std::chrono::duration< double > duration = std::chrono::system_clock::now() - _start_time; - LOG(info) << "Finished indexing " << new_head_info.head_topology().height() - _start_head_info.head_topology().height() << " blocks, took " << duration.count() << " seconds"; - _complete->set_value( true ); - _complete.reset(); - return; - } - - rpc::chain::submit_block_request submit_block; - - *submit_block.mutable_block() = _block_queue.pull(); - _controller.submit_block( submit_block, _target_head.height() ); - - - boost::asio::post( std::bind( &indexer::process_block, this ) ); - } - catch ( boost::sync_queue_is_closed& ) - { - LOG(warning) << "Indexer synchronized queue has been closed"; - } - catch ( const std::exception& e ) - { - return handle_error( e.what() ); - } - catch ( const boost::exception& e ) - { - return handle_error( boost::diagnostic_information( e ) ); - } + try + { + if( _stopped ) + return; + + if( _request_processing_complete && _block_queue.empty() ) + { + const auto new_head_info = _controller.get_head_info(); + const std::chrono::duration< double > duration = std::chrono::system_clock::now() - _start_time; + LOG( info ) << "Finished indexing " + << new_head_info.head_topology().height() - _start_head_info.head_topology().height() + << " blocks, took " << duration.count() << " seconds"; + _complete->set_value( true ); + _complete.reset(); + return; + } + + rpc::chain::submit_block_request submit_block; + + *submit_block.mutable_block() = _block_queue.pull(); + _controller.submit_block( submit_block, _target_head.height() ); + + boost::asio::post( std::bind( &indexer::process_block, this ) ); + } + catch( boost::sync_queue_is_closed& ) + { + LOG( warning ) << "Indexer synchronized queue has been closed"; + } + catch( const std::exception& e ) + { + return handle_error( e.what() ); + } + catch( const boost::exception& e ) + { + return handle_error( boost::diagnostic_information( e ) ); + } } -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/proto_utils.cpp b/src/koinos/chain/proto_utils.cpp index 2e6beca7..518453df 100644 --- a/src/koinos/chain/proto_utils.cpp +++ b/src/koinos/chain/proto_utils.cpp @@ -2,208 +2,221 @@ #include +#include #include #include -#include namespace koinos::chain { -value_type get_field_value( - const google::protobuf::Reflection* reflection, - const google::protobuf::Message& message, - const google::protobuf::FieldDescriptor* field_descriptor, - google::protobuf::FieldDescriptor::Type type ) -{ - value_type v; - - switch ( type ) - { - case google::protobuf::FieldDescriptor::TYPE_INT64: - v.set_int64_value( reflection->GetInt64( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_UINT64: - v.set_uint64_value( reflection->GetUInt64( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_INT32: - v.set_int32_value( reflection->GetInt32( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - v.set_fixed64_value( reflection->GetUInt64( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - v.set_fixed32_value( reflection->GetInt32( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_BOOL: - v.set_bool_value( reflection->GetBool( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_STRING: - v.set_string_value( reflection->GetString( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - v.mutable_message_value()->PackFrom( reflection->GetMessage( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_BYTES: - v.set_bytes_value( reflection->GetString( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_UINT32: - v.set_uint32_value( reflection->GetUInt32( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_ENUM: - { - koinos::chain::enum_type e; - auto ed = reflection->GetEnum( message, field_descriptor ); - e.set_number( ed->number() ); - e.set_name( ed->name() ); - v.mutable_message_value()->PackFrom( e ); - } - break; - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - v.set_sfixed32_value( reflection->GetInt32( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - v.set_sfixed64_value( reflection->GetInt64( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_SINT32: - v.set_sint32_value( reflection->GetInt32( message, field_descriptor ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_SINT64: - v.set_sint64_value( reflection->GetInt64( message, field_descriptor ) ); - break; - default: - KOINOS_ASSERT( false, reversion_exception, "attempted to retrieve the value of an unexpected field type" ); - break; - } - - return v; -} - -value_type get_repeated_field_value( - const google::protobuf::Reflection* reflection, - const google::protobuf::Message& message, - const google::protobuf::FieldDescriptor* field_descriptor, - google::protobuf::FieldDescriptor::Type type ) +value_type get_field_value( const google::protobuf::Reflection* reflection, + const google::protobuf::Message& message, + const google::protobuf::FieldDescriptor* field_descriptor, + google::protobuf::FieldDescriptor::Type type ) { - value_type v; - list_type list; - - int len = reflection->FieldSize( message, field_descriptor ); - - switch ( type ) - { - case google::protobuf::FieldDescriptor::TYPE_INT64: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_int64_value( reflection->GetRepeatedInt64( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_UINT64: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_uint64_value( reflection->GetRepeatedUInt64( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_INT32: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_int32_value( reflection->GetRepeatedInt32( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_fixed64_value( reflection->GetRepeatedUInt64( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_fixed32_value( reflection->GetRepeatedUInt32( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_BOOL: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_bool_value( reflection->GetRepeatedBool( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_STRING: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_string_value( reflection->GetRepeatedString( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - for ( int i = 0; i < len; i++ ) - list.add_values()->mutable_message_value()->PackFrom( reflection->GetRepeatedMessage( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_BYTES: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_bytes_value( reflection->GetRepeatedString( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_UINT32: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_uint32_value( reflection->GetRepeatedUInt32( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_ENUM: - for ( int i = 0; i < len; i++ ) - { - koinos::chain::enum_type e; - auto ed = reflection->GetRepeatedEnum( message, field_descriptor, i ); - e.set_number( ed->number() ); - e.set_name( ed->name() ); - list.add_values()->mutable_message_value()->PackFrom( e ); - } - break; - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_sfixed32_value( reflection->GetRepeatedInt32( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_sfixed64_value( reflection->GetRepeatedInt64( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_SINT32: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_sint32_value( reflection->GetRepeatedInt32( message, field_descriptor, i ) ); - break; - case google::protobuf::FieldDescriptor::TYPE_SINT64: - for ( int i = 0; i < len; i++ ) - list.add_values()->set_sint64_value( reflection->GetRepeatedInt64( message, field_descriptor, i ) ); - break; - default: - KOINOS_ASSERT( false, reversion_exception, "attempted to retrieve the value of an unexpected field type" ); - break; - } - - v.mutable_message_value()->PackFrom( list ); - - return v; + value_type v; + + switch( type ) + { + case google::protobuf::FieldDescriptor::TYPE_INT64: + v.set_int64_value( reflection->GetInt64( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_UINT64: + v.set_uint64_value( reflection->GetUInt64( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_INT32: + v.set_int32_value( reflection->GetInt32( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED64: + v.set_fixed64_value( reflection->GetUInt64( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED32: + v.set_fixed32_value( reflection->GetInt32( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_BOOL: + v.set_bool_value( reflection->GetBool( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_STRING: + v.set_string_value( reflection->GetString( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + v.mutable_message_value()->PackFrom( reflection->GetMessage( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_BYTES: + v.set_bytes_value( reflection->GetString( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_UINT32: + v.set_uint32_value( reflection->GetUInt32( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_ENUM: + { + koinos::chain::enum_type e; + auto ed = reflection->GetEnum( message, field_descriptor ); + e.set_number( ed->number() ); + e.set_name( ed->name() ); + v.mutable_message_value()->PackFrom( e ); + } + break; + case google::protobuf::FieldDescriptor::TYPE_SFIXED32: + v.set_sfixed32_value( reflection->GetInt32( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_SFIXED64: + v.set_sfixed64_value( reflection->GetInt64( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_SINT32: + v.set_sint32_value( reflection->GetInt32( message, field_descriptor ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_SINT64: + v.set_sint64_value( reflection->GetInt64( message, field_descriptor ) ); + break; + default: + KOINOS_ASSERT( false, reversion_exception, "attempted to retrieve the value of an unexpected field type" ); + break; + } + + return v; } -value_type get_nested_field_value( execution_context& context, const google::protobuf::Message& parent_message, std::string field_name ) +value_type get_repeated_field_value( const google::protobuf::Reflection* reflection, + const google::protobuf::Message& message, + const google::protobuf::FieldDescriptor* field_descriptor, + google::protobuf::FieldDescriptor::Type type ) { - auto pool_descriptor = context.descriptor_pool().FindMessageTypeByName( parent_message.GetTypeName() ); - KOINOS_ASSERT( pool_descriptor, internal_error_exception, "${type} descriptor was not found", ("type", parent_message.GetTypeName()) ); - - std::vector< std::string > field_path; - boost::split( field_path, field_name, boost::is_any_of( "." ) ); - - const google::protobuf::Reflection* reflection = parent_message.GetReflection(); - const google::protobuf::Message* message = &parent_message; - const google::protobuf::FieldDescriptor* field_descriptor = nullptr; - google::protobuf::FieldDescriptor::Type type = google::protobuf::FieldDescriptor::Type::MAX_TYPE; - - for ( const auto& segment : field_path ) - { - auto pool_field_descriptor = pool_descriptor->FindFieldByName( segment ); - KOINOS_ASSERT( pool_field_descriptor, field_not_found_exception, "unable to find field ${fname}", ("fname", segment) ); - - auto field_num = pool_field_descriptor->number(); - type = pool_field_descriptor->type(); - auto message_descriptor = message->GetDescriptor(); - field_descriptor = message_descriptor->FindFieldByNumber( field_num ); - KOINOS_ASSERT( field_descriptor, field_not_found_exception, "unable to find field number ${fnum} on ${type} message", ("fnum", field_num)("type", message->GetTypeName()) ); - - if ( &segment != &field_path.back() ) + value_type v; + list_type list; + + int len = reflection->FieldSize( message, field_descriptor ); + + switch( type ) + { + case google::protobuf::FieldDescriptor::TYPE_INT64: + for( int i = 0; i < len; i++ ) + list.add_values()->set_int64_value( reflection->GetRepeatedInt64( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_UINT64: + for( int i = 0; i < len; i++ ) + list.add_values()->set_uint64_value( reflection->GetRepeatedUInt64( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_INT32: + for( int i = 0; i < len; i++ ) + list.add_values()->set_int32_value( reflection->GetRepeatedInt32( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED64: + for( int i = 0; i < len; i++ ) + list.add_values()->set_fixed64_value( reflection->GetRepeatedUInt64( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_FIXED32: + for( int i = 0; i < len; i++ ) + list.add_values()->set_fixed32_value( reflection->GetRepeatedUInt32( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_BOOL: + for( int i = 0; i < len; i++ ) + list.add_values()->set_bool_value( reflection->GetRepeatedBool( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_STRING: + for( int i = 0; i < len; i++ ) + list.add_values()->set_string_value( reflection->GetRepeatedString( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + for( int i = 0; i < len; i++ ) + list.add_values()->mutable_message_value()->PackFrom( + reflection->GetRepeatedMessage( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_BYTES: + for( int i = 0; i < len; i++ ) + list.add_values()->set_bytes_value( reflection->GetRepeatedString( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_UINT32: + for( int i = 0; i < len; i++ ) + list.add_values()->set_uint32_value( reflection->GetRepeatedUInt32( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_ENUM: + for( int i = 0; i < len; i++ ) { - KOINOS_ASSERT( type == google::protobuf::FieldDescriptor::Type::TYPE_MESSAGE, field_not_found_exception, "expected nested field to be within a message" ); - - message = &reflection->GetMessage( *message, field_descriptor ); - reflection = message->GetReflection(); - pool_descriptor = context.descriptor_pool().FindMessageTypeByName( message->GetTypeName() ); + koinos::chain::enum_type e; + auto ed = reflection->GetRepeatedEnum( message, field_descriptor, i ); + e.set_number( ed->number() ); + e.set_name( ed->name() ); + list.add_values()->mutable_message_value()->PackFrom( e ); } - } - - if ( field_descriptor->is_repeated() ) - return get_repeated_field_value( reflection, *message, field_descriptor, type ); + break; + case google::protobuf::FieldDescriptor::TYPE_SFIXED32: + for( int i = 0; i < len; i++ ) + list.add_values()->set_sfixed32_value( reflection->GetRepeatedInt32( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_SFIXED64: + for( int i = 0; i < len; i++ ) + list.add_values()->set_sfixed64_value( reflection->GetRepeatedInt64( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_SINT32: + for( int i = 0; i < len; i++ ) + list.add_values()->set_sint32_value( reflection->GetRepeatedInt32( message, field_descriptor, i ) ); + break; + case google::protobuf::FieldDescriptor::TYPE_SINT64: + for( int i = 0; i < len; i++ ) + list.add_values()->set_sint64_value( reflection->GetRepeatedInt64( message, field_descriptor, i ) ); + break; + default: + KOINOS_ASSERT( false, reversion_exception, "attempted to retrieve the value of an unexpected field type" ); + break; + } + + v.mutable_message_value()->PackFrom( list ); + + return v; +} - return get_field_value( reflection, *message, field_descriptor, type );; +value_type get_nested_field_value( execution_context& context, + const google::protobuf::Message& parent_message, + std::string field_name ) +{ + auto pool_descriptor = context.descriptor_pool().FindMessageTypeByName( parent_message.GetTypeName() ); + KOINOS_ASSERT( pool_descriptor, + internal_error_exception, + "${type} descriptor was not found", + ( "type", parent_message.GetTypeName() ) ); + + std::vector< std::string > field_path; + boost::split( field_path, field_name, boost::is_any_of( "." ) ); + + const google::protobuf::Reflection* reflection = parent_message.GetReflection(); + const google::protobuf::Message* message = &parent_message; + const google::protobuf::FieldDescriptor* field_descriptor = nullptr; + google::protobuf::FieldDescriptor::Type type = google::protobuf::FieldDescriptor::Type::MAX_TYPE; + + for( const auto& segment: field_path ) + { + auto pool_field_descriptor = pool_descriptor->FindFieldByName( segment ); + KOINOS_ASSERT( pool_field_descriptor, + field_not_found_exception, + "unable to find field ${fname}", + ( "fname", segment ) ); + + auto field_num = pool_field_descriptor->number(); + type = pool_field_descriptor->type(); + auto message_descriptor = message->GetDescriptor(); + field_descriptor = message_descriptor->FindFieldByNumber( field_num ); + KOINOS_ASSERT( field_descriptor, + field_not_found_exception, + "unable to find field number ${fnum} on ${type} message", + ( "fnum", field_num )( "type", message->GetTypeName() ) ); + + if( &segment != &field_path.back() ) + { + KOINOS_ASSERT( type == google::protobuf::FieldDescriptor::Type::TYPE_MESSAGE, + field_not_found_exception, + "expected nested field to be within a message" ); + + message = &reflection->GetMessage( *message, field_descriptor ); + reflection = message->GetReflection(); + pool_descriptor = context.descriptor_pool().FindMessageTypeByName( message->GetTypeName() ); + } + } + + if( field_descriptor->is_repeated() ) + return get_repeated_field_value( reflection, *message, field_descriptor, type ); + + return get_field_value( reflection, *message, field_descriptor, type ); + ; } -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/resource_meter.cpp b/src/koinos/chain/resource_meter.cpp index 1e209373..c4f137b8 100644 --- a/src/koinos/chain/resource_meter.cpp +++ b/src/koinos/chain/resource_meter.cpp @@ -1,6 +1,6 @@ +#include #include #include -#include #include @@ -14,167 +14,173 @@ namespace koinos::chain { resource_meter::resource_meter() { - resource_limit_data initial_rld; + resource_limit_data initial_rld; - initial_rld.set_disk_storage_limit( std::numeric_limits< uint64_t >::max() ); - initial_rld.set_network_bandwidth_limit( std::numeric_limits< uint64_t >::max() ); - initial_rld.set_compute_bandwidth_limit( std::numeric_limits< uint64_t >::max() ); + initial_rld.set_disk_storage_limit( std::numeric_limits< uint64_t >::max() ); + initial_rld.set_network_bandwidth_limit( std::numeric_limits< uint64_t >::max() ); + initial_rld.set_compute_bandwidth_limit( std::numeric_limits< uint64_t >::max() ); - set_resource_limit_data( initial_rld ); + set_resource_limit_data( initial_rld ); } resource_meter::~resource_meter() = default; void resource_meter::set_resource_limit_data( const resource_limit_data& rld ) { - _resource_limit_data = rld; - _disk_storage_remaining = _resource_limit_data.disk_storage_limit(); - _system_disk_storage_used = 0; - _network_bandwidth_remaining = _resource_limit_data.network_bandwidth_limit(); - _system_network_bandwidth_used = 0; - _compute_bandwidth_remaining = _resource_limit_data.compute_bandwidth_limit(); - _system_compute_bandwidth_used = 0; + _resource_limit_data = rld; + _disk_storage_remaining = _resource_limit_data.disk_storage_limit(); + _system_disk_storage_used = 0; + _network_bandwidth_remaining = _resource_limit_data.network_bandwidth_limit(); + _system_network_bandwidth_used = 0; + _compute_bandwidth_remaining = _resource_limit_data.compute_bandwidth_limit(); + _system_compute_bandwidth_used = 0; } const resource_limit_data& resource_meter::get_resource_limit_data() const { - return _resource_limit_data; + return _resource_limit_data; } void resource_meter::use_disk_storage( int64_t bytes ) { - KOINOS_ASSERT( bytes <= int64_t( _disk_storage_remaining ), disk_storage_limit_exceeded_exception, "disk storage limit exceeded" ); + KOINOS_ASSERT( bytes <= int64_t( _disk_storage_remaining ), + disk_storage_limit_exceeded_exception, + "disk storage limit exceeded" ); - if ( auto session = _session.lock() ) - { - int128_t rc_cost = int128_t( bytes ) * _resource_limit_data.disk_storage_cost(); - KOINOS_ASSERT( rc_cost <= std::numeric_limits< int64_t >::max(), reversion_exception, "rc overflow" ); - session->use_rc( rc_cost.convert_to< int64_t >() ); - } - else - { - _system_disk_storage_used += bytes; - } + if( auto session = _session.lock() ) + { + int128_t rc_cost = int128_t( bytes ) * _resource_limit_data.disk_storage_cost(); + KOINOS_ASSERT( rc_cost <= std::numeric_limits< int64_t >::max(), reversion_exception, "rc overflow" ); + session->use_rc( rc_cost.convert_to< int64_t >() ); + } + else + { + _system_disk_storage_used += bytes; + } - if ( bytes >= 0 ) - _disk_storage_remaining -= uint64_t( bytes ); - else - _disk_storage_remaining += uint64_t( -1 * bytes ); + if( bytes >= 0 ) + _disk_storage_remaining -= uint64_t( bytes ); + else + _disk_storage_remaining += uint64_t( -1 * bytes ); } uint64_t resource_meter::disk_storage_used() const { - if ( _disk_storage_remaining > _resource_limit_data.disk_storage_limit() ) - return 0; + if( _disk_storage_remaining > _resource_limit_data.disk_storage_limit() ) + return 0; - return _resource_limit_data.disk_storage_limit() - _disk_storage_remaining; + return _resource_limit_data.disk_storage_limit() - _disk_storage_remaining; } uint64_t resource_meter::disk_storage_remaining() const { - if ( auto session = _session.lock() ) - { - auto cost = _resource_limit_data.disk_storage_cost(); + if( auto session = _session.lock() ) + { + auto cost = _resource_limit_data.disk_storage_cost(); - if ( cost > 0 ) - return std::min( session->remaining_rc() / cost, _disk_storage_remaining ); - } + if( cost > 0 ) + return std::min( session->remaining_rc() / cost, _disk_storage_remaining ); + } - return _disk_storage_remaining; + return _disk_storage_remaining; } uint64_t resource_meter::system_disk_storage_used() const { - return std::max( int64_t( 0 ), _system_disk_storage_used ); + return std::max( int64_t( 0 ), _system_disk_storage_used ); } void resource_meter::use_network_bandwidth( int64_t bytes ) { - KOINOS_ASSERT( bytes <= _network_bandwidth_remaining, network_bandwidth_limit_exceeded_exception, "network bandwidth limit exceeded" ); - KOINOS_ASSERT( bytes >= 0, network_bandwidth_limit_exceeded_exception, "cannot consume negative network bandwidth" ); + KOINOS_ASSERT( bytes <= _network_bandwidth_remaining, + network_bandwidth_limit_exceeded_exception, + "network bandwidth limit exceeded" ); + KOINOS_ASSERT( bytes >= 0, network_bandwidth_limit_exceeded_exception, "cannot consume negative network bandwidth" ); - if ( auto session = _session.lock() ) - { - int128_t rc_cost = int128_t( bytes ) * _resource_limit_data.network_bandwidth_cost(); - KOINOS_ASSERT( rc_cost <= std::numeric_limits< int64_t >::max(), reversion_exception, "rc overflow" ); - session->use_rc( rc_cost.convert_to< int64_t >() ); - } - else - { - _system_network_bandwidth_used += bytes; - } + if( auto session = _session.lock() ) + { + int128_t rc_cost = int128_t( bytes ) * _resource_limit_data.network_bandwidth_cost(); + KOINOS_ASSERT( rc_cost <= std::numeric_limits< int64_t >::max(), reversion_exception, "rc overflow" ); + session->use_rc( rc_cost.convert_to< int64_t >() ); + } + else + { + _system_network_bandwidth_used += bytes; + } - _network_bandwidth_remaining -= uint64_t( bytes ); + _network_bandwidth_remaining -= uint64_t( bytes ); } uint64_t resource_meter::network_bandwidth_used() const { - return _resource_limit_data.network_bandwidth_limit() - _network_bandwidth_remaining; + return _resource_limit_data.network_bandwidth_limit() - _network_bandwidth_remaining; } uint64_t resource_meter::network_bandwidth_remaining() const { - if ( auto session = _session.lock() ) - { - auto cost = _resource_limit_data.network_bandwidth_cost(); + if( auto session = _session.lock() ) + { + auto cost = _resource_limit_data.network_bandwidth_cost(); - if ( cost > 0 ) - return std::min( session->remaining_rc() / cost, _network_bandwidth_remaining ); - } + if( cost > 0 ) + return std::min( session->remaining_rc() / cost, _network_bandwidth_remaining ); + } - return _network_bandwidth_remaining; + return _network_bandwidth_remaining; } uint64_t resource_meter::system_network_bandwidth_used() const { - return std::max( int64_t( 0 ), _system_network_bandwidth_used ); + return std::max( int64_t( 0 ), _system_network_bandwidth_used ); } void resource_meter::use_compute_bandwidth( int64_t ticks ) { - KOINOS_ASSERT( ticks <= _compute_bandwidth_remaining, compute_bandwidth_limit_exceeded_exception, "compute bandwidth limit exceeded" ); - KOINOS_ASSERT( ticks >= 0, compute_bandwidth_limit_exceeded_exception, "cannot consume compute bandwidth bandwidth" ); + KOINOS_ASSERT( ticks <= _compute_bandwidth_remaining, + compute_bandwidth_limit_exceeded_exception, + "compute bandwidth limit exceeded" ); + KOINOS_ASSERT( ticks >= 0, compute_bandwidth_limit_exceeded_exception, "cannot consume compute bandwidth bandwidth" ); - if ( auto session = _session.lock() ) - { - int128_t rc_cost = int128_t( ticks ) * _resource_limit_data.compute_bandwidth_cost(); - KOINOS_ASSERT( rc_cost <= std::numeric_limits< int64_t >::max(), reversion_exception, "rc overflow" ); - session->use_rc( rc_cost.convert_to< int64_t >() ); - } - else - { - _system_compute_bandwidth_used += ticks; - } + if( auto session = _session.lock() ) + { + int128_t rc_cost = int128_t( ticks ) * _resource_limit_data.compute_bandwidth_cost(); + KOINOS_ASSERT( rc_cost <= std::numeric_limits< int64_t >::max(), reversion_exception, "rc overflow" ); + session->use_rc( rc_cost.convert_to< int64_t >() ); + } + else + { + _system_compute_bandwidth_used += ticks; + } - _compute_bandwidth_remaining -= uint64_t( ticks ); + _compute_bandwidth_remaining -= uint64_t( ticks ); } uint64_t resource_meter::compute_bandwidth_used() const { - return _resource_limit_data.compute_bandwidth_limit() - _compute_bandwidth_remaining; + return _resource_limit_data.compute_bandwidth_limit() - _compute_bandwidth_remaining; } uint64_t resource_meter::compute_bandwidth_remaining() const { - if ( auto session = _session.lock() ) - { - auto cost = _resource_limit_data.compute_bandwidth_cost(); + if( auto session = _session.lock() ) + { + auto cost = _resource_limit_data.compute_bandwidth_cost(); - if ( cost > 0 ) - return std::min( session->remaining_rc() / cost, _compute_bandwidth_remaining ); - } + if( cost > 0 ) + return std::min( session->remaining_rc() / cost, _compute_bandwidth_remaining ); + } - return _compute_bandwidth_remaining; + return _compute_bandwidth_remaining; } uint64_t resource_meter::system_compute_bandwidth_used() const { - return std::max( int64_t( 0 ), _system_compute_bandwidth_used ); + return std::max( int64_t( 0 ), _system_compute_bandwidth_used ); } void resource_meter::set_session( std::shared_ptr< abstract_rc_session > s ) { - _session = s; + _session = s; } -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/session.cpp b/src/koinos/chain/session.cpp index 793e8e5a..a433b0c5 100644 --- a/src/koinos/chain/session.cpp +++ b/src/koinos/chain/session.cpp @@ -1,48 +1,52 @@ -#include #include +#include namespace koinos::chain { -session::session( int64_t begin_rc ) : _begin_rc( begin_rc ), _end_rc( begin_rc ) {} +session::session( int64_t begin_rc ): + _begin_rc( begin_rc ), + _end_rc( begin_rc ) +{} + session::~session() = default; void session::use_rc( int64_t rc ) { - KOINOS_ASSERT( rc <= _end_rc, insufficient_rc_exception, "insufficient rc" ); - _end_rc -= rc; + KOINOS_ASSERT( rc <= _end_rc, insufficient_rc_exception, "insufficient rc" ); + _end_rc -= rc; } uint64_t session::remaining_rc() { - return uint64_t( std::min( _begin_rc, _end_rc ) ); + return uint64_t( std::min( _begin_rc, _end_rc ) ); } uint64_t session::used_rc() { - if ( _end_rc > _begin_rc ) - return 0; + if( _end_rc > _begin_rc ) + return 0; - return uint64_t( _begin_rc - _end_rc ); + return uint64_t( _begin_rc - _end_rc ); } void session::push_event( const protocol::event_data& ev ) { - _events.push_back( ev ); + _events.push_back( ev ); } void session::push_log( const std::string& log ) { - _logs.push_back( log ); + _logs.push_back( log ); } const std::vector< protocol::event_data >& session::events() { - return _events; + return _events; } const std::vector< std::string >& session::logs() { - return _logs; + return _logs; } -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/state.cpp b/src/koinos/chain/state.cpp index 8d74817a..1fa70936 100644 --- a/src/koinos/chain/state.cpp +++ b/src/koinos/chain/state.cpp @@ -1,12 +1,10 @@ -#include #include +#include #include #include #include -namespace koinos::chain { - -namespace state { +namespace koinos::chain { namespace state { namespace space { @@ -14,96 +12,96 @@ namespace detail { const object_space make_contract_bytecode() { - object_space s; - s.set_system( true ); - s.set_zone( zone::kernel ); - s.set_id( system_space_id::contract_bytecode ); - return s; + object_space s; + s.set_system( true ); + s.set_zone( zone::kernel ); + s.set_id( system_space_id::contract_bytecode ); + return s; } const object_space make_contract_metadata() { - object_space s; - s.set_system( true ); - s.set_zone( zone::kernel ); - s.set_id( system_space_id::contract_metadata ); - return s; + object_space s; + s.set_system( true ); + s.set_zone( zone::kernel ); + s.set_id( system_space_id::contract_metadata ); + return s; } const object_space make_system_call_dispatch() { - object_space s; - s.set_system( true ); - s.set_zone( zone::kernel ); - s.set_id( system_space_id::system_call_dispatch ); - return s; + object_space s; + s.set_system( true ); + s.set_zone( zone::kernel ); + s.set_id( system_space_id::system_call_dispatch ); + return s; } const object_space make_metadata() { - object_space s; - s.set_system( true ); - s.set_zone( zone::kernel ); - s.set_id( system_space_id::metadata ); - return s; + object_space s; + s.set_system( true ); + s.set_zone( zone::kernel ); + s.set_id( system_space_id::metadata ); + return s; } const object_space make_transaction_nonce() { - object_space s; - s.set_system( true ); - s.set_zone( zone::kernel ); - s.set_id( system_space_id::transaction_nonce ); - return s; + object_space s; + s.set_system( true ); + s.set_zone( zone::kernel ); + s.set_id( system_space_id::transaction_nonce ); + return s; } -} // detail +} // namespace detail const object_space contract_bytecode() { - static auto s = detail::make_contract_bytecode(); - return s; + static auto s = detail::make_contract_bytecode(); + return s; } const object_space contract_metadata() { - static auto s = detail::make_contract_metadata(); - return s; + static auto s = detail::make_contract_metadata(); + return s; } const object_space system_call_dispatch() { - static auto s = detail::make_system_call_dispatch(); - return s; + static auto s = detail::make_system_call_dispatch(); + return s; } const object_space metadata() { - static auto s = detail::make_metadata(); - return s; + static auto s = detail::make_metadata(); + return s; } const object_space transaction_nonce() { - static auto s = detail::make_transaction_nonce(); - return s; + static auto s = detail::make_transaction_nonce(); + return s; } -} // space +} // namespace space void assert_permissions( execution_context& context, const object_space& space ) { - if ( context.get_caller_privilege() == privilege::kernel_mode ) - { - KOINOS_ASSERT( space.system(), reversion_exception, "privileged code can only access system space" ); - } - else - { - KOINOS_ASSERT( !space.system(), insufficient_privileges_exception, "user code cannot access system space" ); - KOINOS_ASSERT( space.zone() == context.get_caller(), reversion_exception, "user code cannot access other contract space" ); - } + if( context.get_caller_privilege() == privilege::kernel_mode ) + { + KOINOS_ASSERT( space.system(), reversion_exception, "privileged code can only access system space" ); + } + else + { + KOINOS_ASSERT( !space.system(), insufficient_privileges_exception, "user code cannot access system space" ); + KOINOS_ASSERT( space.zone() == context.get_caller(), + reversion_exception, + "user code cannot access other contract space" ); + } } -} // state - -} // koinos::chain +}} // namespace koinos::chain::state diff --git a/src/koinos/chain/system_calls.cpp b/src/koinos/chain/system_calls.cpp index b8428711..5ecd060f 100644 --- a/src/koinos/chain/system_calls.cpp +++ b/src/koinos/chain/system_calls.cpp @@ -1,23 +1,23 @@ #include #include -#include #include +#include #include #include #include -#include #include +#include +#include #include #include +#include #include #include #include -#include #include -#include #include @@ -33,265 +33,224 @@ namespace koinos::chain { void register_thunks( thunk_dispatcher& td ) { - THUNK_REGISTER_GENESIS( td, - //////////////////////////////////////////////////////////////////////////////// - // - // WARNING! - // - // Do not add any thunks here after genesis - // Any new thunks MUST be added to THUNK_REGISTER - // - //////////////////////////////////////////////////////////////////////////////// - - // General Blockchain Management - (get_head_info) - (apply_block) - (apply_transaction) - (apply_upload_contract_operation) - (apply_call_contract_operation) - (apply_set_system_call_operation) - (apply_set_system_contract_operation) - (pre_block_callback) - (post_block_callback) - (pre_transaction_callback) - (post_transaction_callback) - (get_chain_id) - - // System Helpers - (process_block_signature) - (get_transaction) - (get_transaction_field) - (get_block) - (get_block_field) - (get_last_irreversible_block) - (get_account_nonce) - (verify_account_nonce) - (set_account_nonce) - (check_system_authority) - (get_operation) - - // Resource Subsystem - (get_account_rc) - (consume_account_rc) - (get_resource_limits) - (consume_block_resources) - - // Database - (put_object) - (remove_object) - (get_object) - (get_next_object) - (get_prev_object) - - // Logging - (log) - (event) - - // Cryptography - (hash) - (recover_public_key) - (verify_merkle_root) - (verify_signature) - (verify_vrf_proof) - - // Contract Management - (call) - (exit) - (get_arguments) - (get_contract_id) - (get_caller) - (check_authority) - ) - - THUNK_REGISTER( td, - // Non genesis thunks go here - (nop) - ) + THUNK_REGISTER_GENESIS( + td, + //////////////////////////////////////////////////////////////////////////////// + // + // WARNING! + // + // Do not add any thunks here after genesis + // Any new thunks MUST be added to THUNK_REGISTER + // + //////////////////////////////////////////////////////////////////////////////// + + // General Blockchain Management + (get_head_info)(apply_block)(apply_transaction)(apply_upload_contract_operation)(apply_call_contract_operation)(apply_set_system_call_operation)(apply_set_system_contract_operation)(pre_block_callback)(post_block_callback)(pre_transaction_callback)(post_transaction_callback)( get_chain_id ) + + // System Helpers + (process_block_signature)(get_transaction)(get_transaction_field)(get_block)(get_block_field)(get_last_irreversible_block)(get_account_nonce)(verify_account_nonce)(set_account_nonce)(check_system_authority)( get_operation ) + + // Resource Subsystem + (get_account_rc)(consume_account_rc)(get_resource_limits)( consume_block_resources ) + + // Database + (put_object)(remove_object)(get_object)(get_next_object)( get_prev_object ) + + // Logging + (log)( event ) + + // Cryptography + (hash)(recover_public_key)(verify_merkle_root)(verify_signature)( verify_vrf_proof ) + + // Contract Management + (call)(exit)(get_arguments)(get_contract_id)(get_caller)( check_authority ) ) + + THUNK_REGISTER( td, + // Non genesis thunks go here + ( nop ) ) } // RAII class to ensure apply context block state is consistent if there is an error applying // the block. struct block_guard { - block_guard( execution_context& context, const protocol::block& block ) : + block_guard( execution_context& context, const protocol::block& block ): ctx( context ) - { - ctx.set_block( block ); - } + { + ctx.set_block( block ); + } - ~block_guard() - { - ctx.clear_block(); - } + ~block_guard() + { + ctx.clear_block(); + } - execution_context& ctx; + execution_context& ctx; }; // RAII class to ensure apply context transaction state is consistent if there is an error applying // the transaction. struct transaction_guard { - transaction_guard( execution_context& context, const protocol::transaction& trx ) : + transaction_guard( execution_context& context, const protocol::transaction& trx ): ctx( context ) - { - ctx.set_transaction( trx ); - } + { + ctx.set_transaction( trx ); + } - ~transaction_guard() - { - ctx.clear_transaction(); - } + ~transaction_guard() + { + ctx.clear_transaction(); + } - execution_context& ctx; + execution_context& ctx; }; // RAII class to ensure apply context operation state is consistent if there is an error applying // the operation. struct operation_guard { - operation_guard( execution_context& context, const protocol::operation& op ) : + operation_guard( execution_context& context, const protocol::operation& op ): ctx( context ) - { - ctx.set_operation( op ); - } + { + ctx.set_operation( op ); + } - ~operation_guard() - { - ctx.clear_operation(); - } + ~operation_guard() + { + ctx.clear_operation(); + } - execution_context& ctx; + execution_context& ctx; }; void validate_hash_code( crypto::multicodec id ) { - switch ( id ) - { - case crypto::multicodec::sha1: - [[fallthrough]]; - case crypto::multicodec::sha2_256: - [[fallthrough]]; - case crypto::multicodec::sha2_512: - [[fallthrough]]; - case crypto::multicodec::keccak_256: - [[fallthrough]]; - case crypto::multicodec::ripemd_160: - break; - default: - KOINOS_THROW( unknown_hash_code_exception, "unknown hash code" ); - } + switch( id ) + { + case crypto::multicodec::sha1: + [[fallthrough]]; + case crypto::multicodec::sha2_256: + [[fallthrough]]; + case crypto::multicodec::sha2_512: + [[fallthrough]]; + case crypto::multicodec::keccak_256: + [[fallthrough]]; + case crypto::multicodec::ripemd_160: + break; + default: + KOINOS_THROW( unknown_hash_code_exception, "unknown hash code" ); + } } std::pair< std::string, std::string > hash_compute_keys( crypto::multicodec id ) { - switch ( id ) - { - case crypto::multicodec::sha1: - return { "sha1_base", "sha1_per_byte" }; - case crypto::multicodec::sha2_256: - return { "sha2_256_base", "sha2_256_per_byte" }; - case crypto::multicodec::sha2_512: - return { "sha2_512_base", "sha2_512_per_byte" }; - case crypto::multicodec::keccak_256: - return { "keccak_256_base", "keccak_256_per_byte" }; - case crypto::multicodec::ripemd_160: - return { "ripemd_160_base", "ripemd_160_per_byte" }; - default: - KOINOS_THROW( unknown_hash_code_exception, "unknown hash code" ); - } + switch( id ) + { + case crypto::multicodec::sha1: + return { "sha1_base", "sha1_per_byte" }; + case crypto::multicodec::sha2_256: + return { "sha2_256_base", "sha2_256_per_byte" }; + case crypto::multicodec::sha2_512: + return { "sha2_512_base", "sha2_512_per_byte" }; + case crypto::multicodec::keccak_256: + return { "keccak_256_base", "keccak_256_per_byte" }; + case crypto::multicodec::ripemd_160: + return { "ripemd_160_base", "ripemd_160_per_byte" }; + default: + KOINOS_THROW( unknown_hash_code_exception, "unknown hash code" ); + } } -void generate_receipt( - execution_context& context, - protocol::block_receipt& receipt, - const protocol::block& block, - uint64_t disk_storage_charged, - uint64_t network_bandwidth_charged, - uint64_t compute_bandwidth_charged ) +void generate_receipt( execution_context& context, + protocol::block_receipt& receipt, + const protocol::block& block, + uint64_t disk_storage_charged, + uint64_t network_bandwidth_charged, + uint64_t compute_bandwidth_charged ) { - receipt.set_id( block.id() ); - receipt.set_height( block.header().height() ); - receipt.set_disk_storage_used( context.resource_meter().disk_storage_used() ); - receipt.set_network_bandwidth_used( context.resource_meter().network_bandwidth_used() ); - receipt.set_compute_bandwidth_used( context.resource_meter().compute_bandwidth_used() ); - receipt.set_disk_storage_charged( disk_storage_charged ); - receipt.set_network_bandwidth_charged( network_bandwidth_charged ); - receipt.set_compute_bandwidth_charged( compute_bandwidth_charged ); - - for ( const auto& [ transaction_id, event ] : context.chronicler().events() ) - if ( !transaction_id ) - *receipt.add_events() = event; - - for ( const auto& message : context.chronicler().logs() ) - *receipt.add_logs() = message; - - for ( const auto& entry : context.get_state_node()->get_delta_entries() ) - *receipt.add_state_delta_entries() = entry; + receipt.set_id( block.id() ); + receipt.set_height( block.header().height() ); + receipt.set_disk_storage_used( context.resource_meter().disk_storage_used() ); + receipt.set_network_bandwidth_used( context.resource_meter().network_bandwidth_used() ); + receipt.set_compute_bandwidth_used( context.resource_meter().compute_bandwidth_used() ); + receipt.set_disk_storage_charged( disk_storage_charged ); + receipt.set_network_bandwidth_charged( network_bandwidth_charged ); + receipt.set_compute_bandwidth_charged( compute_bandwidth_charged ); + + for( const auto& [ transaction_id, event ]: context.chronicler().events() ) + if( !transaction_id ) + *receipt.add_events() = event; + + for( const auto& message: context.chronicler().logs() ) + *receipt.add_logs() = message; + + for( const auto& entry: context.get_state_node()->get_delta_entries() ) + *receipt.add_state_delta_entries() = entry; } -void generate_receipt( - execution_context& context, - protocol::transaction_receipt& receipt, - const protocol::transaction& transaction, - uint64_t payer_rc, - uint64_t used_rc, - uint64_t disk_storage_used, - uint64_t network_bandwidth_used, - uint64_t compute_bandwidth_used, - const std::vector< protocol::event_data >& events, - const std::vector< std::string >& logs ) +void generate_receipt( execution_context& context, + protocol::transaction_receipt& receipt, + const protocol::transaction& transaction, + uint64_t payer_rc, + uint64_t used_rc, + uint64_t disk_storage_used, + uint64_t network_bandwidth_used, + uint64_t compute_bandwidth_used, + const std::vector< protocol::event_data >& events, + const std::vector< std::string >& logs ) { - receipt.set_id( transaction.id() ); - receipt.set_payer( transaction.header().payer() ); - receipt.set_max_payer_rc( payer_rc ); - receipt.set_rc_limit( transaction.header().rc_limit() ); - receipt.set_rc_used( used_rc ); - receipt.set_disk_storage_used( disk_storage_used ); - receipt.set_network_bandwidth_used( network_bandwidth_used ); - receipt.set_compute_bandwidth_used( compute_bandwidth_used ); - - for ( const auto& e : events ) - *receipt.add_events() = e; - - for ( const auto& message : logs ) - *receipt.add_logs() = message; - - for ( const auto& entry : context.get_state_node()->get_delta_entries() ) - *receipt.add_state_delta_entries() = entry; + receipt.set_id( transaction.id() ); + receipt.set_payer( transaction.header().payer() ); + receipt.set_max_payer_rc( payer_rc ); + receipt.set_rc_limit( transaction.header().rc_limit() ); + receipt.set_rc_used( used_rc ); + receipt.set_disk_storage_used( disk_storage_used ); + receipt.set_network_bandwidth_used( network_bandwidth_used ); + receipt.set_compute_bandwidth_used( compute_bandwidth_used ); + + for( const auto& e: events ) + *receipt.add_events() = e; + + for( const auto& message: logs ) + *receipt.add_logs() = message; + + for( const auto& entry: context.get_state_node()->get_delta_entries() ) + *receipt.add_state_delta_entries() = entry; } uint64_t hashes_per_leaves( uint64_t leaves ) { - if ( leaves <= 2 ) - return 1; + if( leaves <= 2 ) + return 1; - auto even_leaves = ( ( leaves + 1 ) / 2 ) * 2; - if ( !( even_leaves & ( even_leaves - 1 ) ) ) // When we get to a power of 2, we can short-circuit - return even_leaves - 1; + auto even_leaves = ( ( leaves + 1 ) / 2 ) * 2; + if( !( even_leaves & ( even_leaves - 1 ) ) ) // When we get to a power of 2, we can short-circuit + return even_leaves - 1; - return even_leaves / 2 + hashes_per_leaves( even_leaves / 2 ); + return even_leaves / 2 + hashes_per_leaves( even_leaves / 2 ); } template< typename T > bool validate_utf( const std::basic_string< T >& p_str ) { - typename std::basic_string< T >::const_iterator it = p_str.begin(); - while ( it != p_str.end() ) - { - const boost::locale::utf::code_point cp = boost::locale::utf::utf_traits< T >::decode( it, p_str.end() ); - if ( cp == boost::locale::utf::illegal ) - return false; - else if ( cp == boost::locale::utf::incomplete ) - return false; - } - return true; + typename std::basic_string< T >::const_iterator it = p_str.begin(); + while( it != p_str.end() ) + { + const boost::locale::utf::code_point cp = boost::locale::utf::utf_traits< T >::decode( it, p_str.end() ); + if( cp == boost::locale::utf::illegal ) + return false; + else if( cp == boost::locale::utf::incomplete ) + return false; + } + return true; } namespace thunk { void _nop( execution_context& ) {} -} // thunk +} // namespace thunk THUNK_DEFINE_BEGIN(); @@ -301,500 +260,578 @@ THUNK_DEFINE_BEGIN(); THUNK_DEFINE_VOID( get_head_info_result, get_head_info ) { - auto head = context.get_state_node(); - - get_head_info_result ret; - auto* hi = ret.mutable_value(); - - hi->mutable_head_topology()->set_id( util::converter::as< std::string >( head->id() ) ); - hi->mutable_head_topology()->set_previous( util::converter::as< std::string >( head->parent_id() ) ); - hi->mutable_head_topology()->set_height( head->revision() ); - hi->set_last_irreversible_block( system_call::get_last_irreversible_block( context ) ); - - if ( const auto* block = context.get_block(); block != nullptr ) - { - hi->set_head_block_time( block->header().timestamp() ); - } - else - { - auto head_block_object = system_call::get_object( context, state::space::metadata(), state::key::head_block ); - uint64_t time = head_block_object.exists() ? util::converter::to< protocol::block >( head_block_object.value() ).header().timestamp() : 0; - hi->set_head_block_time( time ); - } - - return ret; + auto head = context.get_state_node(); + + get_head_info_result ret; + auto* hi = ret.mutable_value(); + + hi->mutable_head_topology()->set_id( util::converter::as< std::string >( head->id() ) ); + hi->mutable_head_topology()->set_previous( util::converter::as< std::string >( head->parent_id() ) ); + hi->mutable_head_topology()->set_height( head->revision() ); + hi->set_last_irreversible_block( system_call::get_last_irreversible_block( context ) ); + + if( const auto* block = context.get_block(); block != nullptr ) + { + hi->set_head_block_time( block->header().timestamp() ); + } + else + { + auto head_block_object = system_call::get_object( context, state::space::metadata(), state::key::head_block ); + uint64_t time = head_block_object.exists() + ? util::converter::to< protocol::block >( head_block_object.value() ).header().timestamp() + : 0; + hi->set_head_block_time( time ); + } + + return ret; } -THUNK_DEFINE( void, apply_block, ((const protocol::block&) block) ) +THUNK_DEFINE( void, apply_block, ( (const protocol::block&)block ) ) { - context.receipt() = protocol::block_receipt(); - - try - { - KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "calling privileged thunk from non-privileged code" ); - KOINOS_ASSERT( context.intent() == intent::block_application, insufficient_privileges_exception, "expected block application intent while applying block" ); - - block_guard guard( context, block ); - - context.resource_meter().set_resource_limit_data( system_call::get_resource_limits( context ) ); - - KOINOS_ASSERT( - system_call::hash( context, std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), util::converter::as< std::string >( block.header() ) ) == block.id(), - malformed_block_exception, - "block contains an invalid block id" - ); - - const crypto::multihash tx_root = util::converter::to< crypto::multihash >( block.header().transaction_merkle_root() ); - KOINOS_ASSERT( - tx_root.code() == context.block_hash_code(), - malformed_block_exception, - "unexpected transaction merkle root hash code - was: ${t}, expected: ${e}", - ("t", std::underlying_type_t< crypto::multicodec >( tx_root.code() ))("e", std::underlying_type_t< crypto::multicodec >( context.block_hash_code() )) - ); - - // Check transaction Merkle root - std::vector< std::string > hashes; - hashes.reserve( block.transactions_size() * 2 ); - - std::size_t transactions_bytes_size = 0; - for ( const auto& trx : block.transactions() ) + context.receipt() = protocol::block_receipt(); + + try + { + KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "calling privileged thunk from non-privileged code" ); + KOINOS_ASSERT( context.intent() == intent::block_application, + insufficient_privileges_exception, + "expected block application intent while applying block" ); + + block_guard guard( context, block ); + + context.resource_meter().set_resource_limit_data( system_call::get_resource_limits( context ) ); + + KOINOS_ASSERT( system_call::hash( context, + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), + util::converter::as< std::string >( block.header() ) ) + == block.id(), + malformed_block_exception, + "block contains an invalid block id" ); + + const crypto::multihash tx_root = + util::converter::to< crypto::multihash >( block.header().transaction_merkle_root() ); + KOINOS_ASSERT( tx_root.code() == context.block_hash_code(), + malformed_block_exception, + "unexpected transaction merkle root hash code - was: ${t}, expected: ${e}", + ( "t", std::underlying_type_t< crypto::multicodec >( tx_root.code() ) )( + "e", + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ) ) ); + + // Check transaction Merkle root + std::vector< std::string > hashes; + hashes.reserve( block.transactions_size() * 2 ); + + std::size_t transactions_bytes_size = 0; + for( const auto& trx: block.transactions() ) + { + transactions_bytes_size += trx.ByteSizeLong(); + hashes.emplace_back( system_call::hash( context, + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), + util::converter::as< std::string >( trx.header() ) ) ); + std::stringstream ss; + + for( const auto& sig: trx.signatures() ) { - transactions_bytes_size += trx.ByteSizeLong(); - hashes.emplace_back( system_call::hash( context, std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), util::converter::as< std::string >( trx.header() ) ) ); - std::stringstream ss; - - for ( const auto& sig : trx.signatures() ) - { - ss << sig; - } - - hashes.emplace_back( system_call::hash( context, std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), ss.str() ) ); + ss << sig; } - context.resource_meter().use_network_bandwidth( block.ByteSizeLong() - transactions_bytes_size ); - - KOINOS_ASSERT( system_call::verify_merkle_root( context, block.header().transaction_merkle_root(), hashes ), malformed_block_exception, "transaction merkle root does not match" ); - - auto block_hash = util::converter::to< crypto::multihash >( system_call::hash( context, std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), util::converter::as< std::string >( block.header() ) ) ); - KOINOS_ASSERT( - system_call::process_block_signature( - context, - util::converter::as< std::string >( block_hash ), - block.header(), - block.signature() - ), - invalid_signature_exception, - "failed to process block signature" - ); - - system_call::pre_block_callback( context ); - - // We directly call put_object on the state node so that we do not charge disk_storage for the storage of the new head block - const auto serialized_block = util::converter::as< std::string >( block ); - context.get_state_node()->put_object( state::space::metadata(), state::key::head_block, &serialized_block ); - - for ( const auto& tx : block.transactions() ) + hashes.emplace_back( system_call::hash( context, + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), + ss.str() ) ); + } + + context.resource_meter().use_network_bandwidth( block.ByteSizeLong() - transactions_bytes_size ); + + KOINOS_ASSERT( system_call::verify_merkle_root( context, block.header().transaction_merkle_root(), hashes ), + malformed_block_exception, + "transaction merkle root does not match" ); + + auto block_hash = util::converter::to< crypto::multihash >( + system_call::hash( context, + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), + util::converter::as< std::string >( block.header() ) ) ); + KOINOS_ASSERT( system_call::process_block_signature( context, + util::converter::as< std::string >( block_hash ), + block.header(), + block.signature() ), + invalid_signature_exception, + "failed to process block signature" ); + + system_call::pre_block_callback( context ); + + // We directly call put_object on the state node so that we do not charge disk_storage for the storage of the new + // head block + const auto serialized_block = util::converter::as< std::string >( block ); + context.get_state_node()->put_object( state::space::metadata(), state::key::head_block, &serialized_block ); + + for( const auto& tx: block.transactions() ) + { + try { - try - { - system_call::apply_transaction( context, tx ); - } - catch ( const reversion_exception& ) {} /* do nothing */ - KOINOS_CAPTURE_CATCH_AND_RETHROW( ("transaction_id", util::to_hex( tx.id() )) ) + system_call::apply_transaction( context, tx ); } - - system_call::post_block_callback( context ); - - const auto& meter = context.resource_meter(); - const auto& rld = meter.get_resource_limit_data(); - - uint64_t system_rc_cost = - meter.system_disk_storage_used() * rld.disk_storage_cost() + - meter.system_network_bandwidth_used() * rld.network_bandwidth_cost() + - meter.system_compute_bandwidth_used() * rld.compute_bandwidth_cost(); - - KOINOS_ASSERT( - system_call::consume_account_rc( - context, - block.header().signer(), - system_rc_cost - ), - insufficient_rc_exception, - "unable to consume system rc for block producer: ${p}", ("p", util::to_base58( block.header().signer() )) - ); - - auto disk_storage_used = context.resource_meter().disk_storage_used(); - auto network_bandwidth_used = context.resource_meter().network_bandwidth_used(); - auto compute_bandwidth_used = context.resource_meter().compute_bandwidth_used(); - - KOINOS_ASSERT( - system_call::consume_block_resources( - context, - meter.disk_storage_used(), - meter.network_bandwidth_used(), - meter.compute_bandwidth_used() - ), - failure_exception, - "unable to consume block resources" - ); - - generate_receipt( - context, - std::get< protocol::block_receipt >( context.receipt() ), - block, - disk_storage_used, - network_bandwidth_used, - compute_bandwidth_used ); - } - catch ( ... ) - { - generate_receipt( - context, - std::get< protocol::block_receipt >( context.receipt() ), - block, - context.resource_meter().disk_storage_used(), - context.resource_meter().network_bandwidth_used(), - context.resource_meter().compute_bandwidth_used() ); - throw; - } + catch( const reversion_exception& ) + {} /* do nothing */ + KOINOS_CAPTURE_CATCH_AND_RETHROW( ( "transaction_id", util::to_hex( tx.id() ) ) ) + } + + system_call::post_block_callback( context ); + + const auto& meter = context.resource_meter(); + const auto& rld = meter.get_resource_limit_data(); + + uint64_t system_rc_cost = meter.system_disk_storage_used() * rld.disk_storage_cost() + + meter.system_network_bandwidth_used() * rld.network_bandwidth_cost() + + meter.system_compute_bandwidth_used() * rld.compute_bandwidth_cost(); + + KOINOS_ASSERT( system_call::consume_account_rc( context, block.header().signer(), system_rc_cost ), + insufficient_rc_exception, + "unable to consume system rc for block producer: ${p}", + ( "p", util::to_base58( block.header().signer() ) ) ); + + auto disk_storage_used = context.resource_meter().disk_storage_used(); + auto network_bandwidth_used = context.resource_meter().network_bandwidth_used(); + auto compute_bandwidth_used = context.resource_meter().compute_bandwidth_used(); + + KOINOS_ASSERT( system_call::consume_block_resources( context, + meter.disk_storage_used(), + meter.network_bandwidth_used(), + meter.compute_bandwidth_used() ), + failure_exception, + "unable to consume block resources" ); + + generate_receipt( context, + std::get< protocol::block_receipt >( context.receipt() ), + block, + disk_storage_used, + network_bandwidth_used, + compute_bandwidth_used ); + } + catch( ... ) + { + generate_receipt( context, + std::get< protocol::block_receipt >( context.receipt() ), + block, + context.resource_meter().disk_storage_used(), + context.resource_meter().network_bandwidth_used(), + context.resource_meter().compute_bandwidth_used() ); + throw; + } } -THUNK_DEFINE( void, apply_transaction, ((const protocol::transaction&) trx) ) +THUNK_DEFINE( void, apply_transaction, ( (const protocol::transaction&)trx ) ) { - protocol::transaction_receipt receipt; - std::exception_ptr reverted_exception_ptr; - uint64_t used_rc = 0; - uint64_t disk_storage_used = 0; - uint64_t compute_bandwidth_used = 0; - uint64_t network_bandwidth_used = 0; - uint64_t payer_rc = 0; - std::vector< protocol::event_data > events; - std::vector< std::string > logs; - - try - { - KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "calling privileged thunk from non-privileged code" ); - KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "unable to perform action while context is read only" ); - - transaction_guard guard( context, trx ); - - const auto& payer = trx.header().payer(); - const auto& payee = trx.header().payee(); - - // If the payee is set and not the payer, then the payee account's nonce is used. - bool use_payee_nonce = payee.size() && payee != payer; - const auto& nonce_account = use_payee_nonce ? payee : payer; - - auto start_disk_used = context.resource_meter().disk_storage_used(); - auto start_network_used = context.resource_meter().network_bandwidth_used(); - auto start_compute_used = context.resource_meter().compute_bandwidth_used(); - - /** - * While a reference to the payer_session remains alive, resource usage will be tallied - * and charged to the current payer. - */ - auto payer_session = context.make_session( trx.header().rc_limit() ); - - try - { - payer_rc = system_call::get_account_rc( context, payer ); - KOINOS_ASSERT( payer_rc >= trx.header().rc_limit(), failure_exception, "payer does not have the rc to cover transaction rc limit" ); - - auto chain_id = system_call::get_object( context, state::space::metadata(), state::key::chain_id ); - KOINOS_ASSERT( chain_id.exists(), failure_exception, "chain id does not exist" ); - KOINOS_ASSERT( trx.header().chain_id() == chain_id.value(), failure_exception, "chain id mismatch" ); - - KOINOS_ASSERT( - system_call::hash( context, std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), util::converter::as< std::string >( trx.header() ) ) == trx.id(), - failure_exception, - "transaction contains an invalid transaction id" - ); - - const crypto::multihash op_root = util::converter::to< crypto::multihash >( trx.header().operation_merkle_root() ); - KOINOS_ASSERT( - op_root.code() == context.block_hash_code(), - failure_exception, - "unexpected operation merkle root hash code - was: ${o}, expected: ${e}", - ("o", std::underlying_type_t< crypto::multicodec >( op_root.code() ))("e", std::underlying_type_t< crypto::multicodec >( context.block_hash_code() )) - ); - - // Check operation merkle root - std::vector< std::string > hashes; - hashes.reserve( trx.operations_size() ); - - for ( const auto& op : trx.operations() ) - hashes.emplace_back( system_call::hash( context, std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), util::converter::as< std::string >( op ) ) ); - - KOINOS_ASSERT( system_call::verify_merkle_root( context, trx.header().operation_merkle_root(), hashes ), failure_exception, "operation merkle root does not match" ); - - auto authorized = system_call::check_authority( context, transaction_application, payer ); - KOINOS_ASSERT( authorized, authorization_failure_exception, "account ${account} has not authorized transaction", ("account", util::to_base58( payer )) ); - - // If we are using the payee account's nonce, we also need to ensure they signed the transaction as well - if ( use_payee_nonce ) - { - authorized = system_call::check_authority( context, transaction_application, payee ); - KOINOS_ASSERT( authorized, authorization_failure_exception, "account ${account} has not authorized transaction", ("account", util::to_base58( payee )) ); - } - - KOINOS_ASSERT( - system_call::verify_account_nonce( context, nonce_account, trx.header().nonce() ), - invalid_nonce_exception, - "invalid transaction nonce - account: ${a}, nonce: ${n}, current nonce: ${c}", - ("a", util::to_base58( nonce_account ))("n", util::to_hex( trx.header().nonce() ))("c", util::to_hex( system_call::get_account_nonce( context, nonce_account) )) - ); - - system_call::set_account_nonce( context, nonce_account, trx.header().nonce() ); - } - catch ( const reversion_exception& e ) - { - // All reversions here must become failures. - KOINOS_THROW( failure_exception, e.get_message() ); - } - catch ( const failure_exception& e ) - { - throw; - } - catch ( const std::exception& e ) + protocol::transaction_receipt receipt; + std::exception_ptr reverted_exception_ptr; + uint64_t used_rc = 0; + uint64_t disk_storage_used = 0; + uint64_t compute_bandwidth_used = 0; + uint64_t network_bandwidth_used = 0; + uint64_t payer_rc = 0; + std::vector< protocol::event_data > events; + std::vector< std::string > logs; + + try + { + KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "calling privileged thunk from non-privileged code" ); + KOINOS_ASSERT( !context.read_only(), + read_only_context_exception, + "unable to perform action while context is read only" ); + + transaction_guard guard( context, trx ); + + const auto& payer = trx.header().payer(); + const auto& payee = trx.header().payee(); + + // If the payee is set and not the payer, then the payee account's nonce is used. + bool use_payee_nonce = payee.size() && payee != payer; + const auto& nonce_account = use_payee_nonce ? payee : payer; + + auto start_disk_used = context.resource_meter().disk_storage_used(); + auto start_network_used = context.resource_meter().network_bandwidth_used(); + auto start_compute_used = context.resource_meter().compute_bandwidth_used(); + + /** + * While a reference to the payer_session remains alive, resource usage will be tallied + * and charged to the current payer. + */ + auto payer_session = context.make_session( trx.header().rc_limit() ); + + try + { + payer_rc = system_call::get_account_rc( context, payer ); + KOINOS_ASSERT( payer_rc >= trx.header().rc_limit(), + failure_exception, + "payer does not have the rc to cover transaction rc limit" ); + + auto chain_id = system_call::get_object( context, state::space::metadata(), state::key::chain_id ); + KOINOS_ASSERT( chain_id.exists(), failure_exception, "chain id does not exist" ); + KOINOS_ASSERT( trx.header().chain_id() == chain_id.value(), failure_exception, "chain id mismatch" ); + + KOINOS_ASSERT( system_call::hash( context, + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), + util::converter::as< std::string >( trx.header() ) ) + == trx.id(), + failure_exception, + "transaction contains an invalid transaction id" ); + + const crypto::multihash op_root = + util::converter::to< crypto::multihash >( trx.header().operation_merkle_root() ); + KOINOS_ASSERT( op_root.code() == context.block_hash_code(), + failure_exception, + "unexpected operation merkle root hash code - was: ${o}, expected: ${e}", + ( "o", std::underlying_type_t< crypto::multicodec >( op_root.code() ) )( + "e", + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ) ) ); + + // Check operation merkle root + std::vector< std::string > hashes; + hashes.reserve( trx.operations_size() ); + + for( const auto& op: trx.operations() ) + hashes.emplace_back( + system_call::hash( context, + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), + util::converter::as< std::string >( op ) ) ); + + KOINOS_ASSERT( system_call::verify_merkle_root( context, trx.header().operation_merkle_root(), hashes ), + failure_exception, + "operation merkle root does not match" ); + + auto authorized = system_call::check_authority( context, transaction_application, payer ); + KOINOS_ASSERT( authorized, + authorization_failure_exception, + "account ${account} has not authorized transaction", + ( "account", util::to_base58( payer ) ) ); + + // If we are using the payee account's nonce, we also need to ensure they signed the transaction as well + if( use_payee_nonce ) { - LOG(error) << e.what(); - assert( false ); - throw; + authorized = system_call::check_authority( context, transaction_application, payee ); + KOINOS_ASSERT( authorized, + authorization_failure_exception, + "account ${account} has not authorized transaction", + ( "account", util::to_base58( payee ) ) ); } - // The anonymous node must be created after requiring authority and the pre transaction callback - // because those calls might write to database and those writes must persist regardless of whether - // the rest of the transaction is reverted or not. - auto block_node = context.get_state_node(); - auto trx_node = block_node->create_anonymous_node(); - context.set_state_node( trx_node, block_node->parent() ); - - try - { - system_call::pre_transaction_callback( context ); - - context.resource_meter().use_network_bandwidth( trx.ByteSizeLong() ); + KOINOS_ASSERT( system_call::verify_account_nonce( context, nonce_account, trx.header().nonce() ), + invalid_nonce_exception, + "invalid transaction nonce - account: ${a}, nonce: ${n}, current nonce: ${c}", + ( "a", util::to_base58( nonce_account ) )( "n", util::to_hex( trx.header().nonce() ) )( + "c", + util::to_hex( system_call::get_account_nonce( context, nonce_account ) ) ) ); + + system_call::set_account_nonce( context, nonce_account, trx.header().nonce() ); + } + catch( const reversion_exception& e ) + { + // All reversions here must become failures. + KOINOS_THROW( failure_exception, e.get_message() ); + } + catch( const failure_exception& e ) + { + throw; + } + catch( const std::exception& e ) + { + LOG( error ) << e.what(); + assert( false ); + throw; + } - for ( const auto& o : trx.operations() ) - { - operation_guard guard( context, o ); + // The anonymous node must be created after requiring authority and the pre transaction callback + // because those calls might write to database and those writes must persist regardless of whether + // the rest of the transaction is reverted or not. + auto block_node = context.get_state_node(); + auto trx_node = block_node->create_anonymous_node(); + context.set_state_node( trx_node, block_node->parent() ); - if ( o.has_upload_contract() ) - system_call::apply_upload_contract_operation( context, o.upload_contract() ); - else if ( o.has_call_contract() ) - system_call::apply_call_contract_operation( context, o.call_contract() ); - else if ( o.has_set_system_call() ) - system_call::apply_set_system_call_operation( context, o.set_system_call() ); - else if ( o.has_set_system_contract() ) - system_call::apply_set_system_contract_operation( context, o.set_system_contract() ); - else - KOINOS_ASSERT( false, unknown_operation_exception, "unknown operation" ); - } + try + { + system_call::pre_transaction_callback( context ); - system_call::post_transaction_callback( context ); + context.resource_meter().use_network_bandwidth( trx.ByteSizeLong() ); - trx_node->commit(); - } - catch ( const failure_exception& ) - { - throw; - } - catch ( const reversion_exception& e ) + for( const auto& o: trx.operations() ) { - // If the transaction fails for any other reason within the operations, it is reverted. - // Mana is still charged, but the block does not fail - receipt.set_reverted( true ); - thunk::_log( context, "transaction reverted: " + e.get_message() ); - reverted_exception_ptr = std::current_exception(); - } - catch ( const std::exception& e ) - { - LOG(error) << e.what(); - assert( false ); - throw; - } - catch ( ... ) - { - assert( false ); - throw; + operation_guard guard( context, o ); + + if( o.has_upload_contract() ) + system_call::apply_upload_contract_operation( context, o.upload_contract() ); + else if( o.has_call_contract() ) + system_call::apply_call_contract_operation( context, o.call_contract() ); + else if( o.has_set_system_call() ) + system_call::apply_set_system_call_operation( context, o.set_system_call() ); + else if( o.has_set_system_contract() ) + system_call::apply_set_system_contract_operation( context, o.set_system_contract() ); + else + KOINOS_ASSERT( false, unknown_operation_exception, "unknown operation" ); } - // BEGIN: No throw section - // Throwing will result in lost events and logs on transaction receipts. + system_call::post_transaction_callback( context ); + + trx_node->commit(); + } + catch( const failure_exception& ) + { + throw; + } + catch( const reversion_exception& e ) + { + // If the transaction fails for any other reason within the operations, it is reverted. + // Mana is still charged, but the block does not fail + receipt.set_reverted( true ); + thunk::_log( context, "transaction reverted: " + e.get_message() ); + reverted_exception_ptr = std::current_exception(); + } + catch( const std::exception& e ) + { + LOG( error ) << e.what(); + assert( false ); + throw; + } + catch( ... ) + { + assert( false ); + throw; + } + + // BEGIN: No throw section + // Throwing will result in lost events and logs on transaction receipts. - context.set_state_node( block_node ); + context.set_state_node( block_node ); - used_rc = payer_session->used_rc(); - logs = payer_session->logs(); - if ( !receipt.reverted() ) - events = payer_session->events(); + used_rc = payer_session->used_rc(); + logs = payer_session->logs(); + if( !receipt.reverted() ) + events = payer_session->events(); - disk_storage_used = context.resource_meter().disk_storage_used() - start_disk_used; - network_bandwidth_used = context.resource_meter().network_bandwidth_used() - start_network_used; - compute_bandwidth_used = context.resource_meter().compute_bandwidth_used() - start_compute_used; + disk_storage_used = context.resource_meter().disk_storage_used() - start_disk_used; + network_bandwidth_used = context.resource_meter().network_bandwidth_used() - start_network_used; + compute_bandwidth_used = context.resource_meter().compute_bandwidth_used() - start_compute_used; - payer_session.reset(); + payer_session.reset(); - // END: No throw section + // END: No throw section - KOINOS_ASSERT( - system_call::consume_account_rc( context, payer, used_rc ), - failure_exception, - "unable to consume rc for payer: ${p}", ("p", util::to_base58( payer ) ); - ); + KOINOS_ASSERT( system_call::consume_account_rc( context, payer, used_rc ), + failure_exception, + "unable to consume rc for payer: ${p}", + ( "p", util::to_base58( payer ) ); ); - generate_receipt( context, receipt, trx, payer_rc, used_rc, disk_storage_used, network_bandwidth_used, compute_bandwidth_used, events, logs ); + generate_receipt( context, + receipt, + trx, + payer_rc, + used_rc, + disk_storage_used, + network_bandwidth_used, + compute_bandwidth_used, + events, + logs ); - switch ( context.intent() ) - { + switch( context.intent() ) + { case intent::block_application: - KOINOS_ASSERT( - std::holds_alternative< protocol::block_receipt >( context.receipt() ), - failure_exception, - "expected block receipt with block application intent" - ); - *std::get< protocol::block_receipt >( context.receipt() ).add_transaction_receipts() = receipt; - break; + KOINOS_ASSERT( std::holds_alternative< protocol::block_receipt >( context.receipt() ), + failure_exception, + "expected block receipt with block application intent" ); + *std::get< protocol::block_receipt >( context.receipt() ).add_transaction_receipts() = receipt; + break; case intent::transaction_application: - context.receipt() = receipt; - break; + context.receipt() = receipt; + break; default: - assert( false ); - break; - } - } - catch ( const koinos::exception& e ) - { - generate_receipt( context, receipt, trx, payer_rc, used_rc, disk_storage_used, network_bandwidth_used, compute_bandwidth_used, events, logs ); - - switch ( context.intent() ) - { + assert( false ); + break; + } + } + catch( const koinos::exception& e ) + { + generate_receipt( context, + receipt, + trx, + payer_rc, + used_rc, + disk_storage_used, + network_bandwidth_used, + compute_bandwidth_used, + events, + logs ); + + switch( context.intent() ) + { case intent::block_application: - KOINOS_ASSERT( - std::holds_alternative< protocol::block_receipt >( context.receipt() ), - failure_exception, - "expected block receipt with block application intent" - ); - *std::get< protocol::block_receipt >( context.receipt() ).add_transaction_receipts() = receipt; - break; + KOINOS_ASSERT( std::holds_alternative< protocol::block_receipt >( context.receipt() ), + failure_exception, + "expected block receipt with block application intent" ); + *std::get< protocol::block_receipt >( context.receipt() ).add_transaction_receipts() = receipt; + break; case intent::transaction_application: - context.receipt() = receipt; - break; + context.receipt() = receipt; + break; default: - assert( false ); - break; - } + assert( false ); + break; + } - throw; - } + throw; + } - if ( reverted_exception_ptr ) - std::rethrow_exception( reverted_exception_ptr ); + if( reverted_exception_ptr ) + std::rethrow_exception( reverted_exception_ptr ); } -THUNK_DEFINE( void, apply_upload_contract_operation, ((const protocol::upload_contract_operation&) o) ) +THUNK_DEFINE( void, apply_upload_contract_operation, ( (const protocol::upload_contract_operation&)o ) ) { - KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "calling privileged thunk from non-privileged code" ); - KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "unable to perform action while context is read only" ); - - auto authorized = system_call::check_authority( context, contract_upload, o.contract_id() ); - KOINOS_ASSERT( authorized, authorization_failure_exception, "account ${account} has not authorized action", ("account", util::to_base58( o.contract_id() )) ); - - auto contract_meta_db_object = system_call::get_object( context, state::space::contract_metadata(), o.contract_id() ); - contract_metadata_object contract_meta; - - if ( contract_meta_db_object.exists() ) - contract_meta = util::converter::to< contract_metadata_object >( contract_meta_db_object.value() ); - - contract_meta.set_hash( system_call::hash( context, std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), o.bytecode() ) ); - contract_meta.set_authorizes_call_contract( o.authorizes_call_contract() ); - contract_meta.set_authorizes_transaction_application( o.authorizes_transaction_application() ); - contract_meta.set_authorizes_upload_contract( o.authorizes_upload_contract() ); - - system_call::put_object( context, state::space::contract_bytecode(), o.contract_id(), o.bytecode() ); - system_call::put_object( context, state::space::contract_metadata(), o.contract_id(), util::converter::as< std::string >( contract_meta ) ); + KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "calling privileged thunk from non-privileged code" ); + KOINOS_ASSERT( !context.read_only(), + read_only_context_exception, + "unable to perform action while context is read only" ); + + auto authorized = system_call::check_authority( context, contract_upload, o.contract_id() ); + KOINOS_ASSERT( authorized, + authorization_failure_exception, + "account ${account} has not authorized action", + ( "account", util::to_base58( o.contract_id() ) ) ); + + auto contract_meta_db_object = system_call::get_object( context, state::space::contract_metadata(), o.contract_id() ); + contract_metadata_object contract_meta; + + if( contract_meta_db_object.exists() ) + contract_meta = util::converter::to< contract_metadata_object >( contract_meta_db_object.value() ); + + contract_meta.set_hash( system_call::hash( context, + std::underlying_type_t< crypto::multicodec >( context.block_hash_code() ), + o.bytecode() ) ); + contract_meta.set_authorizes_call_contract( o.authorizes_call_contract() ); + contract_meta.set_authorizes_transaction_application( o.authorizes_transaction_application() ); + contract_meta.set_authorizes_upload_contract( o.authorizes_upload_contract() ); + + system_call::put_object( context, state::space::contract_bytecode(), o.contract_id(), o.bytecode() ); + system_call::put_object( context, + state::space::contract_metadata(), + o.contract_id(), + util::converter::as< std::string >( contract_meta ) ); } -THUNK_DEFINE( void, apply_call_contract_operation, ((const protocol::call_contract_operation&) o) ) +THUNK_DEFINE( void, apply_call_contract_operation, ( (const protocol::call_contract_operation&)o ) ) { - KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "calling privileged thunk from non-privileged code" ); - KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "unable to perform action while context is read only" ); - - // Drop to user mode - with_privilege( - context, - privilege::user_mode, - [&]() { - try - { - system_call::call( context, o.contract_id(), o.entry_point(), o.args() ); - } - catch ( const failure_exception& e ) - { - throw reversion_exception( e.get_data() ); - } - } - ); + KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "calling privileged thunk from non-privileged code" ); + KOINOS_ASSERT( !context.read_only(), + read_only_context_exception, + "unable to perform action while context is read only" ); + + // Drop to user mode + with_privilege( context, + privilege::user_mode, + [ & ]() + { + try + { + system_call::call( context, o.contract_id(), o.entry_point(), o.args() ); + } + catch( const failure_exception& e ) + { + throw reversion_exception( e.get_data() ); + } + } ); } -THUNK_DEFINE( void, apply_set_system_call_operation, ((const protocol::set_system_call_operation&) o) ) +THUNK_DEFINE( void, apply_set_system_call_operation, ( (const protocol::set_system_call_operation&)o ) ) { - KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "calling privileged thunk from non-privileged code" ); - KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "unable to perform action while context is read only" ); - KOINOS_ASSERT( system_call::check_system_authority( context ), system_authorization_failure_exception, "system authority required" ); - - if ( o.target().has_system_call_bundle() ) - { - auto contract_object = system_call::get_object( context, state::space::contract_bytecode(), o.target().system_call_bundle().contract_id() ); - KOINOS_ASSERT( contract_object.exists(), invalid_contract_exception, "contract does not exist" ); - auto contract_meta_object = system_call::get_object( context, state::space::contract_metadata(), o.target().system_call_bundle().contract_id() ); - KOINOS_ASSERT( contract_meta_object.exists(), invalid_contract_exception, "contract metadata does not exist" ); - auto contract_meta = util::converter::to< contract_metadata_object >( contract_meta_object.value() ); - KOINOS_ASSERT( contract_meta.system(), invalid_contract_exception, "contract is not a system contract" ); - KOINOS_ASSERT( o.call_id() != chain::system_call_id::call, reversion_exception, "cannot override call_contract" ); - - if ( context.intent() == intent::block_application ) - LOG(info) << "Overriding system call " << o.call_id() << " with contract " << util::to_base58( o.target().system_call_bundle().contract_id() ) << " at entry point " << util::to_hex( o.target().system_call_bundle().entry_point() ); - } - else - { - KOINOS_ASSERT( thunk_dispatcher::instance().thunk_exists( o.target().thunk_id() ), unknown_thunk_exception, "thunk ${tid} does not exist", ("tid", o.target().thunk_id()) ); - - if ( context.intent() == intent::block_application ) - LOG(info) << "Overriding system call " << o.call_id() << " with thunk " << o.target().thunk_id(); - } - - // Place the override in the database - system_call::put_object( context, state::space::system_call_dispatch(), util::converter::as< std::string >( std::underlying_type_t< koinos::chain::system_call_id >( o.call_id() ) ), util::converter::as< std::string >( o.target() ) ); - - // Emit an event - set_system_call_event event; - event.set_call_id( o.call_id() ); - event.mutable_target()->CopyFrom( o.target() ); - system_call::event( context, "koinos.chain.set_system_call_event", event.SerializeAsString(), {} ); + KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "calling privileged thunk from non-privileged code" ); + KOINOS_ASSERT( !context.read_only(), + read_only_context_exception, + "unable to perform action while context is read only" ); + KOINOS_ASSERT( system_call::check_system_authority( context ), + system_authorization_failure_exception, + "system authority required" ); + + if( o.target().has_system_call_bundle() ) + { + auto contract_object = system_call::get_object( context, + state::space::contract_bytecode(), + o.target().system_call_bundle().contract_id() ); + KOINOS_ASSERT( contract_object.exists(), invalid_contract_exception, "contract does not exist" ); + auto contract_meta_object = system_call::get_object( context, + state::space::contract_metadata(), + o.target().system_call_bundle().contract_id() ); + KOINOS_ASSERT( contract_meta_object.exists(), invalid_contract_exception, "contract metadata does not exist" ); + auto contract_meta = util::converter::to< contract_metadata_object >( contract_meta_object.value() ); + KOINOS_ASSERT( contract_meta.system(), invalid_contract_exception, "contract is not a system contract" ); + KOINOS_ASSERT( o.call_id() != chain::system_call_id::call, reversion_exception, "cannot override call_contract" ); + + if( context.intent() == intent::block_application ) + LOG( info ) << "Overriding system call " << o.call_id() << " with contract " + << util::to_base58( o.target().system_call_bundle().contract_id() ) << " at entry point " + << util::to_hex( o.target().system_call_bundle().entry_point() ); + } + else + { + KOINOS_ASSERT( thunk_dispatcher::instance().thunk_exists( o.target().thunk_id() ), + unknown_thunk_exception, + "thunk ${tid} does not exist", + ( "tid", o.target().thunk_id() ) ); + + if( context.intent() == intent::block_application ) + LOG( info ) << "Overriding system call " << o.call_id() << " with thunk " << o.target().thunk_id(); + } + + // Place the override in the database + system_call::put_object( + context, + state::space::system_call_dispatch(), + util::converter::as< std::string >( std::underlying_type_t< koinos::chain::system_call_id >( o.call_id() ) ), + util::converter::as< std::string >( o.target() ) ); + + // Emit an event + set_system_call_event event; + event.set_call_id( o.call_id() ); + event.mutable_target()->CopyFrom( o.target() ); + system_call::event( context, "koinos.chain.set_system_call_event", event.SerializeAsString(), {} ); } -THUNK_DEFINE( void, apply_set_system_contract_operation, ((const protocol::set_system_contract_operation&) o) ) +THUNK_DEFINE( void, apply_set_system_contract_operation, ( (const protocol::set_system_contract_operation&)o ) ) { - KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "calling privileged thunk from non-privileged code" ); - KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "unable to perform action while context is read only" ); - KOINOS_ASSERT( system_call::check_system_authority( context ), system_authorization_failure_exception, "system authority required" ); - - auto contract_object = system_call::get_object( context, state::space::contract_bytecode(), o.contract_id() ); - KOINOS_ASSERT( contract_object.exists(), invalid_contract_exception, "contract does not exist" ); - auto contract_meta_object = system_call::get_object( context, state::space::contract_metadata(), o.contract_id() ); - KOINOS_ASSERT( contract_meta_object.exists(), invalid_contract_exception, "contract does not exist" ); - auto contract_meta = util::converter::to< contract_metadata_object >( contract_meta_object.value() ); - KOINOS_ASSERT( contract_meta.hash().size(), invalid_contract_exception, "contract hash does not exist" ); - - contract_meta.set_system( o.system_contract() ); - system_call::put_object( context, state::space::contract_metadata(), o.contract_id(), util::converter::as< std::string >( contract_meta ) ); - - // Emit an event - set_system_contract_event event; - event.set_contract_id( o.contract_id() ); - event.set_system_contract( o.system_contract() ); - system_call::event( context, "koinos.chain.set_system_contract_event", event.SerializeAsString(), {} ); + KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "calling privileged thunk from non-privileged code" ); + KOINOS_ASSERT( !context.read_only(), + read_only_context_exception, + "unable to perform action while context is read only" ); + KOINOS_ASSERT( system_call::check_system_authority( context ), + system_authorization_failure_exception, + "system authority required" ); + + auto contract_object = system_call::get_object( context, state::space::contract_bytecode(), o.contract_id() ); + KOINOS_ASSERT( contract_object.exists(), invalid_contract_exception, "contract does not exist" ); + auto contract_meta_object = system_call::get_object( context, state::space::contract_metadata(), o.contract_id() ); + KOINOS_ASSERT( contract_meta_object.exists(), invalid_contract_exception, "contract does not exist" ); + auto contract_meta = util::converter::to< contract_metadata_object >( contract_meta_object.value() ); + KOINOS_ASSERT( contract_meta.hash().size(), invalid_contract_exception, "contract hash does not exist" ); + + contract_meta.set_system( o.system_contract() ); + system_call::put_object( context, + state::space::contract_metadata(), + o.contract_id(), + util::converter::as< std::string >( contract_meta ) ); + + // Emit an event + set_system_contract_event event; + event.set_contract_id( o.contract_id() ); + event.set_system_contract( o.system_contract() ); + system_call::event( context, "koinos.chain.set_system_contract_event", event.SerializeAsString(), {} ); } THUNK_DEFINE_VOID( void, pre_block_callback ) {} @@ -807,642 +844,697 @@ THUNK_DEFINE_VOID( void, post_transaction_callback ) {} THUNK_DEFINE_VOID( get_chain_id_result, get_chain_id ) { - get_chain_id_result ret; - ret.set_value( system_call::get_object( context, state::space::metadata(), state::key::chain_id ).value() ); - return ret; + get_chain_id_result ret; + ret.set_value( system_call::get_object( context, state::space::metadata(), state::key::chain_id ).value() ); + return ret; } /////////////////////////////////////////////////////////////////////////////// // System Helpers // /////////////////////////////////////////////////////////////////////////////// -THUNK_DEFINE( process_block_signature_result, process_block_signature, ((const std::string&) id, (const protocol::block_header&) header, (const std::string&) signature_data) ) +THUNK_DEFINE( process_block_signature_result, + process_block_signature, + ( (const std::string&)id, (const protocol::block_header&)header, (const std::string&)signature_data ) ) { - auto genesis_addr = system_call::get_object( context, state::space::metadata(), state::key::genesis_key ).value(); - - process_block_signature_result ret; - ret.set_value( genesis_addr == util::converter::to< crypto::public_key >( system_call::recover_public_key( context, ecdsa_secp256k1, signature_data, id, true ) ).to_address_bytes() ); - return ret; + auto genesis_addr = system_call::get_object( context, state::space::metadata(), state::key::genesis_key ).value(); + + process_block_signature_result ret; + ret.set_value( genesis_addr + == util::converter::to< crypto::public_key >( + system_call::recover_public_key( context, ecdsa_secp256k1, signature_data, id, true ) ) + .to_address_bytes() ); + return ret; } THUNK_DEFINE_VOID( get_transaction_result, get_transaction ) { - get_transaction_result ret; + get_transaction_result ret; - const auto* transaction = context.get_transaction(); - KOINOS_ASSERT( transaction != nullptr, internal_error_exception, "transaction does not exist" ); - *ret.mutable_value() = *transaction; + const auto* transaction = context.get_transaction(); + KOINOS_ASSERT( transaction != nullptr, internal_error_exception, "transaction does not exist" ); + *ret.mutable_value() = *transaction; - return ret; + return ret; } -THUNK_DEFINE( get_transaction_field_result, get_transaction_field, ((const std::string&) field) ) +THUNK_DEFINE( get_transaction_field_result, get_transaction_field, ( (const std::string&)field ) ) { - get_transaction_field_result ret; + get_transaction_field_result ret; - const auto* transaction = context.get_transaction(); - KOINOS_ASSERT( transaction != nullptr, internal_error_exception, "transaction does not exist" ); + const auto* transaction = context.get_transaction(); + KOINOS_ASSERT( transaction != nullptr, internal_error_exception, "transaction does not exist" ); - *ret.mutable_value() = get_nested_field_value( context, *transaction, field ); + *ret.mutable_value() = get_nested_field_value( context, *transaction, field ); - return ret; + return ret; } THUNK_DEFINE_VOID( get_block_result, get_block ) { - get_block_result ret; + get_block_result ret; - const auto* block = context.get_block(); - KOINOS_ASSERT( block != nullptr, internal_error_exception, "block does not exist" ); + const auto* block = context.get_block(); + KOINOS_ASSERT( block != nullptr, internal_error_exception, "block does not exist" ); - *ret.mutable_value() = *block; + *ret.mutable_value() = *block; - return ret; + return ret; } -THUNK_DEFINE( get_block_field_result, get_block_field, ((const std::string&) field) ) +THUNK_DEFINE( get_block_field_result, get_block_field, ( (const std::string&)field ) ) { - get_block_field_result ret; + get_block_field_result ret; - const auto* block = context.get_block(); - KOINOS_ASSERT( block != nullptr, internal_error_exception, "block does not exist" ); + const auto* block = context.get_block(); + KOINOS_ASSERT( block != nullptr, internal_error_exception, "block does not exist" ); - *ret.mutable_value() = get_nested_field_value( context, *block, field ); + *ret.mutable_value() = get_nested_field_value( context, *block, field ); - return ret; + return ret; } THUNK_DEFINE_VOID( get_last_irreversible_block_result, get_last_irreversible_block ) { - auto head = context.get_state_node(); + auto head = context.get_state_node(); - get_last_irreversible_block_result ret; - ret.set_value( head->revision() > default_irreversible_threshold ? head->revision() - default_irreversible_threshold : 0 ); + get_last_irreversible_block_result ret; + ret.set_value( head->revision() > default_irreversible_threshold ? head->revision() - default_irreversible_threshold + : 0 ); - return ret; + return ret; } -THUNK_DEFINE( get_account_nonce_result, get_account_nonce, ((const std::string&) account ) ) +THUNK_DEFINE( get_account_nonce_result, get_account_nonce, ( (const std::string&)account ) ) { - auto obj = system_call::get_object( context, state::space::transaction_nonce(), account ); - - get_account_nonce_result ret; - - if ( obj.exists() ) - { - ret.set_value( obj.value() ); - } - else - { - value_type nonce_value; - nonce_value.set_uint64_value( 0 ); - ret.set_value( util::converter::as< std::string >( nonce_value ) ); - } - - return ret; + auto obj = system_call::get_object( context, state::space::transaction_nonce(), account ); + + get_account_nonce_result ret; + + if( obj.exists() ) + { + ret.set_value( obj.value() ); + } + else + { + value_type nonce_value; + nonce_value.set_uint64_value( 0 ); + ret.set_value( util::converter::as< std::string >( nonce_value ) ); + } + + return ret; } -THUNK_DEFINE( verify_account_nonce_result, verify_account_nonce, ((const std::string&) account, (const std::string&) nonce) ) +THUNK_DEFINE( verify_account_nonce_result, + verify_account_nonce, + ( (const std::string&)account, (const std::string&)nonce ) ) { - auto nonce_value = util::converter::to< value_type >( nonce ); - KOINOS_ASSERT( - nonce_value.has_uint64_value(), - invalid_nonce_exception, - "nonce did not contain uint64 value - nonce: ${n}, account: ${a}", - ("n", util::to_hex( nonce ))("a", util::to_base58( account )) - ); - - auto current_nonce_value = util::converter::to< value_type >( system_call::get_account_nonce( context, account ) ); - KOINOS_ASSERT( - current_nonce_value.has_uint64_value(), - invalid_nonce_exception, - "current nonce did not contain uint64 value - nonce: ${n}, account: ${a}", - ("n", util::to_hex( current_nonce_value ))("a", util::to_base58( account )) - ); - - verify_account_nonce_result res; - res.set_value( nonce_value.uint64_value() == current_nonce_value.uint64_value() + 1 ); - return res; + auto nonce_value = util::converter::to< value_type >( nonce ); + KOINOS_ASSERT( nonce_value.has_uint64_value(), + invalid_nonce_exception, + "nonce did not contain uint64 value - nonce: ${n}, account: ${a}", + ( "n", util::to_hex( nonce ) )( "a", util::to_base58( account ) ) ); + + auto current_nonce_value = util::converter::to< value_type >( system_call::get_account_nonce( context, account ) ); + KOINOS_ASSERT( current_nonce_value.has_uint64_value(), + invalid_nonce_exception, + "current nonce did not contain uint64 value - nonce: ${n}, account: ${a}", + ( "n", util::to_hex( current_nonce_value ) )( "a", util::to_base58( account ) ) ); + + verify_account_nonce_result res; + res.set_value( nonce_value.uint64_value() == current_nonce_value.uint64_value() + 1 ); + return res; } -THUNK_DEFINE( void, set_account_nonce, ((const std::string&) account, (const std::string&) nonce) ) +THUNK_DEFINE( void, set_account_nonce, ( (const std::string&)account, (const std::string&)nonce ) ) { - KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "calling privileged thunk from non-privileged code" ); + KOINOS_ASSERT( context.get_caller_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "calling privileged thunk from non-privileged code" ); - auto nonce_value = util::converter::to< value_type >( nonce ); - KOINOS_ASSERT( - nonce_value.has_uint64_value(), - invalid_nonce_exception, - "set nonce did not contain uint64 value - nonce: ${n}, account: ${a}", - ("n", util::to_hex( nonce ))("a", util::to_base58( account )) ); + auto nonce_value = util::converter::to< value_type >( nonce ); + KOINOS_ASSERT( nonce_value.has_uint64_value(), + invalid_nonce_exception, + "set nonce did not contain uint64 value - nonce: ${n}, account: ${a}", + ( "n", util::to_hex( nonce ) )( "a", util::to_base58( account ) ) ); - system_call::put_object( context, state::space::transaction_nonce(), account, nonce ); + system_call::put_object( context, state::space::transaction_nonce(), account, nonce ); } THUNK_DEFINE_VOID( check_system_authority_result, check_system_authority ) { - check_system_authority_result res; + check_system_authority_result res; - auto genesis_addr = system_call::get_object( context, state::space::metadata(), state::key::genesis_key ).value(); + auto genesis_addr = system_call::get_object( context, state::space::metadata(), state::key::genesis_key ).value(); - const auto* trx = context.get_transaction(); - KOINOS_ASSERT( trx != nullptr, internal_error_exception, "transaction does not exist" ); + const auto* trx = context.get_transaction(); + KOINOS_ASSERT( trx != nullptr, internal_error_exception, "transaction does not exist" ); - bool authorized = false; + bool authorized = false; - for ( const auto& sig : trx->signatures() ) - { - auto addr = util::converter::to< crypto::public_key >( system_call::recover_public_key( context, ecdsa_secp256k1, sig, trx->id(), true ) ).to_address_bytes(); - authorized = ( addr == genesis_addr ); - if ( authorized ) - break; - } + for( const auto& sig: trx->signatures() ) + { + auto addr = util::converter::to< crypto::public_key >( + system_call::recover_public_key( context, ecdsa_secp256k1, sig, trx->id(), true ) ) + .to_address_bytes(); + authorized = ( addr == genesis_addr ); + if( authorized ) + break; + } - res.set_value( authorized ); + res.set_value( authorized ); - return res; + return res; } THUNK_DEFINE_VOID( get_operation_result, get_operation ) { - get_operation_result ret; + get_operation_result ret; - const auto* op = context.get_operation(); - KOINOS_ASSERT( op != nullptr, operation_not_found_exception, "outside an operational context" ); - *ret.mutable_value() = *op; + const auto* op = context.get_operation(); + KOINOS_ASSERT( op != nullptr, operation_not_found_exception, "outside an operational context" ); + *ret.mutable_value() = *op; - return ret; + return ret; } /////////////////////////////////////////////////////////////////////////////// // Resource Subsystem // /////////////////////////////////////////////////////////////////////////////// -THUNK_DEFINE( get_account_rc_result, get_account_rc, ((const std::string&) account) ) +THUNK_DEFINE( get_account_rc_result, get_account_rc, ( (const std::string&)account ) ) { - auto obj = system_call::get_object( context, state::space::metadata(), state::key::max_account_resources ); - KOINOS_ASSERT( obj.exists(), internal_error_exception, "max_account_resources does not exist" ); + auto obj = system_call::get_object( context, state::space::metadata(), state::key::max_account_resources ); + KOINOS_ASSERT( obj.exists(), internal_error_exception, "max_account_resources does not exist" ); - get_account_rc_result ret; - ret.set_value( util::converter::to< chain::max_account_resources >( obj.value() ).value() ); + get_account_rc_result ret; + ret.set_value( util::converter::to< chain::max_account_resources >( obj.value() ).value() ); - return ret; + return ret; } -THUNK_DEFINE( consume_account_rc_result, consume_account_rc, ((const std::string&) account, (uint64_t) rc) ) +THUNK_DEFINE( consume_account_rc_result, consume_account_rc, ( (const std::string&)account, (uint64_t)rc ) ) { - consume_account_rc_result ret; - ret.set_value( true ); - return ret; + consume_account_rc_result ret; + ret.set_value( true ); + return ret; } THUNK_DEFINE_VOID( get_resource_limits_result, get_resource_limits ) { - resource_limit_data rd; + resource_limit_data rd; - auto obj = system_call::get_object( context, state::space::metadata(), state::key::resource_limit_data ); - KOINOS_ASSERT( obj.exists(), internal_error_exception, "resource_limit_data does not exist" ); + auto obj = system_call::get_object( context, state::space::metadata(), state::key::resource_limit_data ); + KOINOS_ASSERT( obj.exists(), internal_error_exception, "resource_limit_data does not exist" ); - get_resource_limits_result ret; - *ret.mutable_value() = util::converter::to< resource_limit_data >( obj.value() ); - return ret; + get_resource_limits_result ret; + *ret.mutable_value() = util::converter::to< resource_limit_data >( obj.value() ); + return ret; } -THUNK_DEFINE( consume_block_resources_result, consume_block_resources, ((uint64_t) disk, (uint64_t) network, (uint64_t) compute) ) +THUNK_DEFINE( consume_block_resources_result, + consume_block_resources, + ( (uint64_t)disk, (uint64_t)network, (uint64_t)compute ) ) { - consume_block_resources_result ret; - ret.set_value( true ); - return ret; + consume_block_resources_result ret; + ret.set_value( true ); + return ret; } /////////////////////////////////////////////////////////////////////////////// // Database // /////////////////////////////////////////////////////////////////////////////// -THUNK_DEFINE( void, put_object, ((const object_space&) space, (const std::string&) key, (const std::string&) obj) ) +THUNK_DEFINE( void, put_object, ( (const object_space&)space, (const std::string&)key, (const std::string&)obj ) ) { - KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "cannot put object during read only call" ); - context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "object_serialization_per_byte" ) * obj.size() ); + KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "cannot put object during read only call" ); + context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "object_serialization_per_byte" ) + * obj.size() ); - state::assert_permissions( context, space ); + state::assert_permissions( context, space ); - auto state = context.get_state_node(); - KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); - auto val = util::converter::as< state_db::object_value >( obj ); + auto state = context.get_state_node(); + KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); + auto val = util::converter::as< state_db::object_value >( obj ); - context.resource_meter().use_disk_storage( state->put_object( space, key, &val ) ); + context.resource_meter().use_disk_storage( state->put_object( space, key, &val ) ); } -THUNK_DEFINE( void, remove_object, ((const object_space&) space, (const std::string&) key) ) +THUNK_DEFINE( void, remove_object, ( (const object_space&)space, (const std::string&)key ) ) { - KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "cannot remove object during read only call" ); + KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "cannot remove object during read only call" ); - state::assert_permissions( context, space ); + state::assert_permissions( context, space ); - auto state = context.get_state_node(); - KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); + auto state = context.get_state_node(); + KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); - context.resource_meter().use_disk_storage( state->remove_object( space, key ) ); + context.resource_meter().use_disk_storage( state->remove_object( space, key ) ); } -THUNK_DEFINE( get_object_result, get_object, ((const object_space&) space, (const std::string&) key) ) +THUNK_DEFINE( get_object_result, get_object, ( (const object_space&)space, (const std::string&)key ) ) { - state::assert_permissions( context, space ); + state::assert_permissions( context, space ); - abstract_state_node_ptr state = context.get_state_node(); + abstract_state_node_ptr state = context.get_state_node(); - KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); + KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); - const auto result = state->get_object( space, key ); + const auto result = state->get_object( space, key ); - get_object_result ret; + get_object_result ret; - if( result ) - { - context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "object_serialization_per_byte" ) * result->size() ); - ret.mutable_value()->set_exists( true ); - ret.mutable_value()->set_value( result->data(), result->size() ); - } + if( result ) + { + context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "object_serialization_per_byte" ) + * result->size() ); + ret.mutable_value()->set_exists( true ); + ret.mutable_value()->set_value( result->data(), result->size() ); + } - return ret; + return ret; } -THUNK_DEFINE( get_next_object_result, get_next_object, ((const object_space&) space, (const std::string&) key) ) +THUNK_DEFINE( get_next_object_result, get_next_object, ( (const object_space&)space, (const std::string&)key ) ) { - state::assert_permissions( context, space ); + state::assert_permissions( context, space ); - abstract_state_node_ptr state = context.get_state_node(); - KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); + abstract_state_node_ptr state = context.get_state_node(); + KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); - const auto [result, next_key] = state->get_next_object( space, key ); + const auto [ result, next_key ] = state->get_next_object( space, key ); - get_next_object_result ret; + get_next_object_result ret; - if( result ) - { - context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "object_serialization_per_byte" ) * result->size() ); - ret.mutable_value()->set_exists( true ); - ret.mutable_value()->set_value( result->data(), result->size() ); - ret.mutable_value()->set_key( next_key ); - } + if( result ) + { + context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "object_serialization_per_byte" ) + * result->size() ); + ret.mutable_value()->set_exists( true ); + ret.mutable_value()->set_value( result->data(), result->size() ); + ret.mutable_value()->set_key( next_key ); + } - return ret; + return ret; } -THUNK_DEFINE( get_prev_object_result, get_prev_object, ((const object_space&) space, (const std::string&) key) ) +THUNK_DEFINE( get_prev_object_result, get_prev_object, ( (const object_space&)space, (const std::string&)key ) ) { - state::assert_permissions( context, space ); + state::assert_permissions( context, space ); - abstract_state_node_ptr state = context.get_state_node(); - KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); + abstract_state_node_ptr state = context.get_state_node(); + KOINOS_ASSERT( state, internal_error_exception, "current state node does not exist" ); - const auto [result, next_key] = state->get_prev_object( space, key ); + const auto [ result, next_key ] = state->get_prev_object( space, key ); - get_prev_object_result ret; + get_prev_object_result ret; - if( result ) - { - context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "object_serialization_per_byte" ) * result->size() ); - ret.mutable_value()->set_exists( true ); - ret.mutable_value()->set_value( result->data(), result->size() ); - ret.mutable_value()->set_key( next_key ); - } + if( result ) + { + context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "object_serialization_per_byte" ) + * result->size() ); + ret.mutable_value()->set_exists( true ); + ret.mutable_value()->set_value( result->data(), result->size() ); + ret.mutable_value()->set_key( next_key ); + } - return ret; + return ret; } /////////////////////////////////////////////////////////////////////////////// // Logging // /////////////////////////////////////////////////////////////////////////////// -THUNK_DEFINE( void, log, ((const std::string&) msg) ) +THUNK_DEFINE( void, log, ( (const std::string&)msg ) ) { - KOINOS_ASSERT( validate_utf( msg ), reversion_exception, "log entry contains invalid utf-8" ); - context.chronicler().push_log( msg ); + KOINOS_ASSERT( validate_utf( msg ), reversion_exception, "log entry contains invalid utf-8" ); + context.chronicler().push_log( msg ); } -THUNK_DEFINE( void, event, ((const std::string&) name, (const std::string&) data, (const std::vector< std::string >&) impacted) ) +THUNK_DEFINE( void, + event, + ( (const std::string&)name, (const std::string&)data, (const std::vector< std::string >&)impacted ) ) { - KOINOS_ASSERT( name.size(), reversion_exception, "event name cannot be empty" ); - KOINOS_ASSERT( name.size() <= 128, reversion_exception, "event name cannot be larger than 128 bytes" ); - KOINOS_ASSERT( validate_utf( name ), reversion_exception, "event name contains invalid utf-8" ); + KOINOS_ASSERT( name.size(), reversion_exception, "event name cannot be empty" ); + KOINOS_ASSERT( name.size() <= 128, reversion_exception, "event name cannot be larger than 128 bytes" ); + KOINOS_ASSERT( validate_utf( name ), reversion_exception, "event name contains invalid utf-8" ); - context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "event_per_impacted" ) * impacted.size() ); + context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( "event_per_impacted" ) + * impacted.size() ); - const auto& caller = context.get_caller(); + const auto& caller = context.get_caller(); - protocol::event_data ev; - ev.set_source( caller ); - ev.set_name( name ); - ev.set_data( data ); + protocol::event_data ev; + ev.set_source( caller ); + ev.set_name( name ); + ev.set_data( data ); - for ( auto& imp : impacted ) - *ev.add_impacted() = imp; + for( auto& imp: impacted ) + *ev.add_impacted() = imp; - std::optional< std::string > transaction_id; - if ( const auto* transaction = context.get_transaction(); transaction != nullptr ) - transaction_id = transaction->id(); + std::optional< std::string > transaction_id; + if( const auto* transaction = context.get_transaction(); transaction != nullptr ) + transaction_id = transaction->id(); - context.chronicler().push_event( transaction_id, std::move( ev ) ); + context.chronicler().push_event( transaction_id, std::move( ev ) ); } /////////////////////////////////////////////////////////////////////////////// // Cryptography // /////////////////////////////////////////////////////////////////////////////// -THUNK_DEFINE( hash_result, hash, ((uint64_t) id, (const std::string&) obj, (uint64_t) size) ) +THUNK_DEFINE( hash_result, hash, ( (uint64_t)id, (const std::string&)obj, (uint64_t)size ) ) { - auto multicodec = static_cast< crypto::multicodec >( id ); - validate_hash_code( multicodec ); + auto multicodec = static_cast< crypto::multicodec >( id ); + validate_hash_code( multicodec ); - auto [ hash_base, hash_per_byte ] = hash_compute_keys( multicodec ); - context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( hash_base ) + context.get_compute_bandwidth( hash_per_byte ) * obj.size() ); + auto [ hash_base, hash_per_byte ] = hash_compute_keys( multicodec ); + context.resource_meter().use_compute_bandwidth( context.get_compute_bandwidth( hash_base ) + + context.get_compute_bandwidth( hash_per_byte ) * obj.size() ); - auto hash = crypto::hash( multicodec, obj, crypto::digest_size( size ) ); + auto hash = crypto::hash( multicodec, obj, crypto::digest_size( size ) ); - hash_result ret; - ret.set_value( util::converter::as< std::string >( hash ) ); - return ret; + hash_result ret; + ret.set_value( util::converter::as< std::string >( hash ) ); + return ret; } -THUNK_DEFINE( recover_public_key_result, recover_public_key, ((dsa) type, (const std::string&) signature_data, (const std::string&) digest, (bool) compressed) ) +THUNK_DEFINE( recover_public_key_result, + recover_public_key, + ( (dsa)type, (const std::string&)signature_data, (const std::string&)digest, (bool)compressed ) ) { - KOINOS_ASSERT( type == ecdsa_secp256k1, unknown_dsa_exception, "unexpected dsa" ); + KOINOS_ASSERT( type == ecdsa_secp256k1, unknown_dsa_exception, "unexpected dsa" ); - KOINOS_ASSERT( signature_data.size() == 65, invalid_signature_exception, "unexpected signature length" ); - crypto::recoverable_signature signature = util::converter::as< crypto::recoverable_signature >( signature_data ); + KOINOS_ASSERT( signature_data.size() == 65, invalid_signature_exception, "unexpected signature length" ); + crypto::recoverable_signature signature = util::converter::as< crypto::recoverable_signature >( signature_data ); - KOINOS_ASSERT( crypto::public_key::is_canonical( signature ), invalid_signature_exception, "signature must be canonical" ); + KOINOS_ASSERT( crypto::public_key::is_canonical( signature ), + invalid_signature_exception, + "signature must be canonical" ); - auto pub_key = crypto::public_key::recover( signature, util::converter::to< crypto::multihash >( digest ) ); - KOINOS_ASSERT( pub_key.valid(), invalid_signature_exception, "public key is invalid" ); + auto pub_key = crypto::public_key::recover( signature, util::converter::to< crypto::multihash >( digest ) ); + KOINOS_ASSERT( pub_key.valid(), invalid_signature_exception, "public key is invalid" ); - recover_public_key_result ret; - if ( compressed ) - ret.set_value( util::converter::as< std::string >( pub_key ) ); - else - ret.set_value( util::converter::as< std::string >( pub_key.serialize_uncompressed() ) ); + recover_public_key_result ret; + if( compressed ) + ret.set_value( util::converter::as< std::string >( pub_key ) ); + else + ret.set_value( util::converter::as< std::string >( pub_key.serialize_uncompressed() ) ); - return ret; + return ret; } -THUNK_DEFINE( verify_merkle_root_result, verify_merkle_root, ((const std::string&) root, (const std::vector< std::string >&) hashes) ) +THUNK_DEFINE( verify_merkle_root_result, + verify_merkle_root, + ( (const std::string&)root, (const std::vector< std::string >&)hashes ) ) { - uint64_t deserialize_multihash_base = context.get_compute_bandwidth( "deserialize_multihash_base" ); - uint64_t deserialize_multihash_per_byte = context.get_compute_bandwidth( "deserialize_multihash_per_byte" ); - - // Charge for all deserialization - context.resource_meter().use_compute_bandwidth( ( hashes.size() + 1 ) * ( deserialize_multihash_base + root.size() * deserialize_multihash_per_byte ) ); - - auto root_hash = util::converter::to< crypto::multihash >( root ); - - auto [ hash_base_key, hash_per_byte_key ] = hash_compute_keys( root_hash.code() ); - uint64_t hash_base = context.get_compute_bandwidth( hash_base_key ); - uint64_t hash_per_byte = context.get_compute_bandwidth( hash_per_byte_key ); - // Charge for all hashing to compute merkle root - context.resource_meter().use_compute_bandwidth( hashes_per_leaves( hashes.size() ) * ( hash_base + 2 * root_hash.digest().size() * hash_per_byte ) ); - - validate_hash_code( root_hash.code() ); - - std::vector< crypto::multihash > leaves; - - leaves.resize( hashes.size() ); - std::transform( std::begin( hashes ), std::end( hashes ), std::begin( leaves ), [&]( const std::string& s ) - { - auto mh = util::converter::to< crypto::multihash >( s ); - KOINOS_ASSERT( mh.code() == root_hash.code(), unknown_hash_code_exception, "leaf and merkle root hash codes do not match" ); - KOINOS_ASSERT( mh.digest().size() == root_hash.digest().size(), unknown_hash_code_exception, "leaf and merkle root hash sizes do not match" ); - return mh; - } - ); - - auto mtree = crypto::merkle_tree( root_hash.code(), leaves ); - - auto merkle_root = mtree.root()->hash(); - - verify_merkle_root_result ret; - ret.set_value( merkle_root == root_hash ); - return ret; + uint64_t deserialize_multihash_base = context.get_compute_bandwidth( "deserialize_multihash_base" ); + uint64_t deserialize_multihash_per_byte = context.get_compute_bandwidth( "deserialize_multihash_per_byte" ); + + // Charge for all deserialization + context.resource_meter().use_compute_bandwidth( + ( hashes.size() + 1 ) * ( deserialize_multihash_base + root.size() * deserialize_multihash_per_byte ) ); + + auto root_hash = util::converter::to< crypto::multihash >( root ); + + auto [ hash_base_key, hash_per_byte_key ] = hash_compute_keys( root_hash.code() ); + uint64_t hash_base = context.get_compute_bandwidth( hash_base_key ); + uint64_t hash_per_byte = context.get_compute_bandwidth( hash_per_byte_key ); + // Charge for all hashing to compute merkle root + context.resource_meter().use_compute_bandwidth( hashes_per_leaves( hashes.size() ) + * ( hash_base + 2 * root_hash.digest().size() * hash_per_byte ) ); + + validate_hash_code( root_hash.code() ); + + std::vector< crypto::multihash > leaves; + + leaves.resize( hashes.size() ); + std::transform( std::begin( hashes ), + std::end( hashes ), + std::begin( leaves ), + [ & ]( const std::string& s ) + { + auto mh = util::converter::to< crypto::multihash >( s ); + KOINOS_ASSERT( mh.code() == root_hash.code(), + unknown_hash_code_exception, + "leaf and merkle root hash codes do not match" ); + KOINOS_ASSERT( mh.digest().size() == root_hash.digest().size(), + unknown_hash_code_exception, + "leaf and merkle root hash sizes do not match" ); + return mh; + } ); + + auto mtree = crypto::merkle_tree( root_hash.code(), leaves ); + + auto merkle_root = mtree.root()->hash(); + + verify_merkle_root_result ret; + ret.set_value( merkle_root == root_hash ); + return ret; } -THUNK_DEFINE( verify_signature_result, verify_signature, ((dsa) type, (const std::string&) public_key, (const std::string&) signature, (const std::string&) digest, (bool) compressed) ) +THUNK_DEFINE( verify_signature_result, + verify_signature, + ( (dsa)type, + (const std::string&)public_key, + (const std::string&)signature, + (const std::string&)digest, + (bool)compressed ) ) { - KOINOS_ASSERT( type == ecdsa_secp256k1, unknown_dsa_exception, "unexpected dsa" ); + KOINOS_ASSERT( type == ecdsa_secp256k1, unknown_dsa_exception, "unexpected dsa" ); - verify_signature_result ret; - ret.set_value( system_call::recover_public_key( context, type, signature, digest, compressed ) == public_key ); - return ret; + verify_signature_result ret; + ret.set_value( system_call::recover_public_key( context, type, signature, digest, compressed ) == public_key ); + return ret; } -THUNK_DEFINE( verify_vrf_proof_result, verify_vrf_proof, ((dsa) type, (const std::string&) public_key, (const std::string&) proof, (const std::string&) hash, (const std::string&) message) ) +THUNK_DEFINE( verify_vrf_proof_result, + verify_vrf_proof, + ( (dsa)type, + (const std::string&)public_key, + (const std::string&)proof, + (const std::string&)hash, + (const std::string&)message ) ) { - KOINOS_ASSERT( type == ecdsa_secp256k1, unknown_dsa_exception, "unexpected dsa" ); + KOINOS_ASSERT( type == ecdsa_secp256k1, unknown_dsa_exception, "unexpected dsa" ); - verify_vrf_proof_result ret; - ret.set_value( false ); + verify_vrf_proof_result ret; + ret.set_value( false ); - auto pub_key = util::converter::to< crypto::public_key >( public_key ); - auto expected_hash = util::converter::to< crypto::multihash >( hash ); + auto pub_key = util::converter::to< crypto::public_key >( public_key ); + auto expected_hash = util::converter::to< crypto::multihash >( hash ); - try - { - auto proof_hash = pub_key.verify_random_proof( message, proof ); - ret.set_value( proof_hash == expected_hash ); - } - catch ( const crypto::vrf_validation_error& ) { /* do nothing */ } + try + { + auto proof_hash = pub_key.verify_random_proof( message, proof ); + ret.set_value( proof_hash == expected_hash ); + } + catch( const crypto::vrf_validation_error& ) + { /* do nothing */ + } - return ret; + return ret; } /////////////////////////////////////////////////////////////////////////////// // Contract Management // /////////////////////////////////////////////////////////////////////////////// -THUNK_DEFINE( call_result, call, ((const std::string&) contract_id, (uint32_t) entry_point, (const std::string&) args) ) +THUNK_DEFINE( call_result, call, ( (const std::string&)contract_id, (uint32_t)entry_point, (const std::string&)args ) ) { - // We need to be in kernel mode to read the contract data - auto contract_object = system_call::get_object( context, state::space::contract_bytecode(), contract_id ); - KOINOS_ASSERT( contract_object.exists(), invalid_contract_exception, "contract does not exist" ); - auto contract_meta_object = system_call::get_object( context, state::space::contract_metadata(), contract_id ); - KOINOS_ASSERT( contract_meta_object.exists(), invalid_contract_exception, "contract metadata does not exist" ); - auto contract_meta = util::converter::to< contract_metadata_object >( contract_meta_object.value() ); - KOINOS_ASSERT( contract_meta.hash().size(), invalid_contract_exception, "contract hash does not exist" ); - - // authorize should only be called from kernel mode - KOINOS_ASSERT( entry_point != authorize_entrypoint || context.get_caller_privilege() == privilege::kernel_mode, insufficient_privileges_exception, "calling privileged thunk from non-privileged code" ); - - try - { - with_stack_frame( - context, - stack_frame { - .contract_id = contract_id, - .call_privilege = contract_meta.system() ? privilege::kernel_mode : privilege::user_mode, - .call_args = args, - .entry_point = entry_point - }, - [&] - { - chain::host_api hapi( context ); - context.get_backend()->run( hapi, contract_object.value(), contract_meta.hash() ); - } - ); - } - catch ( const success_exception& ) {} - - const auto& res = context.get_result(); - - if ( res.code ) - { - const auto& error = res.res.error(); - - if ( res.code >= reversion ) - throw reversion_exception( res.code, error ); - if ( res.code <= failure ) - throw failure_exception( res.code, error ); - } - - call_result ret; - if ( res.res.has_object() ) - *ret.mutable_value() = res.res.object(); - - return ret; + // We need to be in kernel mode to read the contract data + auto contract_object = system_call::get_object( context, state::space::contract_bytecode(), contract_id ); + KOINOS_ASSERT( contract_object.exists(), invalid_contract_exception, "contract does not exist" ); + auto contract_meta_object = system_call::get_object( context, state::space::contract_metadata(), contract_id ); + KOINOS_ASSERT( contract_meta_object.exists(), invalid_contract_exception, "contract metadata does not exist" ); + auto contract_meta = util::converter::to< contract_metadata_object >( contract_meta_object.value() ); + KOINOS_ASSERT( contract_meta.hash().size(), invalid_contract_exception, "contract hash does not exist" ); + + // authorize should only be called from kernel mode + KOINOS_ASSERT( entry_point != authorize_entrypoint || context.get_caller_privilege() == privilege::kernel_mode, + insufficient_privileges_exception, + "calling privileged thunk from non-privileged code" ); + + try + { + with_stack_frame( + context, + stack_frame{ .contract_id = contract_id, + .call_privilege = contract_meta.system() ? privilege::kernel_mode : privilege::user_mode, + .call_args = args, + .entry_point = entry_point }, + [ & ] + { + chain::host_api hapi( context ); + context.get_backend()->run( hapi, contract_object.value(), contract_meta.hash() ); + } ); + } + catch( const success_exception& ) + {} + + const auto& res = context.get_result(); + + if( res.code ) + { + const auto& error = res.res.error(); + + if( res.code >= reversion ) + throw reversion_exception( res.code, error ); + if( res.code <= failure ) + throw failure_exception( res.code, error ); + } + + call_result ret; + if( res.res.has_object() ) + *ret.mutable_value() = res.res.object(); + + return ret; } -THUNK_DEFINE( void, exit, ((int32_t) code, (result) res) ) +THUNK_DEFINE( void, exit, ( (int32_t)code, (result)res ) ) { - context.set_result( { code, res } ); - - if ( !code ) // code == success - { - throw success_exception( code ); - } - - KOINOS_ASSERT( res.has_error(), reversion_exception, "exit error did not contain error data" ); - const auto& error = context.get_result().res.error(); - - if ( code >= reversion ) - { - if ( validate_utf( error.message() ) ) - throw reversion_exception( code, error ); - else - throw reversion_exception( chain::reversion, "error message contains invalid utf-8" ); - } - else // code <= failure - { - if ( validate_utf( error.message() ) ) - throw failure_exception( code, error ); - else - throw reversion_exception( chain::reversion, "error message contains invalid utf-8" ); - } + context.set_result( { code, res } ); + + if( !code ) // code == success + { + throw success_exception( code ); + } + + KOINOS_ASSERT( res.has_error(), reversion_exception, "exit error did not contain error data" ); + const auto& error = context.get_result().res.error(); + + if( code >= reversion ) + { + if( validate_utf( error.message() ) ) + throw reversion_exception( code, error ); + else + throw reversion_exception( chain::reversion, "error message contains invalid utf-8" ); + } + else // code <= failure + { + if( validate_utf( error.message() ) ) + throw failure_exception( code, error ); + else + throw reversion_exception( chain::reversion, "error message contains invalid utf-8" ); + } } THUNK_DEFINE_VOID( get_arguments_result, get_arguments ) { - get_arguments_result ret; - ret.mutable_value()->set_entry_point( context.get_contract_entry_point() ); - ret.mutable_value()->set_arguments( context.get_contract_call_args() ); - return ret; + get_arguments_result ret; + ret.mutable_value()->set_entry_point( context.get_contract_entry_point() ); + ret.mutable_value()->set_arguments( context.get_contract_call_args() ); + return ret; } THUNK_DEFINE_VOID( get_contract_id_result, get_contract_id ) { - get_contract_id_result ret; - ret.set_value( context.get_contract_id() ); - return ret; + get_contract_id_result ret; + ret.set_value( context.get_contract_id() ); + return ret; } THUNK_DEFINE_VOID( get_caller_result, get_caller ) { - get_caller_result ret; - auto frame0 = context.pop_frame(); // get_caller frame - auto frame1 = context.pop_frame(); // contract frame - std::exception_ptr e; - - try - { - ret.mutable_value()->set_caller( context.get_caller() ); - ret.mutable_value()->set_caller_privilege( context.get_caller_privilege() ); - } - catch ( ... ) - { - e = std::current_exception(); - } - - context.push_frame( std::move( frame1 ) ); - context.push_frame( std::move( frame0 ) ); - - if ( e ) - { - std::rethrow_exception( e ); - } - return ret; + get_caller_result ret; + auto frame0 = context.pop_frame(); // get_caller frame + auto frame1 = context.pop_frame(); // contract frame + std::exception_ptr e; + + try + { + ret.mutable_value()->set_caller( context.get_caller() ); + ret.mutable_value()->set_caller_privilege( context.get_caller_privilege() ); + } + catch( ... ) + { + e = std::current_exception(); + } + + context.push_frame( std::move( frame1 ) ); + context.push_frame( std::move( frame0 ) ); + + if( e ) + { + std::rethrow_exception( e ); + } + return ret; } -THUNK_DEFINE( check_authority_result, check_authority, ((authorization_type) type, (const std::string&) account, (const std::string&) data) ) +THUNK_DEFINE( check_authority_result, + check_authority, + ( (authorization_type)type, (const std::string&)account, (const std::string&)data ) ) { - KOINOS_ASSERT( !context.read_only(), read_only_context_exception, "unable to perform action while context is read only" ); - - check_authority_result res; - - auto account_contract_meta_object = system_call::get_object( context, state::space::contract_metadata(), account ); - bool authorize_override = false; - - if ( account_contract_meta_object.exists() ) - { - auto account_contract_meta = util::converter::to< contract_metadata_object >( account_contract_meta_object.value() ); - - switch ( type ) - { - case contract_call: - authorize_override = account_contract_meta.authorizes_call_contract(); - break; - case transaction_application: - authorize_override = account_contract_meta.authorizes_transaction_application(); - break; - case contract_upload: - authorize_override = account_contract_meta.authorizes_upload_contract(); - break; - default:; - } - } - - bool authorized = false; - - if ( authorize_override ) - { - authorize_arguments args; - args.set_type( type ); - - if ( type == contract_call ) - { - args.mutable_call()->set_contract_id( context.get_caller() ); - args.mutable_call()->set_entry_point( context.get_caller_entry_point() ); - args.mutable_call()->set_caller( thunk::_get_caller( context ).value().caller() ); - args.mutable_call()->set_data( data ); - } - - authorized = util::converter::to< authorize_result >( system_call::call( context, account, authorize_entrypoint, util::converter::as< std::string >( args ) ) ).value(); - } - else - { - const auto* trx = context.get_transaction(); - KOINOS_ASSERT( trx != nullptr, internal_error_exception, "transaction does not exist" ); - - for ( const auto& sig : trx->signatures() ) - { - auto signer_address = util::converter::to< crypto::public_key >( system_call::recover_public_key( context, ecdsa_secp256k1, sig, trx->id(), true ) ).to_address_bytes(); - authorized = ( signer_address == account ); - if ( authorized ) - break; - } - } - - res.set_value( authorized ); - - return res; + KOINOS_ASSERT( !context.read_only(), + read_only_context_exception, + "unable to perform action while context is read only" ); + + check_authority_result res; + + auto account_contract_meta_object = system_call::get_object( context, state::space::contract_metadata(), account ); + bool authorize_override = false; + + if( account_contract_meta_object.exists() ) + { + auto account_contract_meta = + util::converter::to< contract_metadata_object >( account_contract_meta_object.value() ); + + switch( type ) + { + case contract_call: + authorize_override = account_contract_meta.authorizes_call_contract(); + break; + case transaction_application: + authorize_override = account_contract_meta.authorizes_transaction_application(); + break; + case contract_upload: + authorize_override = account_contract_meta.authorizes_upload_contract(); + break; + default:; + } + } + + bool authorized = false; + + if( authorize_override ) + { + authorize_arguments args; + args.set_type( type ); + + if( type == contract_call ) + { + args.mutable_call()->set_contract_id( context.get_caller() ); + args.mutable_call()->set_entry_point( context.get_caller_entry_point() ); + args.mutable_call()->set_caller( thunk::_get_caller( context ).value().caller() ); + args.mutable_call()->set_data( data ); + } + + authorized = + util::converter::to< authorize_result >( + system_call::call( context, account, authorize_entrypoint, util::converter::as< std::string >( args ) ) ) + .value(); + } + else + { + const auto* trx = context.get_transaction(); + KOINOS_ASSERT( trx != nullptr, internal_error_exception, "transaction does not exist" ); + + for( const auto& sig: trx->signatures() ) + { + auto signer_address = util::converter::to< crypto::public_key >( + system_call::recover_public_key( context, ecdsa_secp256k1, sig, trx->id(), true ) ) + .to_address_bytes(); + authorized = ( signer_address == account ); + if( authorized ) + break; + } + } + + res.set_value( authorized ); + + return res; } THUNK_DEFINE_END(); -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/chain/thunk_dispatcher.cpp b/src/koinos/chain/thunk_dispatcher.cpp index 8a59bb6e..0796fbc9 100644 --- a/src/koinos/chain/thunk_dispatcher.cpp +++ b/src/koinos/chain/thunk_dispatcher.cpp @@ -4,30 +4,36 @@ namespace koinos::chain { thunk_dispatcher::thunk_dispatcher() { - register_thunks( *this ); + register_thunks( *this ); } const thunk_dispatcher& thunk_dispatcher::instance() { - static const thunk_dispatcher td; - return td; + static const thunk_dispatcher td; + return td; } -void thunk_dispatcher::call_thunk( uint32_t id, execution_context& ctx, char* ret_ptr, uint32_t ret_len, const char* arg_ptr, uint32_t arg_len, uint32_t* bytes_written )const +void thunk_dispatcher::call_thunk( uint32_t id, + execution_context& ctx, + char* ret_ptr, + uint32_t ret_len, + const char* arg_ptr, + uint32_t arg_len, + uint32_t* bytes_written ) const { - auto it = _dispatch_map.find( id ); - KOINOS_ASSERT( it != _dispatch_map.end(), unknown_thunk_exception, "thunk ${id} not found", ("id", id) ); - it->second( ctx, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); + auto it = _dispatch_map.find( id ); + KOINOS_ASSERT( it != _dispatch_map.end(), unknown_thunk_exception, "thunk ${id} not found", ( "id", id ) ); + it->second( ctx, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); } bool thunk_dispatcher::thunk_exists( uint32_t id ) const { - return _dispatch_map.count( id ); + return _dispatch_map.count( id ); } bool thunk_dispatcher::thunk_is_genesis( uint32_t id ) const { - return _genesis_thunks.count( id ); + return _genesis_thunks.count( id ); } -} // koinos::chain +} // namespace koinos::chain diff --git a/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp b/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp index c54c1900..d9ee5dd5 100644 --- a/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp +++ b/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp @@ -7,309 +7,364 @@ #include #include +#include #include #include -#include namespace koinos::vm_manager::fizzy { namespace constants { - constexpr uint32_t fizzy_max_call_depth = 251; - constexpr std::size_t module_cache_size = 32; -} +constexpr uint32_t fizzy_max_call_depth = 251; +constexpr std::size_t module_cache_size = 32; +} // namespace constants /** * Convert a pointer from inside the VM to a native pointer. */ char* resolve_ptr( FizzyInstance* fizzy_instance, uint32_t ptr, uint32_t size ) { - KOINOS_ASSERT( fizzy_instance != nullptr, null_argument_exception, "fizzy_instance was unexpectedly null pointer" ); - std::size_t mem_size = fizzy_get_instance_memory_size( fizzy_instance ); - char* mem_data = (char *) fizzy_get_instance_memory_data( fizzy_instance ); - KOINOS_ASSERT( mem_data != nullptr, fizzy_returned_null_exception, "fizzy_get_instance_memory_data() unexpectedly returned null pointer" ); - - if ( ptr == mem_size ) - { - if ( size == 0 ) - return mem_data + mem_size; - } - else if ( ptr > mem_size ) - { - return nullptr; - } - - // How much memory exists between pointer and end of memory? - std::size_t mem_at_ptr = mem_size - ptr; - if ( mem_at_ptr < std::size_t( size ) ) - return nullptr; - - return mem_data + ptr; + KOINOS_ASSERT( fizzy_instance != nullptr, null_argument_exception, "fizzy_instance was unexpectedly null pointer" ); + std::size_t mem_size = fizzy_get_instance_memory_size( fizzy_instance ); + char* mem_data = (char*)fizzy_get_instance_memory_data( fizzy_instance ); + KOINOS_ASSERT( mem_data != nullptr, + fizzy_returned_null_exception, + "fizzy_get_instance_memory_data() unexpectedly returned null pointer" ); + + if( ptr == mem_size ) + { + if( size == 0 ) + return mem_data + mem_size; + } + else if( ptr > mem_size ) + { + return nullptr; + } + + // How much memory exists between pointer and end of memory? + std::size_t mem_at_ptr = mem_size - ptr; + if( mem_at_ptr < std::size_t( size ) ) + return nullptr; + + return mem_data + ptr; } -fizzy_vm_backend::fizzy_vm_backend() : - _cache( constants::module_cache_size ) {} +fizzy_vm_backend::fizzy_vm_backend(): + _cache( constants::module_cache_size ) +{} + fizzy_vm_backend::~fizzy_vm_backend() {} std::string fizzy_vm_backend::backend_name() { - return "fizzy"; + return "fizzy"; } -void fizzy_vm_backend::initialize() -{ -} +void fizzy_vm_backend::initialize() {} -std::string fizzy_error_code_name(FizzyErrorCode code) noexcept +std::string fizzy_error_code_name( FizzyErrorCode code ) noexcept { - switch( code ) - { - case FizzySuccess: - return "FizzySuccess"; - case FizzyErrorMalformedModule: - return "FizzyErrorMalformedModule"; - case FizzyErrorInvalidModule: - return "FizzyErrorInvalidModule"; - case FizzyErrorInstantiationFailed: - return "FizzyErrorInstantiationFailed"; - case FizzyErrorMemoryAllocationFailed: - return "FizzyErrorMemoryAllocationFailed"; - case FizzyErrorOther: - return "FizzyErrorOther"; - default: - return "UnknownFizzyError"; - } + switch( code ) + { + case FizzySuccess: + return "FizzySuccess"; + case FizzyErrorMalformedModule: + return "FizzyErrorMalformedModule"; + case FizzyErrorInvalidModule: + return "FizzyErrorInvalidModule"; + case FizzyErrorInstantiationFailed: + return "FizzyErrorInstantiationFailed"; + case FizzyErrorMemoryAllocationFailed: + return "FizzyErrorMemoryAllocationFailed"; + case FizzyErrorOther: + return "FizzyErrorOther"; + default: + return "UnknownFizzyError"; + } } class fizzy_runner { - public: - fizzy_runner( abstract_host_api& h, module_ptr m ) : _hapi(h), _module(m) {} - ~fizzy_runner(); - - void instantiate_module(); - void call_start(); - - FizzyExecutionResult _invoke_thunk( const FizzyValue* args, FizzyExecutionContext* fizzy_context ) noexcept; - FizzyExecutionResult _invoke_system_call( const FizzyValue* args, FizzyExecutionContext* fizzy_context ) noexcept; - - private: - abstract_host_api& _hapi; - module_ptr _module = nullptr; - FizzyInstance* _instance = nullptr; - FizzyExecutionContext* _fizzy_context = nullptr; - int64_t _previous_ticks; - std::exception_ptr _exception; +public: + fizzy_runner( abstract_host_api& h, module_ptr m ): + _hapi( h ), + _module( m ) + {} + + ~fizzy_runner(); + + void instantiate_module(); + void call_start(); + + FizzyExecutionResult _invoke_thunk( const FizzyValue* args, FizzyExecutionContext* fizzy_context ) noexcept; + FizzyExecutionResult _invoke_system_call( const FizzyValue* args, FizzyExecutionContext* fizzy_context ) noexcept; + +private: + abstract_host_api& _hapi; + module_ptr _module = nullptr; + FizzyInstance* _instance = nullptr; + FizzyExecutionContext* _fizzy_context = nullptr; + int64_t _previous_ticks; + std::exception_ptr _exception; }; fizzy_runner::~fizzy_runner() { - if ( _instance != nullptr ) - fizzy_free_instance( _instance ); + if( _instance != nullptr ) + fizzy_free_instance( _instance ); - if ( _fizzy_context != nullptr ) - fizzy_free_execution_context( _fizzy_context ); + if( _fizzy_context != nullptr ) + fizzy_free_execution_context( _fizzy_context ); } module_ptr parse_bytecode( const char* bytecode_data, size_t bytecode_size ) { - FizzyError fizzy_err; - KOINOS_ASSERT( bytecode_data != nullptr, fizzy_returned_null_exception, "fizzy_instance was unexpectedly null pointer" ); - auto ptr = fizzy_parse( reinterpret_cast< const uint8_t* >( bytecode_data ), bytecode_size, &fizzy_err ); - - if ( ptr == nullptr ) - { - std::string error_code = fizzy_error_code_name( fizzy_err.code ); - std::string error_message = fizzy_err.message; - KOINOS_THROW( module_parse_exception, "could not parse fizzy module - ${code}: ${msg}", ("code", error_code)("msg", error_message) ); - } - - return std::make_shared< const module_guard >( ptr ); + FizzyError fizzy_err; + KOINOS_ASSERT( bytecode_data != nullptr, + fizzy_returned_null_exception, + "fizzy_instance was unexpectedly null pointer" ); + auto ptr = fizzy_parse( reinterpret_cast< const uint8_t* >( bytecode_data ), bytecode_size, &fizzy_err ); + + if( ptr == nullptr ) + { + std::string error_code = fizzy_error_code_name( fizzy_err.code ); + std::string error_message = fizzy_err.message; + KOINOS_THROW( module_parse_exception, + "could not parse fizzy module - ${code}: ${msg}", + ( "code", error_code )( "msg", error_message ) ); + } + + return std::make_shared< const module_guard >( ptr ); } void fizzy_runner::instantiate_module() { - FizzyExternalFn invoke_thunk = [](void* voidptr_context, FizzyInstance* fizzy_instance, const FizzyValue* args, FizzyExecutionContext* fizzy_context) noexcept -> FizzyExecutionResult - { - fizzy_runner* runner = static_cast< fizzy_runner* >( voidptr_context ); - return runner->_invoke_thunk( args, fizzy_context ); - }; - - FizzyValueType invoke_thunk_arg_types[] = {FizzyValueTypeI32, FizzyValueTypeI32, FizzyValueTypeI32, FizzyValueTypeI32, FizzyValueTypeI32, FizzyValueTypeI32}; - size_t invoke_thunk_num_args = 6; - FizzyExternalFunction invoke_thunk_fn = {{ FizzyValueTypeI32, invoke_thunk_arg_types, invoke_thunk_num_args }, invoke_thunk, this }; - - FizzyExternalFn invoke_system_call = [](void* voidptr_context, FizzyInstance* fizzy_instance, const FizzyValue* args, FizzyExecutionContext* fizzy_context) noexcept -> FizzyExecutionResult - { - fizzy_runner* runner = static_cast< fizzy_runner* >( voidptr_context ); - return runner->_invoke_system_call( args, fizzy_context ); - }; - - FizzyValueType invoke_system_call_arg_types[] = {FizzyValueTypeI32, FizzyValueTypeI32, FizzyValueTypeI32, FizzyValueTypeI32, FizzyValueTypeI32, FizzyValueTypeI32}; - size_t invoke_system_call_num_args = 6; - FizzyExternalFunction invoke_system_call_fn = {{ FizzyValueTypeI32, invoke_system_call_arg_types, invoke_system_call_num_args }, invoke_system_call, this }; - - size_t num_host_funcs = 2; - FizzyImportedFunction host_funcs[] = {{"env", "invoke_thunk", invoke_thunk_fn}, {"env", "invoke_system_call", invoke_system_call_fn}}; - - FizzyError fizzy_err; - - uint32_t memory_pages_limit = 512; // Number of 64k pages allowed to allocate - - KOINOS_ASSERT( _instance == nullptr, runner_state_exception, "_instance was unexpectedly non-null" ); - _instance = fizzy_resolve_instantiate( _module->get(), host_funcs, num_host_funcs, nullptr, nullptr, nullptr, 0, memory_pages_limit, &fizzy_err ); - if( _instance == nullptr ) - { - std::string error_code = fizzy_error_code_name( fizzy_err.code ); - std::string error_message = fizzy_err.message; - KOINOS_THROW( module_instantiate_exception, "could not instantiate module - ${code}: ${msg}", ("code", error_code)("msg", error_message) ); - } + FizzyExternalFn invoke_thunk = []( void* voidptr_context, + FizzyInstance* fizzy_instance, + const FizzyValue* args, + FizzyExecutionContext* fizzy_context ) noexcept -> FizzyExecutionResult + { + fizzy_runner* runner = static_cast< fizzy_runner* >( voidptr_context ); + return runner->_invoke_thunk( args, fizzy_context ); + }; + + FizzyValueType invoke_thunk_arg_types[] = { FizzyValueTypeI32, + FizzyValueTypeI32, + FizzyValueTypeI32, + FizzyValueTypeI32, + FizzyValueTypeI32, + FizzyValueTypeI32 }; + size_t invoke_thunk_num_args = 6; + FizzyExternalFunction invoke_thunk_fn = { + {FizzyValueTypeI32, invoke_thunk_arg_types, invoke_thunk_num_args}, + invoke_thunk, + this + }; + + FizzyExternalFn invoke_system_call = []( void* voidptr_context, + FizzyInstance* fizzy_instance, + const FizzyValue* args, + FizzyExecutionContext* fizzy_context ) noexcept -> FizzyExecutionResult + { + fizzy_runner* runner = static_cast< fizzy_runner* >( voidptr_context ); + return runner->_invoke_system_call( args, fizzy_context ); + }; + + FizzyValueType invoke_system_call_arg_types[] = { FizzyValueTypeI32, + FizzyValueTypeI32, + FizzyValueTypeI32, + FizzyValueTypeI32, + FizzyValueTypeI32, + FizzyValueTypeI32 }; + size_t invoke_system_call_num_args = 6; + FizzyExternalFunction invoke_system_call_fn = { + {FizzyValueTypeI32, invoke_system_call_arg_types, invoke_system_call_num_args}, + invoke_system_call, + this + }; + + size_t num_host_funcs = 2; + FizzyImportedFunction host_funcs[] = { + {"env", "invoke_thunk", invoke_thunk_fn}, + {"env", "invoke_system_call", invoke_system_call_fn} + }; + + FizzyError fizzy_err; + + uint32_t memory_pages_limit = 512; // Number of 64k pages allowed to allocate + + KOINOS_ASSERT( _instance == nullptr, runner_state_exception, "_instance was unexpectedly non-null" ); + _instance = fizzy_resolve_instantiate( _module->get(), + host_funcs, + num_host_funcs, + nullptr, + nullptr, + nullptr, + 0, + memory_pages_limit, + &fizzy_err ); + if( _instance == nullptr ) + { + std::string error_code = fizzy_error_code_name( fizzy_err.code ); + std::string error_message = fizzy_err.message; + KOINOS_THROW( module_instantiate_exception, + "could not instantiate module - ${code}: ${msg}", + ( "code", error_code )( "msg", error_message ) ); + } } -FizzyExecutionResult fizzy_runner::_invoke_thunk( const FizzyValue* args, FizzyExecutionContext* fizzy_context ) noexcept +FizzyExecutionResult fizzy_runner::_invoke_thunk( const FizzyValue* args, + FizzyExecutionContext* fizzy_context ) noexcept { - FizzyExecutionResult result; - result.has_value = false; - result.value.i64 = 0; - - _exception = std::exception_ptr(); - - try - { - uint32_t tid = args[0].i32; - uint32_t ret_len = args[2].i32; - char* ret_ptr = resolve_ptr(_instance, args[1].i32, ret_len); - uint32_t arg_len = args[4].i32; - const char* arg_ptr = resolve_ptr(_instance, args[3].i32, arg_len); - uint32_t* bytes_written = (uint32_t*)resolve_ptr(_instance, args[5].i32, sizeof(uint32_t)); - - KOINOS_ASSERT( ret_ptr != nullptr, wasm_memory_exception, "invalid ret_ptr in invoke_thunk()" ); - KOINOS_ASSERT( arg_ptr != nullptr, wasm_memory_exception, "invalid arg_ptr in invoke_thunk()" ); - KOINOS_ASSERT( bytes_written != nullptr, wasm_memory_exception, "invalid bytes_written in invoke_thunk()" ); - - int64_t* ticks = fizzy_get_execution_context_ticks(_fizzy_context); - KOINOS_ASSERT( ticks != nullptr, fizzy_returned_null_exception, "fizzy_get_execution_context_ticks() unexpectedly returned null pointer" ); - _hapi.use_meter_ticks( uint64_t( _previous_ticks - *ticks ) ); - - try - { - result.value.i32 = _hapi.invoke_thunk( tid, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); - result.has_value = true; - } - catch ( ... ) - { - _exception = std::current_exception(); - } - - _previous_ticks = _hapi.get_meter_ticks(); - *ticks = _previous_ticks; - } - catch ( ... ) - { + FizzyExecutionResult result; + result.has_value = false; + result.value.i64 = 0; + + _exception = std::exception_ptr(); + + try + { + uint32_t tid = args[ 0 ].i32; + uint32_t ret_len = args[ 2 ].i32; + char* ret_ptr = resolve_ptr( _instance, args[ 1 ].i32, ret_len ); + uint32_t arg_len = args[ 4 ].i32; + const char* arg_ptr = resolve_ptr( _instance, args[ 3 ].i32, arg_len ); + uint32_t* bytes_written = (uint32_t*)resolve_ptr( _instance, args[ 5 ].i32, sizeof( uint32_t ) ); + + KOINOS_ASSERT( ret_ptr != nullptr, wasm_memory_exception, "invalid ret_ptr in invoke_thunk()" ); + KOINOS_ASSERT( arg_ptr != nullptr, wasm_memory_exception, "invalid arg_ptr in invoke_thunk()" ); + KOINOS_ASSERT( bytes_written != nullptr, wasm_memory_exception, "invalid bytes_written in invoke_thunk()" ); + + int64_t* ticks = fizzy_get_execution_context_ticks( _fizzy_context ); + KOINOS_ASSERT( ticks != nullptr, + fizzy_returned_null_exception, + "fizzy_get_execution_context_ticks() unexpectedly returned null pointer" ); + _hapi.use_meter_ticks( uint64_t( _previous_ticks - *ticks ) ); + + try + { + result.value.i32 = _hapi.invoke_thunk( tid, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); + result.has_value = true; + } + catch( ... ) + { _exception = std::current_exception(); - } - - result.trapped = !!_exception; - return result; + } + + _previous_ticks = _hapi.get_meter_ticks(); + *ticks = _previous_ticks; + } + catch( ... ) + { + _exception = std::current_exception(); + } + + result.trapped = !!_exception; + return result; } -FizzyExecutionResult fizzy_runner::_invoke_system_call( const FizzyValue* args, FizzyExecutionContext* fizzy_context ) noexcept +FizzyExecutionResult fizzy_runner::_invoke_system_call( const FizzyValue* args, + FizzyExecutionContext* fizzy_context ) noexcept { - FizzyExecutionResult result; - result.has_value = false; - result.value.i64 = 0; - - _exception = std::exception_ptr(); - - try - { - uint32_t xid = args[0].i32; - uint32_t ret_len = args[2].i32; - char* ret_ptr = resolve_ptr(_instance, args[1].i32, ret_len); - uint32_t arg_len = args[4].i32; - const char* arg_ptr = resolve_ptr(_instance, args[3].i32, arg_len); - uint32_t* bytes_written = (uint32_t*)resolve_ptr(_instance, args[5].i32, sizeof(uint32_t)); - - KOINOS_ASSERT( ret_ptr != nullptr, wasm_memory_exception, "invalid ret_ptr in invoke_system_call()" ); - KOINOS_ASSERT( arg_ptr != nullptr, wasm_memory_exception, "invalid arg_ptr in invoke_system_call()" ); - KOINOS_ASSERT( bytes_written != nullptr, wasm_memory_exception, "invalid bytes_written in invoke_system_call()" ); - - int64_t* ticks = fizzy_get_execution_context_ticks(_fizzy_context); - KOINOS_ASSERT( ticks != nullptr, fizzy_returned_null_exception, "fizzy_get_execution_context_ticks() unexpectedly returned null pointer" ); - _hapi.use_meter_ticks( uint64_t( _previous_ticks - *ticks ) ); - - try - { - result.value.i32 = _hapi.invoke_system_call( xid, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); - result.has_value = true; - } - catch ( ... ) - { - _exception = std::current_exception(); - } - - _previous_ticks = _hapi.get_meter_ticks(); - *ticks = _previous_ticks; - } - catch ( ... ) - { + FizzyExecutionResult result; + result.has_value = false; + result.value.i64 = 0; + + _exception = std::exception_ptr(); + + try + { + uint32_t xid = args[ 0 ].i32; + uint32_t ret_len = args[ 2 ].i32; + char* ret_ptr = resolve_ptr( _instance, args[ 1 ].i32, ret_len ); + uint32_t arg_len = args[ 4 ].i32; + const char* arg_ptr = resolve_ptr( _instance, args[ 3 ].i32, arg_len ); + uint32_t* bytes_written = (uint32_t*)resolve_ptr( _instance, args[ 5 ].i32, sizeof( uint32_t ) ); + + KOINOS_ASSERT( ret_ptr != nullptr, wasm_memory_exception, "invalid ret_ptr in invoke_system_call()" ); + KOINOS_ASSERT( arg_ptr != nullptr, wasm_memory_exception, "invalid arg_ptr in invoke_system_call()" ); + KOINOS_ASSERT( bytes_written != nullptr, wasm_memory_exception, "invalid bytes_written in invoke_system_call()" ); + + int64_t* ticks = fizzy_get_execution_context_ticks( _fizzy_context ); + KOINOS_ASSERT( ticks != nullptr, + fizzy_returned_null_exception, + "fizzy_get_execution_context_ticks() unexpectedly returned null pointer" ); + _hapi.use_meter_ticks( uint64_t( _previous_ticks - *ticks ) ); + + try + { + result.value.i32 = _hapi.invoke_system_call( xid, ret_ptr, ret_len, arg_ptr, arg_len, bytes_written ); + result.has_value = true; + } + catch( ... ) + { _exception = std::current_exception(); - } - - result.trapped = !!_exception; - return result; + } + + _previous_ticks = _hapi.get_meter_ticks(); + *ticks = _previous_ticks; + } + catch( ... ) + { + _exception = std::current_exception(); + } + + result.trapped = !!_exception; + return result; } void fizzy_runner::call_start() { - KOINOS_ASSERT( _fizzy_context == nullptr, runner_state_exception, "_fizzy_context was unexpectedly non-null" ); - _previous_ticks = _hapi.get_meter_ticks(); - _fizzy_context = fizzy_create_metered_execution_context( constants::fizzy_max_call_depth, _previous_ticks ); - KOINOS_ASSERT( _fizzy_context != nullptr, create_context_exception, "could not create execution context" ); - - uint32_t start_func_idx = 0; - bool success = fizzy_find_exported_function_index( _module->get(), "_start", &start_func_idx ); - KOINOS_ASSERT( success, module_start_exception, "module does not have _start function" ); - - FizzyExecutionResult result = fizzy_execute( _instance, start_func_idx, nullptr, _fizzy_context ); - - int64_t* ticks = fizzy_get_execution_context_ticks( _fizzy_context ); - KOINOS_ASSERT( ticks != nullptr, fizzy_returned_null_exception, "fizzy_get_execution_context_ticks() unexpectedly returned null pointer" ); - _hapi.use_meter_ticks( uint64_t( _previous_ticks - *ticks ) ); - - if ( _exception ) - { - std::exception_ptr exc = _exception; - _exception = std::exception_ptr(); - std::rethrow_exception( exc ); - } - - if ( result.trapped ) - { - KOINOS_THROW( wasm_trap_exception, "module exited due to trap" ); - } + KOINOS_ASSERT( _fizzy_context == nullptr, runner_state_exception, "_fizzy_context was unexpectedly non-null" ); + _previous_ticks = _hapi.get_meter_ticks(); + _fizzy_context = fizzy_create_metered_execution_context( constants::fizzy_max_call_depth, _previous_ticks ); + KOINOS_ASSERT( _fizzy_context != nullptr, create_context_exception, "could not create execution context" ); + + uint32_t start_func_idx = 0; + bool success = fizzy_find_exported_function_index( _module->get(), "_start", &start_func_idx ); + KOINOS_ASSERT( success, module_start_exception, "module does not have _start function" ); + + FizzyExecutionResult result = fizzy_execute( _instance, start_func_idx, nullptr, _fizzy_context ); + + int64_t* ticks = fizzy_get_execution_context_ticks( _fizzy_context ); + KOINOS_ASSERT( ticks != nullptr, + fizzy_returned_null_exception, + "fizzy_get_execution_context_ticks() unexpectedly returned null pointer" ); + _hapi.use_meter_ticks( uint64_t( _previous_ticks - *ticks ) ); + + if( _exception ) + { + std::exception_ptr exc = _exception; + _exception = std::exception_ptr(); + std::rethrow_exception( exc ); + } + + if( result.trapped ) + { + KOINOS_THROW( wasm_trap_exception, "module exited due to trap" ); + } } void fizzy_vm_backend::run( abstract_host_api& hapi, const std::string& bytecode, const std::string& id ) { - module_ptr ptr; - - if ( id.size() ) - { - ptr = _cache.get_module( id ); - if ( !ptr ) - { - ptr = parse_bytecode( bytecode.data(), bytecode.size() ); - _cache.put_module( id, ptr ); - } - } - else - { - ptr = parse_bytecode( bytecode.data(), bytecode.size() ); - } + module_ptr ptr; - fizzy_runner runner( hapi, ptr ); - runner.instantiate_module(); - runner.call_start(); + if( id.size() ) + { + ptr = _cache.get_module( id ); + if( !ptr ) + { + ptr = parse_bytecode( bytecode.data(), bytecode.size() ); + _cache.put_module( id, ptr ); + } + } + else + { + ptr = parse_bytecode( bytecode.data(), bytecode.size() ); + } + + fizzy_runner runner( hapi, ptr ); + runner.instantiate_module(); + runner.call_start(); } -} // koinos::vm_manager::fizzy +} // namespace koinos::vm_manager::fizzy diff --git a/src/koinos/vm_manager/fizzy/module_cache.cpp b/src/koinos/vm_manager/fizzy/module_cache.cpp index dae6f5d4..3fcbe862 100644 --- a/src/koinos/vm_manager/fizzy/module_cache.cpp +++ b/src/koinos/vm_manager/fizzy/module_cache.cpp @@ -1,50 +1,52 @@ -#include #include +#include namespace koinos::vm_manager::fizzy { -module_cache::module_cache( std::size_t size ) : _cache_size( size ) {} +module_cache::module_cache( std::size_t size ): + _cache_size( size ) +{} module_cache::~module_cache() { - std::lock_guard< std::mutex > lock( _mutex ); - _module_map.clear(); + std::lock_guard< std::mutex > lock( _mutex ); + _module_map.clear(); } module_ptr module_cache::get_module( const std::string& id ) { - std::lock_guard< std::mutex > lock( _mutex ); + std::lock_guard< std::mutex > lock( _mutex ); - auto itr = _module_map.find( id ); - if ( itr == _module_map.end() ) - return module_ptr(); + auto itr = _module_map.find( id ); + if( itr == _module_map.end() ) + return module_ptr(); - // Erase the entry from the list and push front - _lru_list.erase( itr->second.second ); - _lru_list.push_front( id ); - auto ptr = itr->second.first; - _module_map[ id ] = std::make_pair( ptr, _lru_list.begin() ); + // Erase the entry from the list and push front + _lru_list.erase( itr->second.second ); + _lru_list.push_front( id ); + auto ptr = itr->second.first; + _module_map[ id ] = std::make_pair( ptr, _lru_list.begin() ); - return ptr; + return ptr; } void module_cache::put_module( const std::string& id, module_ptr module ) { - std::lock_guard< std::mutex > lock( _mutex ); + std::lock_guard< std::mutex > lock( _mutex ); - // If the cache is full, remove the last entry from the map, free the fizzy module, and pop back - if ( _lru_list.size() >= _cache_size ) - { - const auto key = _lru_list.back(); - auto it = _module_map.find( key ); - if ( it != _module_map.end() ) - _module_map.erase( it ); + // If the cache is full, remove the last entry from the map, free the fizzy module, and pop back + if( _lru_list.size() >= _cache_size ) + { + const auto key = _lru_list.back(); + auto it = _module_map.find( key ); + if( it != _module_map.end() ) + _module_map.erase( it ); - _lru_list.pop_back(); - } + _lru_list.pop_back(); + } - _lru_list.push_front( id ); - _module_map[ id ] = std::make_pair( module, _lru_list.begin() ); + _lru_list.push_front( id ); + _module_map[ id ] = std::make_pair( module, _lru_list.begin() ); } -} // koinos::vm_manager::fizzy +} // namespace koinos::vm_manager::fizzy diff --git a/src/koinos/vm_manager/host_api.cpp b/src/koinos/vm_manager/host_api.cpp index 966274cc..d6154317 100644 --- a/src/koinos/vm_manager/host_api.cpp +++ b/src/koinos/vm_manager/host_api.cpp @@ -6,4 +6,4 @@ abstract_host_api::abstract_host_api() {} abstract_host_api::~abstract_host_api() {} -} // koinos::vm_manager +} // namespace koinos::vm_manager diff --git a/src/koinos/vm_manager/vm_backend.cpp b/src/koinos/vm_manager/vm_backend.cpp index 4d9713bf..3ce27638 100644 --- a/src/koinos/vm_manager/vm_backend.cpp +++ b/src/koinos/vm_manager/vm_backend.cpp @@ -9,31 +9,32 @@ namespace koinos::vm_manager { vm_backend::vm_backend() {} + vm_backend::~vm_backend() {} std::vector< std::shared_ptr< vm_backend > > get_vm_backends() { - std::vector< std::shared_ptr< vm_backend > > result; + std::vector< std::shared_ptr< vm_backend > > result; - result.push_back( std::make_shared< vm_manager::fizzy::fizzy_vm_backend >() ); + result.push_back( std::make_shared< vm_manager::fizzy::fizzy_vm_backend >() ); - return result; + return result; } std::string get_default_vm_backend_name() { - return "fizzy"; + return "fizzy"; } std::shared_ptr< vm_backend > get_vm_backend( const std::string& name ) { - std::vector< std::shared_ptr< vm_backend > > backends = get_vm_backends(); - for( std::shared_ptr< vm_backend > b : backends ) - { - if( b->backend_name() == name ) - return b; - } - return std::shared_ptr< vm_backend >(); + std::vector< std::shared_ptr< vm_backend > > backends = get_vm_backends(); + for( std::shared_ptr< vm_backend > b: backends ) + { + if( b->backend_name() == name ) + return b; + } + return std::shared_ptr< vm_backend >(); } -} // koinos::vm_manager +} // namespace koinos::vm_manager diff --git a/src/koinos_chain.cpp b/src/koinos_chain.cpp index f3139341..f416b6f2 100644 --- a/src/koinos_chain.cpp +++ b/src/koinos_chain.cpp @@ -21,9 +21,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -37,9 +37,9 @@ #include "git_version.h" -#define FIFO_ALGORITHM "fifo" -#define BLOCK_TIME_ALGORITHM "block-time" -#define POB_ALGORITHM "pob" +#define FIFO_ALGORITHM "fifo" +#define BLOCK_TIME_ALGORITHM "block-time" +#define POB_ALGORITHM "pob" #define HELP_OPTION "help" #define VERSION_OPTION "version" @@ -80,400 +80,452 @@ void attach_request_handler( chain::controller& controller, mq::request_handler& int main( int argc, char** argv ) { - std::string amqp_url, log_level, log_dir, instance_id, fork_algorithm_option; - std::filesystem::path statedir, genesis_data_file; - uint64_t jobs, read_compute_limit; - int32_t syscall_bufsize; - chain::genesis_data genesis_data; - bool reset, log_color, log_datetime; - chain::fork_resolution_algorithm fork_algorithm; - - try - { - program_options::options_description options; - options.add_options() - (HELP_OPTION ",h", "Print this help message and exit") - (VERSION_OPTION ",v", "Print version string and exit") - (BASEDIR_OPTION ",d", program_options::value< std::string >()->default_value( util::get_default_base_directory().string() ), - "Koinos base directory") - (AMQP_OPTION ",a", program_options::value< std::string >(), "AMQP server URL") - (LOG_LEVEL_OPTION ",l", program_options::value< std::string >(), "The log filtering level") - (INSTANCE_ID_OPTION ",i", program_options::value< std::string >(), "An ID that uniquely identifies the instance") - (JOBS_OPTION ",j", program_options::value< uint64_t >(), "The number of worker jobs") - (READ_COMPUTE_BANDWITH_LIMIT_OPTION",b", program_options::value< uint64_t >(), "The compute bandwidth when reading contracts via the API") - (GENESIS_DATA_FILE_OPTION ",g", program_options::value< std::string >(), "The genesis data file") - (STATEDIR_OPTION , program_options::value< std::string >(), - "The location of the blockchain state files (absolute path or relative to basedir/chain)") - (RESET_OPTION , program_options::value< bool >(), "Reset the database") - (FORK_ALGORITHM_OPTION ",f", program_options::value< std::string >(), "The fork resolution algorithm to use. Can be 'fifo', 'pob', or 'block-time'. (Default: 'fifo')") - (LOG_DIR_OPTION , program_options::value< std::string >(), "The logging directory") - (LOG_COLOR_OPTION , program_options::value< bool >(), "Log color toggle") - (LOG_DATETIME_OPTION , program_options::value< bool >(), "Log datetime on console toggle") - (SYSTEM_CALL_BUFFER_SIZE_OPTION , program_options::value< uint32_t >(), "System call RPC invocation buffer size"); - - program_options::variables_map args; - program_options::store( program_options::parse_command_line( argc, argv, options ), args ); - - if ( args.count( HELP_OPTION ) ) - { - std::cout << options << std::endl; - return EXIT_SUCCESS; - } - - if ( args.count( VERSION_OPTION ) ) - { - const auto& v_str = version_string(); - std::cout.write( v_str.c_str(), v_str.size() ); - std::cout << std::endl; - return EXIT_SUCCESS; - } - - auto basedir = std::filesystem::path( args[ BASEDIR_OPTION ].as< std::string >() ); - if ( basedir.is_relative() ) - basedir = std::filesystem::current_path() / basedir; - - YAML::Node config; - YAML::Node global_config; - YAML::Node chain_config; - - auto yaml_config = basedir / "config.yml"; - if ( !std::filesystem::exists( yaml_config ) ) - { - yaml_config = basedir / "config.yaml"; - } - - if ( std::filesystem::exists( yaml_config ) ) - { - config = YAML::LoadFile( yaml_config ); - global_config = config[ "global" ]; - chain_config = config[ util::service::chain ]; - } - - amqp_url = util::get_option< std::string >( AMQP_OPTION, AMQP_DEFAULT, args, chain_config, global_config ); - log_level = util::get_option< std::string >( LOG_LEVEL_OPTION, LOG_LEVEL_DEFAULT, args, chain_config, global_config ); - log_dir = util::get_option< std::string >( LOG_DIR_OPTION, LOG_DIR_DEFAULT, args, chain_config, global_config ); - log_color = util::get_option< bool >( LOG_COLOR_OPTION, LOG_COLOR_DEFAULT, args, chain_config, global_config ); - log_datetime = util::get_option< bool >( LOG_DATETIME_OPTION, LOG_DATETIME_DEFAULT, args, chain_config, global_config ); - instance_id = util::get_option< std::string >( INSTANCE_ID_OPTION, util::random_alphanumeric( 5 ), args, chain_config, global_config ); - statedir = std::filesystem::path( util::get_option< std::string >( STATEDIR_OPTION, STATEDIR_DEFAULT, args, chain_config, global_config ) ); - genesis_data_file = std::filesystem::path( util::get_option< std::string >( GENESIS_DATA_FILE_OPTION, GENESIS_DATA_FILE_DEFAULT, args, chain_config, global_config ) ); - reset = util::get_option< bool >( RESET_OPTION, false, args, chain_config, global_config ); - jobs = util::get_option< uint64_t >( JOBS_OPTION, std::max( JOBS_DEFAULT, uint64_t( std::thread::hardware_concurrency() ) ), args, chain_config, global_config ); - read_compute_limit = util::get_option< uint64_t >( READ_COMPUTE_BANDWITH_LIMIT_OPTION, READ_COMPUTE_BANDWITH_LIMIT_DEFAULT, args, chain_config, global_config ); - fork_algorithm_option = util::get_option< std::string >( FORK_ALGORITHM_OPTION, FORK_ALGORITHM_DEFAULT, args, chain_config, global_config ); - syscall_bufsize = util::get_option< uint32_t >( SYSTEM_CALL_BUFFER_SIZE_OPTION, SYSTEM_CALL_BUFFER_SIZE_DEFAULT, args, chain_config, global_config ); - - std::optional< std::filesystem::path > logdir_path; - if ( !log_dir.empty() ) - { - logdir_path = std::make_optional< std::filesystem::path >( log_dir ); - if ( logdir_path->is_relative() ) - logdir_path = basedir / util::service::chain / *logdir_path; - } - - koinos::initialize_logging( util::service::chain, instance_id, log_level, logdir_path, log_color, log_datetime ); - - LOG(info) << version_string(); - - KOINOS_ASSERT( jobs > 1, invalid_argument, "jobs must be greater than 1" ); - - if ( config.IsNull() ) - { - LOG(warning) << "Could not find config (config.yml or config.yaml expected). Using default values"; - } - - if ( fork_algorithm_option == FIFO_ALGORITHM ) - { - LOG(info) << "Using fork resolution algorithm: " << FIFO_ALGORITHM; - fork_algorithm = chain::fork_resolution_algorithm::fifo; - } - else if ( fork_algorithm_option == BLOCK_TIME_ALGORITHM ) - { - LOG(info) << "Using fork resolution algorithm: " << BLOCK_TIME_ALGORITHM; - fork_algorithm = chain::fork_resolution_algorithm::block_time; - } - else if ( fork_algorithm_option == POB_ALGORITHM ) - { - LOG(info) << "Using fork resolution algorithm: " << POB_ALGORITHM; - fork_algorithm = chain::fork_resolution_algorithm::pob; - } - else - { - KOINOS_THROW( invalid_argument, "${a} is not a valid fork algorithm", ("a", fork_algorithm_option) ); - } - - if ( statedir.is_relative() ) - statedir = basedir / util::service::chain / statedir; - - if ( !std::filesystem::exists( statedir ) ) - std::filesystem::create_directories( statedir ); - - // Load genesis data - if ( genesis_data_file.is_relative() ) - genesis_data_file = basedir / util::service::chain / genesis_data_file; - - KOINOS_ASSERT( - std::filesystem::exists( genesis_data_file ), - invalid_argument, - "unable to locate genesis data file at ${loc}", ("loc", genesis_data_file.string()) - ); - - std::ifstream gifs( genesis_data_file ); - std::stringstream genesis_data_stream; - genesis_data_stream << gifs.rdbuf(); - std::string genesis_json = genesis_data_stream.str(); - gifs.close(); - - google::protobuf::util::JsonParseOptions jpo; - google::protobuf::util::JsonStringToMessage( genesis_json, &genesis_data, jpo ); - - crypto::multihash chain_id = crypto::hash( crypto::multicodec::sha2_256, genesis_data ); - - LOG(info) << "Chain ID: " << chain_id; - LOG(info) << "Number of jobs: " << jobs; - } - catch ( const invalid_argument& e ) - { - LOG(error) << "Invalid argument: " << e.what(); - return EXIT_FAILURE; - } - - std::atomic< bool > stopped = false; - int retcode = EXIT_SUCCESS; - std::vector< boost::thread > threads; - - asio::io_context client_ioc, server_ioc, main_ioc; - auto client = std::make_shared< mq::client >( client_ioc ); - auto request_handler = mq::request_handler( server_ioc ); - chain::controller controller( read_compute_limit, syscall_bufsize ); - - try - { - asio::signal_set signals( server_ioc ); - signals.add( SIGINT ); - signals.add( SIGTERM ); + std::string amqp_url, log_level, log_dir, instance_id, fork_algorithm_option; + std::filesystem::path statedir, genesis_data_file; + uint64_t jobs, read_compute_limit; + int32_t syscall_bufsize; + chain::genesis_data genesis_data; + bool reset, log_color, log_datetime; + chain::fork_resolution_algorithm fork_algorithm; + + try + { + program_options::options_description options; + options.add_options()( HELP_OPTION ",h", "Print this help message and exit" )( VERSION_OPTION ",v", + "Print version string and exit" )( + BASEDIR_OPTION ",d", + program_options::value< std::string >()->default_value( util::get_default_base_directory().string() ), + "Koinos base directory" )( AMQP_OPTION ",a", program_options::value< std::string >(), "AMQP server URL" )( + LOG_LEVEL_OPTION ",l", + program_options::value< std::string >(), + "The log filtering level" )( INSTANCE_ID_OPTION ",i", + program_options::value< std::string >(), + "An ID that uniquely identifies the instance" )( + JOBS_OPTION ",j", + program_options::value< uint64_t >(), + "The number of worker jobs" )( READ_COMPUTE_BANDWITH_LIMIT_OPTION ",b", + program_options::value< uint64_t >(), + "The compute bandwidth when reading contracts via the API" )( + GENESIS_DATA_FILE_OPTION ",g", + program_options::value< std::string >(), + "The genesis data file" )( + STATEDIR_OPTION, + program_options::value< std::string >(), + "The location of the blockchain state files (absolute path or relative to basedir/chain)" )( + RESET_OPTION, + program_options::value< bool >(), + "Reset the database" )( + FORK_ALGORITHM_OPTION ",f", + program_options::value< std::string >(), + "The fork resolution algorithm to use. Can be 'fifo', 'pob', or 'block-time'. (Default: 'fifo')" )( + LOG_DIR_OPTION, + program_options::value< std::string >(), + "The logging directory" )( LOG_COLOR_OPTION, program_options::value< bool >(), "Log color toggle" )( + LOG_DATETIME_OPTION, + program_options::value< bool >(), + "Log datetime on console toggle" )( SYSTEM_CALL_BUFFER_SIZE_OPTION, + program_options::value< uint32_t >(), + "System call RPC invocation buffer size" ); + + program_options::variables_map args; + program_options::store( program_options::parse_command_line( argc, argv, options ), args ); + + if( args.count( HELP_OPTION ) ) + { + std::cout << options << std::endl; + return EXIT_SUCCESS; + } + + if( args.count( VERSION_OPTION ) ) + { + const auto& v_str = version_string(); + std::cout.write( v_str.c_str(), v_str.size() ); + std::cout << std::endl; + return EXIT_SUCCESS; + } + + auto basedir = std::filesystem::path( args[ BASEDIR_OPTION ].as< std::string >() ); + if( basedir.is_relative() ) + basedir = std::filesystem::current_path() / basedir; + + YAML::Node config; + YAML::Node global_config; + YAML::Node chain_config; + + auto yaml_config = basedir / "config.yml"; + if( !std::filesystem::exists( yaml_config ) ) + { + yaml_config = basedir / "config.yaml"; + } + + if( std::filesystem::exists( yaml_config ) ) + { + config = YAML::LoadFile( yaml_config ); + global_config = config[ "global" ]; + chain_config = config[ util::service::chain ]; + } + + amqp_url = util::get_option< std::string >( AMQP_OPTION, AMQP_DEFAULT, args, chain_config, global_config ); + log_level = + util::get_option< std::string >( LOG_LEVEL_OPTION, LOG_LEVEL_DEFAULT, args, chain_config, global_config ); + log_dir = util::get_option< std::string >( LOG_DIR_OPTION, LOG_DIR_DEFAULT, args, chain_config, global_config ); + log_color = util::get_option< bool >( LOG_COLOR_OPTION, LOG_COLOR_DEFAULT, args, chain_config, global_config ); + log_datetime = + util::get_option< bool >( LOG_DATETIME_OPTION, LOG_DATETIME_DEFAULT, args, chain_config, global_config ); + instance_id = util::get_option< std::string >( INSTANCE_ID_OPTION, + util::random_alphanumeric( 5 ), + args, + chain_config, + global_config ); + statedir = std::filesystem::path( + util::get_option< std::string >( STATEDIR_OPTION, STATEDIR_DEFAULT, args, chain_config, global_config ) ); + genesis_data_file = std::filesystem::path( util::get_option< std::string >( GENESIS_DATA_FILE_OPTION, + GENESIS_DATA_FILE_DEFAULT, + args, + chain_config, + global_config ) ); + reset = util::get_option< bool >( RESET_OPTION, false, args, chain_config, global_config ); + jobs = util::get_option< uint64_t >( JOBS_OPTION, + std::max( JOBS_DEFAULT, uint64_t( std::thread::hardware_concurrency() ) ), + args, + chain_config, + global_config ); + read_compute_limit = util::get_option< uint64_t >( READ_COMPUTE_BANDWITH_LIMIT_OPTION, + READ_COMPUTE_BANDWITH_LIMIT_DEFAULT, + args, + chain_config, + global_config ); + fork_algorithm_option = util::get_option< std::string >( FORK_ALGORITHM_OPTION, + FORK_ALGORITHM_DEFAULT, + args, + chain_config, + global_config ); + syscall_bufsize = util::get_option< uint32_t >( SYSTEM_CALL_BUFFER_SIZE_OPTION, + SYSTEM_CALL_BUFFER_SIZE_DEFAULT, + args, + chain_config, + global_config ); + + std::optional< std::filesystem::path > logdir_path; + if( !log_dir.empty() ) + { + logdir_path = std::make_optional< std::filesystem::path >( log_dir ); + if( logdir_path->is_relative() ) + logdir_path = basedir / util::service::chain / *logdir_path; + } + + koinos::initialize_logging( util::service::chain, instance_id, log_level, logdir_path, log_color, log_datetime ); + + LOG( info ) << version_string(); + + KOINOS_ASSERT( jobs > 1, invalid_argument, "jobs must be greater than 1" ); + + if( config.IsNull() ) + { + LOG( warning ) << "Could not find config (config.yml or config.yaml expected). Using default values"; + } + + if( fork_algorithm_option == FIFO_ALGORITHM ) + { + LOG( info ) << "Using fork resolution algorithm: " << FIFO_ALGORITHM; + fork_algorithm = chain::fork_resolution_algorithm::fifo; + } + else if( fork_algorithm_option == BLOCK_TIME_ALGORITHM ) + { + LOG( info ) << "Using fork resolution algorithm: " << BLOCK_TIME_ALGORITHM; + fork_algorithm = chain::fork_resolution_algorithm::block_time; + } + else if( fork_algorithm_option == POB_ALGORITHM ) + { + LOG( info ) << "Using fork resolution algorithm: " << POB_ALGORITHM; + fork_algorithm = chain::fork_resolution_algorithm::pob; + } + else + { + KOINOS_THROW( invalid_argument, "${a} is not a valid fork algorithm", ( "a", fork_algorithm_option ) ); + } + + if( statedir.is_relative() ) + statedir = basedir / util::service::chain / statedir; + + if( !std::filesystem::exists( statedir ) ) + std::filesystem::create_directories( statedir ); + + // Load genesis data + if( genesis_data_file.is_relative() ) + genesis_data_file = basedir / util::service::chain / genesis_data_file; + + KOINOS_ASSERT( std::filesystem::exists( genesis_data_file ), + invalid_argument, + "unable to locate genesis data file at ${loc}", + ( "loc", genesis_data_file.string() ) ); + + std::ifstream gifs( genesis_data_file ); + std::stringstream genesis_data_stream; + genesis_data_stream << gifs.rdbuf(); + std::string genesis_json = genesis_data_stream.str(); + gifs.close(); + + google::protobuf::util::JsonParseOptions jpo; + google::protobuf::util::JsonStringToMessage( genesis_json, &genesis_data, jpo ); + + crypto::multihash chain_id = crypto::hash( crypto::multicodec::sha2_256, genesis_data ); + + LOG( info ) << "Chain ID: " << chain_id; + LOG( info ) << "Number of jobs: " << jobs; + } + catch( const invalid_argument& e ) + { + LOG( error ) << "Invalid argument: " << e.what(); + return EXIT_FAILURE; + } + + std::atomic< bool > stopped = false; + int retcode = EXIT_SUCCESS; + std::vector< boost::thread > threads; + + asio::io_context client_ioc, server_ioc, main_ioc; + auto client = std::make_shared< mq::client >( client_ioc ); + auto request_handler = mq::request_handler( server_ioc ); + chain::controller controller( read_compute_limit, syscall_bufsize ); + + try + { + asio::signal_set signals( server_ioc ); + signals.add( SIGINT ); + signals.add( SIGTERM ); #if defined( SIGQUIT ) - signals.add( SIGQUIT ); + signals.add( SIGQUIT ); #endif - signals.async_wait( [&]( const system::error_code& err, int num ) + signals.async_wait( + [ & ]( const system::error_code& err, int num ) { - LOG(info) << "Caught signal, shutting down..."; - stopped = true; - main_ioc.stop(); + LOG( info ) << "Caught signal, shutting down..."; + stopped = true; + main_ioc.stop(); } ); - boost::thread::attributes attrs; - attrs.set_stack_size( 8192 * 1024 ); - - threads.emplace_back( attrs, [&]() { client_ioc.run(); } ); - threads.emplace_back( attrs, [&]() { client_ioc.run(); } ); - for ( std::size_t i = 0; i < jobs; i++ ) - threads.emplace_back( attrs, [&]() { server_ioc.run(); } ); - - controller.open( statedir, genesis_data, fork_algorithm, reset ); - - LOG(info) << "Connecting AMQP client..."; - client->connect( amqp_url ); - LOG(info) << "Established AMQP client connection to the server"; - - LOG(info) << "Attempting to connect to block_store..."; - rpc::block_store::block_store_request b_req; - b_req.mutable_reserved(); - client->rpc( util::service::block_store, b_req.SerializeAsString() ).get(); - LOG(info) << "Established connection to block_store"; - - LOG(info) << "Attempting to connect to mempool..."; - rpc::mempool::mempool_request m_req; - m_req.mutable_reserved(); - client->rpc( util::service::mempool, m_req.SerializeAsString() ).get(); - LOG(info) << "Established connection to mempool"; - - chain::indexer indexer( client_ioc, controller, client ); - - if ( indexer.index().get() ) - { - controller.set_client( client ); - attach_request_handler( controller, request_handler ); - - LOG(info) << "Connecting AMQP request handler..."; - request_handler.connect( amqp_url ); - LOG(info) << "Established request handler connection to the AMQP server"; - - LOG(info) << "Listening for requests over AMQP"; - auto work = asio::make_work_guard( main_ioc ); - main_ioc.run(); - } - } - catch ( const std::exception& e ) - { - if ( !stopped ) - { - LOG(fatal) << "An unexpected error has occurred: " << e.what(); - retcode = EXIT_FAILURE; - } - } - catch ( const boost::exception& e ) - { - LOG(fatal) << "An unexpected error has occurred: " << boost::diagnostic_information( e ); + boost::thread::attributes attrs; + attrs.set_stack_size( 8'192 * 1'024 ); + + threads.emplace_back( attrs, + [ & ]() + { + client_ioc.run(); + } ); + threads.emplace_back( attrs, + [ & ]() + { + client_ioc.run(); + } ); + for( std::size_t i = 0; i < jobs; i++ ) + threads.emplace_back( attrs, + [ & ]() + { + server_ioc.run(); + } ); + + controller.open( statedir, genesis_data, fork_algorithm, reset ); + + LOG( info ) << "Connecting AMQP client..."; + client->connect( amqp_url ); + LOG( info ) << "Established AMQP client connection to the server"; + + LOG( info ) << "Attempting to connect to block_store..."; + rpc::block_store::block_store_request b_req; + b_req.mutable_reserved(); + client->rpc( util::service::block_store, b_req.SerializeAsString() ).get(); + LOG( info ) << "Established connection to block_store"; + + LOG( info ) << "Attempting to connect to mempool..."; + rpc::mempool::mempool_request m_req; + m_req.mutable_reserved(); + client->rpc( util::service::mempool, m_req.SerializeAsString() ).get(); + LOG( info ) << "Established connection to mempool"; + + chain::indexer indexer( client_ioc, controller, client ); + + if( indexer.index().get() ) + { + controller.set_client( client ); + attach_request_handler( controller, request_handler ); + + LOG( info ) << "Connecting AMQP request handler..."; + request_handler.connect( amqp_url ); + LOG( info ) << "Established request handler connection to the AMQP server"; + + LOG( info ) << "Listening for requests over AMQP"; + auto work = asio::make_work_guard( main_ioc ); + main_ioc.run(); + } + } + catch( const std::exception& e ) + { + if( !stopped ) + { + LOG( fatal ) << "An unexpected error has occurred: " << e.what(); retcode = EXIT_FAILURE; - } - catch ( ... ) - { - LOG(fatal) << "An unexpected error has occurred"; - retcode = EXIT_FAILURE; - } - - controller.close(); - - for ( auto& t : threads ) - t.join(); - - LOG(info) << "Shut down gracefully"; - - return retcode; + } + } + catch( const boost::exception& e ) + { + LOG( fatal ) << "An unexpected error has occurred: " << boost::diagnostic_information( e ); + retcode = EXIT_FAILURE; + } + catch( ... ) + { + LOG( fatal ) << "An unexpected error has occurred"; + retcode = EXIT_FAILURE; + } + + controller.close(); + + for( auto& t: threads ) + t.join(); + + LOG( info ) << "Shut down gracefully"; + + return retcode; } const std::string& version_string() { - static std::string v_str = "Koinos Chain v"; - v_str += std::to_string( KOINOS_MAJOR_VERSION ) + "." + std::to_string( KOINOS_MINOR_VERSION ) + "." + std::to_string( KOINOS_PATCH_VERSION ); - v_str += " (" + std::string( KOINOS_GIT_HASH ) + ")"; - return v_str; + static std::string v_str = "Koinos Chain v"; + v_str += std::to_string( KOINOS_MAJOR_VERSION ) + "." + std::to_string( KOINOS_MINOR_VERSION ) + "." + + std::to_string( KOINOS_PATCH_VERSION ); + v_str += " (" + std::string( KOINOS_GIT_HASH ) + ")"; + return v_str; } -void attach_request_handler( - chain::controller& controller, - mq::request_handler& reqhandler ) +void attach_request_handler( chain::controller& controller, mq::request_handler& reqhandler ) { - reqhandler.add_rpc_handler( - util::service::chain, - [&]( const std::string& msg ) -> std::string + reqhandler.add_rpc_handler( + util::service::chain, + [ & ]( const std::string& msg ) -> std::string + { + rpc::chain::chain_request args; + rpc::chain::chain_response resp; + + if( args.ParseFromString( msg ) ) { - rpc::chain::chain_request args; - rpc::chain::chain_response resp; - - if ( args.ParseFromString( msg ) ) - { - LOG(debug) << "Received RPC: " << args; - - try - { - switch( args.request_case() ) - { - case rpc::chain::chain_request::RequestCase::kReserved: - resp.mutable_reserved(); - break; - case rpc::chain::chain_request::RequestCase::kSubmitBlock: - *resp.mutable_submit_block() = controller.submit_block( args.submit_block() ); - break; - case rpc::chain::chain_request::RequestCase::kSubmitTransaction: - *resp.mutable_submit_transaction() = controller.submit_transaction( args.submit_transaction() ); - break; - case rpc::chain::chain_request::RequestCase::kGetHeadInfo: - *resp.mutable_get_head_info() = controller.get_head_info( args.get_head_info() ); - break; - case rpc::chain::chain_request::RequestCase::kGetChainId: - *resp.mutable_get_chain_id() = controller.get_chain_id( args.get_chain_id() ); - break; - case rpc::chain::chain_request::RequestCase::kGetForkHeads: - *resp.mutable_get_fork_heads() = controller.get_fork_heads( args.get_fork_heads() ); - break; - case rpc::chain::chain_request::RequestCase::kReadContract: - *resp.mutable_read_contract() = controller.read_contract( args.read_contract() ); - break; - case rpc::chain::chain_request::RequestCase::kGetAccountNonce: - *resp.mutable_get_account_nonce() = controller.get_account_nonce( args.get_account_nonce() ); - break; - case rpc::chain::chain_request::RequestCase::kGetAccountRc: - *resp.mutable_get_account_rc() = controller.get_account_rc( args.get_account_rc() ); - break; - case rpc::chain::chain_request::RequestCase::kGetResourceLimits: - *resp.mutable_get_resource_limits() = controller.get_resource_limits( args.get_resource_limits() ); - break; - case rpc::chain::chain_request::RequestCase::kInvokeSystemCall: - *resp.mutable_invoke_system_call() = controller.invoke_system_call( args.invoke_system_call() ); - break; - default: - resp.mutable_error()->set_message( "Error: attempted to call unknown rpc" ); - break; - } - } - catch( const koinos::exception& e ) - { - auto error = resp.mutable_error(); - error->set_message( e.what() ); - - auto j = e.get_json(); - j[ "code" ] = e.get_code(); - error->set_data( j.dump() ); - } - catch( std::exception& e ) - { - auto error = resp.mutable_error(); - error->set_message( e.what() ); - - nlohmann::json j; - j[ "code" ] = chain::internal_error; - error->set_data( j.dump() ); - } - catch( ... ) - { - LOG(error) << "Unexpected error while handling rpc: " << args.ShortDebugString(); - - auto error = resp.mutable_error(); - error->set_message( "unexpected error while handling rpc" ); - - nlohmann::json j; - j[ "code" ] = chain::internal_error; - error->set_data( j.dump() ); - } - } - else - { - LOG(warning) << "Received bad message"; - - auto error = resp.mutable_error(); - error->set_message( "received bad message" ); - - nlohmann::json j; - j[ "code" ] = chain::internal_error; - error->set_data( j.dump() ); - } - - LOG(debug) << "Sending RPC response: " << resp; - - std::string r; - resp.SerializeToString( &r ); - return r; + LOG( debug ) << "Received RPC: " << args; + + try + { + switch( args.request_case() ) + { + case rpc::chain::chain_request::RequestCase::kReserved: + resp.mutable_reserved(); + break; + case rpc::chain::chain_request::RequestCase::kSubmitBlock: + *resp.mutable_submit_block() = controller.submit_block( args.submit_block() ); + break; + case rpc::chain::chain_request::RequestCase::kSubmitTransaction: + *resp.mutable_submit_transaction() = controller.submit_transaction( args.submit_transaction() ); + break; + case rpc::chain::chain_request::RequestCase::kGetHeadInfo: + *resp.mutable_get_head_info() = controller.get_head_info( args.get_head_info() ); + break; + case rpc::chain::chain_request::RequestCase::kGetChainId: + *resp.mutable_get_chain_id() = controller.get_chain_id( args.get_chain_id() ); + break; + case rpc::chain::chain_request::RequestCase::kGetForkHeads: + *resp.mutable_get_fork_heads() = controller.get_fork_heads( args.get_fork_heads() ); + break; + case rpc::chain::chain_request::RequestCase::kReadContract: + *resp.mutable_read_contract() = controller.read_contract( args.read_contract() ); + break; + case rpc::chain::chain_request::RequestCase::kGetAccountNonce: + *resp.mutable_get_account_nonce() = controller.get_account_nonce( args.get_account_nonce() ); + break; + case rpc::chain::chain_request::RequestCase::kGetAccountRc: + *resp.mutable_get_account_rc() = controller.get_account_rc( args.get_account_rc() ); + break; + case rpc::chain::chain_request::RequestCase::kGetResourceLimits: + *resp.mutable_get_resource_limits() = controller.get_resource_limits( args.get_resource_limits() ); + break; + case rpc::chain::chain_request::RequestCase::kInvokeSystemCall: + *resp.mutable_invoke_system_call() = controller.invoke_system_call( args.invoke_system_call() ); + break; + default: + resp.mutable_error()->set_message( "Error: attempted to call unknown rpc" ); + break; + } + } + catch( const koinos::exception& e ) + { + auto error = resp.mutable_error(); + error->set_message( e.what() ); + + auto j = e.get_json(); + j[ "code" ] = e.get_code(); + error->set_data( j.dump() ); + } + catch( std::exception& e ) + { + auto error = resp.mutable_error(); + error->set_message( e.what() ); + + nlohmann::json j; + j[ "code" ] = chain::internal_error; + error->set_data( j.dump() ); + } + catch( ... ) + { + LOG( error ) << "Unexpected error while handling rpc: " << args.ShortDebugString(); + + auto error = resp.mutable_error(); + error->set_message( "unexpected error while handling rpc" ); + + nlohmann::json j; + j[ "code" ] = chain::internal_error; + error->set_data( j.dump() ); + } } - ); - - reqhandler.add_broadcast_handler( - "koinos.block.accept", - [&]( const std::string& msg ) + else { - broadcast::block_accepted bam; - if ( !bam.ParseFromString( msg ) ) - { - LOG(warning) << "Could not parse block accepted broadcast"; - return; - } - - try - { - rpc::chain::submit_block_request sub_block; - sub_block.set_allocated_block( bam.release_block() ); - controller.submit_block( sub_block ); - } - catch( const boost::exception& e ) - { - LOG(warning) << "Error handling block broadcast: " << boost::diagnostic_information( e ); - } - catch( const std::exception& e ) - { - LOG(warning) << "Error handling block broadcast: " << e.what(); - } + LOG( warning ) << "Received bad message"; + + auto error = resp.mutable_error(); + error->set_message( "received bad message" ); + + nlohmann::json j; + j[ "code" ] = chain::internal_error; + error->set_data( j.dump() ); } - ); + + LOG( debug ) << "Sending RPC response: " << resp; + + std::string r; + resp.SerializeToString( &r ); + return r; + } ); + + reqhandler.add_broadcast_handler( "koinos.block.accept", + [ & ]( const std::string& msg ) + { + broadcast::block_accepted bam; + if( !bam.ParseFromString( msg ) ) + { + LOG( warning ) << "Could not parse block accepted broadcast"; + return; + } + + try + { + rpc::chain::submit_block_request sub_block; + sub_block.set_allocated_block( bam.release_block() ); + controller.submit_block( sub_block ); + } + catch( const boost::exception& e ) + { + LOG( warning ) + << "Error handling block broadcast: " << boost::diagnostic_information( e ); + } + catch( const std::exception& e ) + { + LOG( warning ) << "Error handling block broadcast: " << e.what(); + } + } ); } diff --git a/src/koinos_vm_driver.cpp b/src/koinos_vm_driver.cpp index 3735079b..74326a48 100644 --- a/src/koinos_vm_driver.cpp +++ b/src/koinos_vm_driver.cpp @@ -20,87 +20,88 @@ using namespace koinos; int main( int argc, char** argv, char** envp ) { - try - { - boost::program_options::options_description desc( "Koinos VM options" ); - desc.add_options() - ( HELP_OPTION ",h", "print usage message" ) - ( CONTRACT_OPTION ",c", boost::program_options::value< std::string >(), "the contract to run" ) - ( VM_OPTION ",v", boost::program_options::value< std::string >()->default_value( "" ), "the VM backend to use" ) - ( TICKS_OPTION ",t", boost::program_options::value< int64_t >()->default_value( 10 * 1000 * 1000 ), "set maximum allowed ticks" ) - ( LIST_VM_OPTION ",l", "list available VM backends" ) - ; - - boost::program_options::variables_map vmap; - boost::program_options::store( boost::program_options::parse_command_line( argc, argv, desc ), vmap ); - - initialize_logging( "koinos_vm_drivier", {}, "info" ); - - if ( vmap.count( HELP_OPTION ) ) + try + { + boost::program_options::options_description desc( "Koinos VM options" ); + desc.add_options()( HELP_OPTION ",h", "print usage message" )( CONTRACT_OPTION ",c", + boost::program_options::value< std::string >(), + "the contract to run" )( + VM_OPTION ",v", + boost::program_options::value< std::string >()->default_value( "" ), + "the VM backend to use" )( TICKS_OPTION ",t", + boost::program_options::value< int64_t >()->default_value( 10 * 1'000 * 1'000 ), + "set maximum allowed ticks" )( LIST_VM_OPTION ",l", "list available VM backends" ); + + boost::program_options::variables_map vmap; + boost::program_options::store( boost::program_options::parse_command_line( argc, argv, desc ), vmap ); + + initialize_logging( "koinos_vm_drivier", {}, "info" ); + + if( vmap.count( HELP_OPTION ) ) + { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + if( vmap.count( LIST_VM_OPTION ) ) + { + std::cout << "Available VM Backend(s):"; + + std::vector< std::shared_ptr< vm_manager::vm_backend > > backends = vm_manager::get_vm_backends(); + for( auto b: backends ) { - std::cout << desc << std::endl; - return EXIT_SUCCESS; + std::cout << " " << b->backend_name() << std::endl; } + return EXIT_SUCCESS; + } - if ( vmap.count( LIST_VM_OPTION ) ) - { - std::cout << "Available VM Backend(s):"; - - std::vector< std::shared_ptr< vm_manager::vm_backend > > backends = vm_manager::get_vm_backends(); - for( auto b : backends ) - { - std::cout << " " << b->backend_name() << std::endl; - } - return EXIT_SUCCESS; - } - - if ( !vmap.count( CONTRACT_OPTION ) ) - { - std::cout << desc << std::endl; - return EXIT_FAILURE; - } - - std::filesystem::path contract_file{ vmap[ CONTRACT_OPTION ].as< std::string >() }; - if ( contract_file.is_relative() ) - contract_file = std::filesystem::current_path() / contract_file; - - std::ifstream ifs( contract_file ); - std::string bytecode( ( std::istreambuf_iterator< char >( ifs ) ), ( std::istreambuf_iterator< char >() ) ); - - std::string vm_backend_name = vmap[ VM_OPTION ].as< std::string >(); - - auto vm_backend = vm_manager::get_vm_backend( vm_backend_name ); - KOINOS_ASSERT( vm_backend, koinos::chain::unknown_backend_exception, "Couldn't get VM backend" ); - - vm_backend->initialize(); - LOG(info) << "Initialized " << vm_backend->backend_name() << " VM backend"; - - chain::execution_context ctx( vm_backend ); - - auto rld = chain::system_call::get_resource_limits( ctx ); - rld.set_compute_bandwidth_limit( vmap[ TICKS_OPTION ].as< int64_t >() ); - ctx.resource_meter().set_resource_limit_data( rld ); - chain::host_api hapi( ctx ); - - vm_backend->run( hapi, bytecode ); - - if ( ctx.chronicler().logs().size() ) - { - LOG(info) << "Contract output:"; - for ( const auto& message : ctx.chronicler().logs() ) - LOG(info) << message; - } - } - catch( const koinos::exception& e ) - { - LOG(fatal) << boost::diagnostic_information( e ); + if( !vmap.count( CONTRACT_OPTION ) ) + { + std::cout << desc << std::endl; return EXIT_FAILURE; - } - catch (...) - { - LOG(fatal) << "unknown error"; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; + } + + std::filesystem::path contract_file{ vmap[ CONTRACT_OPTION ].as< std::string >() }; + if( contract_file.is_relative() ) + contract_file = std::filesystem::current_path() / contract_file; + + std::ifstream ifs( contract_file ); + std::string bytecode( ( std::istreambuf_iterator< char >( ifs ) ), ( std::istreambuf_iterator< char >() ) ); + + std::string vm_backend_name = vmap[ VM_OPTION ].as< std::string >(); + + auto vm_backend = vm_manager::get_vm_backend( vm_backend_name ); + KOINOS_ASSERT( vm_backend, koinos::chain::unknown_backend_exception, "Couldn't get VM backend" ); + + vm_backend->initialize(); + LOG( info ) << "Initialized " << vm_backend->backend_name() << " VM backend"; + + chain::execution_context ctx( vm_backend ); + + auto rld = chain::system_call::get_resource_limits( ctx ); + rld.set_compute_bandwidth_limit( vmap[ TICKS_OPTION ].as< int64_t >() ); + ctx.resource_meter().set_resource_limit_data( rld ); + chain::host_api hapi( ctx ); + + vm_backend->run( hapi, bytecode ); + + if( ctx.chronicler().logs().size() ) + { + LOG( info ) << "Contract output:"; + for( const auto& message: ctx.chronicler().logs() ) + LOG( info ) << message; + } + } + catch( const koinos::exception& e ) + { + LOG( fatal ) << boost::diagnostic_information( e ); + return EXIT_FAILURE; + } + catch( ... ) + { + LOG( fatal ) << "unknown error"; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; } diff --git a/tests/contracts.cpp b/tests/contracts.cpp index f387c246..7e3bb75e 100644 --- a/tests/contracts.cpp +++ b/tests/contracts.cpp @@ -25,12 +25,12 @@ #include #include -#define KOINOS_DEFINE_GET_WASM( contract_name ) \ -const std::string& get_ ## contract_name ## _wasm () \ -{ \ - static std::string wasm( (const char*) contract_name ## _wasm, contract_name ## _wasm_len ); \ - return wasm; \ -} +#define KOINOS_DEFINE_GET_WASM( contract_name ) \ + const std::string& get_##contract_name##_wasm() \ + { \ + static std::string wasm( (const char*)contract_name##_wasm, contract_name##_wasm_len ); \ + return wasm; \ + } KOINOS_DEFINE_GET_WASM( authorize ) KOINOS_DEFINE_GET_WASM( benchmark ) diff --git a/tests/main.cpp b/tests/main.cpp index fa472287..750ca0b1 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,3 +1,3 @@ #define BOOST_TEST_MODULE chain_tests // OVERRIDE_BOOST_TEST_INCLUDED_WARNING -#include \ No newline at end of file +#include diff --git a/tests/stack_test.cpp b/tests/stack_test.cpp index 2bd816ab..a5fee3af 100644 --- a/tests/stack_test.cpp +++ b/tests/stack_test.cpp @@ -1,8 +1,8 @@ #include -#include #include +#include #include #include @@ -30,727 +30,749 @@ using namespace std::string_literals; struct stack_fixture { - stack_fixture() : + stack_fixture(): vm_backend( koinos::vm_manager::get_vm_backend() ), ctx( vm_backend, chain::intent::transaction_application ), host( ctx ) - { - KOINOS_ASSERT( vm_backend, koinos::chain::unknown_backend_exception, "couldn't get vm backend" ); - - initialize_logging( "koinos_test", {}, "info" ); - - temp = std::filesystem::temp_directory_path() / boost::filesystem::unique_path().string(); - std::filesystem::create_directory( temp ); - - auto seed = "test seed"s; - _genesis_private_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, seed ) ); - - auto entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::genesis_key ); - entry->set_value( _genesis_private_key.get_public_key().to_address_bytes() ); - *entry->mutable_space() = chain::state::space::metadata(); - - koinos::chain::resource_limit_data rd; - - rd.set_disk_storage_cost( 10 ); - rd.set_disk_storage_limit( 204'800 ); - - rd.set_network_bandwidth_cost( 5 ); - rd.set_network_bandwidth_limit( 1'048'576 ); - - rd.set_compute_bandwidth_cost( 1 ); - rd.set_compute_bandwidth_limit( 100'000'000 ); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::resource_limit_data ); - entry->set_value( util::converter::as< std::string >( rd ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - koinos::chain::max_account_resources mar; - - mar.set_value( 100'000'000 ); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::max_account_resources ); - entry->set_value( util::converter::as< std::string >( mar ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::protocol_descriptor ); - - // protoc --experimental_allow_proto3_optional --descriptor_set_out=build/koinos_protocol.pb --include_imports `find koinos -name 'protocol.proto'` - std::string protocol_descriptor = util::from_hex< std::string >( "0x0ac33b0a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f120f676f6f676c652e70726f746f627566224d0a1146696c6544657363726970746f7253657412380a0466696c6518012003280b32242e676f6f676c652e70726f746f6275662e46696c6544657363726970746f7250726f746f520466696c6522e4040a1346696c6544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512180a077061636b61676518022001280952077061636b616765121e0a0a646570656e64656e6379180320032809520a646570656e64656e6379122b0a117075626c69635f646570656e64656e6379180a2003280552107075626c6963446570656e64656e637912270a0f7765616b5f646570656e64656e6379180b20032805520e7765616b446570656e64656e637912430a0c6d6573736167655f7479706518042003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520b6d6573736167655479706512410a09656e756d5f7479706518052003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512410a077365727669636518062003280b32272e676f6f676c652e70726f746f6275662e5365727669636544657363726970746f7250726f746f52077365727669636512430a09657874656e73696f6e18072003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12360a076f7074696f6e7318082001280b321c2e676f6f676c652e70726f746f6275662e46696c654f7074696f6e7352076f7074696f6e7312490a10736f757263655f636f64655f696e666f18092001280b321f2e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f520e736f75726365436f6465496e666f12160a0673796e746178180c20012809520673796e74617822b9060a0f44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123b0a056669656c6418022003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f52056669656c6412430a09657874656e73696f6e18062003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12410a0b6e65737465645f7479706518032003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520a6e65737465645479706512410a09656e756d5f7479706518042003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512580a0f657874656e73696f6e5f72616e676518052003280b322f2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e457874656e73696f6e52616e6765520e657874656e73696f6e52616e676512440a0a6f6e656f665f6465636c18082003280b32252e676f6f676c652e70726f746f6275662e4f6e656f6644657363726970746f7250726f746f52096f6e656f664465636c12390a076f7074696f6e7318072001280b321f2e676f6f676c652e70726f746f6275662e4d6573736167654f7074696f6e7352076f7074696f6e7312550a0e72657365727665645f72616e676518092003280b322e2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180a20032809520c72657365727665644e616d651a7a0a0e457874656e73696f6e52616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e6412400a076f7074696f6e7318032001280b32262e676f6f676c652e70726f746f6275662e457874656e73696f6e52616e67654f7074696f6e7352076f7074696f6e731a370a0d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e64227c0a15457874656e73696f6e52616e67654f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c1060a144669656c6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218032001280552066e756d62657212410a056c6162656c18042001280e322b2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e4c6162656c52056c6162656c123e0a047479706518052001280e322a2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e54797065520474797065121b0a09747970655f6e616d651806200128095208747970654e616d65121a0a08657874656e6465651802200128095208657874656e64656512230a0d64656661756c745f76616c7565180720012809520c64656661756c7456616c7565121f0a0b6f6e656f665f696e646578180920012805520a6f6e656f66496e646578121b0a096a736f6e5f6e616d65180a2001280952086a736f6e4e616d6512370a076f7074696f6e7318082001280b321d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7352076f7074696f6e7312270a0f70726f746f335f6f7074696f6e616c181120012808520e70726f746f334f7074696f6e616c22b6020a0454797065120f0a0b545950455f444f55424c451001120e0a0a545950455f464c4f41541002120e0a0a545950455f494e5436341003120f0a0b545950455f55494e5436341004120e0a0a545950455f494e543332100512100a0c545950455f46495845443634100612100a0c545950455f464958454433321007120d0a09545950455f424f4f4c1008120f0a0b545950455f535452494e471009120e0a0a545950455f47524f5550100a12100a0c545950455f4d455353414745100b120e0a0a545950455f4259544553100c120f0a0b545950455f55494e543332100d120d0a09545950455f454e554d100e12110a0d545950455f5346495845443332100f12110a0d545950455f53464958454436341010120f0a0b545950455f53494e5433321011120f0a0b545950455f53494e543634101222430a054c6162656c12120a0e4c4142454c5f4f5054494f4e414c100112120a0e4c4142454c5f5245515549524544100212120a0e4c4142454c5f5245504541544544100322630a144f6e656f6644657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512370a076f7074696f6e7318022001280b321d2e676f6f676c652e70726f746f6275662e4f6e656f664f7074696f6e7352076f7074696f6e7322e3020a13456e756d44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123f0a0576616c756518022003280b32292e676f6f676c652e70726f746f6275662e456e756d56616c756544657363726970746f7250726f746f520576616c756512360a076f7074696f6e7318032001280b321c2e676f6f676c652e70726f746f6275662e456e756d4f7074696f6e7352076f7074696f6e73125d0a0e72657365727665645f72616e676518042003280b32362e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f2e456e756d526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180520032809520c72657365727665644e616d651a3b0a11456e756d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e642283010a18456e756d56616c756544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218022001280552066e756d626572123b0a076f7074696f6e7318032001280b32212e676f6f676c652e70726f746f6275662e456e756d56616c75654f7074696f6e7352076f7074696f6e7322a7010a165365727669636544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123e0a066d6574686f6418022003280b32262e676f6f676c652e70726f746f6275662e4d6574686f6444657363726970746f7250726f746f52066d6574686f6412390a076f7074696f6e7318032001280b321f2e676f6f676c652e70726f746f6275662e536572766963654f7074696f6e7352076f7074696f6e732289020a154d6574686f6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65121d0a0a696e7075745f747970651802200128095209696e70757454797065121f0a0b6f75747075745f74797065180320012809520a6f75747075745479706512380a076f7074696f6e7318042001280b321e2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e7352076f7074696f6e7312300a10636c69656e745f73747265616d696e671805200128083a0566616c7365520f636c69656e7453747265616d696e6712300a107365727665725f73747265616d696e671806200128083a0566616c7365520f73657276657253747265616d696e672291090a0b46696c654f7074696f6e7312210a0c6a6176615f7061636b616765180120012809520b6a6176615061636b61676512300a146a6176615f6f757465725f636c6173736e616d6518082001280952126a6176614f75746572436c6173736e616d6512350a136a6176615f6d756c7469706c655f66696c6573180a200128083a0566616c736552116a6176614d756c7469706c6546696c657312440a1d6a6176615f67656e65726174655f657175616c735f616e645f686173681814200128084202180152196a61766147656e6572617465457175616c73416e6448617368123a0a166a6176615f737472696e675f636865636b5f75746638181b200128083a0566616c736552136a617661537472696e67436865636b5574663812530a0c6f7074696d697a655f666f7218092001280e32292e676f6f676c652e70726f746f6275662e46696c654f7074696f6e732e4f7074696d697a654d6f64653a055350454544520b6f7074696d697a65466f72121d0a0a676f5f7061636b616765180b200128095209676f5061636b61676512350a1363635f67656e657269635f73657276696365731810200128083a0566616c73655211636347656e65726963536572766963657312390a156a6176615f67656e657269635f73657276696365731811200128083a0566616c736552136a61766147656e65726963536572766963657312350a1370795f67656e657269635f73657276696365731812200128083a0566616c73655211707947656e65726963536572766963657312370a147068705f67656e657269635f7365727669636573182a200128083a0566616c7365521270687047656e65726963536572766963657312250a0a646570726563617465641817200128083a0566616c7365520a64657072656361746564122e0a1063635f656e61626c655f6172656e6173181f200128083a0474727565520e6363456e61626c654172656e6173122a0a116f626a635f636c6173735f707265666978182420012809520f6f626a63436c61737350726566697812290a106373686172705f6e616d657370616365182520012809520f6373686172704e616d65737061636512210a0c73776966745f707265666978182720012809520b737769667450726566697812280a107068705f636c6173735f707265666978182820012809520e706870436c61737350726566697812230a0d7068705f6e616d657370616365182920012809520c7068704e616d65737061636512340a167068705f6d657461646174615f6e616d657370616365182c2001280952147068704d657461646174614e616d65737061636512210a0c727562795f7061636b616765182d20012809520b727562795061636b61676512580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e223a0a0c4f7074696d697a654d6f646512090a0553504545441001120d0a09434f44455f53495a45100212100a0c4c4954455f52554e54494d4510032a0908e8071080808080024a040826102722e3020a0e4d6573736167654f7074696f6e73123c0a176d6573736167655f7365745f776972655f666f726d61741801200128083a0566616c736552146d65737361676553657457697265466f726d6174124c0a1f6e6f5f7374616e646172645f64657363726970746f725f6163636573736f721802200128083a0566616c7365521c6e6f5374616e6461726444657363726970746f724163636573736f7212250a0a646570726563617465641803200128083a0566616c7365520a64657072656361746564121b0a096d61705f656e74727918072001280852086d6170456e74727912580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a04080410054a04080510064a04080610074a04080810094a040809100a22e2030a0c4669656c644f7074696f6e7312410a05637479706518012001280e32232e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e43547970653a06535452494e475205637479706512160a067061636b656418022001280852067061636b656412470a066a737479706518062001280e32242e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e4a53547970653a094a535f4e4f524d414c52066a737479706512190a046c617a791805200128083a0566616c736552046c617a7912250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412190a047765616b180a200128083a0566616c736552047765616b12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e222f0a054354797065120a0a06535452494e47100012080a04434f5244100112100a0c535452494e475f5049454345100222350a064a5354797065120d0a094a535f4e4f524d414c1000120d0a094a535f535452494e471001120d0a094a535f4e554d42455210022a0908e8071080808080024a040804100522730a0c4f6e656f664f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c0010a0b456e756d4f7074696f6e73121f0a0b616c6c6f775f616c696173180220012808520a616c6c6f77416c69617312250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a0408051006229e010a10456e756d56616c75654f7074696f6e7312250a0a646570726563617465641801200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e807108080808002229c010a0e536572766963654f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222e0020a0d4d6574686f644f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412710a116964656d706f74656e63795f6c6576656c18222001280e322f2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e732e4964656d706f74656e63794c6576656c3a134944454d504f54454e43595f554e4b4e4f574e52106964656d706f74656e63794c6576656c12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e22500a104964656d706f74656e63794c6576656c12170a134944454d504f54454e43595f554e4b4e4f574e100012130a0f4e4f5f534944455f454646454354531001120e0a0a4944454d504f54454e5410022a0908e807108080808002229a030a13556e696e7465727072657465644f7074696f6e12410a046e616d6518022003280b322d2e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e2e4e616d655061727452046e616d6512290a106964656e7469666965725f76616c7565180320012809520f6964656e74696669657256616c7565122c0a12706f7369746976655f696e745f76616c75651804200128045210706f736974697665496e7456616c7565122c0a126e656761746976655f696e745f76616c756518052001280352106e65676174697665496e7456616c756512210a0c646f75626c655f76616c7565180620012801520b646f75626c6556616c756512210a0c737472696e675f76616c756518072001280c520b737472696e6756616c756512270a0f6167677265676174655f76616c7565180820012809520e61676772656761746556616c75651a4a0a084e616d6550617274121b0a096e616d655f7061727418012002280952086e616d655061727412210a0c69735f657874656e73696f6e180220022808520b6973457874656e73696f6e22a7020a0e536f75726365436f6465496e666f12440a086c6f636174696f6e18012003280b32282e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f2e4c6f636174696f6e52086c6f636174696f6e1ace010a084c6f636174696f6e12160a04706174681801200328054202100152047061746812160a047370616e1802200328054202100152047370616e12290a106c656164696e675f636f6d6d656e7473180320012809520f6c656164696e67436f6d6d656e7473122b0a11747261696c696e675f636f6d6d656e74731804200128095210747261696c696e67436f6d6d656e7473123a0a196c656164696e675f64657461636865645f636f6d6d656e747318062003280952176c656164696e674465746163686564436f6d6d656e747322d1010a1147656e657261746564436f6465496e666f124d0a0a616e6e6f746174696f6e18012003280b322d2e676f6f676c652e70726f746f6275662e47656e657261746564436f6465496e666f2e416e6e6f746174696f6e520a616e6e6f746174696f6e1a6d0a0a416e6e6f746174696f6e12160a047061746818012003280542021001520470617468121f0a0b736f757263655f66696c65180220012809520a736f7572636546696c6512140a05626567696e1803200128055205626567696e12100a03656e641804200128055203656e64427e0a13636f6d2e676f6f676c652e70726f746f627566421044657363726970746f7250726f746f7348015a2d676f6f676c652e676f6c616e672e6f72672f70726f746f6275662f74797065732f64657363726970746f727062f80101a20203475042aa021a476f6f676c652e50726f746f6275662e5265666c656374696f6e0ab5020a146b6f696e6f732f6f7074696f6e732e70726f746f12066b6f696e6f731a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f2a6d0a0a62797465735f74797065120a0a064241534536341000120a0a06424153453538100112070a034845581002120c0a08424c4f434b5f4944100312120a0e5452414e53414354494f4e5f49441004120f0a0b434f4e54524143545f49441005120b0a074144445245535310063a4c0a056274797065121d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7318d086032001280e32122e6b6f696e6f732e62797465735f7479706552056274797065880101422e5a2c6769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f73620670726f746f330aa8190a1e6b6f696e6f732f70726f746f636f6c2f70726f746f636f6c2e70726f746f120f6b6f696e6f732e70726f746f636f6c1a146b6f696e6f732f6f7074696f6e732e70726f746f2290010a0a6576656e745f64617461121a0a0873657175656e636518012001280d520873657175656e6365121c0a06736f7572636518022001280c420480b518055206736f7572636512120a046e616d6518032001280952046e616d6512120a046461746118042001280c52046461746112200a08696d70616374656418052003280c420480b518065208696d706163746564225e0a14636f6e74726163745f63616c6c5f62756e646c6512250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e742292010a1273797374656d5f63616c6c5f746172676574121b0a087468756e6b5f696418012001280d480052077468756e6b496412550a1273797374656d5f63616c6c5f62756e646c6518022001280b32252e6b6f696e6f732e70726f746f636f6c2e636f6e74726163745f63616c6c5f62756e646c654800521073797374656d43616c6c42756e646c6542080a067461726765742294020a1975706c6f61645f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121a0a0862797465636f646518022001280c520862797465636f646512100a03616269180320012809520361626912380a18617574686f72697a65735f63616c6c5f636f6e74726163741804200128085216617574686f72697a657343616c6c436f6e7472616374122a0a11617574686f72697a65735f7573655f7263180520012808520f617574686f72697a65735573655263123c0a1a617574686f72697a65735f75706c6f61645f636f6e74726163741806200128085218617574686f72697a657355706c6f6164436f6e747261637422750a1763616c6c5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e7412120a046172677318032001280c52046172677322710a197365745f73797374656d5f63616c6c5f6f7065726174696f6e12170a0763616c6c5f696418012001280d520663616c6c4964123b0a0674617267657418022001280b32232e6b6f696e6f732e70726f746f636f6c2e73797374656d5f63616c6c5f7461726765745206746172676574226f0a1d7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e7472616374496412270a0f73797374656d5f636f6e7472616374180220012808520e73797374656d436f6e747261637422f1020a096f7065726174696f6e12550a0f75706c6f61645f636f6e747261637418012001280b322a2e6b6f696e6f732e70726f746f636f6c2e75706c6f61645f636f6e74726163745f6f7065726174696f6e4800520e75706c6f6164436f6e7472616374124f0a0d63616c6c5f636f6e747261637418022001280b32282e6b6f696e6f732e70726f746f636f6c2e63616c6c5f636f6e74726163745f6f7065726174696f6e4800520c63616c6c436f6e747261637412540a0f7365745f73797374656d5f63616c6c18032001280b322a2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f63616c6c5f6f7065726174696f6e4800520d73657453797374656d43616c6c12600a137365745f73797374656d5f636f6e747261637418042001280b322e2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e4800521173657453797374656d436f6e747261637442040a026f7022d0010a127472616e73616374696f6e5f68656164657212190a08636861696e5f696418012001280c5207636861696e4964121d0a0872635f6c696d697418022001280442023001520772634c696d697412140a056e6f6e636518032001280c52056e6f6e636512320a156f7065726174696f6e5f6d65726b6c655f726f6f7418042001280c52136f7065726174696f6e4d65726b6c65526f6f74121a0a05706179657218052001280c420480b5180652057061796572121a0a05706179656518062001280c420480b518065205706179656522bc010a0b7472616e73616374696f6e12140a02696418012001280c420480b5180452026964123b0a0668656164657218022001280b32232e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f6865616465725206686561646572123a0a0a6f7065726174696f6e7318032003280b321a2e6b6f696e6f732e70726f746f636f6c2e6f7065726174696f6e520a6f7065726174696f6e73121e0a0a7369676e61747572657318042003280c520a7369676e61747572657322b2030a137472616e73616374696f6e5f7265636569707412140a02696418012001280c420480b5180452026964121a0a05706179657218022001280c420480b518065205706179657212240a0c6d61785f70617965725f726318032001280442023001520a6d617850617965725263121d0a0872635f6c696d697418042001280442023001520772634c696d6974121b0a0772635f75736564180520012804420230015206726355736564122e0a116469736b5f73746f726167655f7573656418062001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641807200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180820012804420230015214636f6d7075746542616e64776964746855736564121a0a0872657665727465641809200128085208726576657274656412330a066576656e7473180a2003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312120a046c6f6773180b2003280952046c6f677322fb010a0c626c6f636b5f68656164657212200a0870726576696f757318012001280c420480b51803520870726576696f7573121a0a0668656967687418022001280442023001520668656967687412200a0974696d657374616d7018032001280442023001520974696d657374616d70123b0a1a70726576696f75735f73746174655f6d65726b6c655f726f6f7418042001280c521770726576696f757353746174654d65726b6c65526f6f7412360a177472616e73616374696f6e5f6d65726b6c655f726f6f7418052001280c52157472616e73616374696f6e4d65726b6c65526f6f7412160a067369676e657218062001280c52067369676e657222b4010a05626c6f636b12140a02696418012001280c420480b518035202696412350a0668656164657218022001280b321d2e6b6f696e6f732e70726f746f636f6c2e626c6f636b5f686561646572520668656164657212400a0c7472616e73616374696f6e7318032003280b321c2e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e520c7472616e73616374696f6e73121c0a097369676e617475726518042001280c52097369676e617475726522b3030a0d626c6f636b5f7265636569707412140a02696418012001280c420480b5180352026964121a0a06686569676874180220012804420230015206686569676874122e0a116469736b5f73746f726167655f7573656418032001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641804200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180520012804420230015214636f6d7075746542616e64776964746855736564122a0a1173746174655f6d65726b6c655f726f6f7418062001280c520f73746174654d65726b6c65526f6f7412330a066576656e747318072003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312570a147472616e73616374696f6e5f726563656970747318082003280b32242e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f7265636569707452137472616e73616374696f6e526563656970747312120a046c6f677318092003280952046c6f677342375a356769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f732f70726f746f636f6c620670726f746f33" ); - entry->set_value( protocol_descriptor ); - *entry->mutable_space() = chain::state::space::metadata(); - - std::map< std::string, uint64_t > thunk_compute { - { "apply_block", 16465 }, - { "apply_call_contract_operation", 685 }, - { "apply_set_system_call_operation", 136081 }, - { "apply_set_system_contract_operation", 8692 }, - { "apply_transaction", 12542 }, - { "apply_upload_contract_operation", 3130 }, - { "call", 3573 }, - { "check_authority", 12653 }, - { "check_system_authority", 12750 }, - { "consume_account_rc", 735 }, - { "consume_block_resources", 753 }, - { "deserialize_message_per_byte", 1 }, - { "deserialize_multihash_base", 102 }, - { "deserialize_multihash_per_byte", 404 }, - { "event", 1222 }, - { "event_per_impacted", 101 }, - { "exit", 11636 }, - { "get_account_nonce", 821 }, - { "get_account_rc", 1072 }, - { "get_arguments", 809 }, - { "get_block", 1134 }, - { "get_block_field", 1417 }, - { "get_caller", 825 }, - { "get_chain_id", 1046 }, - { "get_contract_id", 778 }, - { "get_head_info", 2099 }, - { "get_last_irreversible_block", 772 }, - { "get_next_object", 11181 }, - { "get_object", 1054 }, - { "get_operation", 1081 }, - { "get_prev_object", 15445 }, - { "get_resource_limits", 1227 }, - { "get_transaction", 1584 }, - { "get_transaction_field", 1530 }, - { "hash", 1570 }, - { "keccak_256_base", 1406 }, - { "keccak_256_per_byte", 1 }, - { "log", 738 }, - { "object_serialization_per_byte", 1 }, - { "post_block_callback", 741 }, - { "post_transaction_callback", 721 }, - { "pre_block_callback", 730 }, - { "pre_transaction_callback", 729 }, - { "process_block_signature", 4499 }, - { "put_object", 1057 }, - { "recover_public_key", 29630 }, - { "remove_object", 893 }, - { "ripemd_160_base", 1343 }, - { "ripemd_160_per_byte", 1 }, - { "set_account_nonce", 749 }, - { "sha1_base", 1151 }, - { "sha1_per_byte", 1 }, - { "sha2_256_base", 1385 }, - { "sha2_256_per_byte", 1 }, - { "sha2_512_base", 1445 }, - { "sha2_512_per_byte", 1 }, - { "verify_account_nonce", 822 }, - { "verify_merkle_root", 1 }, - { "verify_signature", 762 }, - { "verify_vrf_proof", 144067 }, - }; - - koinos::chain::compute_bandwidth_registry cbr; - - for ( const auto& [ key, value ] : thunk_compute ) + { + KOINOS_ASSERT( vm_backend, koinos::chain::unknown_backend_exception, "couldn't get vm backend" ); + + initialize_logging( "koinos_test", {}, "info" ); + + temp = std::filesystem::temp_directory_path() / boost::filesystem::unique_path().string(); + std::filesystem::create_directory( temp ); + + auto seed = "test seed"s; + _genesis_private_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, seed ) ); + + auto entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::genesis_key ); + entry->set_value( _genesis_private_key.get_public_key().to_address_bytes() ); + *entry->mutable_space() = chain::state::space::metadata(); + + koinos::chain::resource_limit_data rd; + + rd.set_disk_storage_cost( 10 ); + rd.set_disk_storage_limit( 204'800 ); + + rd.set_network_bandwidth_cost( 5 ); + rd.set_network_bandwidth_limit( 1'048'576 ); + + rd.set_compute_bandwidth_cost( 1 ); + rd.set_compute_bandwidth_limit( 100'000'000 ); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::resource_limit_data ); + entry->set_value( util::converter::as< std::string >( rd ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + koinos::chain::max_account_resources mar; + + mar.set_value( 100'000'000 ); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::max_account_resources ); + entry->set_value( util::converter::as< std::string >( mar ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::protocol_descriptor ); + + // protoc --experimental_allow_proto3_optional --descriptor_set_out=build/koinos_protocol.pb --include_imports `find + // koinos -name 'protocol.proto'` + std::string protocol_descriptor = util::from_hex< std::string >( + "0x0ac33b0a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f120f676f6f676c652e70726f746f627566224d0a1146696c6544657363726970746f7253657412380a0466696c6518012003280b32242e676f6f676c652e70726f746f6275662e46696c6544657363726970746f7250726f746f520466696c6522e4040a1346696c6544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512180a077061636b61676518022001280952077061636b616765121e0a0a646570656e64656e6379180320032809520a646570656e64656e6379122b0a117075626c69635f646570656e64656e6379180a2003280552107075626c6963446570656e64656e637912270a0f7765616b5f646570656e64656e6379180b20032805520e7765616b446570656e64656e637912430a0c6d6573736167655f7479706518042003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520b6d6573736167655479706512410a09656e756d5f7479706518052003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512410a077365727669636518062003280b32272e676f6f676c652e70726f746f6275662e5365727669636544657363726970746f7250726f746f52077365727669636512430a09657874656e73696f6e18072003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12360a076f7074696f6e7318082001280b321c2e676f6f676c652e70726f746f6275662e46696c654f7074696f6e7352076f7074696f6e7312490a10736f757263655f636f64655f696e666f18092001280b321f2e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f520e736f75726365436f6465496e666f12160a0673796e746178180c20012809520673796e74617822b9060a0f44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123b0a056669656c6418022003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f52056669656c6412430a09657874656e73696f6e18062003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12410a0b6e65737465645f7479706518032003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520a6e65737465645479706512410a09656e756d5f7479706518042003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512580a0f657874656e73696f6e5f72616e676518052003280b322f2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e457874656e73696f6e52616e6765520e657874656e73696f6e52616e676512440a0a6f6e656f665f6465636c18082003280b32252e676f6f676c652e70726f746f6275662e4f6e656f6644657363726970746f7250726f746f52096f6e656f664465636c12390a076f7074696f6e7318072001280b321f2e676f6f676c652e70726f746f6275662e4d6573736167654f7074696f6e7352076f7074696f6e7312550a0e72657365727665645f72616e676518092003280b322e2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180a20032809520c72657365727665644e616d651a7a0a0e457874656e73696f6e52616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e6412400a076f7074696f6e7318032001280b32262e676f6f676c652e70726f746f6275662e457874656e73696f6e52616e67654f7074696f6e7352076f7074696f6e731a370a0d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e64227c0a15457874656e73696f6e52616e67654f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c1060a144669656c6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218032001280552066e756d62657212410a056c6162656c18042001280e322b2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e4c6162656c52056c6162656c123e0a047479706518052001280e322a2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e54797065520474797065121b0a09747970655f6e616d651806200128095208747970654e616d65121a0a08657874656e6465651802200128095208657874656e64656512230a0d64656661756c745f76616c7565180720012809520c64656661756c7456616c7565121f0a0b6f6e656f665f696e646578180920012805520a6f6e656f66496e646578121b0a096a736f6e5f6e616d65180a2001280952086a736f6e4e616d6512370a076f7074696f6e7318082001280b321d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7352076f7074696f6e7312270a0f70726f746f335f6f7074696f6e616c181120012808520e70726f746f334f7074696f6e616c22b6020a0454797065120f0a0b545950455f444f55424c451001120e0a0a545950455f464c4f41541002120e0a0a545950455f494e5436341003120f0a0b545950455f55494e5436341004120e0a0a545950455f494e543332100512100a0c545950455f46495845443634100612100a0c545950455f464958454433321007120d0a09545950455f424f4f4c1008120f0a0b545950455f535452494e471009120e0a0a545950455f47524f5550100a12100a0c545950455f4d455353414745100b120e0a0a545950455f4259544553100c120f0a0b545950455f55494e543332100d120d0a09545950455f454e554d100e12110a0d545950455f5346495845443332100f12110a0d545950455f53464958454436341010120f0a0b545950455f53494e5433321011120f0a0b545950455f53494e543634101222430a054c6162656c12120a0e4c4142454c5f4f5054494f4e414c100112120a0e4c4142454c5f5245515549524544100212120a0e4c4142454c5f5245504541544544100322630a144f6e656f6644657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512370a076f7074696f6e7318022001280b321d2e676f6f676c652e70726f746f6275662e4f6e656f664f7074696f6e7352076f7074696f6e7322e3020a13456e756d44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123f0a0576616c756518022003280b32292e676f6f676c652e70726f746f6275662e456e756d56616c756544657363726970746f7250726f746f520576616c756512360a076f7074696f6e7318032001280b321c2e676f6f676c652e70726f746f6275662e456e756d4f7074696f6e7352076f7074696f6e73125d0a0e72657365727665645f72616e676518042003280b32362e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f2e456e756d526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180520032809520c72657365727665644e616d651a3b0a11456e756d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e642283010a18456e756d56616c756544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218022001280552066e756d626572123b0a076f7074696f6e7318032001280b32212e676f6f676c652e70726f746f6275662e456e756d56616c75654f7074696f6e7352076f7074696f6e7322a7010a165365727669636544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123e0a066d6574686f6418022003280b32262e676f6f676c652e70726f746f6275662e4d6574686f6444657363726970746f7250726f746f52066d6574686f6412390a076f7074696f6e7318032001280b321f2e676f6f676c652e70726f746f6275662e536572766963654f7074696f6e7352076f7074696f6e732289020a154d6574686f6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65121d0a0a696e7075745f747970651802200128095209696e70757454797065121f0a0b6f75747075745f74797065180320012809520a6f75747075745479706512380a076f7074696f6e7318042001280b321e2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e7352076f7074696f6e7312300a10636c69656e745f73747265616d696e671805200128083a0566616c7365520f636c69656e7453747265616d696e6712300a107365727665725f73747265616d696e671806200128083a0566616c7365520f73657276657253747265616d696e672291090a0b46696c654f7074696f6e7312210a0c6a6176615f7061636b616765180120012809520b6a6176615061636b61676512300a146a6176615f6f757465725f636c6173736e616d6518082001280952126a6176614f75746572436c6173736e616d6512350a136a6176615f6d756c7469706c655f66696c6573180a200128083a0566616c736552116a6176614d756c7469706c6546696c657312440a1d6a6176615f67656e65726174655f657175616c735f616e645f686173681814200128084202180152196a61766147656e6572617465457175616c73416e6448617368123a0a166a6176615f737472696e675f636865636b5f75746638181b200128083a0566616c736552136a617661537472696e67436865636b5574663812530a0c6f7074696d697a655f666f7218092001280e32292e676f6f676c652e70726f746f6275662e46696c654f7074696f6e732e4f7074696d697a654d6f64653a055350454544520b6f7074696d697a65466f72121d0a0a676f5f7061636b616765180b200128095209676f5061636b61676512350a1363635f67656e657269635f73657276696365731810200128083a0566616c73655211636347656e65726963536572766963657312390a156a6176615f67656e657269635f73657276696365731811200128083a0566616c736552136a61766147656e65726963536572766963657312350a1370795f67656e657269635f73657276696365731812200128083a0566616c73655211707947656e65726963536572766963657312370a147068705f67656e657269635f7365727669636573182a200128083a0566616c7365521270687047656e65726963536572766963657312250a0a646570726563617465641817200128083a0566616c7365520a64657072656361746564122e0a1063635f656e61626c655f6172656e6173181f200128083a0474727565520e6363456e61626c654172656e6173122a0a116f626a635f636c6173735f707265666978182420012809520f6f626a63436c61737350726566697812290a106373686172705f6e616d657370616365182520012809520f6373686172704e616d65737061636512210a0c73776966745f707265666978182720012809520b737769667450726566697812280a107068705f636c6173735f707265666978182820012809520e706870436c61737350726566697812230a0d7068705f6e616d657370616365182920012809520c7068704e616d65737061636512340a167068705f6d657461646174615f6e616d657370616365182c2001280952147068704d657461646174614e616d65737061636512210a0c727562795f7061636b616765182d20012809520b727562795061636b61676512580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e223a0a0c4f7074696d697a654d6f646512090a0553504545441001120d0a09434f44455f53495a45100212100a0c4c4954455f52554e54494d4510032a0908e8071080808080024a040826102722e3020a0e4d6573736167654f7074696f6e73123c0a176d6573736167655f7365745f776972655f666f726d61741801200128083a0566616c736552146d65737361676553657457697265466f726d6174124c0a1f6e6f5f7374616e646172645f64657363726970746f725f6163636573736f721802200128083a0566616c7365521c6e6f5374616e6461726444657363726970746f724163636573736f7212250a0a646570726563617465641803200128083a0566616c7365520a64657072656361746564121b0a096d61705f656e74727918072001280852086d6170456e74727912580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a04080410054a04080510064a04080610074a04080810094a040809100a22e2030a0c4669656c644f7074696f6e7312410a05637479706518012001280e32232e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e43547970653a06535452494e475205637479706512160a067061636b656418022001280852067061636b656412470a066a737479706518062001280e32242e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e4a53547970653a094a535f4e4f524d414c52066a737479706512190a046c617a791805200128083a0566616c736552046c617a7912250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412190a047765616b180a200128083a0566616c736552047765616b12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e222f0a054354797065120a0a06535452494e47100012080a04434f5244100112100a0c535452494e475f5049454345100222350a064a5354797065120d0a094a535f4e4f524d414c1000120d0a094a535f535452494e471001120d0a094a535f4e554d42455210022a0908e8071080808080024a040804100522730a0c4f6e656f664f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c0010a0b456e756d4f7074696f6e73121f0a0b616c6c6f775f616c696173180220012808520a616c6c6f77416c69617312250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a0408051006229e010a10456e756d56616c75654f7074696f6e7312250a0a646570726563617465641801200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e807108080808002229c010a0e536572766963654f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222e0020a0d4d6574686f644f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412710a116964656d706f74656e63795f6c6576656c18222001280e322f2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e732e4964656d706f74656e63794c6576656c3a134944454d504f54454e43595f554e4b4e4f574e52106964656d706f74656e63794c6576656c12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e22500a104964656d706f74656e63794c6576656c12170a134944454d504f54454e43595f554e4b4e4f574e100012130a0f4e4f5f534944455f454646454354531001120e0a0a4944454d504f54454e5410022a0908e807108080808002229a030a13556e696e7465727072657465644f7074696f6e12410a046e616d6518022003280b322d2e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e2e4e616d655061727452046e616d6512290a106964656e7469666965725f76616c7565180320012809520f6964656e74696669657256616c7565122c0a12706f7369746976655f696e745f76616c75651804200128045210706f736974697665496e7456616c7565122c0a126e656761746976655f696e745f76616c756518052001280352106e65676174697665496e7456616c756512210a0c646f75626c655f76616c7565180620012801520b646f75626c6556616c756512210a0c737472696e675f76616c756518072001280c520b737472696e6756616c756512270a0f6167677265676174655f76616c7565180820012809520e61676772656761746556616c75651a4a0a084e616d6550617274121b0a096e616d655f7061727418012002280952086e616d655061727412210a0c69735f657874656e73696f6e180220022808520b6973457874656e73696f6e22a7020a0e536f75726365436f6465496e666f12440a086c6f636174696f6e18012003280b32282e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f2e4c6f636174696f6e52086c6f636174696f6e1ace010a084c6f636174696f6e12160a04706174681801200328054202100152047061746812160a047370616e1802200328054202100152047370616e12290a106c656164696e675f636f6d6d656e7473180320012809520f6c656164696e67436f6d6d656e7473122b0a11747261696c696e675f636f6d6d656e74731804200128095210747261696c696e67436f6d6d656e7473123a0a196c656164696e675f64657461636865645f636f6d6d656e747318062003280952176c656164696e674465746163686564436f6d6d656e747322d1010a1147656e657261746564436f6465496e666f124d0a0a616e6e6f746174696f6e18012003280b322d2e676f6f676c652e70726f746f6275662e47656e657261746564436f6465496e666f2e416e6e6f746174696f6e520a616e6e6f746174696f6e1a6d0a0a416e6e6f746174696f6e12160a047061746818012003280542021001520470617468121f0a0b736f757263655f66696c65180220012809520a736f7572636546696c6512140a05626567696e1803200128055205626567696e12100a03656e641804200128055203656e64427e0a13636f6d2e676f6f676c652e70726f746f627566421044657363726970746f7250726f746f7348015a2d676f6f676c652e676f6c616e672e6f72672f70726f746f6275662f74797065732f64657363726970746f727062f80101a20203475042aa021a476f6f676c652e50726f746f6275662e5265666c656374696f6e0ab5020a146b6f696e6f732f6f7074696f6e732e70726f746f12066b6f696e6f731a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f2a6d0a0a62797465735f74797065120a0a064241534536341000120a0a06424153453538100112070a034845581002120c0a08424c4f434b5f4944100312120a0e5452414e53414354494f4e5f49441004120f0a0b434f4e54524143545f49441005120b0a074144445245535310063a4c0a056274797065121d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7318d086032001280e32122e6b6f696e6f732e62797465735f7479706552056274797065880101422e5a2c6769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f73620670726f746f330aa8190a1e6b6f696e6f732f70726f746f636f6c2f70726f746f636f6c2e70726f746f120f6b6f696e6f732e70726f746f636f6c1a146b6f696e6f732f6f7074696f6e732e70726f746f2290010a0a6576656e745f64617461121a0a0873657175656e636518012001280d520873657175656e6365121c0a06736f7572636518022001280c420480b518055206736f7572636512120a046e616d6518032001280952046e616d6512120a046461746118042001280c52046461746112200a08696d70616374656418052003280c420480b518065208696d706163746564225e0a14636f6e74726163745f63616c6c5f62756e646c6512250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e742292010a1273797374656d5f63616c6c5f746172676574121b0a087468756e6b5f696418012001280d480052077468756e6b496412550a1273797374656d5f63616c6c5f62756e646c6518022001280b32252e6b6f696e6f732e70726f746f636f6c2e636f6e74726163745f63616c6c5f62756e646c654800521073797374656d43616c6c42756e646c6542080a067461726765742294020a1975706c6f61645f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121a0a0862797465636f646518022001280c520862797465636f646512100a03616269180320012809520361626912380a18617574686f72697a65735f63616c6c5f636f6e74726163741804200128085216617574686f72697a657343616c6c436f6e7472616374122a0a11617574686f72697a65735f7573655f7263180520012808520f617574686f72697a65735573655263123c0a1a617574686f72697a65735f75706c6f61645f636f6e74726163741806200128085218617574686f72697a657355706c6f6164436f6e747261637422750a1763616c6c5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e7412120a046172677318032001280c52046172677322710a197365745f73797374656d5f63616c6c5f6f7065726174696f6e12170a0763616c6c5f696418012001280d520663616c6c4964123b0a0674617267657418022001280b32232e6b6f696e6f732e70726f746f636f6c2e73797374656d5f63616c6c5f7461726765745206746172676574226f0a1d7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e7472616374496412270a0f73797374656d5f636f6e7472616374180220012808520e73797374656d436f6e747261637422f1020a096f7065726174696f6e12550a0f75706c6f61645f636f6e747261637418012001280b322a2e6b6f696e6f732e70726f746f636f6c2e75706c6f61645f636f6e74726163745f6f7065726174696f6e4800520e75706c6f6164436f6e7472616374124f0a0d63616c6c5f636f6e747261637418022001280b32282e6b6f696e6f732e70726f746f636f6c2e63616c6c5f636f6e74726163745f6f7065726174696f6e4800520c63616c6c436f6e747261637412540a0f7365745f73797374656d5f63616c6c18032001280b322a2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f63616c6c5f6f7065726174696f6e4800520d73657453797374656d43616c6c12600a137365745f73797374656d5f636f6e747261637418042001280b322e2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e4800521173657453797374656d436f6e747261637442040a026f7022d0010a127472616e73616374696f6e5f68656164657212190a08636861696e5f696418012001280c5207636861696e4964121d0a0872635f6c696d697418022001280442023001520772634c696d697412140a056e6f6e636518032001280c52056e6f6e636512320a156f7065726174696f6e5f6d65726b6c655f726f6f7418042001280c52136f7065726174696f6e4d65726b6c65526f6f74121a0a05706179657218052001280c420480b5180652057061796572121a0a05706179656518062001280c420480b518065205706179656522bc010a0b7472616e73616374696f6e12140a02696418012001280c420480b5180452026964123b0a0668656164657218022001280b32232e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f6865616465725206686561646572123a0a0a6f7065726174696f6e7318032003280b321a2e6b6f696e6f732e70726f746f636f6c2e6f7065726174696f6e520a6f7065726174696f6e73121e0a0a7369676e61747572657318042003280c520a7369676e61747572657322b2030a137472616e73616374696f6e5f7265636569707412140a02696418012001280c420480b5180452026964121a0a05706179657218022001280c420480b518065205706179657212240a0c6d61785f70617965725f726318032001280442023001520a6d617850617965725263121d0a0872635f6c696d697418042001280442023001520772634c696d6974121b0a0772635f75736564180520012804420230015206726355736564122e0a116469736b5f73746f726167655f7573656418062001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641807200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180820012804420230015214636f6d7075746542616e64776964746855736564121a0a0872657665727465641809200128085208726576657274656412330a066576656e7473180a2003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312120a046c6f6773180b2003280952046c6f677322fb010a0c626c6f636b5f68656164657212200a0870726576696f757318012001280c420480b51803520870726576696f7573121a0a0668656967687418022001280442023001520668656967687412200a0974696d657374616d7018032001280442023001520974696d657374616d70123b0a1a70726576696f75735f73746174655f6d65726b6c655f726f6f7418042001280c521770726576696f757353746174654d65726b6c65526f6f7412360a177472616e73616374696f6e5f6d65726b6c655f726f6f7418052001280c52157472616e73616374696f6e4d65726b6c65526f6f7412160a067369676e657218062001280c52067369676e657222b4010a05626c6f636b12140a02696418012001280c420480b518035202696412350a0668656164657218022001280b321d2e6b6f696e6f732e70726f746f636f6c2e626c6f636b5f686561646572520668656164657212400a0c7472616e73616374696f6e7318032003280b321c2e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e520c7472616e73616374696f6e73121c0a097369676e617475726518042001280c52097369676e617475726522b3030a0d626c6f636b5f7265636569707412140a02696418012001280c420480b5180352026964121a0a06686569676874180220012804420230015206686569676874122e0a116469736b5f73746f726167655f7573656418032001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641804200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180520012804420230015214636f6d7075746542616e64776964746855736564122a0a1173746174655f6d65726b6c655f726f6f7418062001280c520f73746174654d65726b6c65526f6f7412330a066576656e747318072003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312570a147472616e73616374696f6e5f726563656970747318082003280b32242e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f7265636569707452137472616e73616374696f6e526563656970747312120a046c6f677318092003280952046c6f677342375a356769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f732f70726f746f636f6c620670726f746f33" ); + entry->set_value( protocol_descriptor ); + *entry->mutable_space() = chain::state::space::metadata(); + + std::map< std::string, uint64_t > thunk_compute{ + { "apply_block", 16'465}, + { "apply_call_contract_operation", 685}, + { "apply_set_system_call_operation", 136'081}, + {"apply_set_system_contract_operation", 8'692}, + { "apply_transaction", 12'542}, + { "apply_upload_contract_operation", 3'130}, + { "call", 3'573}, + { "check_authority", 12'653}, + { "check_system_authority", 12'750}, + { "consume_account_rc", 735}, + { "consume_block_resources", 753}, + { "deserialize_message_per_byte", 1}, + { "deserialize_multihash_base", 102}, + { "deserialize_multihash_per_byte", 404}, + { "event", 1'222}, + { "event_per_impacted", 101}, + { "exit", 11'636}, + { "get_account_nonce", 821}, + { "get_account_rc", 1'072}, + { "get_arguments", 809}, + { "get_block", 1'134}, + { "get_block_field", 1'417}, + { "get_caller", 825}, + { "get_chain_id", 1'046}, + { "get_contract_id", 778}, + { "get_head_info", 2'099}, + { "get_last_irreversible_block", 772}, + { "get_next_object", 11'181}, + { "get_object", 1'054}, + { "get_operation", 1'081}, + { "get_prev_object", 15'445}, + { "get_resource_limits", 1'227}, + { "get_transaction", 1'584}, + { "get_transaction_field", 1'530}, + { "hash", 1'570}, + { "keccak_256_base", 1'406}, + { "keccak_256_per_byte", 1}, + { "log", 738}, + { "object_serialization_per_byte", 1}, + { "post_block_callback", 741}, + { "post_transaction_callback", 721}, + { "pre_block_callback", 730}, + { "pre_transaction_callback", 729}, + { "process_block_signature", 4'499}, + { "put_object", 1'057}, + { "recover_public_key", 29'630}, + { "remove_object", 893}, + { "ripemd_160_base", 1'343}, + { "ripemd_160_per_byte", 1}, + { "set_account_nonce", 749}, + { "sha1_base", 1'151}, + { "sha1_per_byte", 1}, + { "sha2_256_base", 1'385}, + { "sha2_256_per_byte", 1}, + { "sha2_512_base", 1'445}, + { "sha2_512_per_byte", 1}, + { "verify_account_nonce", 822}, + { "verify_merkle_root", 1}, + { "verify_signature", 762}, + { "verify_vrf_proof", 144'067}, + }; + + koinos::chain::compute_bandwidth_registry cbr; + + for( const auto& [ key, value ]: thunk_compute ) + { + auto centry = cbr.add_entries(); + centry->set_name( key ); + centry->set_compute( value ); + } + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::compute_bandwidth_registry ); + entry->set_value( util::converter::as< std::string >( cbr ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::block_hash_code ); + entry->set_value( util::converter::as< std::string >( + unsigned_varint{ std::underlying_type_t< crypto::multicodec >( crypto::multicodec::sha2_256 ) } ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + db.open( + temp, + [ & ]( state_db::state_node_ptr root ) { - auto centry = cbr.add_entries(); - centry->set_name( key ); - centry->set_compute( value ); - } - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::compute_bandwidth_registry ); - entry->set_value( util::converter::as< std::string >( cbr ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::block_hash_code ); - entry->set_value( util::converter::as< std::string >( unsigned_varint{ std::underlying_type_t< crypto::multicodec >( crypto::multicodec::sha2_256 ) } ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - db.open( - temp, - [&]( state_db::state_node_ptr root ) - { - // Write genesis objects into the database - for ( const auto& entry : _genesis_data.entries() ) - { - KOINOS_ASSERT( - !root->get_object( entry.space(), entry.key() ), - koinos::chain::unexpected_state_exception, - "encountered unexpected object in initial state" - ); - - root->put_object( entry.space(), entry.key(), &entry.value() ); - } - LOG(info) << "Wrote " << _genesis_data.entries().size() << " genesis objects into new database"; - - // Read genesis public key from the database, assert its existence at the correct location - KOINOS_ASSERT( - root->get_object( chain::state::space::metadata(), chain::state::key::genesis_key ), - koinos::chain::unexpected_state_exception, - "could not find genesis public key in database" - ); - - // Calculate and write the chain ID into the database - auto chain_id = crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ); - LOG(info) << "Calculated chain ID: " << chain_id; - auto chain_id_str = util::converter::as< std::string >( chain_id ); - KOINOS_ASSERT( - !root->get_object( chain::state::space::metadata(), chain::state::key::chain_id ), - koinos::chain::unexpected_state_exception, - "encountered unexpected chain id in initial state" - ); - root->put_object( chain::state::space::metadata(), chain::state::key::chain_id, &chain_id_str ); - LOG(info) << "Wrote chain ID into new database"; - }, - &state_db::fifo_comparator, - db.get_unique_lock() ); - - ctx.set_state_node( db.create_writable_node( db.get_head( db.get_shared_lock() )->id(), crypto::hash( crypto::multicodec::sha2_256, 1 ), protocol::block_header(), db.get_shared_lock() ) ); - ctx.reset_cache(); - ctx.push_frame( chain::stack_frame { - .contract_id = "stack_tests"s, - .call_privilege = chain::privilege::kernel_mode - } ); - - ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); - - vm_backend->initialize(); - - - _stack_assertion_private_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "stack_assertion"s ) ); - koinos::protocol::upload_contract_operation op; - op.set_contract_id( util::converter::as< std::string >( _stack_assertion_private_key.get_public_key().to_address_bytes() ) ); - op.set_bytecode( get_stack_assertion_wasm() ); - - koinos::protocol::transaction trx; - sign_transaction( trx, _stack_assertion_private_key ); - ctx.set_transaction( trx ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); - } - - ~stack_fixture() - { - boost::log::core::get()->remove_all_sinks(); - ctx.clear_state_node(); - db.close( db.get_unique_lock() ); - std::filesystem::remove_all( temp ); - } - - void set_transaction_merkle_roots( protocol::transaction& transaction, crypto::multicodec code, crypto::digest_size size = crypto::digest_size( 0 ) ) - { - std::vector< crypto::multihash > operations; - operations.reserve( transaction.operations().size() ); - - for ( const auto& op : transaction.operations() ) - { - operations.emplace_back( crypto::hash( code, op, size ) ); - } - - auto operation_merkle_tree = crypto::merkle_tree( code, operations ); - transaction.mutable_header()->set_operation_merkle_root( util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); - } - - void sign_transaction( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ); - - std::filesystem::path temp; - koinos::state_db::database db; - std::shared_ptr< koinos::vm_manager::vm_backend > vm_backend; - koinos::chain::execution_context ctx; - koinos::chain::host_api host; - koinos::crypto::private_key _genesis_private_key; - koinos::crypto::private_key _stack_assertion_private_key; - chain::genesis_data _genesis_data; + // Write genesis objects into the database + for( const auto& entry: _genesis_data.entries() ) + { + KOINOS_ASSERT( !root->get_object( entry.space(), entry.key() ), + koinos::chain::unexpected_state_exception, + "encountered unexpected object in initial state" ); + + root->put_object( entry.space(), entry.key(), &entry.value() ); + } + LOG( info ) << "Wrote " << _genesis_data.entries().size() << " genesis objects into new database"; + + // Read genesis public key from the database, assert its existence at the correct location + KOINOS_ASSERT( root->get_object( chain::state::space::metadata(), chain::state::key::genesis_key ), + koinos::chain::unexpected_state_exception, + "could not find genesis public key in database" ); + + // Calculate and write the chain ID into the database + auto chain_id = crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ); + LOG( info ) << "Calculated chain ID: " << chain_id; + auto chain_id_str = util::converter::as< std::string >( chain_id ); + KOINOS_ASSERT( !root->get_object( chain::state::space::metadata(), chain::state::key::chain_id ), + koinos::chain::unexpected_state_exception, + "encountered unexpected chain id in initial state" ); + root->put_object( chain::state::space::metadata(), chain::state::key::chain_id, &chain_id_str ); + LOG( info ) << "Wrote chain ID into new database"; + }, + &state_db::fifo_comparator, + db.get_unique_lock() ); + + ctx.set_state_node( db.create_writable_node( db.get_head( db.get_shared_lock() )->id(), + crypto::hash( crypto::multicodec::sha2_256, 1 ), + protocol::block_header(), + db.get_shared_lock() ) ); + ctx.reset_cache(); + ctx.push_frame( + chain::stack_frame{ .contract_id = "stack_tests"s, .call_privilege = chain::privilege::kernel_mode } ); + + ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); + + vm_backend->initialize(); + + _stack_assertion_private_key = + crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "stack_assertion"s ) ); + koinos::protocol::upload_contract_operation op; + op.set_contract_id( + util::converter::as< std::string >( _stack_assertion_private_key.get_public_key().to_address_bytes() ) ); + op.set_bytecode( get_stack_assertion_wasm() ); + + koinos::protocol::transaction trx; + sign_transaction( trx, _stack_assertion_private_key ); + ctx.set_transaction( trx ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); + } + + ~stack_fixture() + { + boost::log::core::get()->remove_all_sinks(); + ctx.clear_state_node(); + db.close( db.get_unique_lock() ); + std::filesystem::remove_all( temp ); + } + + void set_transaction_merkle_roots( protocol::transaction& transaction, + crypto::multicodec code, + crypto::digest_size size = crypto::digest_size( 0 ) ) + { + std::vector< crypto::multihash > operations; + operations.reserve( transaction.operations().size() ); + + for( const auto& op: transaction.operations() ) + { + operations.emplace_back( crypto::hash( code, op, size ) ); + } + + auto operation_merkle_tree = crypto::merkle_tree( code, operations ); + transaction.mutable_header()->set_operation_merkle_root( + util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); + } + + void sign_transaction( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ); + + std::filesystem::path temp; + koinos::state_db::database db; + std::shared_ptr< koinos::vm_manager::vm_backend > vm_backend; + koinos::chain::execution_context ctx; + koinos::chain::host_api host; + koinos::crypto::private_key _genesis_private_key; + koinos::crypto::private_key _stack_assertion_private_key; + chain::genesis_data _genesis_data; }; void stack_fixture::sign_transaction( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ) { - // Signature is on the hash of the active data - transaction.mutable_header()->set_payer( transaction_signing_key.get_public_key().to_address_bytes() ); - auto id_mh = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); - transaction.set_id( util::converter::as< std::string >( id_mh ) ); - transaction.clear_signatures(); - transaction.add_signatures( util::converter::as< std::string >( transaction_signing_key.sign_compact( id_mh ) ) ); + // Signature is on the hash of the active data + transaction.mutable_header()->set_payer( transaction_signing_key.get_public_key().to_address_bytes() ); + auto id_mh = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); + transaction.set_id( util::converter::as< std::string >( id_mh ) ); + transaction.clear_signatures(); + transaction.add_signatures( util::converter::as< std::string >( transaction_signing_key.sign_compact( id_mh ) ) ); } namespace koinos::chain::thunk { void dummy_thunk( execution_context& ctx, const std::string& ) { - system_call::event( ctx, "foo", "bar", std::vector< std::string >() ); + system_call::event( ctx, "foo", "bar", std::vector< std::string >() ); } -} // koinos::chain::thunk +} // namespace koinos::chain::thunk BOOST_FIXTURE_TEST_SUITE( stack_tests, stack_fixture ) BOOST_AUTO_TEST_CASE( simple_user_contract ) -{ try { - /** - * Top User Contract (User Mode, read from DB) - * | Call Contract (Kernel Mode) - * | Apply Call Contract Operation (Drop to User Mode) - * V Apply Transaction (Kernel Mode) - */ - - // User contract checks caller is in user mode (apply_transaction dropping to user) - // And then asserts it is in user mode - - auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); - koinos::protocol::transaction trx; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - protocol::upload_contract_operation upload_op; - upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_user_from_user_wasm() ); - sign_transaction( trx, user_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - trx.mutable_header()->set_rc_limit( 1'000'000 ); - trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); - auto call_op = trx.add_operations()->mutable_call_contract(); - call_op->set_contract_id( upload_op.contract_id() ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx, user_key ); - - ctx.set_transaction( trx ); - try - { +{ + try + { + /** + * Top User Contract (User Mode, read from DB) + * | Call Contract (Kernel Mode) + * | Apply Call Contract Operation (Drop to User Mode) + * V Apply Transaction (Kernel Mode) + */ + + // User contract checks caller is in user mode (apply_transaction dropping to user) + // And then asserts it is in user mode + + auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); + koinos::protocol::transaction trx; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + protocol::upload_contract_operation upload_op; + upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_user_from_user_wasm() ); + sign_transaction( trx, user_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + trx.mutable_header()->set_rc_limit( 1'000'000 ); + trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); + auto call_op = trx.add_operations()->mutable_call_contract(); + call_op->set_contract_id( upload_op.contract_id() ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx, user_key ); + + ctx.set_transaction( trx ); + try + { chain::system_call::apply_transaction( ctx, trx ); - } - catch ( ... ) - { - for ( const auto& message : ctx.chronicler().logs() ) - LOG(error) << message; + } + catch( ... ) + { + for( const auto& message: ctx.chronicler().logs() ) + LOG( error ) << message; throw; - } - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + } + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( syscall_from_user ) -{ try { - /** - * Top System Call (Kernel Mode, read from DB) - * | Call Contract (Kernel Mode) - * | User Code (User Mode, read from DB) - * | Call Contract (Kernel Mode) - * | Apply Call Contract Operation (Drop to User Mode) - * V Apply Transaction (Kernel Mode) - */ - - // Syscall override checks caller is in user mode (user contract calling to syscall) - // And then asserts it is in kernel mode - - auto override_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key"s ) ); - protocol::transaction trx; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - protocol::upload_contract_operation upload_op; - upload_op.set_contract_id( util::converter::as< std::string >( override_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_system_from_user_wasm() ); - sign_transaction( trx, override_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( upload_op.contract_id() ); - set_system_op.set_system_contract( true ); - - sign_transaction( trx, _genesis_private_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - - protocol::set_system_call_operation set_syscall_op; - set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - - auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); - upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_call_system_call_wasm() ); - sign_transaction( trx, user_key ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - // We need to rebuild the cache after a system call override - ctx.reset_cache(); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - - trx.mutable_header()->set_rc_limit( 100'000'000 ); - trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); - auto call_op = trx.add_operations()->mutable_call_contract(); - call_op->set_contract_id( upload_op.contract_id() ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx, user_key ); - - ctx.set_transaction( trx ); - try - { +{ + try + { + /** + * Top System Call (Kernel Mode, read from DB) + * | Call Contract (Kernel Mode) + * | User Code (User Mode, read from DB) + * | Call Contract (Kernel Mode) + * | Apply Call Contract Operation (Drop to User Mode) + * V Apply Transaction (Kernel Mode) + */ + + // Syscall override checks caller is in user mode (user contract calling to syscall) + // And then asserts it is in kernel mode + + auto override_key = + crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key"s ) ); + protocol::transaction trx; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + protocol::upload_contract_operation upload_op; + upload_op.set_contract_id( util::converter::as< std::string >( override_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_system_from_user_wasm() ); + sign_transaction( trx, override_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( upload_op.contract_id() ); + set_system_op.set_system_contract( true ); + + sign_transaction( trx, _genesis_private_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + + protocol::set_system_call_operation set_syscall_op; + set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + + auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); + upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_call_system_call_wasm() ); + sign_transaction( trx, user_key ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + // We need to rebuild the cache after a system call override + ctx.reset_cache(); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + + trx.mutable_header()->set_rc_limit( 100'000'000 ); + trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); + auto call_op = trx.add_operations()->mutable_call_contract(); + call_op->set_contract_id( upload_op.contract_id() ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx, user_key ); + + ctx.set_transaction( trx ); + try + { chain::system_call::apply_transaction( ctx, trx ); - } - catch ( ... ) - { - for ( const auto& message : ctx.chronicler().logs() ) - LOG(error) << message; + } + catch( ... ) + { + for( const auto& message: ctx.chronicler().logs() ) + LOG( error ) << message; throw; - } + } - set_system_op.set_contract_id( call_op->contract_id() ); - sign_transaction( trx, _genesis_private_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + set_system_op.set_contract_id( call_op->contract_id() ); + sign_transaction( trx, _genesis_private_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - nonce_value.set_uint64_value( 2 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx, user_key ); + nonce_value.set_uint64_value( 2 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx, user_key ); - ctx.set_transaction( trx ); - try - { + ctx.set_transaction( trx ); + try + { chain::system_call::apply_transaction( ctx, trx ); BOOST_FAIL( "no reversion when called from system context" ); - } - catch ( ... ) { /* do nothing, success */ } - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + } + catch( ... ) + { /* do nothing, success */ + } + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( user_from_user ) { - /** - * Top User Code (User Mode, read from DB) - * | Call Contract (Kernel Mode) - * | User Code (User Mode, read from DB) - * | Call Contract (Kernel Mode) - * | Apply Call Contract Operation (Drop to User Mode) - * V Apply Transaction (Kernel Mode) - */ - // User contract checks if being called from user mode then asserts it is in user mode - - auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); - koinos::protocol::transaction trx; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - protocol::upload_contract_operation upload_op; - upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_user_from_user_wasm() ); - sign_transaction( trx, user_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - auto calling_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "calling_key"s ) ); - upload_op.set_contract_id( util::converter::as< std::string >( calling_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_call_contract_wasm() ); - sign_transaction( trx, calling_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - trx.mutable_header()->set_rc_limit( 1'000'000 ); - trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); - auto call_op = trx.add_operations()->mutable_call_contract(); - call_op->set_contract_id( upload_op.contract_id() ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx, calling_key ); - - ctx.set_transaction( trx ); - try - { - chain::system_call::apply_transaction( ctx, trx ); - } - catch ( ... ) - { - for ( const auto& message : ctx.chronicler().logs() ) - LOG(error) << message; - - throw; - } - - protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( upload_op.contract_id() ); - set_system_op.set_system_contract( true ); - - sign_transaction( trx, _genesis_private_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - - trx.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx, user_key ); - - ctx.set_transaction( trx ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, trx ), chain::reversion ); + /** + * Top User Code (User Mode, read from DB) + * | Call Contract (Kernel Mode) + * | User Code (User Mode, read from DB) + * | Call Contract (Kernel Mode) + * | Apply Call Contract Operation (Drop to User Mode) + * V Apply Transaction (Kernel Mode) + */ + // User contract checks if being called from user mode then asserts it is in user mode + + auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); + koinos::protocol::transaction trx; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + protocol::upload_contract_operation upload_op; + upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_user_from_user_wasm() ); + sign_transaction( trx, user_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + auto calling_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "calling_key"s ) ); + upload_op.set_contract_id( util::converter::as< std::string >( calling_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_call_contract_wasm() ); + sign_transaction( trx, calling_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + trx.mutable_header()->set_rc_limit( 1'000'000 ); + trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); + auto call_op = trx.add_operations()->mutable_call_contract(); + call_op->set_contract_id( upload_op.contract_id() ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx, calling_key ); + + ctx.set_transaction( trx ); + try + { + chain::system_call::apply_transaction( ctx, trx ); + } + catch( ... ) + { + for( const auto& message: ctx.chronicler().logs() ) + LOG( error ) << message; + + throw; + } + + protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( upload_op.contract_id() ); + set_system_op.set_system_contract( true ); + + sign_transaction( trx, _genesis_private_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx, user_key ); + + ctx.set_transaction( trx ); + KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, trx ), chain::reversion ); } BOOST_AUTO_TEST_CASE( syscall_override_from_thunk ) { - /** - * Top System Call (Kernel Mode, read from DB ) - * | Call Contract (Kernel Mode) - * | System Call (Kernel Mode) - * | User Code (User Mode, read from DB) - * | Call Contract (Kernel Mode) - * | Apply Call Contract Operation (Drop to User Mode) - * V Apply Transaction (Kernel Mode) - */ - const_cast< chain::thunk_dispatcher& >( chain::thunk_dispatcher::instance() ).register_thunk< chain::log_arguments, chain::log_result >( 0, chain::thunk::dummy_thunk ); - auto cbr = util::converter::to< chain::compute_bandwidth_registry >( chain::system_call::get_object( ctx, chain::state::space::metadata(), chain::state::key::compute_bandwidth_registry ).value() ); - auto centry = cbr.add_entries(); - centry->set_name( "nop" ); - centry->set_compute( 0 ); - - chain::system_call::put_object( ctx, chain::state::space::metadata(), chain::state::key::compute_bandwidth_registry, util::converter::as< std::string >( cbr ) ); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - ctx.reset_cache(); - - // Upload and override event - auto override_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key"s ) ); - protocol::transaction trx; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - protocol::upload_contract_operation upload_op; - upload_op.set_contract_id( util::converter::as< std::string >( override_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_system_from_system_wasm() ); - sign_transaction( trx, override_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( upload_op.contract_id() ); - set_system_op.set_system_contract( true ); - - sign_transaction( trx, _genesis_private_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - - protocol::set_system_call_operation set_syscall_op; - set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::event ) ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - - // Override set_contract_result with dummy_thunk - set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); - set_syscall_op.mutable_target()->set_thunk_id( 0 ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - - // Upload user contract - auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); - upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_call_system_call_wasm() ); - sign_transaction( trx, user_key ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - // Call user contract - // We need to update the state node after a system call override - ctx.reset_cache(); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - - trx.mutable_header()->set_rc_limit( 1'000'000 ); - trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); - auto call_op = trx.add_operations()->mutable_call_contract(); - call_op->set_contract_id( upload_op.contract_id() ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx, user_key ); - - ctx.set_transaction( trx ); - try - { - chain::system_call::apply_transaction( ctx, trx ); - } - catch ( ... ) - { - for ( const auto& message : ctx.chronicler().logs() ) - LOG(error) << message; - - throw; - } + /** + * Top System Call (Kernel Mode, read from DB ) + * | Call Contract (Kernel Mode) + * | System Call (Kernel Mode) + * | User Code (User Mode, read from DB) + * | Call Contract (Kernel Mode) + * | Apply Call Contract Operation (Drop to User Mode) + * V Apply Transaction (Kernel Mode) + */ + const_cast< chain::thunk_dispatcher& >( chain::thunk_dispatcher::instance() ) + .register_thunk< chain::log_arguments, chain::log_result >( 0, chain::thunk::dummy_thunk ); + auto cbr = util::converter::to< chain::compute_bandwidth_registry >( + chain::system_call::get_object( ctx, + chain::state::space::metadata(), + chain::state::key::compute_bandwidth_registry ) + .value() ); + auto centry = cbr.add_entries(); + centry->set_name( "nop" ); + centry->set_compute( 0 ); + + chain::system_call::put_object( ctx, + chain::state::space::metadata(), + chain::state::key::compute_bandwidth_registry, + util::converter::as< std::string >( cbr ) ); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + ctx.reset_cache(); + + // Upload and override event + auto override_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key"s ) ); + protocol::transaction trx; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + protocol::upload_contract_operation upload_op; + upload_op.set_contract_id( util::converter::as< std::string >( override_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_system_from_system_wasm() ); + sign_transaction( trx, override_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( upload_op.contract_id() ); + set_system_op.set_system_contract( true ); + + sign_transaction( trx, _genesis_private_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + + protocol::set_system_call_operation set_syscall_op; + set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::event ) ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + + // Override set_contract_result with dummy_thunk + set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); + set_syscall_op.mutable_target()->set_thunk_id( 0 ); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + + // Upload user contract + auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); + upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_call_system_call_wasm() ); + sign_transaction( trx, user_key ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + // Call user contract + // We need to update the state node after a system call override + ctx.reset_cache(); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + + trx.mutable_header()->set_rc_limit( 1'000'000 ); + trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); + auto call_op = trx.add_operations()->mutable_call_contract(); + call_op->set_contract_id( upload_op.contract_id() ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx, user_key ); + + ctx.set_transaction( trx ); + try + { + chain::system_call::apply_transaction( ctx, trx ); + } + catch( ... ) + { + for( const auto& message: ctx.chronicler().logs() ) + LOG( error ) << message; + + throw; + } } BOOST_AUTO_TEST_CASE( syscall_override_from_syscall_override ) { - /** - * Top System Call (Kernel Mode, read from DB ) - * | Call Contract (Kernel Mode) - * | System Call (Kernel Mode, read from DB) - * | Call Contract (Kernel Mode) - * | User Code (User Mode, read from DB) - * | Call Contract (Kernel Mode) - * | Apply Call Contract Operation (Drop to User Mode) - * V Apply Transaction (Kernel Mode) - */ - - // Upload and override event - auto override_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key"s ) ); - protocol::transaction trx; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - protocol::upload_contract_operation upload_op; - upload_op.set_contract_id( util::converter::as< std::string >( override_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_system_from_system_wasm() ); - sign_transaction( trx, override_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( upload_op.contract_id() ); - set_system_op.set_system_contract( true ); - - sign_transaction( trx, _genesis_private_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - - protocol::set_system_call_operation set_syscall_op; - set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::event ) ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - - // Upload and override set_contract_result - auto override_key2 = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key2"s ) ); - upload_op.set_contract_id( util::converter::as< std::string >( override_key2.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_call_system_call2_wasm() ); - sign_transaction( trx, override_key2 ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - set_system_op.set_contract_id( upload_op.contract_id() ); - set_system_op.set_system_contract( true ); - - sign_transaction( trx, _genesis_private_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - - set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - - // Upload user contract - auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); - upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_call_system_call_wasm() ); - sign_transaction( trx, user_key ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - // Call user contract - // We need to rebuild the cache after a system call override - ctx.reset_cache(); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - - trx.mutable_header()->set_rc_limit( 1'000'000 ); - trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); - auto call_op = trx.add_operations()->mutable_call_contract(); - call_op->set_contract_id( upload_op.contract_id() ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx, user_key ); - - ctx.set_transaction( trx ); - try - { - chain::system_call::apply_transaction( ctx, trx ); - } - catch ( ... ) - { - for ( const auto& message : ctx.chronicler().logs() ) - LOG(error) << message; - - throw; - } + /** + * Top System Call (Kernel Mode, read from DB ) + * | Call Contract (Kernel Mode) + * | System Call (Kernel Mode, read from DB) + * | Call Contract (Kernel Mode) + * | User Code (User Mode, read from DB) + * | Call Contract (Kernel Mode) + * | Apply Call Contract Operation (Drop to User Mode) + * V Apply Transaction (Kernel Mode) + */ + + // Upload and override event + auto override_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key"s ) ); + protocol::transaction trx; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + protocol::upload_contract_operation upload_op; + upload_op.set_contract_id( util::converter::as< std::string >( override_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_system_from_system_wasm() ); + sign_transaction( trx, override_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( upload_op.contract_id() ); + set_system_op.set_system_contract( true ); + + sign_transaction( trx, _genesis_private_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + + protocol::set_system_call_operation set_syscall_op; + set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::event ) ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + + // Upload and override set_contract_result + auto override_key2 = + crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key2"s ) ); + upload_op.set_contract_id( util::converter::as< std::string >( override_key2.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_call_system_call2_wasm() ); + sign_transaction( trx, override_key2 ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + set_system_op.set_contract_id( upload_op.contract_id() ); + set_system_op.set_system_contract( true ); + + sign_transaction( trx, _genesis_private_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + + set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + + // Upload user contract + auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); + upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_call_system_call_wasm() ); + sign_transaction( trx, user_key ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + // Call user contract + // We need to rebuild the cache after a system call override + ctx.reset_cache(); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + + trx.mutable_header()->set_rc_limit( 1'000'000 ); + trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); + auto call_op = trx.add_operations()->mutable_call_contract(); + call_op->set_contract_id( upload_op.contract_id() ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx, user_key ); + + ctx.set_transaction( trx ); + try + { + chain::system_call::apply_transaction( ctx, trx ); + } + catch( ... ) + { + for( const auto& message: ctx.chronicler().logs() ) + LOG( error ) << message; + + throw; + } } BOOST_AUTO_TEST_CASE( system_contract_from_syscall_override ) { - /** - * Top System Contract (Kernel Mode, read from DB ) - * | Call Contract (Kernel Mode) - * | System Call (Kernel Mode, read from DB) - * | Call Contract (Kernel Mode) - * | User Code (User Mode, read from DB) - * | Call Contract (Kernel Mode) - * | Apply Call Contract Operation (Drop to User Mode) - * V Apply Transaction (Kernel Mode) - */ - - // Upload and override set_contract_result - auto override_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key"s ) ); - protocol::transaction trx; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - protocol::upload_contract_operation upload_op; - upload_op.set_contract_id( util::converter::as< std::string >( override_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_call_contract_wasm() ); - sign_transaction( trx, override_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( upload_op.contract_id() ); - set_system_op.set_system_contract( true ); - - sign_transaction( trx, _genesis_private_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - - protocol::set_system_call_operation set_syscall_op; - set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - - // Upload system contract - auto system_contract = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); - upload_op.set_contract_id( util::converter::as< std::string >( system_contract.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_system_from_system_wasm() ); - sign_transaction( trx, system_contract ); - ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - set_system_op.set_contract_id( upload_op.contract_id() ); - set_system_op.set_system_contract( true ); - - sign_transaction( trx, _genesis_private_key ); - ctx.set_transaction( trx ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - - // Upload user contract - auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "user_key"s ) ); - upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); - upload_op.set_bytecode( get_call_system_call_wasm() ); - sign_transaction( trx, user_key ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - // Call user contract - // We need to rebuild the cache after a system call override - ctx.reset_cache(); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - - trx.mutable_header()->set_rc_limit( 1'000'000 ); - trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); - auto call_op = trx.add_operations()->mutable_call_contract(); - call_op->set_contract_id( upload_op.contract_id() ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx, user_key ); - - ctx.set_transaction( trx ); - try - { - chain::system_call::apply_transaction( ctx, trx ); - } - catch ( ... ) - { - for ( const auto& message : ctx.chronicler().logs() ) - LOG(error) << message; - - throw; - } + /** + * Top System Contract (Kernel Mode, read from DB ) + * | Call Contract (Kernel Mode) + * | System Call (Kernel Mode, read from DB) + * | Call Contract (Kernel Mode) + * | User Code (User Mode, read from DB) + * | Call Contract (Kernel Mode) + * | Apply Call Contract Operation (Drop to User Mode) + * V Apply Transaction (Kernel Mode) + */ + + // Upload and override set_contract_result + auto override_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "override_key"s ) ); + protocol::transaction trx; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + protocol::upload_contract_operation upload_op; + upload_op.set_contract_id( util::converter::as< std::string >( override_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_call_contract_wasm() ); + sign_transaction( trx, override_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( upload_op.contract_id() ); + set_system_op.set_system_contract( true ); + + sign_transaction( trx, _genesis_private_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + + protocol::set_system_call_operation set_syscall_op; + set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + + // Upload system contract + auto system_contract = + crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "contract_key"s ) ); + upload_op.set_contract_id( + util::converter::as< std::string >( system_contract.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_system_from_system_wasm() ); + sign_transaction( trx, system_contract ); + ctx.set_transaction( trx ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + set_system_op.set_contract_id( upload_op.contract_id() ); + set_system_op.set_system_contract( true ); + + sign_transaction( trx, _genesis_private_key ); + ctx.set_transaction( trx ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + + // Upload user contract + auto user_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "user_key"s ) ); + upload_op.set_contract_id( util::converter::as< std::string >( user_key.get_public_key().to_address_bytes() ) ); + upload_op.set_bytecode( get_call_system_call_wasm() ); + sign_transaction( trx, user_key ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + // Call user contract + // We need to rebuild the cache after a system call override + ctx.reset_cache(); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + + trx.mutable_header()->set_rc_limit( 1'000'000 ); + trx.mutable_header()->set_chain_id( chain::system_call::get_chain_id( ctx ) ); + auto call_op = trx.add_operations()->mutable_call_contract(); + call_op->set_contract_id( upload_op.contract_id() ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx, user_key ); + + ctx.set_transaction( trx ); + try + { + chain::system_call::apply_transaction( ctx, trx ); + } + catch( ... ) + { + for( const auto& message: ctx.chronicler().logs() ) + LOG( error ) << message; + + throw; + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/thunk_test.cpp b/tests/thunk_test.cpp index 6ddef535..1602a1ac 100644 --- a/tests/thunk_test.cpp +++ b/tests/thunk_test.cpp @@ -7,23 +7,23 @@ #include #include -#include #include +#include #include #include #include -#include -#include #include +#include #include +#include #include -#include #include #include #include +#include #include @@ -43,2459 +43,2940 @@ using namespace std::string_literals; struct thunk_fixture { - thunk_fixture() : + thunk_fixture(): vm_backend( koinos::vm_manager::get_vm_backend() ), ctx( vm_backend, chain::intent::block_application ), host( ctx ) - { - KOINOS_ASSERT( vm_backend, koinos::chain::unknown_backend_exception, "could not get vm backend" ); - - initialize_logging( "koinos_test", {}, "info" ); - - temp = std::filesystem::temp_directory_path() / boost::filesystem::unique_path().string(); - std::filesystem::create_directory( temp ); - - auto seed = "test seed"s; - _signing_private_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, seed ) ); - - auto entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::genesis_key ); - entry->set_value( _signing_private_key.get_public_key().to_address_bytes() ); - *entry->mutable_space() = chain::state::space::metadata(); - - koinos::chain::resource_limit_data rd; - - rd.set_disk_storage_cost( 10 ); - rd.set_disk_storage_limit( 500'800 ); - - rd.set_network_bandwidth_cost( 5 ); - rd.set_network_bandwidth_limit( 1'048'576 ); - - rd.set_compute_bandwidth_cost( 1 ); - rd.set_compute_bandwidth_limit( 100'000'000 ); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::resource_limit_data ); - entry->set_value( util::converter::as< std::string >( rd ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - koinos::chain::max_account_resources mar; - - mar.set_value( 10'000'000 ); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::max_account_resources ); - entry->set_value( util::converter::as< std::string >( mar ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::protocol_descriptor ); - - // protoc --experimental_allow_proto3_optional --descriptor_set_out=build/koinos_protocol.pb --include_imports `find koinos -name 'protocol.proto'` - std::string protocol_descriptor = util::from_hex< std::string >( "0x0ac33b0a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f120f676f6f676c652e70726f746f627566224d0a1146696c6544657363726970746f7253657412380a0466696c6518012003280b32242e676f6f676c652e70726f746f6275662e46696c6544657363726970746f7250726f746f520466696c6522e4040a1346696c6544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512180a077061636b61676518022001280952077061636b616765121e0a0a646570656e64656e6379180320032809520a646570656e64656e6379122b0a117075626c69635f646570656e64656e6379180a2003280552107075626c6963446570656e64656e637912270a0f7765616b5f646570656e64656e6379180b20032805520e7765616b446570656e64656e637912430a0c6d6573736167655f7479706518042003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520b6d6573736167655479706512410a09656e756d5f7479706518052003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512410a077365727669636518062003280b32272e676f6f676c652e70726f746f6275662e5365727669636544657363726970746f7250726f746f52077365727669636512430a09657874656e73696f6e18072003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12360a076f7074696f6e7318082001280b321c2e676f6f676c652e70726f746f6275662e46696c654f7074696f6e7352076f7074696f6e7312490a10736f757263655f636f64655f696e666f18092001280b321f2e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f520e736f75726365436f6465496e666f12160a0673796e746178180c20012809520673796e74617822b9060a0f44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123b0a056669656c6418022003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f52056669656c6412430a09657874656e73696f6e18062003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12410a0b6e65737465645f7479706518032003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520a6e65737465645479706512410a09656e756d5f7479706518042003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512580a0f657874656e73696f6e5f72616e676518052003280b322f2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e457874656e73696f6e52616e6765520e657874656e73696f6e52616e676512440a0a6f6e656f665f6465636c18082003280b32252e676f6f676c652e70726f746f6275662e4f6e656f6644657363726970746f7250726f746f52096f6e656f664465636c12390a076f7074696f6e7318072001280b321f2e676f6f676c652e70726f746f6275662e4d6573736167654f7074696f6e7352076f7074696f6e7312550a0e72657365727665645f72616e676518092003280b322e2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180a20032809520c72657365727665644e616d651a7a0a0e457874656e73696f6e52616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e6412400a076f7074696f6e7318032001280b32262e676f6f676c652e70726f746f6275662e457874656e73696f6e52616e67654f7074696f6e7352076f7074696f6e731a370a0d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e64227c0a15457874656e73696f6e52616e67654f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c1060a144669656c6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218032001280552066e756d62657212410a056c6162656c18042001280e322b2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e4c6162656c52056c6162656c123e0a047479706518052001280e322a2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e54797065520474797065121b0a09747970655f6e616d651806200128095208747970654e616d65121a0a08657874656e6465651802200128095208657874656e64656512230a0d64656661756c745f76616c7565180720012809520c64656661756c7456616c7565121f0a0b6f6e656f665f696e646578180920012805520a6f6e656f66496e646578121b0a096a736f6e5f6e616d65180a2001280952086a736f6e4e616d6512370a076f7074696f6e7318082001280b321d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7352076f7074696f6e7312270a0f70726f746f335f6f7074696f6e616c181120012808520e70726f746f334f7074696f6e616c22b6020a0454797065120f0a0b545950455f444f55424c451001120e0a0a545950455f464c4f41541002120e0a0a545950455f494e5436341003120f0a0b545950455f55494e5436341004120e0a0a545950455f494e543332100512100a0c545950455f46495845443634100612100a0c545950455f464958454433321007120d0a09545950455f424f4f4c1008120f0a0b545950455f535452494e471009120e0a0a545950455f47524f5550100a12100a0c545950455f4d455353414745100b120e0a0a545950455f4259544553100c120f0a0b545950455f55494e543332100d120d0a09545950455f454e554d100e12110a0d545950455f5346495845443332100f12110a0d545950455f53464958454436341010120f0a0b545950455f53494e5433321011120f0a0b545950455f53494e543634101222430a054c6162656c12120a0e4c4142454c5f4f5054494f4e414c100112120a0e4c4142454c5f5245515549524544100212120a0e4c4142454c5f5245504541544544100322630a144f6e656f6644657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512370a076f7074696f6e7318022001280b321d2e676f6f676c652e70726f746f6275662e4f6e656f664f7074696f6e7352076f7074696f6e7322e3020a13456e756d44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123f0a0576616c756518022003280b32292e676f6f676c652e70726f746f6275662e456e756d56616c756544657363726970746f7250726f746f520576616c756512360a076f7074696f6e7318032001280b321c2e676f6f676c652e70726f746f6275662e456e756d4f7074696f6e7352076f7074696f6e73125d0a0e72657365727665645f72616e676518042003280b32362e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f2e456e756d526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180520032809520c72657365727665644e616d651a3b0a11456e756d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e642283010a18456e756d56616c756544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218022001280552066e756d626572123b0a076f7074696f6e7318032001280b32212e676f6f676c652e70726f746f6275662e456e756d56616c75654f7074696f6e7352076f7074696f6e7322a7010a165365727669636544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123e0a066d6574686f6418022003280b32262e676f6f676c652e70726f746f6275662e4d6574686f6444657363726970746f7250726f746f52066d6574686f6412390a076f7074696f6e7318032001280b321f2e676f6f676c652e70726f746f6275662e536572766963654f7074696f6e7352076f7074696f6e732289020a154d6574686f6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65121d0a0a696e7075745f747970651802200128095209696e70757454797065121f0a0b6f75747075745f74797065180320012809520a6f75747075745479706512380a076f7074696f6e7318042001280b321e2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e7352076f7074696f6e7312300a10636c69656e745f73747265616d696e671805200128083a0566616c7365520f636c69656e7453747265616d696e6712300a107365727665725f73747265616d696e671806200128083a0566616c7365520f73657276657253747265616d696e672291090a0b46696c654f7074696f6e7312210a0c6a6176615f7061636b616765180120012809520b6a6176615061636b61676512300a146a6176615f6f757465725f636c6173736e616d6518082001280952126a6176614f75746572436c6173736e616d6512350a136a6176615f6d756c7469706c655f66696c6573180a200128083a0566616c736552116a6176614d756c7469706c6546696c657312440a1d6a6176615f67656e65726174655f657175616c735f616e645f686173681814200128084202180152196a61766147656e6572617465457175616c73416e6448617368123a0a166a6176615f737472696e675f636865636b5f75746638181b200128083a0566616c736552136a617661537472696e67436865636b5574663812530a0c6f7074696d697a655f666f7218092001280e32292e676f6f676c652e70726f746f6275662e46696c654f7074696f6e732e4f7074696d697a654d6f64653a055350454544520b6f7074696d697a65466f72121d0a0a676f5f7061636b616765180b200128095209676f5061636b61676512350a1363635f67656e657269635f73657276696365731810200128083a0566616c73655211636347656e65726963536572766963657312390a156a6176615f67656e657269635f73657276696365731811200128083a0566616c736552136a61766147656e65726963536572766963657312350a1370795f67656e657269635f73657276696365731812200128083a0566616c73655211707947656e65726963536572766963657312370a147068705f67656e657269635f7365727669636573182a200128083a0566616c7365521270687047656e65726963536572766963657312250a0a646570726563617465641817200128083a0566616c7365520a64657072656361746564122e0a1063635f656e61626c655f6172656e6173181f200128083a0474727565520e6363456e61626c654172656e6173122a0a116f626a635f636c6173735f707265666978182420012809520f6f626a63436c61737350726566697812290a106373686172705f6e616d657370616365182520012809520f6373686172704e616d65737061636512210a0c73776966745f707265666978182720012809520b737769667450726566697812280a107068705f636c6173735f707265666978182820012809520e706870436c61737350726566697812230a0d7068705f6e616d657370616365182920012809520c7068704e616d65737061636512340a167068705f6d657461646174615f6e616d657370616365182c2001280952147068704d657461646174614e616d65737061636512210a0c727562795f7061636b616765182d20012809520b727562795061636b61676512580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e223a0a0c4f7074696d697a654d6f646512090a0553504545441001120d0a09434f44455f53495a45100212100a0c4c4954455f52554e54494d4510032a0908e8071080808080024a040826102722e3020a0e4d6573736167654f7074696f6e73123c0a176d6573736167655f7365745f776972655f666f726d61741801200128083a0566616c736552146d65737361676553657457697265466f726d6174124c0a1f6e6f5f7374616e646172645f64657363726970746f725f6163636573736f721802200128083a0566616c7365521c6e6f5374616e6461726444657363726970746f724163636573736f7212250a0a646570726563617465641803200128083a0566616c7365520a64657072656361746564121b0a096d61705f656e74727918072001280852086d6170456e74727912580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a04080410054a04080510064a04080610074a04080810094a040809100a22e2030a0c4669656c644f7074696f6e7312410a05637479706518012001280e32232e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e43547970653a06535452494e475205637479706512160a067061636b656418022001280852067061636b656412470a066a737479706518062001280e32242e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e4a53547970653a094a535f4e4f524d414c52066a737479706512190a046c617a791805200128083a0566616c736552046c617a7912250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412190a047765616b180a200128083a0566616c736552047765616b12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e222f0a054354797065120a0a06535452494e47100012080a04434f5244100112100a0c535452494e475f5049454345100222350a064a5354797065120d0a094a535f4e4f524d414c1000120d0a094a535f535452494e471001120d0a094a535f4e554d42455210022a0908e8071080808080024a040804100522730a0c4f6e656f664f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c0010a0b456e756d4f7074696f6e73121f0a0b616c6c6f775f616c696173180220012808520a616c6c6f77416c69617312250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a0408051006229e010a10456e756d56616c75654f7074696f6e7312250a0a646570726563617465641801200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e807108080808002229c010a0e536572766963654f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222e0020a0d4d6574686f644f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412710a116964656d706f74656e63795f6c6576656c18222001280e322f2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e732e4964656d706f74656e63794c6576656c3a134944454d504f54454e43595f554e4b4e4f574e52106964656d706f74656e63794c6576656c12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e22500a104964656d706f74656e63794c6576656c12170a134944454d504f54454e43595f554e4b4e4f574e100012130a0f4e4f5f534944455f454646454354531001120e0a0a4944454d504f54454e5410022a0908e807108080808002229a030a13556e696e7465727072657465644f7074696f6e12410a046e616d6518022003280b322d2e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e2e4e616d655061727452046e616d6512290a106964656e7469666965725f76616c7565180320012809520f6964656e74696669657256616c7565122c0a12706f7369746976655f696e745f76616c75651804200128045210706f736974697665496e7456616c7565122c0a126e656761746976655f696e745f76616c756518052001280352106e65676174697665496e7456616c756512210a0c646f75626c655f76616c7565180620012801520b646f75626c6556616c756512210a0c737472696e675f76616c756518072001280c520b737472696e6756616c756512270a0f6167677265676174655f76616c7565180820012809520e61676772656761746556616c75651a4a0a084e616d6550617274121b0a096e616d655f7061727418012002280952086e616d655061727412210a0c69735f657874656e73696f6e180220022808520b6973457874656e73696f6e22a7020a0e536f75726365436f6465496e666f12440a086c6f636174696f6e18012003280b32282e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f2e4c6f636174696f6e52086c6f636174696f6e1ace010a084c6f636174696f6e12160a04706174681801200328054202100152047061746812160a047370616e1802200328054202100152047370616e12290a106c656164696e675f636f6d6d656e7473180320012809520f6c656164696e67436f6d6d656e7473122b0a11747261696c696e675f636f6d6d656e74731804200128095210747261696c696e67436f6d6d656e7473123a0a196c656164696e675f64657461636865645f636f6d6d656e747318062003280952176c656164696e674465746163686564436f6d6d656e747322d1010a1147656e657261746564436f6465496e666f124d0a0a616e6e6f746174696f6e18012003280b322d2e676f6f676c652e70726f746f6275662e47656e657261746564436f6465496e666f2e416e6e6f746174696f6e520a616e6e6f746174696f6e1a6d0a0a416e6e6f746174696f6e12160a047061746818012003280542021001520470617468121f0a0b736f757263655f66696c65180220012809520a736f7572636546696c6512140a05626567696e1803200128055205626567696e12100a03656e641804200128055203656e64427e0a13636f6d2e676f6f676c652e70726f746f627566421044657363726970746f7250726f746f7348015a2d676f6f676c652e676f6c616e672e6f72672f70726f746f6275662f74797065732f64657363726970746f727062f80101a20203475042aa021a476f6f676c652e50726f746f6275662e5265666c656374696f6e0ab5020a146b6f696e6f732f6f7074696f6e732e70726f746f12066b6f696e6f731a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f2a6d0a0a62797465735f74797065120a0a064241534536341000120a0a06424153453538100112070a034845581002120c0a08424c4f434b5f4944100312120a0e5452414e53414354494f4e5f49441004120f0a0b434f4e54524143545f49441005120b0a074144445245535310063a4c0a056274797065121d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7318d086032001280e32122e6b6f696e6f732e62797465735f7479706552056274797065880101422e5a2c6769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f73620670726f746f330aa8190a1e6b6f696e6f732f70726f746f636f6c2f70726f746f636f6c2e70726f746f120f6b6f696e6f732e70726f746f636f6c1a146b6f696e6f732f6f7074696f6e732e70726f746f2290010a0a6576656e745f64617461121a0a0873657175656e636518012001280d520873657175656e6365121c0a06736f7572636518022001280c420480b518055206736f7572636512120a046e616d6518032001280952046e616d6512120a046461746118042001280c52046461746112200a08696d70616374656418052003280c420480b518065208696d706163746564225e0a14636f6e74726163745f63616c6c5f62756e646c6512250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e742292010a1273797374656d5f63616c6c5f746172676574121b0a087468756e6b5f696418012001280d480052077468756e6b496412550a1273797374656d5f63616c6c5f62756e646c6518022001280b32252e6b6f696e6f732e70726f746f636f6c2e636f6e74726163745f63616c6c5f62756e646c654800521073797374656d43616c6c42756e646c6542080a067461726765742294020a1975706c6f61645f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121a0a0862797465636f646518022001280c520862797465636f646512100a03616269180320012809520361626912380a18617574686f72697a65735f63616c6c5f636f6e74726163741804200128085216617574686f72697a657343616c6c436f6e7472616374122a0a11617574686f72697a65735f7573655f7263180520012808520f617574686f72697a65735573655263123c0a1a617574686f72697a65735f75706c6f61645f636f6e74726163741806200128085218617574686f72697a657355706c6f6164436f6e747261637422750a1763616c6c5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e7412120a046172677318032001280c52046172677322710a197365745f73797374656d5f63616c6c5f6f7065726174696f6e12170a0763616c6c5f696418012001280d520663616c6c4964123b0a0674617267657418022001280b32232e6b6f696e6f732e70726f746f636f6c2e73797374656d5f63616c6c5f7461726765745206746172676574226f0a1d7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e7472616374496412270a0f73797374656d5f636f6e7472616374180220012808520e73797374656d436f6e747261637422f1020a096f7065726174696f6e12550a0f75706c6f61645f636f6e747261637418012001280b322a2e6b6f696e6f732e70726f746f636f6c2e75706c6f61645f636f6e74726163745f6f7065726174696f6e4800520e75706c6f6164436f6e7472616374124f0a0d63616c6c5f636f6e747261637418022001280b32282e6b6f696e6f732e70726f746f636f6c2e63616c6c5f636f6e74726163745f6f7065726174696f6e4800520c63616c6c436f6e747261637412540a0f7365745f73797374656d5f63616c6c18032001280b322a2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f63616c6c5f6f7065726174696f6e4800520d73657453797374656d43616c6c12600a137365745f73797374656d5f636f6e747261637418042001280b322e2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e4800521173657453797374656d436f6e747261637442040a026f7022d0010a127472616e73616374696f6e5f68656164657212190a08636861696e5f696418012001280c5207636861696e4964121d0a0872635f6c696d697418022001280442023001520772634c696d697412140a056e6f6e636518032001280c52056e6f6e636512320a156f7065726174696f6e5f6d65726b6c655f726f6f7418042001280c52136f7065726174696f6e4d65726b6c65526f6f74121a0a05706179657218052001280c420480b5180652057061796572121a0a05706179656518062001280c420480b518065205706179656522bc010a0b7472616e73616374696f6e12140a02696418012001280c420480b5180452026964123b0a0668656164657218022001280b32232e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f6865616465725206686561646572123a0a0a6f7065726174696f6e7318032003280b321a2e6b6f696e6f732e70726f746f636f6c2e6f7065726174696f6e520a6f7065726174696f6e73121e0a0a7369676e61747572657318042003280c520a7369676e61747572657322b2030a137472616e73616374696f6e5f7265636569707412140a02696418012001280c420480b5180452026964121a0a05706179657218022001280c420480b518065205706179657212240a0c6d61785f70617965725f726318032001280442023001520a6d617850617965725263121d0a0872635f6c696d697418042001280442023001520772634c696d6974121b0a0772635f75736564180520012804420230015206726355736564122e0a116469736b5f73746f726167655f7573656418062001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641807200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180820012804420230015214636f6d7075746542616e64776964746855736564121a0a0872657665727465641809200128085208726576657274656412330a066576656e7473180a2003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312120a046c6f6773180b2003280952046c6f677322fb010a0c626c6f636b5f68656164657212200a0870726576696f757318012001280c420480b51803520870726576696f7573121a0a0668656967687418022001280442023001520668656967687412200a0974696d657374616d7018032001280442023001520974696d657374616d70123b0a1a70726576696f75735f73746174655f6d65726b6c655f726f6f7418042001280c521770726576696f757353746174654d65726b6c65526f6f7412360a177472616e73616374696f6e5f6d65726b6c655f726f6f7418052001280c52157472616e73616374696f6e4d65726b6c65526f6f7412160a067369676e657218062001280c52067369676e657222b4010a05626c6f636b12140a02696418012001280c420480b518035202696412350a0668656164657218022001280b321d2e6b6f696e6f732e70726f746f636f6c2e626c6f636b5f686561646572520668656164657212400a0c7472616e73616374696f6e7318032003280b321c2e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e520c7472616e73616374696f6e73121c0a097369676e617475726518042001280c52097369676e617475726522b3030a0d626c6f636b5f7265636569707412140a02696418012001280c420480b5180352026964121a0a06686569676874180220012804420230015206686569676874122e0a116469736b5f73746f726167655f7573656418032001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641804200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180520012804420230015214636f6d7075746542616e64776964746855736564122a0a1173746174655f6d65726b6c655f726f6f7418062001280c520f73746174654d65726b6c65526f6f7412330a066576656e747318072003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312570a147472616e73616374696f6e5f726563656970747318082003280b32242e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f7265636569707452137472616e73616374696f6e526563656970747312120a046c6f677318092003280952046c6f677342375a356769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f732f70726f746f636f6c620670726f746f33" ); - entry->set_value( protocol_descriptor ); - *entry->mutable_space() = chain::state::space::metadata(); - - std::map< std::string, uint64_t > thunk_compute { - { "apply_block", 16465 }, - { "apply_call_contract_operation", 685 }, - { "apply_set_system_call_operation", 136081 }, - { "apply_set_system_contract_operation", 8692 }, - { "apply_transaction", 12542 }, - { "apply_upload_contract_operation", 3130 }, - { "call", 3573 }, - { "check_authority", 12653 }, - { "check_system_authority", 12750 }, - { "consume_account_rc", 735 }, - { "consume_block_resources", 753 }, - { "deserialize_message_per_byte", 1 }, - { "deserialize_multihash_base", 102 }, - { "deserialize_multihash_per_byte", 404 }, - { "event", 1222 }, - { "event_per_impacted", 101 }, - { "exit", 11636 }, - { "get_account_nonce", 821 }, - { "get_account_rc", 1072 }, - { "get_arguments", 809 }, - { "get_block", 1134 }, - { "get_block_field", 1417 }, - { "get_caller", 825 }, - { "get_chain_id", 1046 }, - { "get_contract_id", 778 }, - { "get_head_info", 2099 }, - { "get_last_irreversible_block", 772 }, - { "get_next_object", 11181 }, - { "get_object", 1054 }, - { "get_operation", 1081 }, - { "get_prev_object", 15445 }, - { "get_resource_limits", 1227 }, - { "get_transaction", 1584 }, - { "get_transaction_field", 1530 }, - { "hash", 1570 }, - { "keccak_256_base", 1406 }, - { "keccak_256_per_byte", 1 }, - { "log", 738 }, - { "object_serialization_per_byte", 1 }, - { "post_block_callback", 741 }, - { "post_transaction_callback", 721 }, - { "pre_block_callback", 730 }, - { "pre_transaction_callback", 729 }, - { "process_block_signature", 4499 }, - { "put_object", 1057 }, - { "recover_public_key", 29630 }, - { "remove_object", 893 }, - { "ripemd_160_base", 1343 }, - { "ripemd_160_per_byte", 1 }, - { "set_account_nonce", 749 }, - { "sha1_base", 1151 }, - { "sha1_per_byte", 1 }, - { "sha2_256_base", 1385 }, - { "sha2_256_per_byte", 1 }, - { "sha2_512_base", 1445 }, - { "sha2_512_per_byte", 1 }, - { "verify_account_nonce", 822 }, - { "verify_merkle_root", 1 }, - { "verify_signature", 762 }, - { "verify_vrf_proof", 144067 }, - }; - - koinos::chain::compute_bandwidth_registry cbr; - - for ( const auto& [ key, value ] : thunk_compute ) - { - auto centry = cbr.add_entries(); - centry->set_name( key ); - centry->set_compute( value ); - } - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::compute_bandwidth_registry ); - entry->set_value( util::converter::as< std::string >( cbr ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::block_hash_code ); - entry->set_value( util::converter::as< std::string >( unsigned_varint{ std::underlying_type_t< crypto::multicodec >( crypto::multicodec::sha2_256 ) } ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - db.open( - temp, - [&]( state_db::state_node_ptr root ) - { - // Write genesis objects into the database - for ( const auto& entry : _genesis_data.entries() ) - { - KOINOS_ASSERT( - !root->get_object( entry.space(), entry.key() ), - koinos::chain::unexpected_state_exception, - "encountered unexpected object in initial state" - ); - - root->put_object( entry.space(), entry.key(), &entry.value() ); - } - LOG(info) << "Wrote " << _genesis_data.entries().size() << " genesis objects into new database"; - - // Read genesis public key from the database, assert its existence at the correct location - KOINOS_ASSERT( - root->get_object( chain::state::space::metadata(), chain::state::key::genesis_key ), - koinos::chain::unexpected_state_exception, - "could not find genesis public key in database" - ); - - // Calculate and write the chain ID into the database - auto chain_id = crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ); - LOG(info) << "Calculated chain ID: " << chain_id; - auto chain_id_str = util::converter::as< std::string >( chain_id ); - KOINOS_ASSERT( - !root->get_object( chain::state::space::metadata(), chain::state::key::chain_id ), - koinos::chain::unexpected_state_exception, - "encountered unexpected chain id in initial state" - ); - root->put_object( chain::state::space::metadata(), chain::state::key::chain_id, &chain_id_str ); - LOG(info) << "Wrote chain ID into new database"; - }, - &state_db::fifo_comparator, - db.get_unique_lock() ); - - auto shared_db_lock = db.get_shared_lock(); - ctx.set_state_node( db.create_writable_node( db.get_head( shared_db_lock )->id(), crypto::hash( crypto::multicodec::sha2_256, 1 ), protocol::block_header(), shared_db_lock ) ); - ctx.reset_cache(); - ctx.push_frame( chain::stack_frame { - .contract_id = "thunk_tests"s, - .call_privilege = chain::privilege::kernel_mode - } ); - - ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); - - vm_backend->initialize(); - } - - ~thunk_fixture() - { - boost::log::core::get()->remove_all_sinks(); - ctx.clear_state_node(); - db.close( db.get_unique_lock() ); - std::filesystem::remove_all( temp ); - } - - void set_transaction_merkle_roots( protocol::transaction& transaction, crypto::multicodec code, crypto::digest_size size = crypto::digest_size( 0 ) ) - { - std::vector< crypto::multihash > operations; - operations.reserve( transaction.operations().size() ); - - for ( const auto& op : transaction.operations() ) + { + KOINOS_ASSERT( vm_backend, koinos::chain::unknown_backend_exception, "could not get vm backend" ); + + initialize_logging( "koinos_test", {}, "info" ); + + temp = std::filesystem::temp_directory_path() / boost::filesystem::unique_path().string(); + std::filesystem::create_directory( temp ); + + auto seed = "test seed"s; + _signing_private_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, seed ) ); + + auto entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::genesis_key ); + entry->set_value( _signing_private_key.get_public_key().to_address_bytes() ); + *entry->mutable_space() = chain::state::space::metadata(); + + koinos::chain::resource_limit_data rd; + + rd.set_disk_storage_cost( 10 ); + rd.set_disk_storage_limit( 500'800 ); + + rd.set_network_bandwidth_cost( 5 ); + rd.set_network_bandwidth_limit( 1'048'576 ); + + rd.set_compute_bandwidth_cost( 1 ); + rd.set_compute_bandwidth_limit( 100'000'000 ); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::resource_limit_data ); + entry->set_value( util::converter::as< std::string >( rd ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + koinos::chain::max_account_resources mar; + + mar.set_value( 10'000'000 ); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::max_account_resources ); + entry->set_value( util::converter::as< std::string >( mar ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::protocol_descriptor ); + + // protoc --experimental_allow_proto3_optional --descriptor_set_out=build/koinos_protocol.pb --include_imports `find + // koinos -name 'protocol.proto'` + std::string protocol_descriptor = util::from_hex< std::string >( + "0x0ac33b0a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f120f676f6f676c652e70726f746f627566224d0a1146696c6544657363726970746f7253657412380a0466696c6518012003280b32242e676f6f676c652e70726f746f6275662e46696c6544657363726970746f7250726f746f520466696c6522e4040a1346696c6544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512180a077061636b61676518022001280952077061636b616765121e0a0a646570656e64656e6379180320032809520a646570656e64656e6379122b0a117075626c69635f646570656e64656e6379180a2003280552107075626c6963446570656e64656e637912270a0f7765616b5f646570656e64656e6379180b20032805520e7765616b446570656e64656e637912430a0c6d6573736167655f7479706518042003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520b6d6573736167655479706512410a09656e756d5f7479706518052003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512410a077365727669636518062003280b32272e676f6f676c652e70726f746f6275662e5365727669636544657363726970746f7250726f746f52077365727669636512430a09657874656e73696f6e18072003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12360a076f7074696f6e7318082001280b321c2e676f6f676c652e70726f746f6275662e46696c654f7074696f6e7352076f7074696f6e7312490a10736f757263655f636f64655f696e666f18092001280b321f2e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f520e736f75726365436f6465496e666f12160a0673796e746178180c20012809520673796e74617822b9060a0f44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123b0a056669656c6418022003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f52056669656c6412430a09657874656e73696f6e18062003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12410a0b6e65737465645f7479706518032003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520a6e65737465645479706512410a09656e756d5f7479706518042003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512580a0f657874656e73696f6e5f72616e676518052003280b322f2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e457874656e73696f6e52616e6765520e657874656e73696f6e52616e676512440a0a6f6e656f665f6465636c18082003280b32252e676f6f676c652e70726f746f6275662e4f6e656f6644657363726970746f7250726f746f52096f6e656f664465636c12390a076f7074696f6e7318072001280b321f2e676f6f676c652e70726f746f6275662e4d6573736167654f7074696f6e7352076f7074696f6e7312550a0e72657365727665645f72616e676518092003280b322e2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180a20032809520c72657365727665644e616d651a7a0a0e457874656e73696f6e52616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e6412400a076f7074696f6e7318032001280b32262e676f6f676c652e70726f746f6275662e457874656e73696f6e52616e67654f7074696f6e7352076f7074696f6e731a370a0d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e64227c0a15457874656e73696f6e52616e67654f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c1060a144669656c6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218032001280552066e756d62657212410a056c6162656c18042001280e322b2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e4c6162656c52056c6162656c123e0a047479706518052001280e322a2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e54797065520474797065121b0a09747970655f6e616d651806200128095208747970654e616d65121a0a08657874656e6465651802200128095208657874656e64656512230a0d64656661756c745f76616c7565180720012809520c64656661756c7456616c7565121f0a0b6f6e656f665f696e646578180920012805520a6f6e656f66496e646578121b0a096a736f6e5f6e616d65180a2001280952086a736f6e4e616d6512370a076f7074696f6e7318082001280b321d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7352076f7074696f6e7312270a0f70726f746f335f6f7074696f6e616c181120012808520e70726f746f334f7074696f6e616c22b6020a0454797065120f0a0b545950455f444f55424c451001120e0a0a545950455f464c4f41541002120e0a0a545950455f494e5436341003120f0a0b545950455f55494e5436341004120e0a0a545950455f494e543332100512100a0c545950455f46495845443634100612100a0c545950455f464958454433321007120d0a09545950455f424f4f4c1008120f0a0b545950455f535452494e471009120e0a0a545950455f47524f5550100a12100a0c545950455f4d455353414745100b120e0a0a545950455f4259544553100c120f0a0b545950455f55494e543332100d120d0a09545950455f454e554d100e12110a0d545950455f5346495845443332100f12110a0d545950455f53464958454436341010120f0a0b545950455f53494e5433321011120f0a0b545950455f53494e543634101222430a054c6162656c12120a0e4c4142454c5f4f5054494f4e414c100112120a0e4c4142454c5f5245515549524544100212120a0e4c4142454c5f5245504541544544100322630a144f6e656f6644657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512370a076f7074696f6e7318022001280b321d2e676f6f676c652e70726f746f6275662e4f6e656f664f7074696f6e7352076f7074696f6e7322e3020a13456e756d44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123f0a0576616c756518022003280b32292e676f6f676c652e70726f746f6275662e456e756d56616c756544657363726970746f7250726f746f520576616c756512360a076f7074696f6e7318032001280b321c2e676f6f676c652e70726f746f6275662e456e756d4f7074696f6e7352076f7074696f6e73125d0a0e72657365727665645f72616e676518042003280b32362e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f2e456e756d526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180520032809520c72657365727665644e616d651a3b0a11456e756d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e642283010a18456e756d56616c756544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218022001280552066e756d626572123b0a076f7074696f6e7318032001280b32212e676f6f676c652e70726f746f6275662e456e756d56616c75654f7074696f6e7352076f7074696f6e7322a7010a165365727669636544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123e0a066d6574686f6418022003280b32262e676f6f676c652e70726f746f6275662e4d6574686f6444657363726970746f7250726f746f52066d6574686f6412390a076f7074696f6e7318032001280b321f2e676f6f676c652e70726f746f6275662e536572766963654f7074696f6e7352076f7074696f6e732289020a154d6574686f6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65121d0a0a696e7075745f747970651802200128095209696e70757454797065121f0a0b6f75747075745f74797065180320012809520a6f75747075745479706512380a076f7074696f6e7318042001280b321e2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e7352076f7074696f6e7312300a10636c69656e745f73747265616d696e671805200128083a0566616c7365520f636c69656e7453747265616d696e6712300a107365727665725f73747265616d696e671806200128083a0566616c7365520f73657276657253747265616d696e672291090a0b46696c654f7074696f6e7312210a0c6a6176615f7061636b616765180120012809520b6a6176615061636b61676512300a146a6176615f6f757465725f636c6173736e616d6518082001280952126a6176614f75746572436c6173736e616d6512350a136a6176615f6d756c7469706c655f66696c6573180a200128083a0566616c736552116a6176614d756c7469706c6546696c657312440a1d6a6176615f67656e65726174655f657175616c735f616e645f686173681814200128084202180152196a61766147656e6572617465457175616c73416e6448617368123a0a166a6176615f737472696e675f636865636b5f75746638181b200128083a0566616c736552136a617661537472696e67436865636b5574663812530a0c6f7074696d697a655f666f7218092001280e32292e676f6f676c652e70726f746f6275662e46696c654f7074696f6e732e4f7074696d697a654d6f64653a055350454544520b6f7074696d697a65466f72121d0a0a676f5f7061636b616765180b200128095209676f5061636b61676512350a1363635f67656e657269635f73657276696365731810200128083a0566616c73655211636347656e65726963536572766963657312390a156a6176615f67656e657269635f73657276696365731811200128083a0566616c736552136a61766147656e65726963536572766963657312350a1370795f67656e657269635f73657276696365731812200128083a0566616c73655211707947656e65726963536572766963657312370a147068705f67656e657269635f7365727669636573182a200128083a0566616c7365521270687047656e65726963536572766963657312250a0a646570726563617465641817200128083a0566616c7365520a64657072656361746564122e0a1063635f656e61626c655f6172656e6173181f200128083a0474727565520e6363456e61626c654172656e6173122a0a116f626a635f636c6173735f707265666978182420012809520f6f626a63436c61737350726566697812290a106373686172705f6e616d657370616365182520012809520f6373686172704e616d65737061636512210a0c73776966745f707265666978182720012809520b737769667450726566697812280a107068705f636c6173735f707265666978182820012809520e706870436c61737350726566697812230a0d7068705f6e616d657370616365182920012809520c7068704e616d65737061636512340a167068705f6d657461646174615f6e616d657370616365182c2001280952147068704d657461646174614e616d65737061636512210a0c727562795f7061636b616765182d20012809520b727562795061636b61676512580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e223a0a0c4f7074696d697a654d6f646512090a0553504545441001120d0a09434f44455f53495a45100212100a0c4c4954455f52554e54494d4510032a0908e8071080808080024a040826102722e3020a0e4d6573736167654f7074696f6e73123c0a176d6573736167655f7365745f776972655f666f726d61741801200128083a0566616c736552146d65737361676553657457697265466f726d6174124c0a1f6e6f5f7374616e646172645f64657363726970746f725f6163636573736f721802200128083a0566616c7365521c6e6f5374616e6461726444657363726970746f724163636573736f7212250a0a646570726563617465641803200128083a0566616c7365520a64657072656361746564121b0a096d61705f656e74727918072001280852086d6170456e74727912580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a04080410054a04080510064a04080610074a04080810094a040809100a22e2030a0c4669656c644f7074696f6e7312410a05637479706518012001280e32232e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e43547970653a06535452494e475205637479706512160a067061636b656418022001280852067061636b656412470a066a737479706518062001280e32242e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e4a53547970653a094a535f4e4f524d414c52066a737479706512190a046c617a791805200128083a0566616c736552046c617a7912250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412190a047765616b180a200128083a0566616c736552047765616b12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e222f0a054354797065120a0a06535452494e47100012080a04434f5244100112100a0c535452494e475f5049454345100222350a064a5354797065120d0a094a535f4e4f524d414c1000120d0a094a535f535452494e471001120d0a094a535f4e554d42455210022a0908e8071080808080024a040804100522730a0c4f6e656f664f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c0010a0b456e756d4f7074696f6e73121f0a0b616c6c6f775f616c696173180220012808520a616c6c6f77416c69617312250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a0408051006229e010a10456e756d56616c75654f7074696f6e7312250a0a646570726563617465641801200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e807108080808002229c010a0e536572766963654f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222e0020a0d4d6574686f644f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412710a116964656d706f74656e63795f6c6576656c18222001280e322f2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e732e4964656d706f74656e63794c6576656c3a134944454d504f54454e43595f554e4b4e4f574e52106964656d706f74656e63794c6576656c12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e22500a104964656d706f74656e63794c6576656c12170a134944454d504f54454e43595f554e4b4e4f574e100012130a0f4e4f5f534944455f454646454354531001120e0a0a4944454d504f54454e5410022a0908e807108080808002229a030a13556e696e7465727072657465644f7074696f6e12410a046e616d6518022003280b322d2e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e2e4e616d655061727452046e616d6512290a106964656e7469666965725f76616c7565180320012809520f6964656e74696669657256616c7565122c0a12706f7369746976655f696e745f76616c75651804200128045210706f736974697665496e7456616c7565122c0a126e656761746976655f696e745f76616c756518052001280352106e65676174697665496e7456616c756512210a0c646f75626c655f76616c7565180620012801520b646f75626c6556616c756512210a0c737472696e675f76616c756518072001280c520b737472696e6756616c756512270a0f6167677265676174655f76616c7565180820012809520e61676772656761746556616c75651a4a0a084e616d6550617274121b0a096e616d655f7061727418012002280952086e616d655061727412210a0c69735f657874656e73696f6e180220022808520b6973457874656e73696f6e22a7020a0e536f75726365436f6465496e666f12440a086c6f636174696f6e18012003280b32282e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f2e4c6f636174696f6e52086c6f636174696f6e1ace010a084c6f636174696f6e12160a04706174681801200328054202100152047061746812160a047370616e1802200328054202100152047370616e12290a106c656164696e675f636f6d6d656e7473180320012809520f6c656164696e67436f6d6d656e7473122b0a11747261696c696e675f636f6d6d656e74731804200128095210747261696c696e67436f6d6d656e7473123a0a196c656164696e675f64657461636865645f636f6d6d656e747318062003280952176c656164696e674465746163686564436f6d6d656e747322d1010a1147656e657261746564436f6465496e666f124d0a0a616e6e6f746174696f6e18012003280b322d2e676f6f676c652e70726f746f6275662e47656e657261746564436f6465496e666f2e416e6e6f746174696f6e520a616e6e6f746174696f6e1a6d0a0a416e6e6f746174696f6e12160a047061746818012003280542021001520470617468121f0a0b736f757263655f66696c65180220012809520a736f7572636546696c6512140a05626567696e1803200128055205626567696e12100a03656e641804200128055203656e64427e0a13636f6d2e676f6f676c652e70726f746f627566421044657363726970746f7250726f746f7348015a2d676f6f676c652e676f6c616e672e6f72672f70726f746f6275662f74797065732f64657363726970746f727062f80101a20203475042aa021a476f6f676c652e50726f746f6275662e5265666c656374696f6e0ab5020a146b6f696e6f732f6f7074696f6e732e70726f746f12066b6f696e6f731a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f2a6d0a0a62797465735f74797065120a0a064241534536341000120a0a06424153453538100112070a034845581002120c0a08424c4f434b5f4944100312120a0e5452414e53414354494f4e5f49441004120f0a0b434f4e54524143545f49441005120b0a074144445245535310063a4c0a056274797065121d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7318d086032001280e32122e6b6f696e6f732e62797465735f7479706552056274797065880101422e5a2c6769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f73620670726f746f330aa8190a1e6b6f696e6f732f70726f746f636f6c2f70726f746f636f6c2e70726f746f120f6b6f696e6f732e70726f746f636f6c1a146b6f696e6f732f6f7074696f6e732e70726f746f2290010a0a6576656e745f64617461121a0a0873657175656e636518012001280d520873657175656e6365121c0a06736f7572636518022001280c420480b518055206736f7572636512120a046e616d6518032001280952046e616d6512120a046461746118042001280c52046461746112200a08696d70616374656418052003280c420480b518065208696d706163746564225e0a14636f6e74726163745f63616c6c5f62756e646c6512250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e742292010a1273797374656d5f63616c6c5f746172676574121b0a087468756e6b5f696418012001280d480052077468756e6b496412550a1273797374656d5f63616c6c5f62756e646c6518022001280b32252e6b6f696e6f732e70726f746f636f6c2e636f6e74726163745f63616c6c5f62756e646c654800521073797374656d43616c6c42756e646c6542080a067461726765742294020a1975706c6f61645f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121a0a0862797465636f646518022001280c520862797465636f646512100a03616269180320012809520361626912380a18617574686f72697a65735f63616c6c5f636f6e74726163741804200128085216617574686f72697a657343616c6c436f6e7472616374122a0a11617574686f72697a65735f7573655f7263180520012808520f617574686f72697a65735573655263123c0a1a617574686f72697a65735f75706c6f61645f636f6e74726163741806200128085218617574686f72697a657355706c6f6164436f6e747261637422750a1763616c6c5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e7412120a046172677318032001280c52046172677322710a197365745f73797374656d5f63616c6c5f6f7065726174696f6e12170a0763616c6c5f696418012001280d520663616c6c4964123b0a0674617267657418022001280b32232e6b6f696e6f732e70726f746f636f6c2e73797374656d5f63616c6c5f7461726765745206746172676574226f0a1d7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e7472616374496412270a0f73797374656d5f636f6e7472616374180220012808520e73797374656d436f6e747261637422f1020a096f7065726174696f6e12550a0f75706c6f61645f636f6e747261637418012001280b322a2e6b6f696e6f732e70726f746f636f6c2e75706c6f61645f636f6e74726163745f6f7065726174696f6e4800520e75706c6f6164436f6e7472616374124f0a0d63616c6c5f636f6e747261637418022001280b32282e6b6f696e6f732e70726f746f636f6c2e63616c6c5f636f6e74726163745f6f7065726174696f6e4800520c63616c6c436f6e747261637412540a0f7365745f73797374656d5f63616c6c18032001280b322a2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f63616c6c5f6f7065726174696f6e4800520d73657453797374656d43616c6c12600a137365745f73797374656d5f636f6e747261637418042001280b322e2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e4800521173657453797374656d436f6e747261637442040a026f7022d0010a127472616e73616374696f6e5f68656164657212190a08636861696e5f696418012001280c5207636861696e4964121d0a0872635f6c696d697418022001280442023001520772634c696d697412140a056e6f6e636518032001280c52056e6f6e636512320a156f7065726174696f6e5f6d65726b6c655f726f6f7418042001280c52136f7065726174696f6e4d65726b6c65526f6f74121a0a05706179657218052001280c420480b5180652057061796572121a0a05706179656518062001280c420480b518065205706179656522bc010a0b7472616e73616374696f6e12140a02696418012001280c420480b5180452026964123b0a0668656164657218022001280b32232e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f6865616465725206686561646572123a0a0a6f7065726174696f6e7318032003280b321a2e6b6f696e6f732e70726f746f636f6c2e6f7065726174696f6e520a6f7065726174696f6e73121e0a0a7369676e61747572657318042003280c520a7369676e61747572657322b2030a137472616e73616374696f6e5f7265636569707412140a02696418012001280c420480b5180452026964121a0a05706179657218022001280c420480b518065205706179657212240a0c6d61785f70617965725f726318032001280442023001520a6d617850617965725263121d0a0872635f6c696d697418042001280442023001520772634c696d6974121b0a0772635f75736564180520012804420230015206726355736564122e0a116469736b5f73746f726167655f7573656418062001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641807200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180820012804420230015214636f6d7075746542616e64776964746855736564121a0a0872657665727465641809200128085208726576657274656412330a066576656e7473180a2003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312120a046c6f6773180b2003280952046c6f677322fb010a0c626c6f636b5f68656164657212200a0870726576696f757318012001280c420480b51803520870726576696f7573121a0a0668656967687418022001280442023001520668656967687412200a0974696d657374616d7018032001280442023001520974696d657374616d70123b0a1a70726576696f75735f73746174655f6d65726b6c655f726f6f7418042001280c521770726576696f757353746174654d65726b6c65526f6f7412360a177472616e73616374696f6e5f6d65726b6c655f726f6f7418052001280c52157472616e73616374696f6e4d65726b6c65526f6f7412160a067369676e657218062001280c52067369676e657222b4010a05626c6f636b12140a02696418012001280c420480b518035202696412350a0668656164657218022001280b321d2e6b6f696e6f732e70726f746f636f6c2e626c6f636b5f686561646572520668656164657212400a0c7472616e73616374696f6e7318032003280b321c2e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e520c7472616e73616374696f6e73121c0a097369676e617475726518042001280c52097369676e617475726522b3030a0d626c6f636b5f7265636569707412140a02696418012001280c420480b5180352026964121a0a06686569676874180220012804420230015206686569676874122e0a116469736b5f73746f726167655f7573656418032001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641804200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180520012804420230015214636f6d7075746542616e64776964746855736564122a0a1173746174655f6d65726b6c655f726f6f7418062001280c520f73746174654d65726b6c65526f6f7412330a066576656e747318072003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312570a147472616e73616374696f6e5f726563656970747318082003280b32242e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f7265636569707452137472616e73616374696f6e526563656970747312120a046c6f677318092003280952046c6f677342375a356769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f732f70726f746f636f6c620670726f746f33" ); + entry->set_value( protocol_descriptor ); + *entry->mutable_space() = chain::state::space::metadata(); + + std::map< std::string, uint64_t > thunk_compute{ + { "apply_block", 16'465}, + { "apply_call_contract_operation", 685}, + { "apply_set_system_call_operation", 136'081}, + {"apply_set_system_contract_operation", 8'692}, + { "apply_transaction", 12'542}, + { "apply_upload_contract_operation", 3'130}, + { "call", 3'573}, + { "check_authority", 12'653}, + { "check_system_authority", 12'750}, + { "consume_account_rc", 735}, + { "consume_block_resources", 753}, + { "deserialize_message_per_byte", 1}, + { "deserialize_multihash_base", 102}, + { "deserialize_multihash_per_byte", 404}, + { "event", 1'222}, + { "event_per_impacted", 101}, + { "exit", 11'636}, + { "get_account_nonce", 821}, + { "get_account_rc", 1'072}, + { "get_arguments", 809}, + { "get_block", 1'134}, + { "get_block_field", 1'417}, + { "get_caller", 825}, + { "get_chain_id", 1'046}, + { "get_contract_id", 778}, + { "get_head_info", 2'099}, + { "get_last_irreversible_block", 772}, + { "get_next_object", 11'181}, + { "get_object", 1'054}, + { "get_operation", 1'081}, + { "get_prev_object", 15'445}, + { "get_resource_limits", 1'227}, + { "get_transaction", 1'584}, + { "get_transaction_field", 1'530}, + { "hash", 1'570}, + { "keccak_256_base", 1'406}, + { "keccak_256_per_byte", 1}, + { "log", 738}, + { "object_serialization_per_byte", 1}, + { "post_block_callback", 741}, + { "post_transaction_callback", 721}, + { "pre_block_callback", 730}, + { "pre_transaction_callback", 729}, + { "process_block_signature", 4'499}, + { "put_object", 1'057}, + { "recover_public_key", 29'630}, + { "remove_object", 893}, + { "ripemd_160_base", 1'343}, + { "ripemd_160_per_byte", 1}, + { "set_account_nonce", 749}, + { "sha1_base", 1'151}, + { "sha1_per_byte", 1}, + { "sha2_256_base", 1'385}, + { "sha2_256_per_byte", 1}, + { "sha2_512_base", 1'445}, + { "sha2_512_per_byte", 1}, + { "verify_account_nonce", 822}, + { "verify_merkle_root", 1}, + { "verify_signature", 762}, + { "verify_vrf_proof", 144'067}, + }; + + koinos::chain::compute_bandwidth_registry cbr; + + for( const auto& [ key, value ]: thunk_compute ) + { + auto centry = cbr.add_entries(); + centry->set_name( key ); + centry->set_compute( value ); + } + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::compute_bandwidth_registry ); + entry->set_value( util::converter::as< std::string >( cbr ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::block_hash_code ); + entry->set_value( util::converter::as< std::string >( + unsigned_varint{ std::underlying_type_t< crypto::multicodec >( crypto::multicodec::sha2_256 ) } ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + db.open( + temp, + [ & ]( state_db::state_node_ptr root ) { - operations.emplace_back( crypto::hash( code, op, size ) ); - } - - auto operation_merkle_tree = crypto::merkle_tree( code, operations ); - transaction.mutable_header()->set_operation_merkle_root( util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); - } - - void sign_transaction( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ) - { - // Signature is on the hash of the active data - transaction.mutable_header()->set_payer( transaction_signing_key.get_public_key().to_address_bytes() ); - auto id_mh = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); - transaction.set_id( util::converter::as< std::string >( id_mh ) ); - transaction.clear_signatures(); - transaction.add_signatures( util::converter::as< std::string >( transaction_signing_key.sign_compact( id_mh ) ) ); - } - - void set_block_merkle_roots( protocol::block& block, crypto::multicodec code, crypto::digest_size size = crypto::digest_size( 0 ) ) - { - std::vector< crypto::multihash > hashes; - hashes.reserve( block.transactions().size() * 2 ); - - for ( const auto& trx : block.transactions() ) - { - hashes.emplace_back( crypto::hash( code, trx.header(), size ) ); - hashes.emplace_back( crypto::hash( code, trx.signatures(), size ) ); - } - - auto transaction_merkle_tree = crypto::merkle_tree( code, hashes ); - block.mutable_header()->set_transaction_merkle_root( util::converter::as< std::string >( transaction_merkle_tree.root()->hash() ) ); - } - - std::filesystem::path temp; - koinos::state_db::database db; - std::shared_ptr< koinos::vm_manager::vm_backend > vm_backend; - koinos::chain::execution_context ctx; - koinos::chain::host_api host; - koinos::crypto::private_key _signing_private_key; - chain::genesis_data _genesis_data; + // Write genesis objects into the database + for( const auto& entry: _genesis_data.entries() ) + { + KOINOS_ASSERT( !root->get_object( entry.space(), entry.key() ), + koinos::chain::unexpected_state_exception, + "encountered unexpected object in initial state" ); + + root->put_object( entry.space(), entry.key(), &entry.value() ); + } + LOG( info ) << "Wrote " << _genesis_data.entries().size() << " genesis objects into new database"; + + // Read genesis public key from the database, assert its existence at the correct location + KOINOS_ASSERT( root->get_object( chain::state::space::metadata(), chain::state::key::genesis_key ), + koinos::chain::unexpected_state_exception, + "could not find genesis public key in database" ); + + // Calculate and write the chain ID into the database + auto chain_id = crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ); + LOG( info ) << "Calculated chain ID: " << chain_id; + auto chain_id_str = util::converter::as< std::string >( chain_id ); + KOINOS_ASSERT( !root->get_object( chain::state::space::metadata(), chain::state::key::chain_id ), + koinos::chain::unexpected_state_exception, + "encountered unexpected chain id in initial state" ); + root->put_object( chain::state::space::metadata(), chain::state::key::chain_id, &chain_id_str ); + LOG( info ) << "Wrote chain ID into new database"; + }, + &state_db::fifo_comparator, + db.get_unique_lock() ); + + auto shared_db_lock = db.get_shared_lock(); + ctx.set_state_node( db.create_writable_node( db.get_head( shared_db_lock )->id(), + crypto::hash( crypto::multicodec::sha2_256, 1 ), + protocol::block_header(), + shared_db_lock ) ); + ctx.reset_cache(); + ctx.push_frame( + chain::stack_frame{ .contract_id = "thunk_tests"s, .call_privilege = chain::privilege::kernel_mode } ); + + ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); + + vm_backend->initialize(); + } + + ~thunk_fixture() + { + boost::log::core::get()->remove_all_sinks(); + ctx.clear_state_node(); + db.close( db.get_unique_lock() ); + std::filesystem::remove_all( temp ); + } + + void set_transaction_merkle_roots( protocol::transaction& transaction, + crypto::multicodec code, + crypto::digest_size size = crypto::digest_size( 0 ) ) + { + std::vector< crypto::multihash > operations; + operations.reserve( transaction.operations().size() ); + + for( const auto& op: transaction.operations() ) + { + operations.emplace_back( crypto::hash( code, op, size ) ); + } + + auto operation_merkle_tree = crypto::merkle_tree( code, operations ); + transaction.mutable_header()->set_operation_merkle_root( + util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); + } + + void sign_transaction( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ) + { + // Signature is on the hash of the active data + transaction.mutable_header()->set_payer( transaction_signing_key.get_public_key().to_address_bytes() ); + auto id_mh = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); + transaction.set_id( util::converter::as< std::string >( id_mh ) ); + transaction.clear_signatures(); + transaction.add_signatures( util::converter::as< std::string >( transaction_signing_key.sign_compact( id_mh ) ) ); + } + + void set_block_merkle_roots( protocol::block& block, + crypto::multicodec code, + crypto::digest_size size = crypto::digest_size( 0 ) ) + { + std::vector< crypto::multihash > hashes; + hashes.reserve( block.transactions().size() * 2 ); + + for( const auto& trx: block.transactions() ) + { + hashes.emplace_back( crypto::hash( code, trx.header(), size ) ); + hashes.emplace_back( crypto::hash( code, trx.signatures(), size ) ); + } + + auto transaction_merkle_tree = crypto::merkle_tree( code, hashes ); + block.mutable_header()->set_transaction_merkle_root( + util::converter::as< std::string >( transaction_merkle_tree.root()->hash() ) ); + } + + std::filesystem::path temp; + koinos::state_db::database db; + std::shared_ptr< koinos::vm_manager::vm_backend > vm_backend; + koinos::chain::execution_context ctx; + koinos::chain::host_api host; + koinos::crypto::private_key _signing_private_key; + chain::genesis_data _genesis_data; }; enum token_entry : uint32_t { - name = 0x82a3537f, - symbol = 0xb76a7ca1, - decimals = 0xee80fd2f, - total_supply = 0xb0da3934, - balance_of = 0x5c721497, - transfer = 0x27f576ca, - mint = 0xdc6f17bb + name = 0x82a3537f, + symbol = 0xb76a7ca1, + decimals = 0xee80fd2f, + total_supply = 0xb0da3934, + balance_of = 0x5c721497, + transfer = 0x27f576ca, + mint = 0xdc6f17bb }; namespace koinos::chain::thunk { void test_thunk( execution_context& ctx, const std::string& s ) { - thunk::_log( ctx, "thunk: " + s ); + thunk::_log( ctx, "thunk: " + s ); } -} // koinos::chain::thunk +} // namespace koinos::chain::thunk BOOST_FIXTURE_TEST_SUITE( thunk_tests, thunk_fixture ) BOOST_AUTO_TEST_CASE( get_transaction_field ) -{ try { - koinos::protocol::transaction trx; - - koinos::contracts::token::transfer_arguments xfer_arg; - xfer_arg.set_from( _signing_private_key.get_public_key().to_address_bytes() ); - xfer_arg.set_to( _signing_private_key.get_public_key().to_address_bytes() ); - xfer_arg.set_value( 100 ); - - auto op = trx.add_operations()->mutable_call_contract(); - op->set_contract_id( util::from_hex< std::string >( "0xDEADBEEF" ) ); - op->set_entry_point( token_entry::transfer ); - op->set_args( xfer_arg.SerializeAsString() ); - trx.mutable_header()->set_rc_limit( 10'000'000 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string>( uint64_t( 12 ) ) ); - trx.mutable_header()->set_payer( util::from_hex< std::string >( "0x1234" ) ); - trx.mutable_header()->set_payee( util::from_hex< std::string >( "0xABCD" ) ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - trx.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, trx.header() ) ) ); - sign_transaction( trx, _signing_private_key ); - ctx.set_transaction( trx ); - - BOOST_TEST_MESSAGE( "Testing dynamic transaction field retrieval" ); - - koinos::chain::value_type val; - - BOOST_TEST_MESSAGE( "Retrieving ID" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "id" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.id() ); - - BOOST_TEST_MESSAGE( "Retrieving header" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "header" ); - BOOST_REQUIRE( val.has_message_value() ); - koinos::protocol::transaction_header hdr; - val.message_value().UnpackTo( &hdr ); - BOOST_REQUIRE( google::protobuf::util::MessageDifferencer::Equals( hdr, trx.header() ) ); - - BOOST_TEST_MESSAGE( "Retrieving header.rc_limit" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "header.rc_limit" ); - BOOST_REQUIRE_EQUAL( val.uint64_value(), trx.header().rc_limit() ); - - BOOST_TEST_MESSAGE( "Retrieving header.nonce" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "header.nonce" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.header().nonce() ); - - BOOST_TEST_MESSAGE( "Retrieving header.operation_merkle_root" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "header.operation_merkle_root" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.header().operation_merkle_root() ); - - BOOST_TEST_MESSAGE( "Retrieving header.payer" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "header.payer" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.header().payer() ); - - BOOST_TEST_MESSAGE( "Retrieving header.payee" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "header.payee" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.header().payee() ); - - BOOST_TEST_MESSAGE( "Retrieving operations" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "operations" ); - BOOST_REQUIRE( val.has_message_value() ); - koinos::chain::list_type list; - val.message_value().UnpackTo( &list ); - BOOST_REQUIRE_EQUAL( list.values_size(), 1 ); - koinos::protocol::operation op_; - list.values( 0 ).message_value().UnpackTo( &op_ ); - BOOST_REQUIRE( google::protobuf::util::MessageDifferencer::Equals( op_, trx.operations( 0 ) ) ); - - BOOST_TEST_MESSAGE( "Retrieving signatures" ); - val = koinos::chain::system_call::get_transaction_field( ctx, "signatures" ); - val.message_value().UnpackTo( &list ); - for ( int i = 0; i < list.values_size(); i++ ) - { +{ + try + { + koinos::protocol::transaction trx; + + koinos::contracts::token::transfer_arguments xfer_arg; + xfer_arg.set_from( _signing_private_key.get_public_key().to_address_bytes() ); + xfer_arg.set_to( _signing_private_key.get_public_key().to_address_bytes() ); + xfer_arg.set_value( 100 ); + + auto op = trx.add_operations()->mutable_call_contract(); + op->set_contract_id( util::from_hex< std::string >( "0xDEADBEEF" ) ); + op->set_entry_point( token_entry::transfer ); + op->set_args( xfer_arg.SerializeAsString() ); + trx.mutable_header()->set_rc_limit( 10'000'000 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( uint64_t( 12 ) ) ); + trx.mutable_header()->set_payer( util::from_hex< std::string >( "0x1234" ) ); + trx.mutable_header()->set_payee( util::from_hex< std::string >( "0xABCD" ) ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + trx.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, trx.header() ) ) ); + sign_transaction( trx, _signing_private_key ); + ctx.set_transaction( trx ); + + BOOST_TEST_MESSAGE( "Testing dynamic transaction field retrieval" ); + + koinos::chain::value_type val; + + BOOST_TEST_MESSAGE( "Retrieving ID" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "id" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.id() ); + + BOOST_TEST_MESSAGE( "Retrieving header" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "header" ); + BOOST_REQUIRE( val.has_message_value() ); + koinos::protocol::transaction_header hdr; + val.message_value().UnpackTo( &hdr ); + BOOST_REQUIRE( google::protobuf::util::MessageDifferencer::Equals( hdr, trx.header() ) ); + + BOOST_TEST_MESSAGE( "Retrieving header.rc_limit" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "header.rc_limit" ); + BOOST_REQUIRE_EQUAL( val.uint64_value(), trx.header().rc_limit() ); + + BOOST_TEST_MESSAGE( "Retrieving header.nonce" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "header.nonce" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.header().nonce() ); + + BOOST_TEST_MESSAGE( "Retrieving header.operation_merkle_root" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "header.operation_merkle_root" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.header().operation_merkle_root() ); + + BOOST_TEST_MESSAGE( "Retrieving header.payer" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "header.payer" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.header().payer() ); + + BOOST_TEST_MESSAGE( "Retrieving header.payee" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "header.payee" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), trx.header().payee() ); + + BOOST_TEST_MESSAGE( "Retrieving operations" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "operations" ); + BOOST_REQUIRE( val.has_message_value() ); + koinos::chain::list_type list; + val.message_value().UnpackTo( &list ); + BOOST_REQUIRE_EQUAL( list.values_size(), 1 ); + koinos::protocol::operation op_; + list.values( 0 ).message_value().UnpackTo( &op_ ); + BOOST_REQUIRE( google::protobuf::util::MessageDifferencer::Equals( op_, trx.operations( 0 ) ) ); + + BOOST_TEST_MESSAGE( "Retrieving signatures" ); + val = koinos::chain::system_call::get_transaction_field( ctx, "signatures" ); + val.message_value().UnpackTo( &list ); + for( int i = 0; i < list.values_size(); i++ ) + { BOOST_REQUIRE_EQUAL( trx.signatures( i ), list.values( i ).bytes_value() ); - } - - BOOST_TEST_MESSAGE( "Testing dynamic transaction field not found" ); + } - KOINOS_REQUIRE_THROW( chain::system_call::get_transaction_field( ctx, "non_existent_field" ), chain::field_not_found ); + BOOST_TEST_MESSAGE( "Testing dynamic transaction field not found" ); - ctx.clear_transaction(); + KOINOS_REQUIRE_THROW( chain::system_call::get_transaction_field( ctx, "non_existent_field" ), + chain::field_not_found ); - BOOST_TEST_MESSAGE( "Testing dynamic transaction field unexpected access" ); + ctx.clear_transaction(); - KOINOS_REQUIRE_THROW( chain::system_call::get_transaction_field( ctx, "id" ), chain::internal_error ); + BOOST_TEST_MESSAGE( "Testing dynamic transaction field unexpected access" ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + KOINOS_REQUIRE_THROW( chain::system_call::get_transaction_field( ctx, "id" ), chain::internal_error ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( get_block_field ) -{ try { - koinos::protocol::block block; - - auto duration = std::chrono::system_clock::now().time_since_epoch(); - block.mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); - block.mutable_header()->set_height( 2 ); - block.mutable_header()->set_previous_state_merkle_root( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - block.mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - - koinos::protocol::transaction trx; - - koinos::contracts::token::transfer_arguments xfer_arg; - xfer_arg.set_from( _signing_private_key.get_public_key().to_address_bytes() ); - xfer_arg.set_to( _signing_private_key.get_public_key().to_address_bytes() ); - xfer_arg.set_value( 100 ); - - auto op3 = trx.add_operations()->mutable_call_contract(); - op3->set_contract_id( op3->contract_id() ); - op3->set_entry_point( token_entry::transfer ); - op3->set_args( xfer_arg.SerializeAsString() ); - trx.mutable_header()->set_rc_limit( 10'000'000 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string>( uint64_t( 12 ) ) ); - trx.mutable_header()->set_payer( util::from_hex< std::string >( "0x1234" ) ); - trx.mutable_header()->set_payee( util::from_hex< std::string >( "0xABCD" ) ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - trx.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, trx.header() ) ) ); - sign_transaction( trx, _signing_private_key ); - - *block.add_transactions() = trx; - - ctx.set_block( block ); - - BOOST_TEST_MESSAGE( "Testing dynamic block field retrieval" ); - - koinos::chain::value_type val; - - BOOST_TEST_MESSAGE( "Retrieving ID" ); - val = koinos::chain::system_call::get_block_field( ctx, "id" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), block.id() ); - - BOOST_TEST_MESSAGE( "Retrieving header" ); - val = koinos::chain::system_call::get_block_field( ctx, "header" ); - BOOST_REQUIRE( val.has_message_value() ); - koinos::protocol::block_header hdr; - val.message_value().UnpackTo( &hdr ); - BOOST_REQUIRE( google::protobuf::util::MessageDifferencer::Equals( hdr, block.header() ) ); - - BOOST_TEST_MESSAGE( "Retrieving header.previous" ); - val = koinos::chain::system_call::get_block_field( ctx, "header.previous" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), block.header().previous() ); - - BOOST_TEST_MESSAGE( "Retrieving header.height" ); - val = koinos::chain::system_call::get_block_field( ctx, "header.height" ); - BOOST_REQUIRE_EQUAL( val.uint64_value(), block.header().height() ); - - BOOST_TEST_MESSAGE( "Retrieving header.timestamp" ); - val = koinos::chain::system_call::get_block_field( ctx, "header.timestamp" ); - BOOST_REQUIRE_EQUAL( val.uint64_value(), block.header().timestamp() ); - - BOOST_TEST_MESSAGE( "Retrieving header.previous_state_merkle_root" ); - val = koinos::chain::system_call::get_block_field( ctx, "header.previous_state_merkle_root" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), block.header().previous_state_merkle_root() ); - - BOOST_TEST_MESSAGE( "Retrieving header.transaction_merkle_root" ); - val = koinos::chain::system_call::get_block_field( ctx, "header.transaction_merkle_root" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), block.header().transaction_merkle_root() ); - - BOOST_TEST_MESSAGE( "Retrieving header.signer" ); - val = koinos::chain::system_call::get_block_field( ctx, "header.signer" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), block.header().signer() ); - - BOOST_TEST_MESSAGE( "Retrieving transactions" ); - val = koinos::chain::system_call::get_block_field( ctx, "transactions" ); - BOOST_REQUIRE( val.has_message_value() ); - koinos::chain::list_type list; - val.message_value().UnpackTo( &list ); - BOOST_REQUIRE_EQUAL( list.values_size(), 1 ); - for ( int i = 0; i < list.values_size(); i++ ) - { +{ + try + { + koinos::protocol::block block; + + auto duration = std::chrono::system_clock::now().time_since_epoch(); + block.mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); + block.mutable_header()->set_height( 2 ); + block.mutable_header()->set_previous_state_merkle_root( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + block.mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + + koinos::protocol::transaction trx; + + koinos::contracts::token::transfer_arguments xfer_arg; + xfer_arg.set_from( _signing_private_key.get_public_key().to_address_bytes() ); + xfer_arg.set_to( _signing_private_key.get_public_key().to_address_bytes() ); + xfer_arg.set_value( 100 ); + + auto op3 = trx.add_operations()->mutable_call_contract(); + op3->set_contract_id( op3->contract_id() ); + op3->set_entry_point( token_entry::transfer ); + op3->set_args( xfer_arg.SerializeAsString() ); + trx.mutable_header()->set_rc_limit( 10'000'000 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( uint64_t( 12 ) ) ); + trx.mutable_header()->set_payer( util::from_hex< std::string >( "0x1234" ) ); + trx.mutable_header()->set_payee( util::from_hex< std::string >( "0xABCD" ) ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + trx.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, trx.header() ) ) ); + sign_transaction( trx, _signing_private_key ); + + *block.add_transactions() = trx; + + ctx.set_block( block ); + + BOOST_TEST_MESSAGE( "Testing dynamic block field retrieval" ); + + koinos::chain::value_type val; + + BOOST_TEST_MESSAGE( "Retrieving ID" ); + val = koinos::chain::system_call::get_block_field( ctx, "id" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), block.id() ); + + BOOST_TEST_MESSAGE( "Retrieving header" ); + val = koinos::chain::system_call::get_block_field( ctx, "header" ); + BOOST_REQUIRE( val.has_message_value() ); + koinos::protocol::block_header hdr; + val.message_value().UnpackTo( &hdr ); + BOOST_REQUIRE( google::protobuf::util::MessageDifferencer::Equals( hdr, block.header() ) ); + + BOOST_TEST_MESSAGE( "Retrieving header.previous" ); + val = koinos::chain::system_call::get_block_field( ctx, "header.previous" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), block.header().previous() ); + + BOOST_TEST_MESSAGE( "Retrieving header.height" ); + val = koinos::chain::system_call::get_block_field( ctx, "header.height" ); + BOOST_REQUIRE_EQUAL( val.uint64_value(), block.header().height() ); + + BOOST_TEST_MESSAGE( "Retrieving header.timestamp" ); + val = koinos::chain::system_call::get_block_field( ctx, "header.timestamp" ); + BOOST_REQUIRE_EQUAL( val.uint64_value(), block.header().timestamp() ); + + BOOST_TEST_MESSAGE( "Retrieving header.previous_state_merkle_root" ); + val = koinos::chain::system_call::get_block_field( ctx, "header.previous_state_merkle_root" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), block.header().previous_state_merkle_root() ); + + BOOST_TEST_MESSAGE( "Retrieving header.transaction_merkle_root" ); + val = koinos::chain::system_call::get_block_field( ctx, "header.transaction_merkle_root" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), block.header().transaction_merkle_root() ); + + BOOST_TEST_MESSAGE( "Retrieving header.signer" ); + val = koinos::chain::system_call::get_block_field( ctx, "header.signer" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), block.header().signer() ); + + BOOST_TEST_MESSAGE( "Retrieving transactions" ); + val = koinos::chain::system_call::get_block_field( ctx, "transactions" ); + BOOST_REQUIRE( val.has_message_value() ); + koinos::chain::list_type list; + val.message_value().UnpackTo( &list ); + BOOST_REQUIRE_EQUAL( list.values_size(), 1 ); + for( int i = 0; i < list.values_size(); i++ ) + { koinos::protocol::transaction tx; list.values( i ).message_value().UnpackTo( &tx ); BOOST_REQUIRE( google::protobuf::util::MessageDifferencer::Equals( block.transactions( i ), tx ) ); - } - - BOOST_TEST_MESSAGE( "Retrieving signature" ); - val = koinos::chain::system_call::get_block_field( ctx, "signature" ); - BOOST_REQUIRE_EQUAL( val.bytes_value(), block.signature() ); + } - BOOST_TEST_MESSAGE( "Testing dynamic block field not found" ); + BOOST_TEST_MESSAGE( "Retrieving signature" ); + val = koinos::chain::system_call::get_block_field( ctx, "signature" ); + BOOST_REQUIRE_EQUAL( val.bytes_value(), block.signature() ); - KOINOS_REQUIRE_THROW( chain::system_call::get_block_field( ctx, "non_existent_field" ), chain::field_not_found ); + BOOST_TEST_MESSAGE( "Testing dynamic block field not found" ); - ctx.clear_block(); + KOINOS_REQUIRE_THROW( chain::system_call::get_block_field( ctx, "non_existent_field" ), chain::field_not_found ); - BOOST_TEST_MESSAGE( "Testing dynamic block field unexpected access" ); + ctx.clear_block(); - KOINOS_REQUIRE_THROW( chain::system_call::get_block_field( ctx, "id" ), chain::internal_error ); + BOOST_TEST_MESSAGE( "Testing dynamic block field unexpected access" ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + KOINOS_REQUIRE_THROW( chain::system_call::get_block_field( ctx, "id" ), chain::internal_error ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( get_operation ) -{ try { - auto test_key_a = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "test a"s ) ); - auto test_address_a = test_key_a.get_public_key().to_address_bytes(); - - protocol::operation op; - op.mutable_call_contract()->set_contract_id( test_address_a ); +{ + try + { + auto test_key_a = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "test a"s ) ); + auto test_address_a = test_key_a.get_public_key().to_address_bytes(); - BOOST_CHECK( !ctx.get_operation() ); - KOINOS_CHECK_THROW( chain::system_call::get_operation( ctx ), chain::operation_not_found ); + protocol::operation op; + op.mutable_call_contract()->set_contract_id( test_address_a ); - ctx.set_operation( op ); + BOOST_CHECK( !ctx.get_operation() ); + KOINOS_CHECK_THROW( chain::system_call::get_operation( ctx ), chain::operation_not_found ); - BOOST_CHECK_EQUAL( ctx.get_operation(), &op ); - auto op2 = chain::system_call::get_operation( ctx ); - BOOST_CHECK( op2.has_call_contract() ); - BOOST_CHECK_EQUAL( op2.call_contract().contract_id(), test_address_a ); + ctx.set_operation( op ); - ctx.clear_operation(); + BOOST_CHECK_EQUAL( ctx.get_operation(), &op ); + auto op2 = chain::system_call::get_operation( ctx ); + BOOST_CHECK( op2.has_call_contract() ); + BOOST_CHECK_EQUAL( op2.call_contract().contract_id(), test_address_a ); - BOOST_CHECK( !ctx.get_operation() ); - KOINOS_CHECK_THROW( chain::system_call::get_operation( ctx ), chain::operation_not_found ); + ctx.clear_operation(); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_CHECK( !ctx.get_operation() ); + KOINOS_CHECK_THROW( chain::system_call::get_operation( ctx ), chain::operation_not_found ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( db_crud ) -{ try { - std::string object_data; - - chain::object_space test_space; - test_space.set_system( true ); - test_space.set_zone( chain::state::zone::kernel ); - test_space.set_id( 100 ); - - object_data = "object1"s; - - BOOST_TEST_MESSAGE( "Test putting an object" ); - - chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 1 ), object_data ); - auto db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); - BOOST_REQUIRE( object_data == "object1" ); - - BOOST_TEST_MESSAGE( "Testing getting a non-existent object" ); - - db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 2 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - - BOOST_TEST_MESSAGE( "Test iteration" ); - - object_data = "object2"s; - chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 2 ), object_data ); - object_data = "object3"s; - chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 3 ), object_data ); - - db_obj = chain::system_call::get_next_object( ctx, test_space, util::converter::as< std::string >( 2 ) ); - BOOST_REQUIRE( db_obj.value() == "object3" ); - - db_obj = chain::system_call::get_prev_object( ctx, test_space, util::converter::as< std::string >( 2 ) ); - BOOST_REQUIRE( db_obj.value() == "object1" ); - - BOOST_TEST_MESSAGE( "Test iterator overrun" ); - - db_obj = chain::system_call::get_next_object( ctx, test_space, util::converter::as< std::string >( 3 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - db_obj = chain::system_call::get_next_object( ctx, test_space, util::converter::as< std::string >( 4 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - db_obj = chain::system_call::get_prev_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - db_obj = chain::system_call::get_prev_object( ctx, test_space, util::converter::as< std::string >( 0 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - - object_data = "space1.object1"s; - chain::system_call::put_object( ctx, chain::state::space::contract_bytecode(), util::converter::as< std::string >( 1 ), object_data ); - db_obj = chain::system_call::get_next_object( ctx, test_space, util::converter::as< std::string >( 3 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - db_obj = chain::system_call::get_next_object( ctx, chain::state::space::contract_bytecode(), util::converter::as< std::string >( 1 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - db_obj = chain::system_call::get_prev_object( ctx, chain::state::space::contract_bytecode(), util::converter::as< std::string >( 1 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - - BOOST_TEST_MESSAGE( "Test object modification" ); - object_data = "object1.1"s; - chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 1 ), object_data ); - db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); - BOOST_REQUIRE( db_obj.value() == "object1.1" ); - - BOOST_TEST_MESSAGE( "Test object deletion" ); - object_data.clear(); - chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 1 ), object_data ); - db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); - BOOST_REQUIRE( db_obj.exists() ); - BOOST_REQUIRE( db_obj.value().size() == 0 ); - - chain::system_call::remove_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); - db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); - BOOST_REQUIRE( !db_obj.exists() ); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + std::string object_data; + + chain::object_space test_space; + test_space.set_system( true ); + test_space.set_zone( chain::state::zone::kernel ); + test_space.set_id( 100 ); + + object_data = "object1"s; + + BOOST_TEST_MESSAGE( "Test putting an object" ); + + chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 1 ), object_data ); + auto db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); + BOOST_REQUIRE( object_data == "object1" ); + + BOOST_TEST_MESSAGE( "Testing getting a non-existent object" ); + + db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 2 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + + BOOST_TEST_MESSAGE( "Test iteration" ); + + object_data = "object2"s; + chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 2 ), object_data ); + object_data = "object3"s; + chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 3 ), object_data ); + + db_obj = chain::system_call::get_next_object( ctx, test_space, util::converter::as< std::string >( 2 ) ); + BOOST_REQUIRE( db_obj.value() == "object3" ); + + db_obj = chain::system_call::get_prev_object( ctx, test_space, util::converter::as< std::string >( 2 ) ); + BOOST_REQUIRE( db_obj.value() == "object1" ); + + BOOST_TEST_MESSAGE( "Test iterator overrun" ); + + db_obj = chain::system_call::get_next_object( ctx, test_space, util::converter::as< std::string >( 3 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + db_obj = chain::system_call::get_next_object( ctx, test_space, util::converter::as< std::string >( 4 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + db_obj = chain::system_call::get_prev_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + db_obj = chain::system_call::get_prev_object( ctx, test_space, util::converter::as< std::string >( 0 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + + object_data = "space1.object1"s; + chain::system_call::put_object( ctx, + chain::state::space::contract_bytecode(), + util::converter::as< std::string >( 1 ), + object_data ); + db_obj = chain::system_call::get_next_object( ctx, test_space, util::converter::as< std::string >( 3 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + db_obj = chain::system_call::get_next_object( ctx, + chain::state::space::contract_bytecode(), + util::converter::as< std::string >( 1 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + db_obj = chain::system_call::get_prev_object( ctx, + chain::state::space::contract_bytecode(), + util::converter::as< std::string >( 1 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + + BOOST_TEST_MESSAGE( "Test object modification" ); + object_data = "object1.1"s; + chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 1 ), object_data ); + db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); + BOOST_REQUIRE( db_obj.value() == "object1.1" ); + + BOOST_TEST_MESSAGE( "Test object deletion" ); + object_data.clear(); + chain::system_call::put_object( ctx, test_space, util::converter::as< std::string >( 1 ), object_data ); + db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); + BOOST_REQUIRE( db_obj.exists() ); + BOOST_REQUIRE( db_obj.value().size() == 0 ); + + chain::system_call::remove_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); + db_obj = chain::system_call::get_object( ctx, test_space, util::converter::as< std::string >( 1 ) ); + BOOST_REQUIRE( !db_obj.exists() ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( db_permissions ) -{ try { - auto test_key_a = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "test a"s ) ); - auto test_address_a = test_key_a.get_public_key().to_address_bytes(); - - auto test_key_b = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "test b"s ) ); - auto test_address_b = test_key_b.get_public_key().to_address_bytes(); - - chain::object_space space; - - - BOOST_TEST_MESSAGE( "Test failure accessing user data outside your zone from user context" ); - - ctx.push_frame( chain::stack_frame{ .contract_id = test_address_a, .call_privilege = chain::user_mode } ); - ctx.push_frame( chain::stack_frame{ .call_privilege = chain::user_mode } ); - - space.set_zone( test_address_b ); - space.set_system( false ); - - KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::reversion ); - - - BOOST_TEST_MESSAGE( "Test success accessing user data inside your zone from user context" ); +{ + try + { + auto test_key_a = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "test a"s ) ); + auto test_address_a = test_key_a.get_public_key().to_address_bytes(); - space.set_zone( test_address_a ); + auto test_key_b = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "test b"s ) ); + auto test_address_b = test_key_b.get_public_key().to_address_bytes(); - BOOST_CHECK_NO_THROW( chain::state::assert_permissions( ctx, space ) ); + chain::object_space space; + BOOST_TEST_MESSAGE( "Test failure accessing user data outside your zone from user context" ); - BOOST_TEST_MESSAGE( "Test failure accessing kernel data outside your zone from user context" ); + ctx.push_frame( chain::stack_frame{ .contract_id = test_address_a, .call_privilege = chain::user_mode } ); + ctx.push_frame( chain::stack_frame{ .call_privilege = chain::user_mode } ); - space.set_zone( test_address_b ); - space.set_system( true ); + space.set_zone( test_address_b ); + space.set_system( false ); - KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::insufficient_privileges ); + KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::reversion ); + BOOST_TEST_MESSAGE( "Test success accessing user data inside your zone from user context" ); - BOOST_TEST_MESSAGE( "Test failure accessing kernel data inside your zone from user context" ); + space.set_zone( test_address_a ); - space.set_zone( test_address_a ); + BOOST_CHECK_NO_THROW( chain::state::assert_permissions( ctx, space ) ); - KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::insufficient_privileges ); + BOOST_TEST_MESSAGE( "Test failure accessing kernel data outside your zone from user context" ); + space.set_zone( test_address_b ); + space.set_system( true ); - BOOST_TEST_MESSAGE( "Test failure accessing user data outside your zone from kernel context" ); + KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::insufficient_privileges ); - ctx.pop_frame(); - ctx.pop_frame(); + BOOST_TEST_MESSAGE( "Test failure accessing kernel data inside your zone from user context" ); - ctx.push_frame( chain::stack_frame{ .contract_id = test_address_a, .call_privilege = chain::kernel_mode } ); - ctx.push_frame( chain::stack_frame{ .call_privilege = chain::kernel_mode } ); + space.set_zone( test_address_a ); - space.set_zone( test_address_b ); - space.set_system( false ); + KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::insufficient_privileges ); - KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::reversion ); + BOOST_TEST_MESSAGE( "Test failure accessing user data outside your zone from kernel context" ); + ctx.pop_frame(); + ctx.pop_frame(); - BOOST_TEST_MESSAGE( "Test failure accessing user data inside your zone from kernel context" ); + ctx.push_frame( chain::stack_frame{ .contract_id = test_address_a, .call_privilege = chain::kernel_mode } ); + ctx.push_frame( chain::stack_frame{ .call_privilege = chain::kernel_mode } ); - space.set_zone( test_address_a ); + space.set_zone( test_address_b ); + space.set_system( false ); - KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::reversion ); + KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::reversion ); + BOOST_TEST_MESSAGE( "Test failure accessing user data inside your zone from kernel context" ); - BOOST_TEST_MESSAGE( "Test success accessing kernel data outside your zone from kernel context" ); + space.set_zone( test_address_a ); - space.set_zone( test_address_b ); - space.set_system( true ); + KOINOS_CHECK_THROW( chain::state::assert_permissions( ctx, space ), chain::reversion ); - BOOST_CHECK_NO_THROW( chain::state::assert_permissions( ctx, space ) ); + BOOST_TEST_MESSAGE( "Test success accessing kernel data outside your zone from kernel context" ); + space.set_zone( test_address_b ); + space.set_system( true ); - BOOST_TEST_MESSAGE( "Test success accessing kernel data inside your zone from kernel context" ); + BOOST_CHECK_NO_THROW( chain::state::assert_permissions( ctx, space ) ); - space.set_zone( test_address_a ); + BOOST_TEST_MESSAGE( "Test success accessing kernel data inside your zone from kernel context" ); - BOOST_CHECK_NO_THROW( chain::state::assert_permissions( ctx, space ) ); + space.set_zone( test_address_a ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_CHECK_NO_THROW( chain::state::assert_permissions( ctx, space ) ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( contract_tests ) -{ try { - BOOST_TEST_MESSAGE( "Test uploading a contract" ); - - auto contract_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); - auto contract_address = contract_private_key.get_public_key().to_address_bytes(); - koinos::protocol::transaction trx; - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); - - koinos::protocol::upload_contract_operation op; - op.set_contract_id( util::converter::as< std::string >( contract_address ) ); - op.set_bytecode( get_hello_wasm() ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); - - auto bytecode_object = koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_bytecode(), op.contract_id() ); - auto meta = util::converter::to< koinos::chain::contract_metadata_object >( koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_metadata(), op.contract_id() ).value() ); - - BOOST_REQUIRE( bytecode_object.exists() ); - BOOST_REQUIRE( bytecode_object.value().size() == op.bytecode().size() ); - BOOST_REQUIRE( std::memcmp( bytecode_object.value().c_str(), op.bytecode().c_str(), op.bytecode().size() ) == 0 ); - BOOST_REQUIRE( meta.hash() == util::converter::as< std::string >( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, bytecode_object.value() ) ) ); - - BOOST_TEST_MESSAGE( "Test executing a contract" ); - - koinos::protocol::call_contract_operation op2; - op2.set_contract_id( op.contract_id() ); - koinos::chain::system_call::apply_call_contract_operation( ctx, op2 ); - BOOST_REQUIRE_EQUAL( "Greetings from koinos vm", ctx.chronicler().logs()[0] ); - - BOOST_TEST_MESSAGE( "Test contract return" ); - - // Upload the return test contract - op.set_bytecode( get_contract_return_wasm() ); - koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); - - auto contract_ret = koinos::chain::system_call::call(ctx, op.contract_id(), 0, "echo"); - - BOOST_REQUIRE_EQUAL( contract_ret, "echo" ); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + BOOST_TEST_MESSAGE( "Test uploading a contract" ); + + auto contract_private_key = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); + auto contract_address = contract_private_key.get_public_key().to_address_bytes(); + koinos::protocol::transaction trx; + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); + + koinos::protocol::upload_contract_operation op; + op.set_contract_id( util::converter::as< std::string >( contract_address ) ); + op.set_bytecode( get_hello_wasm() ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); + + auto bytecode_object = + koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_bytecode(), op.contract_id() ); + auto meta = util::converter::to< koinos::chain::contract_metadata_object >( + koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_metadata(), op.contract_id() ) + .value() ); + + BOOST_REQUIRE( bytecode_object.exists() ); + BOOST_REQUIRE( bytecode_object.value().size() == op.bytecode().size() ); + BOOST_REQUIRE( std::memcmp( bytecode_object.value().c_str(), op.bytecode().c_str(), op.bytecode().size() ) == 0 ); + BOOST_REQUIRE( meta.hash() + == util::converter::as< std::string >( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, bytecode_object.value() ) ) ); + + BOOST_TEST_MESSAGE( "Test executing a contract" ); + + koinos::protocol::call_contract_operation op2; + op2.set_contract_id( op.contract_id() ); + koinos::chain::system_call::apply_call_contract_operation( ctx, op2 ); + BOOST_REQUIRE_EQUAL( "Greetings from koinos vm", ctx.chronicler().logs()[ 0 ] ); + + BOOST_TEST_MESSAGE( "Test contract return" ); + + // Upload the return test contract + op.set_bytecode( get_contract_return_wasm() ); + koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); + + auto contract_ret = koinos::chain::system_call::call( ctx, op.contract_id(), 0, "echo" ); + + BOOST_REQUIRE_EQUAL( contract_ret, "echo" ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( override_tests ) -{ try { - BOOST_TEST_MESSAGE( "Test set system call operation" ); - - auto seed = "non-genesis key"s; - auto random_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, seed ) ); - - koinos::protocol::transaction tx; - sign_transaction( tx, random_private_key ); - ctx.set_transaction( tx ); - - // Upload a test contract to use as override - auto contract_address = random_private_key.get_public_key().to_address_bytes(); - - koinos::protocol::upload_contract_operation contract_op; - contract_op.set_contract_id( util::converter::as< std::string >( contract_address ) ); - contract_op.set_bytecode( get_hello_wasm() ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, contract_op ); - - koinos::protocol::call_contract_operation call_op; - call_op.set_contract_id( contract_op.contract_id() ); - koinos::chain::system_call::apply_call_contract_operation( ctx, call_op ); - auto original_message = host._ctx.chronicler().logs()[0]; - for ( const auto& message : host._ctx.chronicler().logs() ) - LOG(info) << message; - BOOST_REQUIRE_EQUAL( "Greetings from koinos vm", original_message ); - - // Override log with a contract that prepends a message before printing - auto random_private_key2 = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "key2"s ) ); - auto contract_address2 = random_private_key2.get_public_key().to_address_bytes(); - - koinos::protocol::upload_contract_operation contract_op2; - contract_op2.set_contract_id( util::converter::as< std::string >( contract_address2 ) ); - contract_op2.set_bytecode( get_syscall_override_wasm() ); - - sign_transaction( tx, random_private_key2 ); - ctx.set_transaction( tx ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, contract_op2 ); - - // Set the system call - koinos::protocol::set_system_call_operation set_op; - set_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); - set_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( contract_op2.contract_id() ); - set_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); - - BOOST_TEST_MESSAGE( "Test failure to override system call without genesis key" ); - - KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ), koinos::chain::system_authorization_failure ); - - BOOST_TEST_MESSAGE( "Test failure to set system contract without genesis key" ); - - koinos::protocol::set_system_contract_operation system_contract_op; - system_contract_op.set_contract_id( contract_op2.contract_id() ); - system_contract_op.set_system_contract( true ); - - KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_set_system_contract_operation( ctx, system_contract_op ), koinos::chain::system_authorization_failure ); - - BOOST_TEST_MESSAGE( "Test failure to override system call without system contract" ); - - // Overriding system calls requires the genesis key - sign_transaction( tx, _signing_private_key ); - ctx.set_transaction( tx ); - - KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ), koinos::chain::invalid_contract ); - - BOOST_TEST_MESSAGE( "Test success overriding a system call with the genesis key" ); - - koinos::chain::system_call::apply_set_system_contract_operation( ctx, system_contract_op ); - koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ); - - // Fetch the created call bundle from the database and check it has been updated - auto call_target = koinos::util::converter::to< koinos::protocol::system_call_target >( koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::system_call_dispatch(), util::converter::as< std::string >( set_op.call_id() ) ).value() ); - BOOST_REQUIRE( call_target.has_system_call_bundle() ); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - ctx.reset_cache(); - call_target = koinos::util::converter::to< koinos::protocol::system_call_target >( koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::system_call_dispatch(), util::converter::as< std::string >( set_op.call_id() ) ).value() ); - BOOST_REQUIRE( call_target.has_system_call_bundle() ); - BOOST_REQUIRE( call_target.system_call_bundle().contract_id() == set_op.target().system_call_bundle().contract_id() ); - BOOST_REQUIRE( call_target.system_call_bundle().entry_point() == set_op.target().system_call_bundle().entry_point() ); - - // Ensure exception thrown on invalid contract - auto false_id = koinos::crypto::hash( koinos::crypto::multicodec::ripemd_160, 1234 ); - set_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( util::converter::as< std::string >( false_id ) ); - KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ), koinos::chain::invalid_contract ); - - // Test invoking the overridden system call - koinos::chain::system_call::apply_call_contract_operation( ctx, call_op ); - BOOST_REQUIRE_EQUAL( "test: " + original_message, host._ctx.chronicler().logs()[1] ); - - koinos::chain::system_call::log( host._ctx, "Hello World" ); - BOOST_REQUIRE_EQUAL( "test: Hello World", host._ctx.chronicler().logs()[2] ); - - BOOST_TEST_MESSAGE( "Test adding a new thunk" ); - - const_cast< chain::thunk_dispatcher& >( chain::thunk_dispatcher::instance() ).register_thunk< chain::log_arguments, chain::log_result >( 0, chain::thunk::test_thunk ); - chain::log_arguments log_args; - log_args.set_message( "Hello World" ); - auto args = util::converter::as< std::string >( log_args ); - char ret_buf[100]; - uint32_t bytes_written = 0; - ctx.set_privilege( chain::privilege::user_mode ); - KOINOS_CHECK_THROW( host.invoke_system_call( 0, ret_buf, 100, args.data(), uint32_t( args.size() ), &bytes_written ), chain::unknown_thunk ); - - BOOST_TEST_MESSAGE( "Test overriding a system call with another thunk" ); - - set_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); - set_op.mutable_target()->set_thunk_id( 0 ); - ctx.set_privilege( chain::privilege::kernel_mode ); - koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - ctx.reset_cache(); - - KOINOS_CHECK_THROW( koinos::chain::system_call::log( host._ctx, "Hello World" ), chain::reversion ); - - auto cbr = util::converter::to< chain::compute_bandwidth_registry >( chain::system_call::get_object( ctx, chain::state::space::metadata(), chain::state::key::compute_bandwidth_registry ).value() ); - auto centry = cbr.add_entries(); - centry->set_name( "nop" ); - centry->set_compute( 0 ); - - chain::system_call::put_object( ctx, chain::state::space::metadata(), chain::state::key::compute_bandwidth_registry, util::converter::as< std::string >( cbr ) ); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - ctx.reset_cache(); - - koinos::chain::system_call::log( host._ctx, "Hello World" ); - BOOST_REQUIRE_EQUAL( "thunk: Hello World", host._ctx.chronicler().logs()[3] ); - - host.invoke_system_call( chain::system_call_id::log, ret_buf, 100, args.data(), uint32_t( args.size() ), &bytes_written ); - ctx.set_privilege( chain::privilege::user_mode ); - KOINOS_CHECK_THROW( host.invoke_system_call( 0, ret_buf, 100, args.data(), uint32_t( args.size() ), &bytes_written ), chain::unknown_thunk ); - ctx.set_privilege( chain::privilege::kernel_mode ); - - BOOST_TEST_MESSAGE( "Test enabling new thunk passthrough" ); - - set_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::nop ) ); - koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - ctx.reset_cache(); - - host.invoke_system_call( 0, ret_buf, 100, args.data(), uint32_t( args.size() ), &bytes_written ); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + BOOST_TEST_MESSAGE( "Test set system call operation" ); + + auto seed = "non-genesis key"s; + auto random_private_key = + koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, seed ) ); + + koinos::protocol::transaction tx; + sign_transaction( tx, random_private_key ); + ctx.set_transaction( tx ); + + // Upload a test contract to use as override + auto contract_address = random_private_key.get_public_key().to_address_bytes(); + + koinos::protocol::upload_contract_operation contract_op; + contract_op.set_contract_id( util::converter::as< std::string >( contract_address ) ); + contract_op.set_bytecode( get_hello_wasm() ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, contract_op ); + + koinos::protocol::call_contract_operation call_op; + call_op.set_contract_id( contract_op.contract_id() ); + koinos::chain::system_call::apply_call_contract_operation( ctx, call_op ); + auto original_message = host._ctx.chronicler().logs()[ 0 ]; + for( const auto& message: host._ctx.chronicler().logs() ) + LOG( info ) << message; + BOOST_REQUIRE_EQUAL( "Greetings from koinos vm", original_message ); + + // Override log with a contract that prepends a message before printing + auto random_private_key2 = + koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "key2"s ) ); + auto contract_address2 = random_private_key2.get_public_key().to_address_bytes(); + + koinos::protocol::upload_contract_operation contract_op2; + contract_op2.set_contract_id( util::converter::as< std::string >( contract_address2 ) ); + contract_op2.set_bytecode( get_syscall_override_wasm() ); + + sign_transaction( tx, random_private_key2 ); + ctx.set_transaction( tx ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, contract_op2 ); + + // Set the system call + koinos::protocol::set_system_call_operation set_op; + set_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); + set_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( contract_op2.contract_id() ); + set_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); + + BOOST_TEST_MESSAGE( "Test failure to override system call without genesis key" ); + + KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ), + koinos::chain::system_authorization_failure ); + + BOOST_TEST_MESSAGE( "Test failure to set system contract without genesis key" ); + + koinos::protocol::set_system_contract_operation system_contract_op; + system_contract_op.set_contract_id( contract_op2.contract_id() ); + system_contract_op.set_system_contract( true ); + + KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_set_system_contract_operation( ctx, system_contract_op ), + koinos::chain::system_authorization_failure ); + + BOOST_TEST_MESSAGE( "Test failure to override system call without system contract" ); + + // Overriding system calls requires the genesis key + sign_transaction( tx, _signing_private_key ); + ctx.set_transaction( tx ); + + KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ), + koinos::chain::invalid_contract ); + + BOOST_TEST_MESSAGE( "Test success overriding a system call with the genesis key" ); + + koinos::chain::system_call::apply_set_system_contract_operation( ctx, system_contract_op ); + koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ); + + // Fetch the created call bundle from the database and check it has been updated + auto call_target = koinos::util::converter::to< koinos::protocol::system_call_target >( + koinos::chain::system_call::get_object( ctx, + koinos::chain::state::space::system_call_dispatch(), + util::converter::as< std::string >( set_op.call_id() ) ) + .value() ); + BOOST_REQUIRE( call_target.has_system_call_bundle() ); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + ctx.reset_cache(); + call_target = koinos::util::converter::to< koinos::protocol::system_call_target >( + koinos::chain::system_call::get_object( ctx, + koinos::chain::state::space::system_call_dispatch(), + util::converter::as< std::string >( set_op.call_id() ) ) + .value() ); + BOOST_REQUIRE( call_target.has_system_call_bundle() ); + BOOST_REQUIRE( call_target.system_call_bundle().contract_id() + == set_op.target().system_call_bundle().contract_id() ); + BOOST_REQUIRE( call_target.system_call_bundle().entry_point() + == set_op.target().system_call_bundle().entry_point() ); + + // Ensure exception thrown on invalid contract + auto false_id = koinos::crypto::hash( koinos::crypto::multicodec::ripemd_160, 1'234 ); + set_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( + util::converter::as< std::string >( false_id ) ); + KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ), + koinos::chain::invalid_contract ); + + // Test invoking the overridden system call + koinos::chain::system_call::apply_call_contract_operation( ctx, call_op ); + BOOST_REQUIRE_EQUAL( "test: " + original_message, host._ctx.chronicler().logs()[ 1 ] ); + + koinos::chain::system_call::log( host._ctx, "Hello World" ); + BOOST_REQUIRE_EQUAL( "test: Hello World", host._ctx.chronicler().logs()[ 2 ] ); + + BOOST_TEST_MESSAGE( "Test adding a new thunk" ); + + const_cast< chain::thunk_dispatcher& >( chain::thunk_dispatcher::instance() ) + .register_thunk< chain::log_arguments, chain::log_result >( 0, chain::thunk::test_thunk ); + chain::log_arguments log_args; + log_args.set_message( "Hello World" ); + auto args = util::converter::as< std::string >( log_args ); + char ret_buf[ 100 ]; + uint32_t bytes_written = 0; + ctx.set_privilege( chain::privilege::user_mode ); + KOINOS_CHECK_THROW( + host.invoke_system_call( 0, ret_buf, 100, args.data(), uint32_t( args.size() ), &bytes_written ), + chain::unknown_thunk ); + + BOOST_TEST_MESSAGE( "Test overriding a system call with another thunk" ); + + set_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); + set_op.mutable_target()->set_thunk_id( 0 ); + ctx.set_privilege( chain::privilege::kernel_mode ); + koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + ctx.reset_cache(); + + KOINOS_CHECK_THROW( koinos::chain::system_call::log( host._ctx, "Hello World" ), chain::reversion ); + + auto cbr = util::converter::to< chain::compute_bandwidth_registry >( + chain::system_call::get_object( ctx, + chain::state::space::metadata(), + chain::state::key::compute_bandwidth_registry ) + .value() ); + auto centry = cbr.add_entries(); + centry->set_name( "nop" ); + centry->set_compute( 0 ); + + chain::system_call::put_object( ctx, + chain::state::space::metadata(), + chain::state::key::compute_bandwidth_registry, + util::converter::as< std::string >( cbr ) ); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + ctx.reset_cache(); + + koinos::chain::system_call::log( host._ctx, "Hello World" ); + BOOST_REQUIRE_EQUAL( "thunk: Hello World", host._ctx.chronicler().logs()[ 3 ] ); + + host.invoke_system_call( chain::system_call_id::log, + ret_buf, + 100, + args.data(), + uint32_t( args.size() ), + &bytes_written ); + ctx.set_privilege( chain::privilege::user_mode ); + KOINOS_CHECK_THROW( + host.invoke_system_call( 0, ret_buf, 100, args.data(), uint32_t( args.size() ), &bytes_written ), + chain::unknown_thunk ); + ctx.set_privilege( chain::privilege::kernel_mode ); + + BOOST_TEST_MESSAGE( "Test enabling new thunk passthrough" ); + + set_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::nop ) ); + koinos::chain::system_call::apply_set_system_call_operation( ctx, set_op ); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + ctx.reset_cache(); + + host.invoke_system_call( 0, ret_buf, 100, args.data(), uint32_t( args.size() ), &bytes_written ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( thunk_test ) -{ try { - BOOST_TEST_MESSAGE( "thunk test" ); - - chain::log_arguments args; - - std::string arg; - std::string ret; - uint32_t bytes_written = 0; - - args.set_message( "Hello World" ); - args.SerializeToString( &arg ); - - host.invoke_thunk( - chain::system_call_id::log, - ret.data(), - uint32_t( ret.size() ), - arg.data(), - uint32_t( arg.size() ), - &bytes_written - ); - - BOOST_CHECK_EQUAL( ret.size(), 0 ); - BOOST_REQUIRE_EQUAL( "Hello World", ctx.chronicler().logs()[0] ); - - ctx.push_frame( chain::stack_frame{ .contract_id = "user_contract", .call_privilege = chain::user_mode } ); - KOINOS_REQUIRE_THROW( host.invoke_thunk( chain::system_call_id::log, ret.data(), uint32_t( ret.size() ), arg.data(), uint32_t( arg.size() ), &bytes_written ), chain::insufficient_privileges ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + BOOST_TEST_MESSAGE( "thunk test" ); + + chain::log_arguments args; + + std::string arg; + std::string ret; + uint32_t bytes_written = 0; + + args.set_message( "Hello World" ); + args.SerializeToString( &arg ); + + host.invoke_thunk( chain::system_call_id::log, + ret.data(), + uint32_t( ret.size() ), + arg.data(), + uint32_t( arg.size() ), + &bytes_written ); + + BOOST_CHECK_EQUAL( ret.size(), 0 ); + BOOST_REQUIRE_EQUAL( "Hello World", ctx.chronicler().logs()[ 0 ] ); + + ctx.push_frame( chain::stack_frame{ .contract_id = "user_contract", .call_privilege = chain::user_mode } ); + KOINOS_REQUIRE_THROW( host.invoke_thunk( chain::system_call_id::log, + ret.data(), + uint32_t( ret.size() ), + arg.data(), + uint32_t( arg.size() ), + &bytes_written ), + chain::insufficient_privileges ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( system_call_test ) -{ try { - BOOST_TEST_MESSAGE( "system call test" ); - - chain::log_arguments args; - - std::string arg; - std::string ret; - uint32_t bytes_written = 0; - - args.set_message( "Hello World" ); - args.SerializeToString( &arg ); - - host.invoke_system_call( - chain::system_call_id::log, - ret.data(), - uint32_t( ret.size() ), - arg.data(), - uint32_t( arg.size() ), - &bytes_written - ); - - BOOST_CHECK_EQUAL( ret.size(), 0 ); - BOOST_REQUIRE_EQUAL( "Hello World", ctx.chronicler().logs()[0] ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + BOOST_TEST_MESSAGE( "system call test" ); + + chain::log_arguments args; + + std::string arg; + std::string ret; + uint32_t bytes_written = 0; + + args.set_message( "Hello World" ); + args.SerializeToString( &arg ); + + host.invoke_system_call( chain::system_call_id::log, + ret.data(), + uint32_t( ret.size() ), + arg.data(), + uint32_t( arg.size() ), + &bytes_written ); + + BOOST_CHECK_EQUAL( ret.size(), 0 ); + BOOST_REQUIRE_EQUAL( "Hello World", ctx.chronicler().logs()[ 0 ] ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( get_head_info_thunk_test ) -{ try { - BOOST_TEST_MESSAGE( "get_head_info thunk test" ); - - BOOST_CHECK_EQUAL( chain::system_call::get_head_info( ctx ).head_topology().height(), 1 ); +{ + try + { + BOOST_TEST_MESSAGE( "get_head_info thunk test" ); - koinos::protocol::block block; - block.mutable_header()->set_timestamp( 1000 ); - ctx.set_block( block ); + BOOST_CHECK_EQUAL( chain::system_call::get_head_info( ctx ).head_topology().height(), 1 ); - BOOST_REQUIRE( chain::system_call::get_head_info( ctx ).head_block_time() == block.header().timestamp() ); + koinos::protocol::block block; + block.mutable_header()->set_timestamp( 1'000 ); + ctx.set_block( block ); - ctx.clear_block(); + BOOST_REQUIRE( chain::system_call::get_head_info( ctx ).head_block_time() == block.header().timestamp() ); - chain::system_call::put_object( ctx, chain::state::space::metadata(), chain::state::key::head_block, util::converter::as< std::string >( block ) ); + ctx.clear_block(); - BOOST_REQUIRE( chain::system_call::get_head_info( ctx ).head_block_time() == block.header().timestamp() ); + chain::system_call::put_object( ctx, + chain::state::space::metadata(), + chain::state::key::head_block, + util::converter::as< std::string >( block ) ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_REQUIRE( chain::system_call::get_head_info( ctx ).head_block_time() == block.header().timestamp() ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( hash_thunk_test ) -{ try { - BOOST_TEST_MESSAGE( "hash thunk test" ); - - std::string test_string = "hash::string"; +{ + try + { + BOOST_TEST_MESSAGE( "hash thunk test" ); - auto thunk_hash = util::converter::to< crypto::multihash >( chain::system_call::hash( ctx, static_cast< uint64_t >( crypto::multicodec::sha2_256 ), test_string ) ); - auto native_hash = crypto::hash( crypto::multicodec::sha2_256, test_string ); + std::string test_string = "hash::string"; - BOOST_CHECK_EQUAL( thunk_hash, native_hash ); + auto thunk_hash = util::converter::to< crypto::multihash >( + chain::system_call::hash( ctx, static_cast< uint64_t >( crypto::multicodec::sha2_256 ), test_string ) ); + auto native_hash = crypto::hash( crypto::multicodec::sha2_256, test_string ); - koinos::block_topology block_topology; - block_topology.set_height( 100 ); - block_topology.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, "random::id"s ) ) ); - block_topology.set_previous( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, "random::previous"s ) ) ); + BOOST_CHECK_EQUAL( thunk_hash, native_hash ); - std::string blob; - block_topology.SerializeToString( &blob ); - thunk_hash = util::converter::to< crypto::multihash >( chain::system_call::hash( ctx, static_cast< uint64_t >( crypto::multicodec::sha2_256 ), blob ) ); - native_hash = crypto::hash( crypto::multicodec::sha2_256, block_topology ); + koinos::block_topology block_topology; + block_topology.set_height( 100 ); + block_topology.set_id( + util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, "random::id"s ) ) ); + block_topology.set_previous( + util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, "random::previous"s ) ) ); - BOOST_CHECK_EQUAL( thunk_hash, native_hash ); + std::string blob; + block_topology.SerializeToString( &blob ); + thunk_hash = util::converter::to< crypto::multihash >( + chain::system_call::hash( ctx, static_cast< uint64_t >( crypto::multicodec::sha2_256 ), blob ) ); + native_hash = crypto::hash( crypto::multicodec::sha2_256, block_topology ); - KOINOS_REQUIRE_THROW( chain::system_call::hash( ctx, 0xDEADBEEF /* unknown code */, blob ), koinos::chain::unknown_hash_code ); + BOOST_CHECK_EQUAL( thunk_hash, native_hash ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + KOINOS_REQUIRE_THROW( chain::system_call::hash( ctx, 0xDEADBEEF /* unknown code */, blob ), + koinos::chain::unknown_hash_code ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( privileged_calls ) { - ctx.set_privilege( chain::privilege::user_mode ); - - KOINOS_REQUIRE_THROW( chain::system_call::apply_block( ctx, protocol::block{} ), koinos::chain::insufficient_privileges ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, protocol::transaction() ), koinos::chain::insufficient_privileges ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_upload_contract_operation( ctx, protocol::upload_contract_operation{} ), koinos::chain::insufficient_privileges ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_call_contract_operation( ctx, protocol::call_contract_operation{} ), koinos::chain::insufficient_privileges ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_set_system_call_operation( ctx, protocol::set_system_call_operation{} ), koinos::chain::insufficient_privileges ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_set_system_contract_operation( ctx, protocol::set_system_contract_operation{} ), koinos::chain::insufficient_privileges ); + ctx.set_privilege( chain::privilege::user_mode ); + + KOINOS_REQUIRE_THROW( chain::system_call::apply_block( ctx, protocol::block{} ), + koinos::chain::insufficient_privileges ); + KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, protocol::transaction() ), + koinos::chain::insufficient_privileges ); + KOINOS_REQUIRE_THROW( + chain::system_call::apply_upload_contract_operation( ctx, protocol::upload_contract_operation{} ), + koinos::chain::insufficient_privileges ); + KOINOS_REQUIRE_THROW( chain::system_call::apply_call_contract_operation( ctx, protocol::call_contract_operation{} ), + koinos::chain::insufficient_privileges ); + KOINOS_REQUIRE_THROW( + chain::system_call::apply_set_system_call_operation( ctx, protocol::set_system_call_operation{} ), + koinos::chain::insufficient_privileges ); + KOINOS_REQUIRE_THROW( + chain::system_call::apply_set_system_contract_operation( ctx, protocol::set_system_contract_operation{} ), + koinos::chain::insufficient_privileges ); } BOOST_AUTO_TEST_CASE( last_irreversible_block_test ) -{ try { - - BOOST_TEST_MESSAGE( "last irreversible block test" ); - auto shared_db_lock = db.get_shared_lock(); +{ + try + { + BOOST_TEST_MESSAGE( "last irreversible block test" ); + auto shared_db_lock = db.get_shared_lock(); - for( uint64_t i = 0; i < chain::default_irreversible_threshold; i++ ) - { + for( uint64_t i = 0; i < chain::default_irreversible_threshold; i++ ) + { auto lib = chain::system_call::get_last_irreversible_block( ctx ); BOOST_REQUIRE_EQUAL( lib, 0 ); db.finalize_node( ctx.get_state_node()->id(), shared_db_lock ); - ctx.set_state_node( db.create_writable_node( ctx.get_state_node()->id(), crypto::hash( crypto::multicodec::sha2_256, i ), protocol::block_header(), shared_db_lock ) ); - } - - auto lib = chain::system_call::get_last_irreversible_block( ctx ); - BOOST_REQUIRE_EQUAL( lib, 1 ); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + ctx.set_state_node( db.create_writable_node( ctx.get_state_node()->id(), + crypto::hash( crypto::multicodec::sha2_256, i ), + protocol::block_header(), + shared_db_lock ) ); + } + + auto lib = chain::system_call::get_last_irreversible_block( ctx ); + BOOST_REQUIRE_EQUAL( lib, 1 ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( stack_tests ) -{ try { - BOOST_TEST_MESSAGE( "apply context stack tests" ); - ctx.pop_frame(); +{ + try + { + BOOST_TEST_MESSAGE( "apply context stack tests" ); + ctx.pop_frame(); - KOINOS_REQUIRE_THROW( ctx.pop_frame(), chain::internal_error ); + KOINOS_REQUIRE_THROW( ctx.pop_frame(), chain::internal_error ); - auto call1 = util::converter::as< std::string >( crypto::hash( crypto::multicodec::ripemd_160, "call1"s ) ); - ctx.push_frame( chain::stack_frame{ .contract_id = call1 } ); - BOOST_CHECK_EQUAL( "", ctx.get_caller() ); - BOOST_CHECK_EQUAL( call1, ctx.get_contract_id() ); + auto call1 = util::converter::as< std::string >( crypto::hash( crypto::multicodec::ripemd_160, "call1"s ) ); + ctx.push_frame( chain::stack_frame{ .contract_id = call1 } ); + BOOST_CHECK_EQUAL( "", ctx.get_caller() ); + BOOST_CHECK_EQUAL( call1, ctx.get_contract_id() ); - auto call2 = util::converter::as< std::string >( crypto::hash( crypto::multicodec::ripemd_160, "call2"s ) ); - ctx.push_frame( chain::stack_frame{ .contract_id = call2 } ); + auto call2 = util::converter::as< std::string >( crypto::hash( crypto::multicodec::ripemd_160, "call2"s ) ); + ctx.push_frame( chain::stack_frame{ .contract_id = call2 } ); - BOOST_CHECK_EQUAL( call1, ctx.get_caller() ); - BOOST_CHECK_EQUAL( call2, ctx.get_contract_id() ); + BOOST_CHECK_EQUAL( call1, ctx.get_caller() ); + BOOST_CHECK_EQUAL( call2, ctx.get_contract_id() ); - auto last_frame = ctx.pop_frame(); - BOOST_CHECK_EQUAL( call2, last_frame.contract_id ); - BOOST_CHECK_EQUAL( "", ctx.get_caller() ); + auto last_frame = ctx.pop_frame(); + BOOST_CHECK_EQUAL( call2, last_frame.contract_id ); + BOOST_CHECK_EQUAL( "", ctx.get_caller() ); - for ( int i = 2; i <= chain::execution_context::stack_limit; i++ ) - { + for( int i = 2; i <= chain::execution_context::stack_limit; i++ ) + { ctx.push_frame( chain::stack_frame{} ); - } - - KOINOS_REQUIRE_THROW( ctx.push_frame( chain::stack_frame{} ), chain::reversion ); + } -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + KOINOS_REQUIRE_THROW( ctx.push_frame( chain::stack_frame{} ), chain::reversion ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( check_authority ) -{ try { - auto foo_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "foo"s ) ); - auto foo_account_string = foo_key.get_public_key().to_address_bytes(); - - auto bar_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "bar"s ) ); - auto bar_account_string = bar_key.get_public_key().to_address_bytes(); +{ + try + { + auto foo_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "foo"s ) ); + auto foo_account_string = foo_key.get_public_key().to_address_bytes(); - protocol::transaction trx; - sign_transaction( trx, foo_key ); - ctx.set_transaction( trx ); + auto bar_key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "bar"s ) ); + auto bar_account_string = bar_key.get_public_key().to_address_bytes(); - BOOST_CHECK( chain::system_call::check_authority( ctx, koinos::chain::contract_call, foo_account_string ) ); + protocol::transaction trx; + sign_transaction( trx, foo_key ); + ctx.set_transaction( trx ); - BOOST_CHECK( !chain::system_call::check_authority( ctx, koinos::chain::contract_call, bar_account_string ) ); + BOOST_CHECK( chain::system_call::check_authority( ctx, koinos::chain::contract_call, foo_account_string ) ); - trx.clear_signatures(); - BOOST_CHECK( !chain::system_call::check_authority( ctx, koinos::chain::contract_call, foo_account_string ) ); + BOOST_CHECK( !chain::system_call::check_authority( ctx, koinos::chain::contract_call, bar_account_string ) ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + trx.clear_signatures(); + BOOST_CHECK( !chain::system_call::check_authority( ctx, koinos::chain::contract_call, foo_account_string ) ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( transaction_nonce_test ) -{ try { - using namespace koinos; +{ + try + { + using namespace koinos; - ctx.set_intent( chain::intent::transaction_application ); + ctx.set_intent( chain::intent::transaction_application ); - BOOST_TEST_MESSAGE( "Test transaction nonce" ); + BOOST_TEST_MESSAGE( "Test transaction nonce" ); - auto key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "alpha bravo charlie delta"s ) ); + auto key = + crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "alpha bravo charlie delta"s ) ); - protocol::transaction transaction; + protocol::transaction transaction; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - transaction.mutable_header()->set_payer( key.get_public_key().to_address_bytes() ); - transaction.mutable_header()->set_chain_id( koinos::chain::system_call::get_object( ctx, chain::state::space::metadata(), chain::state::key::chain_id ).value() ); - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, key ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + transaction.mutable_header()->set_payer( key.get_public_key().to_address_bytes() ); + transaction.mutable_header()->set_chain_id( + koinos::chain::system_call::get_object( ctx, chain::state::space::metadata(), chain::state::key::chain_id ) + .value() ); + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, key ); - chain::system_call::apply_transaction( ctx, transaction ); + chain::system_call::apply_transaction( ctx, transaction ); - auto payer = transaction.header().payer(); - auto nonce = chain::system_call::get_account_nonce( ctx, payer ); - BOOST_REQUIRE_EQUAL( nonce, util::converter::as< std::string >( nonce_value ) ); + auto payer = transaction.header().payer(); + auto nonce = chain::system_call::get_account_nonce( ctx, payer ); + BOOST_REQUIRE_EQUAL( nonce, util::converter::as< std::string >( nonce_value ) ); - BOOST_TEST_MESSAGE( "Test duplicate transaction nonce" ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, key ); + BOOST_TEST_MESSAGE( "Test duplicate transaction nonce" ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, key ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_nonce ); + KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_nonce ); - nonce = chain::system_call::get_account_nonce( ctx, payer ); - BOOST_REQUIRE_EQUAL( nonce, util::converter::as< std::string >( nonce_value ) ); + nonce = chain::system_call::get_account_nonce( ctx, payer ); + BOOST_REQUIRE_EQUAL( nonce, util::converter::as< std::string >( nonce_value ) ); - BOOST_TEST_MESSAGE( "Test next transaction nonce" ); - nonce_value.set_uint64_value( 2 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, key ); + BOOST_TEST_MESSAGE( "Test next transaction nonce" ); + nonce_value.set_uint64_value( 2 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, key ); - chain::system_call::apply_transaction( ctx, transaction ); + chain::system_call::apply_transaction( ctx, transaction ); - nonce = chain::system_call::get_account_nonce( ctx, payer ); - BOOST_REQUIRE_EQUAL( nonce, util::converter::as< std::string >( nonce_value ) ); + nonce = chain::system_call::get_account_nonce( ctx, payer ); + BOOST_REQUIRE_EQUAL( nonce, util::converter::as< std::string >( nonce_value ) ); - BOOST_TEST_MESSAGE( "Test duplicate transaction nonce" ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, key ); + BOOST_TEST_MESSAGE( "Test duplicate transaction nonce" ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, key ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_nonce ); + KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_nonce ); - nonce = chain::system_call::get_account_nonce( ctx, payer ); - BOOST_REQUIRE_EQUAL( nonce, util::converter::as< std::string >( nonce_value ) ); + nonce = chain::system_call::get_account_nonce( ctx, payer ); + BOOST_REQUIRE_EQUAL( nonce, util::converter::as< std::string >( nonce_value ) ); - BOOST_TEST_MESSAGE( "Test skipping transaction nonce" ); - nonce_value.set_uint64_value( 10 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, key ); + BOOST_TEST_MESSAGE( "Test skipping transaction nonce" ); + nonce_value.set_uint64_value( 10 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, key ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_nonce ); + KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_nonce ); - nonce = chain::system_call::get_account_nonce( ctx, payer ); - BOOST_REQUIRE( nonce_value.ParseFromString( nonce ) ); - BOOST_REQUIRE_EQUAL( nonce_value.uint64_value(), uint64_t( 2 ) ); + nonce = chain::system_call::get_account_nonce( ctx, payer ); + BOOST_REQUIRE( nonce_value.ParseFromString( nonce ) ); + BOOST_REQUIRE_EQUAL( nonce_value.uint64_value(), uint64_t( 2 ) ); - BOOST_TEST_MESSAGE( "Test old nonce" ); - nonce_value.set_uint64_value( 0 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, key ); + BOOST_TEST_MESSAGE( "Test old nonce" ); + nonce_value.set_uint64_value( 0 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, key ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_nonce ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_nonce ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( get_contract_id_test ) -{ try { - auto contract_id = util::converter::as< std::string >( crypto::hash( crypto::multicodec::ripemd_160, "get_contract_id_test"s ) ); +{ + try + { + auto contract_id = + util::converter::as< std::string >( crypto::hash( crypto::multicodec::ripemd_160, "get_contract_id_test"s ) ); - ctx.push_frame( chain::stack_frame { - .contract_id = contract_id, - .call_privilege = chain::privilege::kernel_mode - } ); + ctx.push_frame( chain::stack_frame{ .contract_id = contract_id, .call_privilege = chain::privilege::kernel_mode } ); - auto id = chain::system_call::get_contract_id( ctx ); + auto id = chain::system_call::get_contract_id( ctx ); - BOOST_REQUIRE_EQUAL( contract_id, id ); - //BOOST_REQUIRE( contract_id.size() == id.size() ); - //auto id_bytes = util::converter::as< std::vector< std::byte > >( id ); - //BOOST_REQUIRE( std::equal( contract_id.begin(), contract_id.end(), id_bytes.begin() ) ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_REQUIRE_EQUAL( contract_id, id ); + // BOOST_REQUIRE( contract_id.size() == id.size() ); + // auto id_bytes = util::converter::as< std::vector< std::byte > >( id ); + // BOOST_REQUIRE( std::equal( contract_id.begin(), contract_id.end(), id_bytes.begin() ) ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( token_tests ) -{ try { - using namespace koinos; - - auto contract_private_key = crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, "token_contract"s ) ); - auto contract_address = contract_private_key.get_public_key().to_address_bytes(); - protocol::transaction trx; - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); - - koinos::protocol::upload_contract_operation op; - op.set_contract_id( util::converter::as< std::string >( contract_address ) ); - op.set_bytecode( get_koin_wasm() ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); - - koinos::protocol::set_system_contract_operation sys_op; - sys_op.set_contract_id( op.contract_id() ); - sys_op.set_system_contract( true ); - - sign_transaction( trx, _signing_private_key ); - ctx.set_transaction( trx ); - - koinos::chain::system_call::apply_set_system_contract_operation( ctx, sys_op ); - - BOOST_TEST_MESSAGE( "Test executing a contract" ); - - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); - - ctx.push_frame( chain::stack_frame{ .contract_id = "token_tests"s, .call_privilege = chain::user_mode } ); - - auto response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::name, "" ); - auto name = util::converter::to< koinos::contracts::token::name_result >( response ); - LOG(info) << name.value(); - - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::symbol, "" ); - auto symbol = util::converter::to< koinos::contracts::token::symbol_result >( response ); - LOG(info) << symbol.value(); - - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::decimals, "" ); - auto decimals = util::converter::to< koinos::contracts::token::decimals_result >( response ); - LOG(info) << decimals.value(); - - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::total_supply, "" ); - auto supply = util::converter::to< koinos::contracts::token::total_supply_result >( response ); - LOG(info) << "KOIN supply: " << supply.value(); - - auto alice_private_key = crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); - auto alice_address = alice_private_key.get_public_key().to_address_bytes(); - - auto bob_private_key = crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "bob"s ) ); - auto bob_address = bob_private_key.get_public_key().to_address_bytes(); - - koinos::contracts::token::balance_of_arguments balance_of_args; - balance_of_args.set_owner( util::converter::as< std::string >( alice_address ) ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::balance_of, util::converter::as< std::string >( balance_of_args ) ); - auto balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); - LOG(info) << "'alice' balance: " << balance.value(); - - balance_of_args.set_owner( util::converter::as< std::string >( bob_address ) ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::balance_of, util::converter::as< std::string >( balance_of_args ) ); - balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); - LOG(info) << "'bob' balance: " << balance.value(); - - auto session = ctx.make_session( 10'000'000 ); - - LOG(info) << "Mint to 'alice'"; - koinos::contracts::token::mint_arguments mint_args; - mint_args.set_to( util::converter::as< std::string >( alice_address ) ); - mint_args.set_value( 100 ); - - KOINOS_CHECK_THROW( koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::mint, util::converter::as< std::string >( mint_args ) ), chain::authorization_failure ); - BOOST_CHECK_EQUAL( session->events().size(), 0 ); - - session = ctx.make_session( 10'000'000 ); - - ctx.set_privilege( chain::privilege::kernel_mode ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::mint, util::converter::as< std::string >( mint_args ) ); - BOOST_CHECK_NO_THROW( util::converter::to< koinos::contracts::token::mint_result >( response ) ); - - BOOST_REQUIRE_EQUAL( session->events().size(), 1 ); - { - const auto& event = session->events()[0]; +{ + try + { + using namespace koinos; + + auto contract_private_key = + crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, "token_contract"s ) ); + auto contract_address = contract_private_key.get_public_key().to_address_bytes(); + protocol::transaction trx; + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); + + koinos::protocol::upload_contract_operation op; + op.set_contract_id( util::converter::as< std::string >( contract_address ) ); + op.set_bytecode( get_koin_wasm() ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); + + koinos::protocol::set_system_contract_operation sys_op; + sys_op.set_contract_id( op.contract_id() ); + sys_op.set_system_contract( true ); + + sign_transaction( trx, _signing_private_key ); + ctx.set_transaction( trx ); + + koinos::chain::system_call::apply_set_system_contract_operation( ctx, sys_op ); + + BOOST_TEST_MESSAGE( "Test executing a contract" ); + + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); + + ctx.push_frame( chain::stack_frame{ .contract_id = "token_tests"s, .call_privilege = chain::user_mode } ); + + auto response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::name, "" ); + auto name = util::converter::to< koinos::contracts::token::name_result >( response ); + LOG( info ) << name.value(); + + response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::symbol, "" ); + auto symbol = util::converter::to< koinos::contracts::token::symbol_result >( response ); + LOG( info ) << symbol.value(); + + response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::decimals, "" ); + auto decimals = util::converter::to< koinos::contracts::token::decimals_result >( response ); + LOG( info ) << decimals.value(); + + response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::total_supply, "" ); + auto supply = util::converter::to< koinos::contracts::token::total_supply_result >( response ); + LOG( info ) << "KOIN supply: " << supply.value(); + + auto alice_private_key = + crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); + auto alice_address = alice_private_key.get_public_key().to_address_bytes(); + + auto bob_private_key = + crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "bob"s ) ); + auto bob_address = bob_private_key.get_public_key().to_address_bytes(); + + koinos::contracts::token::balance_of_arguments balance_of_args; + balance_of_args.set_owner( util::converter::as< std::string >( alice_address ) ); + response = koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::balance_of, + util::converter::as< std::string >( balance_of_args ) ); + auto balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); + LOG( info ) << "'alice' balance: " << balance.value(); + + balance_of_args.set_owner( util::converter::as< std::string >( bob_address ) ); + response = koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::balance_of, + util::converter::as< std::string >( balance_of_args ) ); + balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); + LOG( info ) << "'bob' balance: " << balance.value(); + + auto session = ctx.make_session( 10'000'000 ); + + LOG( info ) << "Mint to 'alice'"; + koinos::contracts::token::mint_arguments mint_args; + mint_args.set_to( util::converter::as< std::string >( alice_address ) ); + mint_args.set_value( 100 ); + + KOINOS_CHECK_THROW( koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::mint, + util::converter::as< std::string >( mint_args ) ), + chain::authorization_failure ); + BOOST_CHECK_EQUAL( session->events().size(), 0 ); + + session = ctx.make_session( 10'000'000 ); + + ctx.set_privilege( chain::privilege::kernel_mode ); + response = koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::mint, + util::converter::as< std::string >( mint_args ) ); + BOOST_CHECK_NO_THROW( util::converter::to< koinos::contracts::token::mint_result >( response ) ); + + BOOST_REQUIRE_EQUAL( session->events().size(), 1 ); + { + const auto& event = session->events()[ 0 ]; BOOST_CHECK_EQUAL( event.source(), op.contract_id() ); BOOST_CHECK_EQUAL( event.name(), "koin.mint" ); BOOST_CHECK_EQUAL( event.impacted().size(), 1 ); - BOOST_CHECK_EQUAL( event.impacted()[0], mint_args.to() ); + BOOST_CHECK_EQUAL( event.impacted()[ 0 ], mint_args.to() ); auto mint_event = util::converter::to< koinos::contracts::token::mint_event >( event.data() ); BOOST_CHECK_EQUAL( mint_event.to(), mint_args.to() ); BOOST_CHECK_EQUAL( mint_event.value(), mint_args.value() ); - } - - ctx.set_privilege( chain::privilege::user_mode ); - balance_of_args.set_owner( util::converter::as< std::string >( alice_address ) ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::balance_of, util::converter::as< std::string >( balance_of_args ) ); - balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); - - LOG(info) << "'alice' balance: " << balance.value(); - - balance_of_args.set_owner( util::converter::as< std::string >( bob_address ) ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::balance_of, util::converter::as< std::string >( balance_of_args ) ); - balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); - - LOG(info) << "'bob' balance: " << balance.value(); - - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::total_supply, "" ); - supply = util::converter::to< koinos::contracts::token::total_supply_result >( response ); - LOG(info) << "KOIN supply: " << supply.value(); - - LOG(info) << "Transfer from 'alice' to 'bob'"; - koinos::contracts::token::transfer_arguments transfer_args; - transfer_args.set_from( util::converter::as< std::string >( alice_address ) ); - transfer_args.set_to( util::converter::as< std::string >( bob_address ) ); - transfer_args.set_value( 25 ); - - ctx.set_transaction( trx ); - session = ctx.make_session( 10'000'000 ); - - KOINOS_REQUIRE_THROW( - koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::transfer, util::converter::as< std::string >( transfer_args ) ), - chain::authorization_failure - ); - - sign_transaction( trx, bob_private_key ); - ctx.set_transaction( trx ); - session = ctx.make_session( 10'000'000 ); - - KOINOS_REQUIRE_THROW( - koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::transfer, util::converter::as< std::string >( transfer_args ) ), - chain::authorization_failure - ); - - sign_transaction( trx, alice_private_key ); - ctx.set_transaction( trx ); - - session = ctx.make_session( 10'000'000 ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::transfer, util::converter::as< std::string >( transfer_args ) ); - BOOST_CHECK_NO_THROW( util::converter::to< koinos::contracts::token::transfer_result >( response ) ); - - balance_of_args.set_owner( util::converter::as< std::string >( alice_address ) ); - session = ctx.make_session( 10'000'000 ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::balance_of, util::converter::as< std::string >( balance_of_args ) ); - balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); - - LOG(info) << "'alice' balance: " << balance.value(); - - balance_of_args.set_owner( util::converter::as< std::string >( bob_address ) ); - session = ctx.make_session( 10'000'000 ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::balance_of, util::converter::as< std::string >( balance_of_args ) ); - balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); - - LOG(info) << "'bob' balance: " << balance.value(); - - session = ctx.make_session( 10'000'000 ); - response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::total_supply, "" ); - supply = util::converter::to< koinos::contracts::token::total_supply_result >( response ); - LOG(info) << "KOIN supply: " << supply.value(); -} -catch( const koinos::vm_manager::vm_exception& e ) -{ - LOG(info) << e.what(); - BOOST_FAIL("VM Exception"); + } + + ctx.set_privilege( chain::privilege::user_mode ); + balance_of_args.set_owner( util::converter::as< std::string >( alice_address ) ); + response = koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::balance_of, + util::converter::as< std::string >( balance_of_args ) ); + balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); + + LOG( info ) << "'alice' balance: " << balance.value(); + + balance_of_args.set_owner( util::converter::as< std::string >( bob_address ) ); + response = koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::balance_of, + util::converter::as< std::string >( balance_of_args ) ); + balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); + + LOG( info ) << "'bob' balance: " << balance.value(); + + response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::total_supply, "" ); + supply = util::converter::to< koinos::contracts::token::total_supply_result >( response ); + LOG( info ) << "KOIN supply: " << supply.value(); + + LOG( info ) << "Transfer from 'alice' to 'bob'"; + koinos::contracts::token::transfer_arguments transfer_args; + transfer_args.set_from( util::converter::as< std::string >( alice_address ) ); + transfer_args.set_to( util::converter::as< std::string >( bob_address ) ); + transfer_args.set_value( 25 ); + + ctx.set_transaction( trx ); + session = ctx.make_session( 10'000'000 ); + + KOINOS_REQUIRE_THROW( koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::transfer, + util::converter::as< std::string >( transfer_args ) ), + chain::authorization_failure ); + + sign_transaction( trx, bob_private_key ); + ctx.set_transaction( trx ); + session = ctx.make_session( 10'000'000 ); + + KOINOS_REQUIRE_THROW( koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::transfer, + util::converter::as< std::string >( transfer_args ) ), + chain::authorization_failure ); + + sign_transaction( trx, alice_private_key ); + ctx.set_transaction( trx ); + + session = ctx.make_session( 10'000'000 ); + response = koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::transfer, + util::converter::as< std::string >( transfer_args ) ); + BOOST_CHECK_NO_THROW( util::converter::to< koinos::contracts::token::transfer_result >( response ) ); + + balance_of_args.set_owner( util::converter::as< std::string >( alice_address ) ); + session = ctx.make_session( 10'000'000 ); + response = koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::balance_of, + util::converter::as< std::string >( balance_of_args ) ); + balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); + + LOG( info ) << "'alice' balance: " << balance.value(); + + balance_of_args.set_owner( util::converter::as< std::string >( bob_address ) ); + session = ctx.make_session( 10'000'000 ); + response = koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::balance_of, + util::converter::as< std::string >( balance_of_args ) ); + balance = util::converter::to< koinos::contracts::token::balance_of_result >( response ); + + LOG( info ) << "'bob' balance: " << balance.value(); + + session = ctx.make_session( 10'000'000 ); + response = koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::total_supply, "" ); + supply = util::converter::to< koinos::contracts::token::total_supply_result >( response ); + LOG( info ) << "KOIN supply: " << supply.value(); + } + catch( const koinos::vm_manager::vm_exception& e ) + { + LOG( info ) << e.what(); + BOOST_FAIL( "VM Exception" ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) } -KOINOS_CATCH_LOG_AND_RETHROW(info) } BOOST_AUTO_TEST_CASE( call_contract_operation_failure ) -{ try { - auto contract_private_key = crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, "token_contract"s ) ); - auto contract_address = contract_private_key.get_public_key().to_address_bytes(); - protocol::transaction trx; - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); - - auto alice_private_key = crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); - auto alice_address = alice_private_key.get_public_key().to_address_bytes(); +{ + try + { + auto contract_private_key = + crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, "token_contract"s ) ); + auto contract_address = contract_private_key.get_public_key().to_address_bytes(); + protocol::transaction trx; + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); - auto session = ctx.make_session( 10'000'000 ); + auto alice_private_key = + crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); + auto alice_address = alice_private_key.get_public_key().to_address_bytes(); - BOOST_TEST_MESSAGE( "Upload token contract" ); + auto session = ctx.make_session( 10'000'000 ); - protocol::upload_contract_operation op; - op.set_contract_id( util::converter::as< std::string >( contract_address ) ); - op.set_bytecode( get_koin_wasm() ); + BOOST_TEST_MESSAGE( "Upload token contract" ); - chain::system_call::apply_upload_contract_operation( ctx, op ); + protocol::upload_contract_operation op; + op.set_contract_id( util::converter::as< std::string >( contract_address ) ); + op.set_bytecode( get_koin_wasm() ); - koinos::protocol::set_system_contract_operation sys_op; - sys_op.set_contract_id( op.contract_id() ); - sys_op.set_system_contract( true ); + chain::system_call::apply_upload_contract_operation( ctx, op ); - sign_transaction( trx, _signing_private_key ); - ctx.set_transaction( trx ); + koinos::protocol::set_system_contract_operation sys_op; + sys_op.set_contract_id( op.contract_id() ); + sys_op.set_system_contract( true ); - koinos::chain::system_call::apply_set_system_contract_operation( ctx, sys_op ); + sign_transaction( trx, _signing_private_key ); + ctx.set_transaction( trx ); - BOOST_TEST_MESSAGE( "Check direct call throws a failure" ); + koinos::chain::system_call::apply_set_system_contract_operation( ctx, sys_op ); - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); + BOOST_TEST_MESSAGE( "Check direct call throws a failure" ); - contracts::token::mint_arguments mint_args; - mint_args.set_to( util::converter::as< std::string >( alice_address ) ); - mint_args.set_value( 100 ); - ctx.set_privilege( chain::privilege::user_mode ); + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); - KOINOS_CHECK_THROW( koinos::chain::system_call::call( ctx, op.contract_id(), token_entry::mint, util::converter::as< std::string >( mint_args ) ), chain::authorization_failure ); + contracts::token::mint_arguments mint_args; + mint_args.set_to( util::converter::as< std::string >( alice_address ) ); + mint_args.set_value( 100 ); + ctx.set_privilege( chain::privilege::user_mode ); - BOOST_TEST_MESSAGE( "Check reversion is thrown when called through 'apply_call_contract_operation'" ); + KOINOS_CHECK_THROW( koinos::chain::system_call::call( ctx, + op.contract_id(), + token_entry::mint, + util::converter::as< std::string >( mint_args ) ), + chain::authorization_failure ); - protocol::call_contract_operation call_op; - call_op.set_contract_id( util::converter::as< std::string >( contract_address ) ); - call_op.set_entry_point( token_entry::mint ); - call_op.set_args( util::converter::as< std::string >( mint_args ) ); - ctx.set_privilege( chain::privilege::kernel_mode ); + BOOST_TEST_MESSAGE( "Check reversion is thrown when called through 'apply_call_contract_operation'" ); - KOINOS_CHECK_THROW( chain::system_call::apply_call_contract_operation( ctx, call_op ), chain::reversion ); + protocol::call_contract_operation call_op; + call_op.set_contract_id( util::converter::as< std::string >( contract_address ) ); + call_op.set_entry_point( token_entry::mint ); + call_op.set_args( util::converter::as< std::string >( mint_args ) ); + ctx.set_privilege( chain::privilege::kernel_mode ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + KOINOS_CHECK_THROW( chain::system_call::apply_call_contract_operation( ctx, call_op ), chain::reversion ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( tick_limit ) -{ try { - using namespace koinos; - BOOST_TEST_MESSAGE( "Upload forever contract" ); - - auto contract_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); - protocol::transaction trx; - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); - - protocol::upload_contract_operation op; - op.set_contract_id( util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); - op.set_bytecode( get_forever_wasm() ); - - chain::system_call::apply_upload_contract_operation( ctx, op ); - - auto bytecode_object = koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_bytecode(), op.contract_id() ); - auto meta = util::converter::to< koinos::chain::contract_metadata_object >( koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_metadata(), op.contract_id() ).value() ); - - BOOST_REQUIRE( bytecode_object.exists() ); - BOOST_REQUIRE( bytecode_object.value().size() == op.bytecode().size() ); - BOOST_REQUIRE( std::memcmp( bytecode_object.value().c_str(), op.bytecode().c_str(), op.bytecode().size() ) == 0 ); - BOOST_REQUIRE( meta.hash() == util::converter::as< std::string >( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, bytecode_object.value() ) ) ); - - koinos::protocol::call_contract_operation op2; - op2.set_contract_id( op.contract_id() ); - - BOOST_TEST_MESSAGE( "Execute forever contract inside a session" ); - - auto compute_bandwidth_remaining = ctx.resource_meter().compute_bandwidth_remaining(); - - auto session = ctx.make_session( 1'000'000 ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_call_contract_operation( ctx, op2 ), chain::insufficient_rc ); - BOOST_REQUIRE_EQUAL( session->used_rc(), 1'000'000 ); - BOOST_REQUIRE_EQUAL( session->remaining_rc(), 0 ); - session.reset(); - - BOOST_REQUIRE_EQUAL( ctx.resource_meter().compute_bandwidth_remaining(), compute_bandwidth_remaining - 1'000'000 ); - - // We lower the compute bandwidth block-wide so the test doesn't take long - auto rl = chain::system_call::get_resource_limits( ctx ); - rl.set_compute_bandwidth_limit( 1'000'000 ); - ctx.resource_meter().set_resource_limit_data( rl ); - - BOOST_TEST_MESSAGE( "Execute forever contract outside a session" ); - BOOST_REQUIRE_THROW( chain::system_call::apply_call_contract_operation( ctx, op2 ), chain::reversion_exception ); - - BOOST_REQUIRE_EQUAL( ctx.resource_meter().compute_bandwidth_remaining(), 0 ); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + using namespace koinos; + BOOST_TEST_MESSAGE( "Upload forever contract" ); + + auto contract_private_key = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); + protocol::transaction trx; + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); + + protocol::upload_contract_operation op; + op.set_contract_id( + util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); + op.set_bytecode( get_forever_wasm() ); + + chain::system_call::apply_upload_contract_operation( ctx, op ); + + auto bytecode_object = + koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_bytecode(), op.contract_id() ); + auto meta = util::converter::to< koinos::chain::contract_metadata_object >( + koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_metadata(), op.contract_id() ) + .value() ); + + BOOST_REQUIRE( bytecode_object.exists() ); + BOOST_REQUIRE( bytecode_object.value().size() == op.bytecode().size() ); + BOOST_REQUIRE( std::memcmp( bytecode_object.value().c_str(), op.bytecode().c_str(), op.bytecode().size() ) == 0 ); + BOOST_REQUIRE( meta.hash() + == util::converter::as< std::string >( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, bytecode_object.value() ) ) ); + + koinos::protocol::call_contract_operation op2; + op2.set_contract_id( op.contract_id() ); + + BOOST_TEST_MESSAGE( "Execute forever contract inside a session" ); + + auto compute_bandwidth_remaining = ctx.resource_meter().compute_bandwidth_remaining(); + + auto session = ctx.make_session( 1'000'000 ); + KOINOS_REQUIRE_THROW( chain::system_call::apply_call_contract_operation( ctx, op2 ), chain::insufficient_rc ); + BOOST_REQUIRE_EQUAL( session->used_rc(), 1'000'000 ); + BOOST_REQUIRE_EQUAL( session->remaining_rc(), 0 ); + session.reset(); + + BOOST_REQUIRE_EQUAL( ctx.resource_meter().compute_bandwidth_remaining(), compute_bandwidth_remaining - 1'000'000 ); + + // We lower the compute bandwidth block-wide so the test doesn't take long + auto rl = chain::system_call::get_resource_limits( ctx ); + rl.set_compute_bandwidth_limit( 1'000'000 ); + ctx.resource_meter().set_resource_limit_data( rl ); + + BOOST_TEST_MESSAGE( "Execute forever contract outside a session" ); + BOOST_REQUIRE_THROW( chain::system_call::apply_call_contract_operation( ctx, op2 ), chain::reversion_exception ); + + BOOST_REQUIRE_EQUAL( ctx.resource_meter().compute_bandwidth_remaining(), 0 ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( disk_usage ) -{ try { - auto resource_limits = chain::system_call::get_resource_limits( ctx ); - ctx.resource_meter().set_resource_limit_data( resource_limits ); - - auto rc_limit = 10'000'000; - auto payer_session = ctx.make_session( rc_limit ); - - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_remaining(), resource_limits.disk_storage_limit() ); +{ + try + { + auto resource_limits = chain::system_call::get_resource_limits( ctx ); + ctx.resource_meter().set_resource_limit_data( resource_limits ); - chain::object_space objs; - objs.set_zone( std::string{ "test" } ); - objs.set_system( true ); + auto rc_limit = 10'000'000; + auto payer_session = ctx.make_session( rc_limit ); - auto key = "object_key"; + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_remaining(), resource_limits.disk_storage_limit() ); - chain::system_call::put_object( ctx, objs, key, std::string{ "stuff" } ); + chain::object_space objs; + objs.set_zone( std::string{ "test" } ); + objs.set_system( true ); - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), resource_limits.disk_storage_limit() - ctx.resource_meter().disk_storage_remaining() ); + auto key = "object_key"; - payer_session.reset(); + chain::system_call::put_object( ctx, objs, key, std::string{ "stuff" } ); - ctx.resource_meter().set_resource_limit_data( resource_limits ); - payer_session = ctx.make_session( rc_limit ); + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), + resource_limits.disk_storage_limit() - ctx.resource_meter().disk_storage_remaining() ); - chain::system_call::put_object( ctx, objs, key, std::string{ "stuf" } ); + payer_session.reset(); - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 0 ); + ctx.resource_meter().set_resource_limit_data( resource_limits ); + payer_session = ctx.make_session( rc_limit ); - chain::system_call::put_object( ctx, objs, key, std::string{ "stufff" } ); + chain::system_call::put_object( ctx, objs, key, std::string{ "stuf" } ); - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 1 ); + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 0 ); - chain::system_call::remove_object( ctx, objs, key ); + chain::system_call::put_object( ctx, objs, key, std::string{ "stufff" } ); - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 0 ); + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 1 ); - payer_session.reset(); + chain::system_call::remove_object( ctx, objs, key ); - ctx.resource_meter().set_resource_limit_data( resource_limits ); - payer_session = ctx.make_session( rc_limit ); - ctx.resource_meter().use_disk_storage( -100 ); + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 0 ); - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 0 ); - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_remaining(), resource_limits.disk_storage_limit() + 100 ); - BOOST_CHECK_EQUAL( payer_session->used_rc(), 0 ); - BOOST_CHECK_EQUAL( payer_session->remaining_rc(), rc_limit ); + payer_session.reset(); - ctx.resource_meter().use_disk_storage( 200 ); + ctx.resource_meter().set_resource_limit_data( resource_limits ); + payer_session = ctx.make_session( rc_limit ); + ctx.resource_meter().use_disk_storage( -100 ); - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 100 ); - BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_remaining(), resource_limits.disk_storage_limit() - 100 ); - BOOST_CHECK_EQUAL( payer_session->used_rc(), 100 * resource_limits.disk_storage_cost() ); - BOOST_CHECK_EQUAL( payer_session->remaining_rc(), rc_limit - payer_session->used_rc() ); + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 0 ); + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_remaining(), resource_limits.disk_storage_limit() + 100 ); + BOOST_CHECK_EQUAL( payer_session->used_rc(), 0 ); + BOOST_CHECK_EQUAL( payer_session->remaining_rc(), rc_limit ); + ctx.resource_meter().use_disk_storage( 200 ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_used(), 100 ); + BOOST_CHECK_EQUAL( ctx.resource_meter().disk_storage_remaining(), resource_limits.disk_storage_limit() - 100 ); + BOOST_CHECK_EQUAL( payer_session->used_rc(), 100 * resource_limits.disk_storage_cost() ); + BOOST_CHECK_EQUAL( payer_session->remaining_rc(), rc_limit - payer_session->used_rc() ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( transaction_reversion ) -{ try { - using namespace koinos; - - BOOST_TEST_MESSAGE( "Upload KOIN contract for testing and set balance for 'alice'" ); - - auto alice_private_key = crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); - auto alice_address = alice_private_key.get_public_key().to_address_bytes(); - - auto bob_private_key = crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "bob"s ) ); - auto bob_address = bob_private_key.get_public_key().to_address_bytes(); - - auto contract_private_key = crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, "token_contract"s ) ); - auto contract_address = contract_private_key.get_public_key().to_address_bytes(); - - BOOST_TEST_MESSAGE( "Test a reverted transaction" ); - - // This is purposefully calling on a non-existent contract, which will result in a reversion - protocol::call_contract_operation call_op; - call_op.set_contract_id( contract_address ); - - protocol::transaction transaction; - chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - transaction.mutable_header()->set_chain_id( chain::system_call::get_object( ctx, chain::state::space::metadata(), chain::state::key::chain_id ).value() ); - *transaction.add_operations()->mutable_call_contract() = call_op; - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, alice_private_key ); - - auto shared_db_lock = db.get_shared_lock(); - const auto head_state_node = db.get_head( shared_db_lock ); - auto control_state_node = db.create_writable_node( head_state_node->id(), crypto::hash( crypto::multicodec::sha2_256, "control"s ), protocol::block_header(), shared_db_lock ); - auto trx_state_node = db.create_writable_node( head_state_node->id(), crypto::hash( crypto::multicodec::sha2_256, "transaction"s ), protocol::block_header(), shared_db_lock ); - - auto session = ctx.make_session( 1'000'000 ); - - ctx.set_intent( chain::intent::transaction_application ); - - ctx.set_state_node( trx_state_node ); - KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_contract ); - db.finalize_node( trx_state_node->id(), shared_db_lock ); - - ctx.set_state_node( control_state_node ); - chain::system_call::set_account_nonce( ctx, transaction.header().payer(), transaction.header().nonce() ); - db.finalize_node( control_state_node->id(), shared_db_lock ); - - BOOST_REQUIRE( trx_state_node->merkle_root() == control_state_node->merkle_root() ); - - BOOST_TEST_MESSAGE( "Test proper throwing when transaction is not reverted" ); - - transaction.mutable_header()->set_rc_limit( 10'000'001 ); - sign_transaction( transaction, alice_private_key ); - - auto failed_trx_state_node = db.create_writable_node( head_state_node->id(), crypto::hash( crypto::multicodec::sha2_256, "failed_trx"s ), protocol::block_header(), shared_db_lock ); - ctx.set_state_node( failed_trx_state_node ); - - KOINOS_CHECK_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::failure ); - - auto parent_node = db.get_node( crypto::multihash::zero( crypto::multicodec::sha2_256 ), shared_db_lock ); - protocol::block block; - block.mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - block.mutable_header()->set_height( 1 ); - block.mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ).count() ); - block.mutable_header()->set_previous_state_merkle_root( util::converter::as< std::string >( parent_node->merkle_root() ) ); - *block.add_transactions() = transaction; - set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); - block.mutable_header()->set_signer( _signing_private_key.get_public_key().to_address_bytes() ); - block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); - block.set_signature( util::converter::as< std::string >( _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( block.id() ) ) ) ); - - auto block_state_node = db.create_writable_node( head_state_node->id(), crypto::hash( crypto::multicodec::sha2_256, "block"s ), protocol::block_header(), shared_db_lock ); - ctx.set_state_node( block_state_node ); - ctx.set_intent( chain::intent::block_application ); - - try - { +{ + try + { + using namespace koinos; + + BOOST_TEST_MESSAGE( "Upload KOIN contract for testing and set balance for 'alice'" ); + + auto alice_private_key = + crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); + auto alice_address = alice_private_key.get_public_key().to_address_bytes(); + + auto bob_private_key = + crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "bob"s ) ); + auto bob_address = bob_private_key.get_public_key().to_address_bytes(); + + auto contract_private_key = + crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, "token_contract"s ) ); + auto contract_address = contract_private_key.get_public_key().to_address_bytes(); + + BOOST_TEST_MESSAGE( "Test a reverted transaction" ); + + // This is purposefully calling on a non-existent contract, which will result in a reversion + protocol::call_contract_operation call_op; + call_op.set_contract_id( contract_address ); + + protocol::transaction transaction; + chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + transaction.mutable_header()->set_chain_id( + chain::system_call::get_object( ctx, chain::state::space::metadata(), chain::state::key::chain_id ).value() ); + *transaction.add_operations()->mutable_call_contract() = call_op; + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, alice_private_key ); + + auto shared_db_lock = db.get_shared_lock(); + const auto head_state_node = db.get_head( shared_db_lock ); + auto control_state_node = db.create_writable_node( head_state_node->id(), + crypto::hash( crypto::multicodec::sha2_256, "control"s ), + protocol::block_header(), + shared_db_lock ); + auto trx_state_node = db.create_writable_node( head_state_node->id(), + crypto::hash( crypto::multicodec::sha2_256, "transaction"s ), + protocol::block_header(), + shared_db_lock ); + + auto session = ctx.make_session( 1'000'000 ); + + ctx.set_intent( chain::intent::transaction_application ); + + ctx.set_state_node( trx_state_node ); + KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::invalid_contract ); + db.finalize_node( trx_state_node->id(), shared_db_lock ); + + ctx.set_state_node( control_state_node ); + chain::system_call::set_account_nonce( ctx, transaction.header().payer(), transaction.header().nonce() ); + db.finalize_node( control_state_node->id(), shared_db_lock ); + + BOOST_REQUIRE( trx_state_node->merkle_root() == control_state_node->merkle_root() ); + + BOOST_TEST_MESSAGE( "Test proper throwing when transaction is not reverted" ); + + transaction.mutable_header()->set_rc_limit( 10'000'001 ); + sign_transaction( transaction, alice_private_key ); + + auto failed_trx_state_node = db.create_writable_node( head_state_node->id(), + crypto::hash( crypto::multicodec::sha2_256, "failed_trx"s ), + protocol::block_header(), + shared_db_lock ); + ctx.set_state_node( failed_trx_state_node ); + + KOINOS_CHECK_THROW( chain::system_call::apply_transaction( ctx, transaction ), chain::failure ); + + auto parent_node = db.get_node( crypto::multihash::zero( crypto::multicodec::sha2_256 ), shared_db_lock ); + protocol::block block; + block.mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + block.mutable_header()->set_height( 1 ); + block.mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ) + .count() ); + block.mutable_header()->set_previous_state_merkle_root( + util::converter::as< std::string >( parent_node->merkle_root() ) ); + *block.add_transactions() = transaction; + set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); + block.mutable_header()->set_signer( _signing_private_key.get_public_key().to_address_bytes() ); + block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); + block.set_signature( util::converter::as< std::string >( + _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( block.id() ) ) ) ); + + auto block_state_node = db.create_writable_node( head_state_node->id(), + crypto::hash( crypto::multicodec::sha2_256, "block"s ), + protocol::block_header(), + shared_db_lock ); + ctx.set_state_node( block_state_node ); + ctx.set_intent( chain::intent::block_application ); + + try + { chain::system_call::apply_block( ctx, block ); BOOST_FAIL( "expected exception not thrown" ); - } - catch ( const chain::reversion_exception& ) - { + } + catch( const chain::reversion_exception& ) + { BOOST_FAIL( "reversion_exception exception erroneously thrown" ); - } - catch ( const chain::failure_exception& e ) - { + } + catch( const chain::failure_exception& e ) + { const auto& data = e.get_json(); BOOST_REQUIRE( data.count( "transaction_id" ) ); BOOST_REQUIRE_EQUAL( data[ "transaction_id" ], util::to_hex( transaction.id() ) ); - } - - BOOST_TEST_MESSAGE( "Submitting reverted transactioon within a block" ); - - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - sign_transaction( transaction, alice_private_key ); - block.clear_transactions(); - *block.add_transactions() = transaction; - set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); - block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); - block.set_signature( util::converter::as< std::string >( _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( block.id() ) ) ) ); - - db.discard_node( block_state_node->id(), shared_db_lock ); - block_state_node = db.create_writable_node( head_state_node->id(), crypto::hash( crypto::multicodec::sha2_256, "block"s ), protocol::block_header(), shared_db_lock ); - ctx.set_state_node( block_state_node ); - - chain::system_call::apply_block( ctx, block ); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + } + + BOOST_TEST_MESSAGE( "Submitting reverted transactioon within a block" ); + + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + sign_transaction( transaction, alice_private_key ); + block.clear_transactions(); + *block.add_transactions() = transaction; + set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); + block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); + block.set_signature( util::converter::as< std::string >( + _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( block.id() ) ) ) ); + + db.discard_node( block_state_node->id(), shared_db_lock ); + block_state_node = db.create_writable_node( head_state_node->id(), + crypto::hash( crypto::multicodec::sha2_256, "block"s ), + protocol::block_header(), + shared_db_lock ); + ctx.set_state_node( block_state_node ); + + chain::system_call::apply_block( ctx, block ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( authorize_tests ) { - using namespace koinos; - - auto key_a = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "test_key_a"s ) ); - auto key_b = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "test_key_b"s ) ); - - // Upload KOIN contract - auto contract_private_key = crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, "token_contract"s ) ); - auto contract_address = contract_private_key.get_public_key().to_address_bytes(); - protocol::transaction trx; - chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); - - koinos::protocol::upload_contract_operation upload_op; - upload_op.set_contract_id( util::converter::as< std::string >( contract_address ) ); - upload_op.set_bytecode( get_koin_wasm() ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - koinos::protocol::set_system_contract_operation sys_op; - sys_op.set_contract_id( upload_op.contract_id() ); - sys_op.set_system_contract( true ); - - sign_transaction( trx, _signing_private_key ); - ctx.set_transaction( trx ); - - koinos::chain::system_call::apply_set_system_contract_operation( ctx, sys_op ); - - // Mint to key_a - koinos::contracts::token::mint_arguments mint_args; - mint_args.set_to( util::converter::as< std::string >( key_a.get_public_key().to_address_bytes() ) ); - mint_args.set_value( 100 ); - - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); - - auto session = ctx.make_session( 100'000'000 ); + using namespace koinos; - auto response = koinos::chain::system_call::call( ctx, upload_op.contract_id(), token_entry::mint, util::converter::as< std::string >( mint_args ) ); - BOOST_CHECK_NO_THROW( util::converter::to< koinos::contracts::token::mint_result >( response ) ); + auto key_a = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "test_key_a"s ) ); + auto key_b = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "test_key_b"s ) ); - BOOST_TEST_MESSAGE( "Override authorize call contract" ); - upload_op.set_contract_id( key_a.get_public_key().to_address_bytes() ); - upload_op.set_bytecode( get_authorize_wasm() ); - upload_op.set_authorizes_call_contract( true ); - - sign_transaction( trx, key_a ); - ctx.set_transaction( trx ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - BOOST_TEST_MESSAGE( "Transfer from 'a' to 'b'" ); - koinos::contracts::token::transfer_arguments transfer_args; - transfer_args.set_from( util::converter::as< std::string >( key_a.get_public_key().to_address_bytes() ) ); - transfer_args.set_to( util::converter::as< std::string >( key_b.get_public_key().to_address_bytes() ) ); - transfer_args.set_value( 25 ); - - sign_transaction( trx, key_a ); - KOINOS_REQUIRE_THROW( - koinos::chain::system_call::call( ctx, util::converter::as< std::string >( contract_address ), token_entry::transfer, util::converter::as< std::string >( transfer_args ) ), - chain::authorization_failure - ); - - BOOST_CHECK( !chain::system_call::check_authority( ctx, chain::contract_call, key_a.get_public_key().to_address_bytes() ) ); - BOOST_CHECK( chain::system_call::check_authority( ctx, chain::contract_call, key_a.get_public_key().to_address_bytes(), "\1" ) ); - - sign_transaction( trx, key_b ); - koinos::chain::system_call::call( ctx, util::converter::as< std::string >( contract_address ), token_entry::transfer, util::converter::as< std::string >( transfer_args ) ); - BOOST_TEST_PASSPOINT(); - - BOOST_TEST_MESSAGE( "Override authorize upload contract" ); - - upload_op.set_authorizes_upload_contract( true ); - upload_op.set_authorizes_call_contract( false ); - - sign_transaction( trx, key_a ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - - koinos::chain::system_call::call( ctx, util::converter::as< std::string >( contract_address ), token_entry::transfer, util::converter::as< std::string >( transfer_args ) ); - - upload_op.set_authorizes_upload_contract( false ); - upload_op.set_authorizes_transaction_application( true ); - - KOINOS_REQUIRE_THROW( - koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ), - chain::authorization_failure ); - - sign_transaction( trx, key_b ); - koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - BOOST_TEST_PASSPOINT(); - - BOOST_TEST_MESSAGE( "Override authorize use rc" ); - - ctx.set_intent( koinos::chain::intent::transaction_application ); - auto op = trx.add_operations()->mutable_call_contract(); - op->set_contract_id( util::converter::as< std::string >( contract_address ) ); - op->set_entry_point( token_entry::transfer ); - op->set_args( util::converter::as< std::string >( transfer_args ) ); - set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); - trx.mutable_header()->set_chain_id( koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::metadata(), koinos::chain::state::key::chain_id ).value() ); - trx.mutable_header()->set_payer( key_a.get_public_key().to_address_bytes() ); - trx.mutable_header()->set_rc_limit( 10'000'000 ); - auto id_mh = crypto::hash( crypto::multicodec::sha2_256, trx.header() ); - trx.set_id( util::converter::as< std::string >( id_mh ) ); - trx.clear_signatures(); - trx.add_signatures( util::converter::as< std::string >( key_a.sign_compact( id_mh ) ) ); - - KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, trx ), chain::authorization_failure ); - - trx.add_signatures( util::converter::as< std::string >( key_b.sign_compact( id_mh ) ) ); - - koinos::chain::system_call::apply_transaction( ctx, trx ); - - BOOST_TEST_MESSAGE( "Try calling authorize directly" ); - - ctx.set_transaction( trx ); - chain::system_call::call( ctx, key_a.get_public_key().to_address_bytes(), chain::authorize_entrypoint, std::string() ); - BOOST_TEST_PASSPOINT(); - - ctx.push_frame( chain::stack_frame { - .contract_id = "thunk_tests"s, - .call_privilege = chain::privilege::user_mode - } ); - - KOINOS_REQUIRE_THROW( - chain::system_call::call( ctx, key_a.get_public_key().to_address_bytes(), chain::authorize_entrypoint, std::string() ), - chain::insufficient_privileges - ) - - auto authorized = chain::system_call::check_authority( ctx, chain::authorization_type::contract_call, key_a.get_public_key().to_address_bytes() ); - BOOST_CHECK_EQUAL( authorized, true ); + // Upload KOIN contract + auto contract_private_key = + crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, "token_contract"s ) ); + auto contract_address = contract_private_key.get_public_key().to_address_bytes(); + protocol::transaction trx; + chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + trx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); + + koinos::protocol::upload_contract_operation upload_op; + upload_op.set_contract_id( util::converter::as< std::string >( contract_address ) ); + upload_op.set_bytecode( get_koin_wasm() ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + koinos::protocol::set_system_contract_operation sys_op; + sys_op.set_contract_id( upload_op.contract_id() ); + sys_op.set_system_contract( true ); + + sign_transaction( trx, _signing_private_key ); + ctx.set_transaction( trx ); + + koinos::chain::system_call::apply_set_system_contract_operation( ctx, sys_op ); + + // Mint to key_a + koinos::contracts::token::mint_arguments mint_args; + mint_args.set_to( util::converter::as< std::string >( key_a.get_public_key().to_address_bytes() ) ); + mint_args.set_value( 100 ); + + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); + + auto session = ctx.make_session( 100'000'000 ); + + auto response = koinos::chain::system_call::call( ctx, + upload_op.contract_id(), + token_entry::mint, + util::converter::as< std::string >( mint_args ) ); + BOOST_CHECK_NO_THROW( util::converter::to< koinos::contracts::token::mint_result >( response ) ); + + BOOST_TEST_MESSAGE( "Override authorize call contract" ); + upload_op.set_contract_id( key_a.get_public_key().to_address_bytes() ); + upload_op.set_bytecode( get_authorize_wasm() ); + upload_op.set_authorizes_call_contract( true ); + + sign_transaction( trx, key_a ); + ctx.set_transaction( trx ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + BOOST_TEST_MESSAGE( "Transfer from 'a' to 'b'" ); + koinos::contracts::token::transfer_arguments transfer_args; + transfer_args.set_from( util::converter::as< std::string >( key_a.get_public_key().to_address_bytes() ) ); + transfer_args.set_to( util::converter::as< std::string >( key_b.get_public_key().to_address_bytes() ) ); + transfer_args.set_value( 25 ); + + sign_transaction( trx, key_a ); + KOINOS_REQUIRE_THROW( koinos::chain::system_call::call( ctx, + util::converter::as< std::string >( contract_address ), + token_entry::transfer, + util::converter::as< std::string >( transfer_args ) ), + chain::authorization_failure ); + + BOOST_CHECK( + !chain::system_call::check_authority( ctx, chain::contract_call, key_a.get_public_key().to_address_bytes() ) ); + BOOST_CHECK( + chain::system_call::check_authority( ctx, chain::contract_call, key_a.get_public_key().to_address_bytes(), "\1" ) ); + + sign_transaction( trx, key_b ); + koinos::chain::system_call::call( ctx, + util::converter::as< std::string >( contract_address ), + token_entry::transfer, + util::converter::as< std::string >( transfer_args ) ); + BOOST_TEST_PASSPOINT(); + + BOOST_TEST_MESSAGE( "Override authorize upload contract" ); + + upload_op.set_authorizes_upload_contract( true ); + upload_op.set_authorizes_call_contract( false ); + + sign_transaction( trx, key_a ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + + koinos::chain::system_call::call( ctx, + util::converter::as< std::string >( contract_address ), + token_entry::transfer, + util::converter::as< std::string >( transfer_args ) ); + + upload_op.set_authorizes_upload_contract( false ); + upload_op.set_authorizes_transaction_application( true ); + + KOINOS_REQUIRE_THROW( koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ), + chain::authorization_failure ); + + sign_transaction( trx, key_b ); + koinos::chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + BOOST_TEST_PASSPOINT(); + + BOOST_TEST_MESSAGE( "Override authorize use rc" ); + + ctx.set_intent( koinos::chain::intent::transaction_application ); + auto op = trx.add_operations()->mutable_call_contract(); + op->set_contract_id( util::converter::as< std::string >( contract_address ) ); + op->set_entry_point( token_entry::transfer ); + op->set_args( util::converter::as< std::string >( transfer_args ) ); + set_transaction_merkle_roots( trx, koinos::crypto::multicodec::sha2_256 ); + trx.mutable_header()->set_chain_id( koinos::chain::system_call::get_object( ctx, + koinos::chain::state::space::metadata(), + koinos::chain::state::key::chain_id ) + .value() ); + trx.mutable_header()->set_payer( key_a.get_public_key().to_address_bytes() ); + trx.mutable_header()->set_rc_limit( 10'000'000 ); + auto id_mh = crypto::hash( crypto::multicodec::sha2_256, trx.header() ); + trx.set_id( util::converter::as< std::string >( id_mh ) ); + trx.clear_signatures(); + trx.add_signatures( util::converter::as< std::string >( key_a.sign_compact( id_mh ) ) ); + + KOINOS_REQUIRE_THROW( chain::system_call::apply_transaction( ctx, trx ), chain::authorization_failure ); + + trx.add_signatures( util::converter::as< std::string >( key_b.sign_compact( id_mh ) ) ); + + koinos::chain::system_call::apply_transaction( ctx, trx ); + + BOOST_TEST_MESSAGE( "Try calling authorize directly" ); + + ctx.set_transaction( trx ); + chain::system_call::call( ctx, + key_a.get_public_key().to_address_bytes(), + chain::authorize_entrypoint, + std::string() ); + BOOST_TEST_PASSPOINT(); + + ctx.push_frame( chain::stack_frame{ .contract_id = "thunk_tests"s, .call_privilege = chain::privilege::user_mode } ); + + KOINOS_REQUIRE_THROW( chain::system_call::call( ctx, + key_a.get_public_key().to_address_bytes(), + chain::authorize_entrypoint, + std::string() ), + chain::insufficient_privileges ) + + auto authorized = chain::system_call::check_authority( ctx, + chain::authorization_type::contract_call, + key_a.get_public_key().to_address_bytes() ); + BOOST_CHECK_EQUAL( authorized, true ); } BOOST_AUTO_TEST_CASE( get_chain_id ) { - auto chain_id = crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ); - auto chain_id_str = util::converter::as< std::string >( chain_id ); - BOOST_REQUIRE_EQUAL( chain_id_str, chain::system_call::get_chain_id( ctx ) ); + auto chain_id = crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ); + auto chain_id_str = util::converter::as< std::string >( chain_id ); + BOOST_REQUIRE_EQUAL( chain_id_str, chain::system_call::get_chain_id( ctx ) ); } BOOST_AUTO_TEST_CASE( system_resources ) -{ try { - auto resource_limits = chain::system_call::get_resource_limits( ctx ); - auto& meter = ctx.resource_meter(); - - BOOST_TEST_MESSAGE( "Set and check initial resource meter" ); - - meter.set_resource_limit_data( resource_limits ); - - uint64_t disk_storage_used = 0; - uint64_t system_disk_storage_used = 0; - uint64_t network_bandwidth_used = 0; - uint64_t system_network_bandwidth_used = 0; - uint64_t compute_bandwidth_used = 0; - uint64_t system_compute_bandwidth_used = 0; - - BOOST_CHECK_EQUAL( meter.disk_storage_remaining(), resource_limits.disk_storage_limit() - disk_storage_used ); - BOOST_CHECK_EQUAL( meter.disk_storage_used(), disk_storage_used ); - BOOST_CHECK_EQUAL( meter.system_disk_storage_used(), system_disk_storage_used ); - BOOST_CHECK_EQUAL( meter.network_bandwidth_remaining(), resource_limits.network_bandwidth_limit() - network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.network_bandwidth_used(), network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.system_network_bandwidth_used(), system_network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.compute_bandwidth_remaining(), resource_limits.compute_bandwidth_limit() - compute_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.compute_bandwidth_used(), compute_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.system_compute_bandwidth_used(), system_compute_bandwidth_used ); - - BOOST_TEST_MESSAGE( "Use system resources" ); - - meter.use_disk_storage( 100 ); - disk_storage_used += 100; - system_disk_storage_used += 100; - - BOOST_CHECK_EQUAL( meter.disk_storage_remaining(), resource_limits.disk_storage_limit() - disk_storage_used ); - BOOST_CHECK_EQUAL( meter.disk_storage_used(), disk_storage_used ); - BOOST_CHECK_EQUAL( meter.system_disk_storage_used(), system_disk_storage_used ); - - meter.use_network_bandwidth( 200 ); - network_bandwidth_used += 200; - system_network_bandwidth_used += 200; - - BOOST_CHECK_EQUAL( meter.network_bandwidth_remaining(), resource_limits.network_bandwidth_limit() - network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.network_bandwidth_used(), network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.system_network_bandwidth_used(), system_network_bandwidth_used ); - - meter.use_compute_bandwidth( 300 ); - compute_bandwidth_used += 300; - system_compute_bandwidth_used += 300; - - BOOST_CHECK_EQUAL( meter.compute_bandwidth_remaining(), resource_limits.compute_bandwidth_limit() - compute_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.compute_bandwidth_used(), compute_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.system_compute_bandwidth_used(), system_compute_bandwidth_used ); - - BOOST_TEST_MESSAGE( "Use session resources" ); - - auto session = ctx.make_session( 1'000'000 ); - - meter.use_disk_storage( 400 ); - disk_storage_used += 400; - - meter.use_network_bandwidth( 500 ); - network_bandwidth_used += 500; - - meter.use_compute_bandwidth( 600 ); - compute_bandwidth_used += 600; - - session.reset(); - - BOOST_CHECK_EQUAL( meter.disk_storage_remaining(), resource_limits.disk_storage_limit() - disk_storage_used ); - BOOST_CHECK_EQUAL( meter.disk_storage_used(), disk_storage_used ); - BOOST_CHECK_EQUAL( meter.system_disk_storage_used(), system_disk_storage_used ); - - BOOST_CHECK_EQUAL( meter.network_bandwidth_remaining(), resource_limits.network_bandwidth_limit() - network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.network_bandwidth_used(), network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.system_network_bandwidth_used(), system_network_bandwidth_used ); - - BOOST_CHECK_EQUAL( meter.compute_bandwidth_remaining(), resource_limits.compute_bandwidth_limit() - compute_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.compute_bandwidth_used(), compute_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.system_compute_bandwidth_used(), system_compute_bandwidth_used ); - - BOOST_TEST_MESSAGE( "End session and resume using system resources" ); - - meter.use_disk_storage( 700 ); - disk_storage_used += 700; - system_disk_storage_used += 700; - - BOOST_CHECK_EQUAL( meter.disk_storage_remaining(), resource_limits.disk_storage_limit() - disk_storage_used ); - BOOST_CHECK_EQUAL( meter.disk_storage_used(), disk_storage_used ); - BOOST_CHECK_EQUAL( meter.system_disk_storage_used(), system_disk_storage_used ); - - meter.use_network_bandwidth( 800 ); - network_bandwidth_used += 800; - system_network_bandwidth_used += 800; +{ + try + { + auto resource_limits = chain::system_call::get_resource_limits( ctx ); + auto& meter = ctx.resource_meter(); - BOOST_CHECK_EQUAL( meter.network_bandwidth_remaining(), resource_limits.network_bandwidth_limit() - network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.network_bandwidth_used(), network_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.system_network_bandwidth_used(), system_network_bandwidth_used ); + BOOST_TEST_MESSAGE( "Set and check initial resource meter" ); - meter.use_compute_bandwidth( 900 ); - compute_bandwidth_used += 900; - system_compute_bandwidth_used += 900; + meter.set_resource_limit_data( resource_limits ); - BOOST_CHECK_EQUAL( meter.compute_bandwidth_remaining(), resource_limits.compute_bandwidth_limit() - compute_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.compute_bandwidth_used(), compute_bandwidth_used ); - BOOST_CHECK_EQUAL( meter.system_compute_bandwidth_used(), system_compute_bandwidth_used ); + uint64_t disk_storage_used = 0; + uint64_t system_disk_storage_used = 0; + uint64_t network_bandwidth_used = 0; + uint64_t system_network_bandwidth_used = 0; + uint64_t compute_bandwidth_used = 0; + uint64_t system_compute_bandwidth_used = 0; + + BOOST_CHECK_EQUAL( meter.disk_storage_remaining(), resource_limits.disk_storage_limit() - disk_storage_used ); + BOOST_CHECK_EQUAL( meter.disk_storage_used(), disk_storage_used ); + BOOST_CHECK_EQUAL( meter.system_disk_storage_used(), system_disk_storage_used ); + BOOST_CHECK_EQUAL( meter.network_bandwidth_remaining(), + resource_limits.network_bandwidth_limit() - network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.network_bandwidth_used(), network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.system_network_bandwidth_used(), system_network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.compute_bandwidth_remaining(), + resource_limits.compute_bandwidth_limit() - compute_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.compute_bandwidth_used(), compute_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.system_compute_bandwidth_used(), system_compute_bandwidth_used ); + + BOOST_TEST_MESSAGE( "Use system resources" ); + + meter.use_disk_storage( 100 ); + disk_storage_used += 100; + system_disk_storage_used += 100; + + BOOST_CHECK_EQUAL( meter.disk_storage_remaining(), resource_limits.disk_storage_limit() - disk_storage_used ); + BOOST_CHECK_EQUAL( meter.disk_storage_used(), disk_storage_used ); + BOOST_CHECK_EQUAL( meter.system_disk_storage_used(), system_disk_storage_used ); + + meter.use_network_bandwidth( 200 ); + network_bandwidth_used += 200; + system_network_bandwidth_used += 200; + + BOOST_CHECK_EQUAL( meter.network_bandwidth_remaining(), + resource_limits.network_bandwidth_limit() - network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.network_bandwidth_used(), network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.system_network_bandwidth_used(), system_network_bandwidth_used ); + + meter.use_compute_bandwidth( 300 ); + compute_bandwidth_used += 300; + system_compute_bandwidth_used += 300; + + BOOST_CHECK_EQUAL( meter.compute_bandwidth_remaining(), + resource_limits.compute_bandwidth_limit() - compute_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.compute_bandwidth_used(), compute_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.system_compute_bandwidth_used(), system_compute_bandwidth_used ); + + BOOST_TEST_MESSAGE( "Use session resources" ); + + auto session = ctx.make_session( 1'000'000 ); + + meter.use_disk_storage( 400 ); + disk_storage_used += 400; + + meter.use_network_bandwidth( 500 ); + network_bandwidth_used += 500; + + meter.use_compute_bandwidth( 600 ); + compute_bandwidth_used += 600; + + session.reset(); + + BOOST_CHECK_EQUAL( meter.disk_storage_remaining(), resource_limits.disk_storage_limit() - disk_storage_used ); + BOOST_CHECK_EQUAL( meter.disk_storage_used(), disk_storage_used ); + BOOST_CHECK_EQUAL( meter.system_disk_storage_used(), system_disk_storage_used ); + + BOOST_CHECK_EQUAL( meter.network_bandwidth_remaining(), + resource_limits.network_bandwidth_limit() - network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.network_bandwidth_used(), network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.system_network_bandwidth_used(), system_network_bandwidth_used ); + + BOOST_CHECK_EQUAL( meter.compute_bandwidth_remaining(), + resource_limits.compute_bandwidth_limit() - compute_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.compute_bandwidth_used(), compute_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.system_compute_bandwidth_used(), system_compute_bandwidth_used ); + + BOOST_TEST_MESSAGE( "End session and resume using system resources" ); + + meter.use_disk_storage( 700 ); + disk_storage_used += 700; + system_disk_storage_used += 700; + + BOOST_CHECK_EQUAL( meter.disk_storage_remaining(), resource_limits.disk_storage_limit() - disk_storage_used ); + BOOST_CHECK_EQUAL( meter.disk_storage_used(), disk_storage_used ); + BOOST_CHECK_EQUAL( meter.system_disk_storage_used(), system_disk_storage_used ); + + meter.use_network_bandwidth( 800 ); + network_bandwidth_used += 800; + system_network_bandwidth_used += 800; + + BOOST_CHECK_EQUAL( meter.network_bandwidth_remaining(), + resource_limits.network_bandwidth_limit() - network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.network_bandwidth_used(), network_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.system_network_bandwidth_used(), system_network_bandwidth_used ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + meter.use_compute_bandwidth( 900 ); + compute_bandwidth_used += 900; + system_compute_bandwidth_used += 900; + + BOOST_CHECK_EQUAL( meter.compute_bandwidth_remaining(), + resource_limits.compute_bandwidth_limit() - compute_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.compute_bandwidth_used(), compute_bandwidth_used ); + BOOST_CHECK_EQUAL( meter.system_compute_bandwidth_used(), system_compute_bandwidth_used ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( system_rc ) -{ try { - crypto::multihash koin_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "koin" } ); - crypto::private_key koin_pk = crypto::private_key::regenerate( koin_seed ); - auto koin_id = koin_pk.get_public_key().to_address_bytes(); - - protocol::upload_contract_operation upload_op; - upload_op.set_bytecode( get_koin_wasm() ); - upload_op.set_contract_id( koin_id ); +{ + try + { + crypto::multihash koin_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "koin" } ); + crypto::private_key koin_pk = crypto::private_key::regenerate( koin_seed ); + auto koin_id = koin_pk.get_public_key().to_address_bytes(); - protocol::transaction trx; - sign_transaction( trx, koin_pk ); + protocol::upload_contract_operation upload_op; + upload_op.set_bytecode( get_koin_wasm() ); + upload_op.set_contract_id( koin_id ); - ctx.set_transaction( trx ); + protocol::transaction trx; + sign_transaction( trx, koin_pk ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + ctx.set_transaction( trx ); - protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( koin_id ); - set_system_op.set_system_contract( true ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - sign_transaction( trx, _signing_private_key ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( koin_id ); + set_system_op.set_system_contract( true ); - protocol::set_system_call_operation set_syscall_op; - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( koin_id ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x2d464aab ); - set_syscall_op.set_call_id( chain::get_account_rc ); + sign_transaction( trx, _signing_private_key ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + protocol::set_system_call_operation set_syscall_op; + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( koin_id ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x2d464aab ); + set_syscall_op.set_call_id( chain::get_account_rc ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x80e3f5c9 ); - set_syscall_op.set_call_id( chain::consume_account_rc ); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x80e3f5c9 ); + set_syscall_op.set_call_id( chain::consume_account_rc ); - BOOST_TEST_MESSAGE( "Testing failure to pay for system rc" ); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - auto parent_node = ctx.get_state_node(); + BOOST_TEST_MESSAGE( "Testing failure to pay for system rc" ); - protocol::block block; - block.mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - block.mutable_header()->set_height( 1 ); - block.mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ).count() ); - block.mutable_header()->set_previous_state_merkle_root( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); - block.mutable_header()->set_signer( _signing_private_key.get_public_key().to_address_bytes() ); - block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); - block.set_signature( util::converter::as< std::string >( _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( block.id() ) ) ) ); + auto parent_node = ctx.get_state_node(); - ctx.set_state_node( parent_node->create_anonymous_node() ); - ctx.set_intent( chain::intent::block_application ); - ctx.reset_cache(); + protocol::block block; + block.mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + block.mutable_header()->set_height( 1 ); + block.mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ) + .count() ); + block.mutable_header()->set_previous_state_merkle_root( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); + block.mutable_header()->set_signer( _signing_private_key.get_public_key().to_address_bytes() ); + block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); + block.set_signature( util::converter::as< std::string >( + _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( block.id() ) ) ) ); - KOINOS_CHECK_THROW( chain::system_call::apply_block( ctx, block ), chain::insufficient_rc ); + ctx.set_state_node( parent_node->create_anonymous_node() ); + ctx.set_intent( chain::intent::block_application ); + ctx.reset_cache(); - ctx.set_state_node( parent_node ); + KOINOS_CHECK_THROW( chain::system_call::apply_block( ctx, block ), chain::insufficient_rc ); - BOOST_TEST_MESSAGE( "Mint KOIN to producer address" ); + ctx.set_state_node( parent_node ); - koinos::contracts::token::mint_arguments mint_args; - mint_args.set_to( _signing_private_key.get_public_key().to_address_bytes() ); - mint_args.set_value( 1'000'000'000 ); + BOOST_TEST_MESSAGE( "Mint KOIN to producer address" ); - BOOST_CHECK_NO_THROW( koinos::chain::system_call::call( ctx, koin_id, token_entry::mint, util::converter::as< std::string >( mint_args ) ) ); + koinos::contracts::token::mint_arguments mint_args; + mint_args.set_to( _signing_private_key.get_public_key().to_address_bytes() ); + mint_args.set_value( 1'000'000'000 ); - BOOST_TEST_MESSAGE( "Testing block production with sufficient rc" ); + BOOST_CHECK_NO_THROW( koinos::chain::system_call::call( ctx, + koin_id, + token_entry::mint, + util::converter::as< std::string >( mint_args ) ) ); - ctx.set_state_node( parent_node->create_anonymous_node() ); - ctx.set_intent( chain::intent::block_application ); - ctx.reset_cache(); + BOOST_TEST_MESSAGE( "Testing block production with sufficient rc" ); - BOOST_CHECK_NO_THROW( chain::system_call::apply_block( ctx, block ) ); + ctx.set_state_node( parent_node->create_anonymous_node() ); + ctx.set_intent( chain::intent::block_application ); + ctx.reset_cache(); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_CHECK_NO_THROW( chain::system_call::apply_block( ctx, block ) ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( contract_exit ) -{ try { - crypto::multihash exit_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "exit_contract" } ); - crypto::private_key exit_pk = crypto::private_key::regenerate( exit_seed ); - auto exit_contract_id = exit_pk.get_public_key().to_address_bytes(); +{ + try + { + crypto::multihash exit_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "exit_contract" } ); + crypto::private_key exit_pk = crypto::private_key::regenerate( exit_seed ); + auto exit_contract_id = exit_pk.get_public_key().to_address_bytes(); - crypto::multihash call_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "call_contract" } ); - crypto::private_key call_pk = crypto::private_key::regenerate( call_seed ); - auto call_contract_id = call_pk.get_public_key().to_address_bytes(); + crypto::multihash call_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "call_contract" } ); + crypto::private_key call_pk = crypto::private_key::regenerate( call_seed ); + auto call_contract_id = call_pk.get_public_key().to_address_bytes(); - protocol::upload_contract_operation upload_exit_op; - upload_exit_op.set_bytecode( get_exit_wasm() ); - upload_exit_op.set_contract_id( exit_contract_id ); + protocol::upload_contract_operation upload_exit_op; + upload_exit_op.set_bytecode( get_exit_wasm() ); + upload_exit_op.set_contract_id( exit_contract_id ); - protocol::upload_contract_operation upload_call_op; - upload_call_op.set_bytecode( get_call_wasm() ); - upload_call_op.set_contract_id( call_contract_id ); + protocol::upload_contract_operation upload_call_op; + upload_call_op.set_bytecode( get_call_wasm() ); + upload_call_op.set_contract_id( call_contract_id ); - protocol::transaction trx; - sign_transaction( trx, exit_pk ); - auto trx_id = crypto::hash( crypto::multicodec::sha2_256, trx.header() ); - trx.add_signatures( util::converter::as< std::string >( call_pk.sign_compact( trx_id ) ) ); - ctx.set_transaction( trx ); + protocol::transaction trx; + sign_transaction( trx, exit_pk ); + auto trx_id = crypto::hash( crypto::multicodec::sha2_256, trx.header() ); + trx.add_signatures( util::converter::as< std::string >( call_pk.sign_compact( trx_id ) ) ); + ctx.set_transaction( trx ); - chain::system_call::apply_upload_contract_operation( ctx, upload_exit_op ); - chain::system_call::apply_upload_contract_operation( ctx, upload_call_op ); + chain::system_call::apply_upload_contract_operation( ctx, upload_exit_op ); + chain::system_call::apply_upload_contract_operation( ctx, upload_call_op ); - BOOST_TEST_MESSAGE( "Testing failure returned to a user contract" ); + BOOST_TEST_MESSAGE( "Testing failure returned to a user contract" ); - chain::exit_arguments args; - args.set_code( chain::failure ); - args.mutable_res()->mutable_error()->set_message( "chain failure" ); + chain::exit_arguments args; + args.set_code( chain::failure ); + args.mutable_res()->mutable_error()->set_message( "chain failure" ); - chain::call_arguments call; - call.set_contract_id( exit_contract_id ); - call.set_args( util::converter::as< std::string >( args ) ); + chain::call_arguments call; + call.set_contract_id( exit_contract_id ); + call.set_args( util::converter::as< std::string >( args ) ); - auto call_res = chain::system_call::call( ctx, call_contract_id, 0, util::converter::as< std::string >( call ) ); - auto returned_res = util::converter::to< chain::exit_arguments >( call_res ); + auto call_res = chain::system_call::call( ctx, call_contract_id, 0, util::converter::as< std::string >( call ) ); + auto returned_res = util::converter::to< chain::exit_arguments >( call_res ); - LOG(info) << call_res; - LOG(info) << returned_res; + LOG( info ) << call_res; + LOG( info ) << returned_res; - BOOST_CHECK_EQUAL( returned_res.code(), args.code() ); - BOOST_CHECK_EQUAL( returned_res.res().error().message(), args.res().error().message() ); + BOOST_CHECK_EQUAL( returned_res.code(), args.code() ); + BOOST_CHECK_EQUAL( returned_res.res().error().message(), args.res().error().message() ); - BOOST_TEST_MESSAGE( "Testing reversion returned to a user contract" ); + BOOST_TEST_MESSAGE( "Testing reversion returned to a user contract" ); - args.set_code( chain::reversion ); - args.mutable_res()->mutable_error()->set_message( "chain reversion" ); + args.set_code( chain::reversion ); + args.mutable_res()->mutable_error()->set_message( "chain reversion" ); - call.set_args( util::converter::as< std::string >( args ) ); + call.set_args( util::converter::as< std::string >( args ) ); - try - { + try + { chain::system_call::call( ctx, call_contract_id, 0, util::converter::as< std::string >( call ) ); BOOST_TEST( false, "call did not throw reversion" ); - } - catch ( const koinos::exception& e ) - { + } + catch( const koinos::exception& e ) + { BOOST_CHECK_EQUAL( e.get_code(), args.code() ); BOOST_CHECK_EQUAL( e.get_message(), args.res().error().message() ); - } + } - BOOST_TEST_MESSAGE( "Testing failure returned to a system contract" ); + BOOST_TEST_MESSAGE( "Testing failure returned to a system contract" ); - protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( call_contract_id ); - set_system_op.set_system_contract( true ); + protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( call_contract_id ); + set_system_op.set_system_contract( true ); - sign_transaction( trx, _signing_private_key ); + sign_transaction( trx, _signing_private_key ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - args.set_code( chain::failure ); - args.mutable_res()->mutable_error()->set_message( "chain failure" ); + args.set_code( chain::failure ); + args.mutable_res()->mutable_error()->set_message( "chain failure" ); - call.set_args( util::converter::as< std::string >( args ) ); + call.set_args( util::converter::as< std::string >( args ) ); - call_res = chain::system_call::call( ctx, call_contract_id, 0, util::converter::as< std::string >( call ) ); - returned_res = util::converter::to< chain::exit_arguments >( call_res ); + call_res = chain::system_call::call( ctx, call_contract_id, 0, util::converter::as< std::string >( call ) ); + returned_res = util::converter::to< chain::exit_arguments >( call_res ); - BOOST_CHECK_EQUAL( returned_res.code(), args.code() ); - BOOST_CHECK_EQUAL( returned_res.res().error().message(), args.res().error().message() ); + BOOST_CHECK_EQUAL( returned_res.code(), args.code() ); + BOOST_CHECK_EQUAL( returned_res.res().error().message(), args.res().error().message() ); - BOOST_TEST_MESSAGE( "Testing reversion returned to a system contract" ); + BOOST_TEST_MESSAGE( "Testing reversion returned to a system contract" ); - args.set_code( chain::reversion ); - args.mutable_res()->mutable_error()->set_message( "chain reversion" ); + args.set_code( chain::reversion ); + args.mutable_res()->mutable_error()->set_message( "chain reversion" ); - call.set_args( util::converter::as< std::string >( args ) ); + call.set_args( util::converter::as< std::string >( args ) ); - call_res = chain::system_call::call( ctx, call_contract_id, 0, util::converter::as< std::string >( call ) ); - returned_res = util::converter::to< chain::exit_arguments >( call_res ); + call_res = chain::system_call::call( ctx, call_contract_id, 0, util::converter::as< std::string >( call ) ); + returned_res = util::converter::to< chain::exit_arguments >( call_res ); - BOOST_CHECK_EQUAL( returned_res.code(), args.code() ); - BOOST_CHECK_EQUAL( returned_res.res().error().message(), args.res().error().message() ); + BOOST_CHECK_EQUAL( returned_res.code(), args.code() ); + BOOST_CHECK_EQUAL( returned_res.res().error().message(), args.res().error().message() ); - BOOST_TEST_MESSAGE( "Testing failure is thrown when calling contract natively" ); + BOOST_TEST_MESSAGE( "Testing failure is thrown when calling contract natively" ); - args.set_code( chain::failure ); - args.mutable_res()->mutable_error()->set_message( "chain failure" ); + args.set_code( chain::failure ); + args.mutable_res()->mutable_error()->set_message( "chain failure" ); - try - { + try + { chain::system_call::call( ctx, exit_contract_id, 0, util::converter::as< std::string >( args ) ); BOOST_TEST( false, "call did not throw failure" ); - } - catch ( const koinos::exception& e ) - { + } + catch( const koinos::exception& e ) + { BOOST_CHECK_EQUAL( e.get_code(), args.code() ); BOOST_CHECK_EQUAL( e.get_message(), args.res().error().message() ); - } + } - BOOST_TEST_MESSAGE( "Testing reversion is thrown when calling contract natively" ); + BOOST_TEST_MESSAGE( "Testing reversion is thrown when calling contract natively" ); - args.set_code( chain::reversion ); - args.mutable_res()->mutable_error()->set_message( "chain reversion" ); + args.set_code( chain::reversion ); + args.mutable_res()->mutable_error()->set_message( "chain reversion" ); - try - { + try + { chain::system_call::call( ctx, exit_contract_id, 0, util::converter::as< std::string >( args ) ); BOOST_TEST( false, "call did not throw reversion" ); - } - catch ( const koinos::exception& e ) - { + } + catch( const koinos::exception& e ) + { BOOST_CHECK_EQUAL( e.get_code(), args.code() ); BOOST_CHECK_EQUAL( e.get_message(), args.res().error().message() ); - } - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + } + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( syscall_override_return ) -{ try { - crypto::multihash echo_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "echo_contract" } ); - crypto::private_key echo_pk = crypto::private_key::regenerate( echo_seed ); - auto echo_contract_id = echo_pk.get_public_key().to_address_bytes(); - - crypto::multihash override_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "get_arguments_override" } ); - crypto::private_key override_pk = crypto::private_key::regenerate( override_seed ); - auto override_contract_id = override_pk.get_public_key().to_address_bytes(); +{ + try + { + crypto::multihash echo_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "echo_contract" } ); + crypto::private_key echo_pk = crypto::private_key::regenerate( echo_seed ); + auto echo_contract_id = echo_pk.get_public_key().to_address_bytes(); - protocol::upload_contract_operation upload_op; - upload_op.set_bytecode( get_echo_wasm() ); - upload_op.set_contract_id( echo_contract_id ); + crypto::multihash override_seed = + crypto::hash( crypto::multicodec::sha2_256, std::string{ "get_arguments_override" } ); + crypto::private_key override_pk = crypto::private_key::regenerate( override_seed ); + auto override_contract_id = override_pk.get_public_key().to_address_bytes(); - protocol::transaction trx; - sign_transaction( trx, echo_pk ); + protocol::upload_contract_operation upload_op; + upload_op.set_bytecode( get_echo_wasm() ); + upload_op.set_contract_id( echo_contract_id ); - ctx.set_transaction( trx ); + protocol::transaction trx; + sign_transaction( trx, echo_pk ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + ctx.set_transaction( trx ); - chain::system_call::call( ctx, echo_contract_id, 0, "hello world" ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - BOOST_REQUIRE_EQUAL( ctx.chronicler().logs().size(), 1 ); - BOOST_CHECK_EQUAL( ctx.chronicler().logs()[0], "hello world" ); + chain::system_call::call( ctx, echo_contract_id, 0, "hello world" ); - upload_op.set_bytecode( get_get_arguments_override_wasm() ); - upload_op.set_contract_id( override_contract_id ); + BOOST_REQUIRE_EQUAL( ctx.chronicler().logs().size(), 1 ); + BOOST_CHECK_EQUAL( ctx.chronicler().logs()[ 0 ], "hello world" ); - sign_transaction( trx, override_pk ); - chain::system_call::apply_upload_contract_operation( ctx, upload_op ); + upload_op.set_bytecode( get_get_arguments_override_wasm() ); + upload_op.set_contract_id( override_contract_id ); - protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( override_contract_id ); - set_system_op.set_system_contract( true ); + sign_transaction( trx, override_pk ); + chain::system_call::apply_upload_contract_operation( ctx, upload_op ); - sign_transaction( trx, _signing_private_key ); - chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); + protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( override_contract_id ); + set_system_op.set_system_contract( true ); - protocol::set_system_call_operation set_syscall_op; - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( override_contract_id ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x0 ); - set_syscall_op.set_call_id( chain::get_arguments ); + sign_transaction( trx, _signing_private_key ); + chain::system_call::apply_set_system_contract_operation( ctx, set_system_op ); - chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); + protocol::set_system_call_operation set_syscall_op; + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( override_contract_id ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x0 ); + set_syscall_op.set_call_id( chain::get_arguments ); - ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); - ctx.reset_cache(); + chain::system_call::apply_set_system_call_operation( ctx, set_syscall_op ); - chain::system_call::call( ctx, echo_contract_id, 0, "hello world" ); + ctx.set_state_node( ctx.get_state_node()->create_anonymous_node() ); + ctx.reset_cache(); - BOOST_REQUIRE_EQUAL( ctx.chronicler().logs().size(), 2 ); - BOOST_CHECK_EQUAL( ctx.chronicler().logs()[1], "override" ); + chain::system_call::call( ctx, echo_contract_id, 0, "hello world" ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_REQUIRE_EQUAL( ctx.chronicler().logs().size(), 2 ); + BOOST_CHECK_EQUAL( ctx.chronicler().logs()[ 1 ], "override" ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} #define THUNK_TIME_PRINT_STATS false BOOST_AUTO_TEST_CASE( thunk_time ) -{ try { - crypto::multihash contract_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "contract" } ); - crypto::private_key contract_pk = crypto::private_key::regenerate( contract_seed ); - - protocol::upload_contract_operation op; - op.set_bytecode( get_benchmark_wasm() ); - op.set_contract_id( contract_pk.get_public_key().to_address_bytes() ); +{ + try + { + crypto::multihash contract_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "contract" } ); + crypto::private_key contract_pk = crypto::private_key::regenerate( contract_seed ); - crypto::multihash empty_contract_seed = crypto::hash( crypto::multicodec::sha2_256, std::string{ "empty_contract" } ); - crypto::private_key empty_contract_pk = crypto::private_key::regenerate( empty_contract_seed ); + protocol::upload_contract_operation op; + op.set_bytecode( get_benchmark_wasm() ); + op.set_contract_id( contract_pk.get_public_key().to_address_bytes() ); - protocol::upload_contract_operation empty_contract_op; - empty_contract_op.set_bytecode( get_empty_contract_wasm() ); - empty_contract_op.set_contract_id( empty_contract_pk.get_public_key().to_address_bytes() ); + crypto::multihash empty_contract_seed = + crypto::hash( crypto::multicodec::sha2_256, std::string{ "empty_contract" } ); + crypto::private_key empty_contract_pk = crypto::private_key::regenerate( empty_contract_seed ); - protocol::transaction trx; - sign_transaction( trx, contract_pk ); - auto trx_id = crypto::hash( crypto::multicodec::sha2_256, trx.header() ); - trx.add_signatures( util::converter::as< std::string >( empty_contract_pk.sign_compact( trx_id ) ) ); - trx.add_signatures( util::converter::as< std::string >( _signing_private_key.sign_compact( trx_id ) ) ); - ctx.set_transaction( trx ); + protocol::upload_contract_operation empty_contract_op; + empty_contract_op.set_bytecode( get_empty_contract_wasm() ); + empty_contract_op.set_contract_id( empty_contract_pk.get_public_key().to_address_bytes() ); + protocol::transaction trx; + sign_transaction( trx, contract_pk ); + auto trx_id = crypto::hash( crypto::multicodec::sha2_256, trx.header() ); + trx.add_signatures( util::converter::as< std::string >( empty_contract_pk.sign_compact( trx_id ) ) ); + trx.add_signatures( util::converter::as< std::string >( _signing_private_key.sign_compact( trx_id ) ) ); + ctx.set_transaction( trx ); - protocol::block b; - b.mutable_header()->set_height( 10 ); - auto id_mh = crypto::hash( crypto::multicodec::sha2_256, b.header() ); - b.set_id( util::converter::as< std::string >( id_mh ) ); - b.set_signature( util::converter::as< std::string >( contract_pk.sign_compact( id_mh ) ) ); - ctx.set_block( b ); + protocol::block b; + b.mutable_header()->set_height( 10 ); + auto id_mh = crypto::hash( crypto::multicodec::sha2_256, b.header() ); + b.set_id( util::converter::as< std::string >( id_mh ) ); + b.set_signature( util::converter::as< std::string >( contract_pk.sign_compact( id_mh ) ) ); + ctx.set_block( b ); - chain::system_call::apply_upload_contract_operation( ctx, op ); + chain::system_call::apply_upload_contract_operation( ctx, op ); - chain::system_call::apply_upload_contract_operation( ctx, empty_contract_op ); + chain::system_call::apply_upload_contract_operation( ctx, empty_contract_op ); - protocol::set_system_contract_operation ssconp; - ssconp.set_contract_id( empty_contract_pk.get_public_key().to_address_bytes() ); - ssconp.set_system_contract( true ); + protocol::set_system_contract_operation ssconp; + ssconp.set_contract_id( empty_contract_pk.get_public_key().to_address_bytes() ); + ssconp.set_system_contract( true ); - chain::system_call::apply_set_system_contract_operation( ctx, ssconp ); + chain::system_call::apply_set_system_contract_operation( ctx, ssconp ); - LOG(info) << "benchmark contract key: " << util::to_base58( contract_pk.get_public_key().to_address_bytes() ); - LOG(info) << "empty contract key: " << util::to_base58( empty_contract_pk.get_public_key().to_address_bytes() ); + LOG( info ) << "benchmark contract key: " << util::to_base58( contract_pk.get_public_key().to_address_bytes() ); + LOG( info ) << "empty contract key: " << util::to_base58( empty_contract_pk.get_public_key().to_address_bytes() ); - const uint64_t global_run = 100; - std::vector< double > benchmarks; + const uint64_t global_run = 100; + std::vector< double > benchmarks; - LOG(info) << "Calibrating compute from smart contract benchmark..."; + LOG( info ) << "Calibrating compute from smart contract benchmark..."; - for ( uint64_t i = 0; i < global_run; i++ ) - { + for( uint64_t i = 0; i < global_run; i++ ) + { try { - ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); - auto session = ctx.make_session( 1'000'000 ); + ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); + auto session = ctx.make_session( 1'000'000 ); - uint64_t compute_bandwidth_start = ctx.resource_meter().compute_bandwidth_used(); + uint64_t compute_bandwidth_start = ctx.resource_meter().compute_bandwidth_used(); #if THUNK_TIME_PRINT_STATS - uint64_t network_bandwidth_start = ctx.resource_meter().network_bandwidth_used(); - uint64_t disk_storage_start = ctx.resource_meter().disk_storage_used(); + uint64_t network_bandwidth_start = ctx.resource_meter().network_bandwidth_used(); + uint64_t disk_storage_start = ctx.resource_meter().disk_storage_used(); #endif - chain::host_api hapi( ctx ); - auto hash = util::converter::as< std::string >( crypto::multihash::empty( crypto::multicodec::sha2_256 ) ); + chain::host_api hapi( ctx ); + auto hash = util::converter::as< std::string >( crypto::multihash::empty( crypto::multicodec::sha2_256 ) ); - auto start = std::chrono::high_resolution_clock::now(); - try - { - ctx.get_backend()->run( hapi, get_benchmark_wasm(), hash ); - } - catch ( chain::success_exception& ) {} - auto stop = std::chrono::high_resolution_clock::now(); + auto start = std::chrono::high_resolution_clock::now(); + try + { + ctx.get_backend()->run( hapi, get_benchmark_wasm(), hash ); + } + catch( chain::success_exception& ) + {} + auto stop = std::chrono::high_resolution_clock::now(); - uint64_t compute_bandwidth_stop = ctx.resource_meter().compute_bandwidth_used(); + uint64_t compute_bandwidth_stop = ctx.resource_meter().compute_bandwidth_used(); #if THUNK_TIME_PRINT_STATS - uint64_t network_bandwidth_stop = ctx.resource_meter().network_bandwidth_used(); - uint64_t disk_storage_stop = ctx.resource_meter().disk_storage_used(); + uint64_t network_bandwidth_stop = ctx.resource_meter().network_bandwidth_used(); + uint64_t disk_storage_stop = ctx.resource_meter().disk_storage_used(); #endif - uint64_t compute_used = compute_bandwidth_stop - compute_bandwidth_start; + uint64_t compute_used = compute_bandwidth_stop - compute_bandwidth_start; #if THUNK_TIME_PRINT_STATS - uint64_t network_used = network_bandwidth_stop - network_bandwidth_start; - uint64_t disk_used = disk_storage_stop - disk_storage_start; + uint64_t network_used = network_bandwidth_stop - network_bandwidth_start; + uint64_t disk_used = disk_storage_stop - disk_storage_start; #endif - auto duration = std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ); + auto duration = std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ); #if THUNK_TIME_PRINT_STATS - LOG(info) << "benchmark contract took: " << duration.count() << "us"; - LOG(info) << " -> compute: " << compute_used; - LOG(info) << " -> network: " << network_used; - LOG(info) << " -> disk: " << disk_used; - LOG(info) << " -> approximate nanoseconds per compute: " << compute_used / double( duration.count() ); + LOG( info ) << "benchmark contract took: " << duration.count() << "us"; + LOG( info ) << " -> compute: " << compute_used; + LOG( info ) << " -> network: " << network_used; + LOG( info ) << " -> disk: " << disk_used; + LOG( info ) << " -> approximate nanoseconds per compute: " << compute_used / double( duration.count() ); #endif - benchmarks.push_back( compute_used / double( duration.count() ) ); + benchmarks.push_back( compute_used / double( duration.count() ) ); } - catch ( const koinos::exception& e ) + catch( const koinos::exception& e ) { - LOG(error) << "Error: " << e.what(); + LOG( error ) << "Error: " << e.what(); } - } + } - auto mean = []( const std::vector< double >& v ) -> double { + auto mean = []( const std::vector< double >& v ) -> double + { double sum = 0; - for ( const auto& e : v ) - sum += e; + for( const auto& e: v ) + sum += e; return sum / v.size(); - }; + }; - auto median = []( std::vector< double > v ) -> double { + auto median = []( std::vector< double > v ) -> double + { std::sort( v.begin(), v.end() ); - if ( v.size() % 2 == 0 ) - return ( v[ v.size() / 2 - 1 ] + v[ v.size() / 2 ] ) / 2; + if( v.size() % 2 == 0 ) + return ( v[ v.size() / 2 - 1 ] + v[ v.size() / 2 ] ) / 2; return v[ v.size() / 2 ]; - }; + }; - auto mode = []( std::vector< double > v ) -> double { + auto mode = []( std::vector< double > v ) -> double + { std::sort( v.begin(), v.end() ); double max_count = 1, res = v[ 0 ], count = 1; - for ( int i = 1; i < v.size(); i++ ) + for( int i = 1; i < v.size(); i++ ) { - if ( v[i] == v[ i - 1 ] ) - { - count++; - } - else { - if ( count > max_count ) - { - max_count = count; - res = v[i - 1]; - } - count = 1; - } + if( v[ i ] == v[ i - 1 ] ) + { + count++; + } + else + { + if( count > max_count ) + { + max_count = count; + res = v[ i - 1 ]; + } + count = 1; + } } - if ( count > max_count ) + if( count > max_count ) { - max_count = count; - res = v[ v.size() - 1 ]; + max_count = count; + res = v[ v.size() - 1 ]; } return res; - }; + }; - LOG(info) << "mean: " << mean( benchmarks ); - LOG(info) << "median: " << median( benchmarks ); - LOG(info) << "mode: " << mode( benchmarks ); - LOG(info) << "min: " << *std::min_element( benchmarks.begin(), benchmarks.end() ); - LOG(info) << "max: " << *std::max_element( benchmarks.begin(), benchmarks.end() ); + LOG( info ) << "mean: " << mean( benchmarks ); + LOG( info ) << "median: " << median( benchmarks ); + LOG( info ) << "mode: " << mode( benchmarks ); + LOG( info ) << "min: " << *std::min_element( benchmarks.begin(), benchmarks.end() ); + LOG( info ) << "max: " << *std::max_element( benchmarks.begin(), benchmarks.end() ); - double compute_per_nanosecond = mean( benchmarks ); + double compute_per_nanosecond = mean( benchmarks ); - std::map< std::string, uint64_t > calls; - auto timer = [&]( const std::string& name, std::function< void(void) > call, std::function< void(void) > pre = [](){}, std::function< void(void) > post = [](){} ) - { - LOG(info) << "Testing " << name << "..."; + std::map< std::string, uint64_t > calls; + auto timer = [ & ]( + const std::string& name, + std::function< void( void ) > call, + std::function< void( void ) > pre = []() {}, + std::function< void( void ) > post = []() {} ) + { + LOG( info ) << "Testing " << name << "..."; uint64_t total_time = 0; - uint64_t runs = global_run; + uint64_t runs = global_run; - for ( uint64_t i = 0; i < runs; i++ ) + for( uint64_t i = 0; i < runs; i++ ) { - try - { - ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); - auto session = ctx.make_session( 1'000'000 ); - pre(); - uint64_t compute_bandwidth_start = ctx.resource_meter().compute_bandwidth_used(); - auto start = std::chrono::steady_clock::now(); - call(); - auto stop = std::chrono::steady_clock::now(); - uint64_t compute_bandwidth_stop = ctx.resource_meter().compute_bandwidth_used(); - post(); - - uint64_t compute_used = compute_bandwidth_stop - compute_bandwidth_start; - auto duration = std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ); - - //LOG(info) << "system call: " << name << ", took: " << duration.count() << "ns, actual compute used: " << compute_used << ", proposed compute cost: " << duration.count() / compute_per_nanosecond ; - total_time += duration.count(); - } - catch ( const koinos::exception& e ) - { - LOG(error) << "error: " << e.what(); - throw e; - } + try + { + ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); + auto session = ctx.make_session( 1'000'000 ); + pre(); + uint64_t compute_bandwidth_start = ctx.resource_meter().compute_bandwidth_used(); + auto start = std::chrono::steady_clock::now(); + call(); + auto stop = std::chrono::steady_clock::now(); + uint64_t compute_bandwidth_stop = ctx.resource_meter().compute_bandwidth_used(); + post(); + + uint64_t compute_used = compute_bandwidth_stop - compute_bandwidth_start; + auto duration = std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ); + + // LOG(info) << "system call: " << name << ", took: " << duration.count() << "ns, actual compute used: " << + // compute_used << ", proposed compute cost: " << duration.count() / compute_per_nanosecond ; + total_time += duration.count(); + } + catch( const koinos::exception& e ) + { + LOG( error ) << "error: " << e.what(); + throw e; + } } - calls[ name ] = (total_time + runs - 1) / runs; - }; - - chain::object_space objs; - objs.set_zone( std::string{ "test" } ); - objs.set_system( true ); - - chain::system_call::put_object( ctx, objs, std::string{ "remove_key" }, std::string{ "stuff" } ); - - protocol::set_system_call_operation sscop; - sscop.mutable_target()->mutable_system_call_bundle()->set_contract_id( empty_contract_op.contract_id() ); - sscop.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x00 ); - sscop.set_call_id( 1000 ); - - protocol::call_contract_operation cco; - cco.set_entry_point( 0x00 ); - cco.set_contract_id( empty_contract_pk.get_public_key().to_address_bytes() ); - - auto mtree = crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::transaction >{} ); - - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - - chain::system_call::set_account_nonce( ctx, std::string{ "0x123" }, util::converter::as< std::string >( nonce_value ) ); - - protocol::operation call_op; - call_op.mutable_call_contract()->set_contract_id( contract_pk.get_public_key().to_address_bytes() ); - ctx.set_operation( call_op ); - - protocol::transaction transaction; - transaction.mutable_header()->set_chain_id( chain::system_call::get_object( ctx, chain::state::space::metadata(), chain::state::key::chain_id ).value() ); - transaction.mutable_header()->set_payer( _signing_private_key.get_public_key().to_address_bytes() ); - transaction.mutable_header()->set_payee( _signing_private_key.get_public_key().to_address_bytes() ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - auto operation_merkle_tree = crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::operation >{} ); - transaction.mutable_header()->set_operation_merkle_root( util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); - trx_id = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); - transaction.set_id( util::converter::as< std::string >( trx_id ) ); - transaction.add_signatures( util::converter::as< std::string >( contract_pk.sign_compact( trx_id ) ) ); - transaction.add_signatures( util::converter::as< std::string >( empty_contract_pk.sign_compact( trx_id ) ) ); - transaction.add_signatures( util::converter::as< std::string >( _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( transaction.id() ) ) ) ); - ctx.set_transaction( transaction ); - - auto parent_node = db.get_node( crypto::multihash::zero( crypto::multicodec::sha2_256 ), db.get_shared_lock() ); - protocol::block block; - block.mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - block.mutable_header()->set_height( 1 ); - block.mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ).count() ); - block.mutable_header()->set_previous_state_merkle_root( util::converter::as< std::string >( parent_node->merkle_root() ) ); - auto transaction_merkle_tree = crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::transaction >{} ); - block.mutable_header()->set_transaction_merkle_root( util::converter::as< std::string >( transaction_merkle_tree.root()->hash() ) ); - block.mutable_header()->set_signer( _signing_private_key.get_public_key().to_address_bytes() ); - block.set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); - block.set_signature( util::converter::as< std::string >( _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( block.id() ) ) ) ); - ctx.set_block( block ); - - auto header_str = util::converter::as< std::string >( block.header() ); - auto nonce_str = util::converter::as< std::string >( nonce_value ); - - std::string message = "test"; - const auto res = _signing_private_key.generate_random_proof( message ); - const auto& proof = res.first; - const auto& proof_hash = util::converter::as< std::string >( res.second ); - auto serialized_public_key = util::converter::as< std::string >( _signing_private_key.get_public_key() ); - - std::map< std::string, std::function< void( void ) > > system_call_map { - { "check_system_authority", [&]() { chain::system_call::check_system_authority( ctx ); } }, - { "recover_public_key", [&]() { chain::system_call::recover_public_key( ctx, chain::dsa::ecdsa_secp256k1, transaction.signatures( 0 ), transaction.id(), true ); } }, - { "check_authority", [&]() { chain::system_call::check_authority( ctx, chain::contract_call, transaction.header().payer() ); } }, - { "get_last_irreversible_block", [&]() { chain::system_call::get_last_irreversible_block( ctx ); } }, - { "hash", [&]() { chain::system_call::hash( ctx, std::underlying_type_t< crypto::multicodec >( crypto::multicodec::sha2_256 ), header_str ); } }, - { "get_caller", [&]() { chain::system_call::get_caller( ctx ); } }, - { "get_contract_id", [&]() { chain::system_call::get_contract_id( ctx ); } }, - { "get_account_nonce", [&]() { chain::system_call::get_account_nonce( ctx, transaction.header().payer() ); } }, - { "get_account_rc", [&]() { chain::system_call::get_account_rc( ctx, transaction.header().payer() ); } }, - { "consume_account_rc", [&]() { chain::system_call::consume_account_rc( ctx, transaction.header().payer(), 1 ); } }, - { "get_transaction_field", [&]() { chain::system_call::get_transaction_field( ctx, "header" ); } }, - { "get_block_field", [&]() { chain::system_call::get_block_field( ctx, "header" ); } }, - { "verify_signature", [&]() { chain::system_call::verify_signature( ctx, chain::dsa::ecdsa_secp256k1, trx.signatures( 0 ), trx.signatures( 0 ), trx.id(), true ); } }, - { "get_resource_limits", [&]() { chain::system_call::get_resource_limits( ctx ); } }, - { "consume_block_resources", [&]() { chain::system_call::consume_block_resources( ctx, 1, 1, 1 ); } }, - { "log", [&]() { chain::system_call::log( ctx, "message" ); } }, - { "exit", [&]() { try { chain::system_call::exit( ctx, 0, chain::result() ); } catch ( ... ) {} } }, - { "process_block_signature", [&]() { chain::system_call::process_block_signature( ctx, block.id(), block.header(), block.signature() ); } }, - { "get_arguments", [&] { chain::system_call::get_arguments( ctx ); } }, - { "put_object", [&]() { chain::system_call::put_object( ctx, objs, std::string{ "key" }, header_str ); } }, - { "get_object", [&]() { chain::system_call::get_object( ctx, objs, std::string{ "key" } ); } }, - { "get_next_object", [&]() { chain::system_call::get_next_object( ctx, objs, std::string{ "key" } ); } }, - { "get_prev_object", [&]() { chain::system_call::get_prev_object( ctx, objs, std::string{ "key" } ); } }, - { "call", [&]() { chain::system_call::call( ctx, empty_contract_op.contract_id(), 0x00, empty_contract_op.bytecode() ); } }, - { "apply_set_system_call_operation", [&]() { chain::system_call::apply_set_system_call_operation( ctx, sscop ); } }, - { "apply_set_system_contract_operation", [&]() { chain::system_call::apply_set_system_contract_operation( ctx, ssconp ); } }, - { "apply_call_contract_operation", [&]() { chain::system_call::apply_call_contract_operation( ctx, cco ); } }, - { "get_transaction", [&]() { chain::system_call::get_transaction( ctx ); } }, - { "get_block", [&]() { chain::system_call::get_block( ctx ); } }, - { "get_head_info", [&]() { chain::system_call::get_head_info( ctx ); } }, - { "remove_object", [&]() { chain::system_call::remove_object( ctx, objs, std::string{ "remove_key" } ); } }, - { "pre_transaction_callback", [&]() { chain::system_call::pre_transaction_callback( ctx ); } }, - { "post_transaction_callback", [&]() { chain::system_call::post_transaction_callback( ctx ); } }, - { "pre_block_callback", [&]() { chain::system_call::pre_block_callback( ctx ); } }, - { "post_block_callback", [&]() { chain::system_call::post_block_callback( ctx ); } }, - { "verify_account_nonce", [&]() { chain::system_call::verify_account_nonce( ctx, std::string{ "0x123" }, nonce_str ); } }, - { "set_account_nonce", [&]() { chain::system_call::set_account_nonce( ctx, std::string{ "0x123" }, nonce_str ); } }, - { "verify_vrf_proof", [&]() { chain::system_call::verify_vrf_proof( ctx, chain::dsa::ecdsa_secp256k1, serialized_public_key, proof, proof_hash, message ); } }, - { "get_chain_id", [&]() { chain::system_call::get_chain_id( ctx ); } }, - { "get_operation", [&]() { chain::system_call::get_operation( ctx ); } } - }; - - for ( const auto& [ name, call ] : system_call_map ) + calls[ name ] = ( total_time + runs - 1 ) / runs; + }; + + chain::object_space objs; + objs.set_zone( std::string{ "test" } ); + objs.set_system( true ); + + chain::system_call::put_object( ctx, objs, std::string{ "remove_key" }, std::string{ "stuff" } ); + + protocol::set_system_call_operation sscop; + sscop.mutable_target()->mutable_system_call_bundle()->set_contract_id( empty_contract_op.contract_id() ); + sscop.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x00 ); + sscop.set_call_id( 1'000 ); + + protocol::call_contract_operation cco; + cco.set_entry_point( 0x00 ); + cco.set_contract_id( empty_contract_pk.get_public_key().to_address_bytes() ); + + auto mtree = crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::transaction >{} ); + + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + + chain::system_call::set_account_nonce( ctx, + std::string{ "0x123" }, + util::converter::as< std::string >( nonce_value ) ); + + protocol::operation call_op; + call_op.mutable_call_contract()->set_contract_id( contract_pk.get_public_key().to_address_bytes() ); + ctx.set_operation( call_op ); + + protocol::transaction transaction; + transaction.mutable_header()->set_chain_id( + chain::system_call::get_object( ctx, chain::state::space::metadata(), chain::state::key::chain_id ).value() ); + transaction.mutable_header()->set_payer( _signing_private_key.get_public_key().to_address_bytes() ); + transaction.mutable_header()->set_payee( _signing_private_key.get_public_key().to_address_bytes() ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + auto operation_merkle_tree = + crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::operation >{} ); + transaction.mutable_header()->set_operation_merkle_root( + util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); + trx_id = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); + transaction.set_id( util::converter::as< std::string >( trx_id ) ); + transaction.add_signatures( util::converter::as< std::string >( contract_pk.sign_compact( trx_id ) ) ); + transaction.add_signatures( util::converter::as< std::string >( empty_contract_pk.sign_compact( trx_id ) ) ); + transaction.add_signatures( util::converter::as< std::string >( + _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( transaction.id() ) ) ) ); + ctx.set_transaction( transaction ); + + auto parent_node = db.get_node( crypto::multihash::zero( crypto::multicodec::sha2_256 ), db.get_shared_lock() ); + protocol::block block; + block.mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + block.mutable_header()->set_height( 1 ); + block.mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ) + .count() ); + block.mutable_header()->set_previous_state_merkle_root( + util::converter::as< std::string >( parent_node->merkle_root() ) ); + auto transaction_merkle_tree = + crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::transaction >{} ); + block.mutable_header()->set_transaction_merkle_root( + util::converter::as< std::string >( transaction_merkle_tree.root()->hash() ) ); + block.mutable_header()->set_signer( _signing_private_key.get_public_key().to_address_bytes() ); + block.set_id( + util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); + block.set_signature( util::converter::as< std::string >( + _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( block.id() ) ) ) ); + ctx.set_block( block ); + + auto header_str = util::converter::as< std::string >( block.header() ); + auto nonce_str = util::converter::as< std::string >( nonce_value ); + + std::string message = "test"; + const auto res = _signing_private_key.generate_random_proof( message ); + const auto& proof = res.first; + const auto& proof_hash = util::converter::as< std::string >( res.second ); + auto serialized_public_key = util::converter::as< std::string >( _signing_private_key.get_public_key() ); + + std::map< std::string, std::function< void( void ) > > system_call_map{ + { "check_system_authority", + [ & ]() + { + chain::system_call::check_system_authority( ctx ); + }}, + { "recover_public_key", + [ & ]() + { + chain::system_call::recover_public_key( ctx, + chain::dsa::ecdsa_secp256k1, + transaction.signatures( 0 ), + transaction.id(), + true ); + }}, + { "check_authority", + [ & ]() + { + chain::system_call::check_authority( ctx, chain::contract_call, transaction.header().payer() ); + }}, + { "get_last_irreversible_block", + [ & ]() + { + chain::system_call::get_last_irreversible_block( ctx ); + }}, + { "hash", + [ & ]() + { + chain::system_call::hash( ctx, + std::underlying_type_t< crypto::multicodec >( crypto::multicodec::sha2_256 ), + header_str ); + }}, + { "get_caller", + [ & ]() + { + chain::system_call::get_caller( ctx ); + }}, + { "get_contract_id", + [ & ]() + { + chain::system_call::get_contract_id( ctx ); + }}, + { "get_account_nonce", + [ & ]() + { + chain::system_call::get_account_nonce( ctx, transaction.header().payer() ); + }}, + { "get_account_rc", + [ & ]() + { + chain::system_call::get_account_rc( ctx, transaction.header().payer() ); + }}, + { "consume_account_rc", + [ & ]() + { + chain::system_call::consume_account_rc( ctx, transaction.header().payer(), 1 ); + }}, + { "get_transaction_field", + [ & ]() + { + chain::system_call::get_transaction_field( ctx, "header" ); + }}, + { "get_block_field", + [ & ]() + { + chain::system_call::get_block_field( ctx, "header" ); + }}, + { "verify_signature", + [ & ]() + { + chain::system_call::verify_signature( ctx, + chain::dsa::ecdsa_secp256k1, + trx.signatures( 0 ), + trx.signatures( 0 ), + trx.id(), + true ); + }}, + { "get_resource_limits", + [ & ]() + { + chain::system_call::get_resource_limits( ctx ); + }}, + { "consume_block_resources", + [ & ]() + { + chain::system_call::consume_block_resources( ctx, 1, 1, 1 ); + }}, + { "log", + [ & ]() + { + chain::system_call::log( ctx, "message" ); + }}, + { "exit", + [ & ]() + { + try + { + chain::system_call::exit( ctx, 0, chain::result() ); + } + catch( ... ) + {} + }}, + { "process_block_signature", + [ & ]() + { + chain::system_call::process_block_signature( ctx, block.id(), block.header(), block.signature() ); + }}, + { "get_arguments", + [ & ] + { + chain::system_call::get_arguments( ctx ); + }}, + { "put_object", + [ & ]() + { + chain::system_call::put_object( ctx, objs, std::string{ "key" }, header_str ); + }}, + { "get_object", + [ & ]() + { + chain::system_call::get_object( ctx, objs, std::string{ "key" } ); + }}, + { "get_next_object", + [ & ]() + { + chain::system_call::get_next_object( ctx, objs, std::string{ "key" } ); + }}, + { "get_prev_object", + [ & ]() + { + chain::system_call::get_prev_object( ctx, objs, std::string{ "key" } ); + }}, + { "call", + [ & ]() + { + chain::system_call::call( ctx, empty_contract_op.contract_id(), 0x00, empty_contract_op.bytecode() ); + }}, + { "apply_set_system_call_operation", + [ & ]() + { + chain::system_call::apply_set_system_call_operation( ctx, sscop ); + }}, + {"apply_set_system_contract_operation", + [ & ]() + { + chain::system_call::apply_set_system_contract_operation( ctx, ssconp ); + }}, + { "apply_call_contract_operation", + [ & ]() + { + chain::system_call::apply_call_contract_operation( ctx, cco ); + }}, + { "get_transaction", + [ & ]() + { + chain::system_call::get_transaction( ctx ); + }}, + { "get_block", + [ & ]() + { + chain::system_call::get_block( ctx ); + }}, + { "get_head_info", + [ & ]() + { + chain::system_call::get_head_info( ctx ); + }}, + { "remove_object", + [ & ]() + { + chain::system_call::remove_object( ctx, objs, std::string{ "remove_key" } ); + }}, + { "pre_transaction_callback", + [ & ]() + { + chain::system_call::pre_transaction_callback( ctx ); + }}, + { "post_transaction_callback", + [ & ]() + { + chain::system_call::post_transaction_callback( ctx ); + }}, + { "pre_block_callback", + [ & ]() + { + chain::system_call::pre_block_callback( ctx ); + }}, + { "post_block_callback", + [ & ]() + { + chain::system_call::post_block_callback( ctx ); + }}, + { "verify_account_nonce", + [ & ]() + { + chain::system_call::verify_account_nonce( ctx, std::string{ "0x123" }, nonce_str ); + }}, + { "set_account_nonce", + [ & ]() + { + chain::system_call::set_account_nonce( ctx, std::string{ "0x123" }, nonce_str ); + }}, + { "verify_vrf_proof", + [ & ]() + { + chain::system_call::verify_vrf_proof( ctx, + chain::dsa::ecdsa_secp256k1, + serialized_public_key, + proof, + proof_hash, + message ); + }}, + { "get_chain_id", + [ & ]() + { + chain::system_call::get_chain_id( ctx ); + }}, + { "get_operation", + [ & ]() + { + chain::system_call::get_operation( ctx ); + }} + }; + + for( const auto& [ name, call ]: system_call_map ) timer( name, call ); - ctx.clear_block(); - ctx.clear_transaction(); - ctx.set_transaction( transaction ); + ctx.clear_block(); + ctx.clear_transaction(); + ctx.set_transaction( transaction ); - ctx.set_intent( chain::intent::transaction_application ); - timer( "apply_transaction", - [&]() + ctx.set_intent( chain::intent::transaction_application ); + timer( + "apply_transaction", + [ & ]() { - chain::system_call::apply_transaction( ctx, transaction ); + chain::system_call::apply_transaction( ctx, transaction ); }, - [&]() + [ & ]() { - transaction.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - operation_merkle_tree = crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::operation >{} ); - transaction.mutable_header()->set_operation_merkle_root( util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); - trx_id = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); - transaction.set_id( util::converter::as< std::string >( trx_id ) ); - transaction.clear_signatures(); - transaction.add_signatures( util::converter::as< std::string >( contract_pk.sign_compact( trx_id ) ) ); - transaction.add_signatures( util::converter::as< std::string >( empty_contract_pk.sign_compact( trx_id ) ) ); - transaction.add_signatures( util::converter::as< std::string >( _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( transaction.id() ) ) ) ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + operation_merkle_tree = + crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::operation >{} ); + transaction.mutable_header()->set_operation_merkle_root( + util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); + trx_id = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); + transaction.set_id( util::converter::as< std::string >( trx_id ) ); + transaction.clear_signatures(); + transaction.add_signatures( util::converter::as< std::string >( contract_pk.sign_compact( trx_id ) ) ); + transaction.add_signatures( util::converter::as< std::string >( empty_contract_pk.sign_compact( trx_id ) ) ); + transaction.add_signatures( util::converter::as< std::string >( + _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( transaction.id() ) ) ) ); }, - [&]() + [ & ]() { - nonce_value.set_uint64_value( nonce_value.uint64_value() + 1 ); - } - ); - - nonce_value.set_uint64_value( 1 ); - - transaction.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - operation_merkle_tree = crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::operation >{} ); - transaction.mutable_header()->set_operation_merkle_root( util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); - trx_id = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); - transaction.set_id( util::converter::as< std::string >( trx_id ) ); - transaction.clear_signatures(); - transaction.add_signatures( util::converter::as< std::string >( contract_pk.sign_compact( trx_id ) ) ); - transaction.add_signatures( util::converter::as< std::string >( _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( transaction.id() ) ) ) ); - transaction.add_signatures( util::converter::as< std::string >( empty_contract_pk.sign_compact( trx_id ) ) ); - ctx.set_transaction( transaction ); - - timer( "apply_upload_contract_operation", [&](){ chain::system_call::apply_upload_contract_operation( ctx, empty_contract_op ); } ); - - ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); - - ctx.set_intent( chain::intent::block_application ); - timer( "apply_block", [&]() { chain::system_call::apply_block( ctx, block ); } ); - - std::fstream rand_stream( "/dev/random", std::ios_base::in ); + nonce_value.set_uint64_value( nonce_value.uint64_value() + 1 ); + } ); - auto create_random_payload = [&]( uint64_t payload_size ) -> std::string { + nonce_value.set_uint64_value( 1 ); + + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + operation_merkle_tree = crypto::merkle_tree( crypto::multicodec::sha2_256, std::vector< protocol::operation >{} ); + transaction.mutable_header()->set_operation_merkle_root( + util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); + trx_id = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); + transaction.set_id( util::converter::as< std::string >( trx_id ) ); + transaction.clear_signatures(); + transaction.add_signatures( util::converter::as< std::string >( contract_pk.sign_compact( trx_id ) ) ); + transaction.add_signatures( util::converter::as< std::string >( + _signing_private_key.sign_compact( util::converter::to< crypto::multihash >( transaction.id() ) ) ) ); + transaction.add_signatures( util::converter::as< std::string >( empty_contract_pk.sign_compact( trx_id ) ) ); + ctx.set_transaction( transaction ); + + timer( "apply_upload_contract_operation", + [ & ]() + { + chain::system_call::apply_upload_contract_operation( ctx, empty_contract_op ); + } ); + + ctx.resource_meter().set_resource_limit_data( chain::system_call::get_resource_limits( ctx ) ); + + ctx.set_intent( chain::intent::block_application ); + timer( "apply_block", + [ & ]() + { + chain::system_call::apply_block( ctx, block ); + } ); + + std::fstream rand_stream( "/dev/random", std::ios_base::in ); + + auto create_random_payload = [ & ]( uint64_t payload_size ) -> std::string + { std::string res( payload_size, 0x00 ); rand_stream.read( const_cast< char* >( res.data() ), payload_size ); BOOST_REQUIRE_EQUAL( payload_size, res.size() ); return res; - }; + }; - auto lin_reg = []( const std::vector< uint64_t >& x_points, const std::vector< uint64_t >& y_points ) -> std::pair< double, double > { + auto lin_reg = []( const std::vector< uint64_t >& x_points, + const std::vector< uint64_t >& y_points ) -> std::pair< double, double > + { double x_mean = std::accumulate( std::begin( x_points ), std::end( x_points ), 0 ) / double( x_points.size() ); double y_mean = std::accumulate( std::begin( y_points ), std::end( y_points ), 0 ) / double( y_points.size() ); - double ss_xy = 0; - double ss_xx = 0; + double ss_xy = 0; + double ss_xx = 0; { - std::vector< uint64_t > xy; - for( std::size_t i = 0; i < x_points.size(); i++ ) - { - xy.push_back( x_points[i] * y_points[i] ); - } + std::vector< uint64_t > xy; + for( std::size_t i = 0; i < x_points.size(); i++ ) + { + xy.push_back( x_points[ i ] * y_points[ i ] ); + } - ss_xy = std::accumulate( std::begin( xy ), std::end( xy ), 0 ) - ( x_points.size() * x_mean * y_mean ); + ss_xy = std::accumulate( std::begin( xy ), std::end( xy ), 0 ) - ( x_points.size() * x_mean * y_mean ); } { - std::vector< uint64_t > xx; + std::vector< uint64_t > xx; - for( std::size_t i = 0; i < x_points.size(); i++ ) - { - xx.push_back( x_points[i] * x_points[i] ); - } + for( std::size_t i = 0; i < x_points.size(); i++ ) + { + xx.push_back( x_points[ i ] * x_points[ i ] ); + } - ss_xx = std::accumulate( std::begin( xx ), std::end( xx ), 0 ) - ( x_points.size() * x_mean * x_mean ); + ss_xx = std::accumulate( std::begin( xx ), std::end( xx ), 0 ) - ( x_points.size() * x_mean * x_mean ); } double b_1 = double( ss_xy ) / ss_xx; double b_0 = y_mean - ( b_1 * x_mean ); return { b_0, b_1 }; - }; + }; - auto sample_hash_algorithm = [&]( koinos::crypto::multicodec code ) -> std::pair< std::vector< uint64_t >, std::vector< uint64_t > > { + auto sample_hash_algorithm = + [ & ]( koinos::crypto::multicodec code ) -> std::pair< std::vector< uint64_t >, std::vector< uint64_t > > + { std::vector< uint64_t > payload_sizes; std::vector< uint64_t > hash_times; @@ -2505,68 +2986,70 @@ BOOST_AUTO_TEST_CASE( thunk_time ) ctx.resource_meter().set_resource_limit_data( rld ); auto session = ctx.make_session( 1'000'000'000 ); - uint64_t runs = std::max( uint64_t( 1 ), global_run / 1000 ); + uint64_t runs = std::max( uint64_t( 1 ), global_run / 1'000 ); - for ( int i = 0; i < 1024; i += 4 ) + for( int i = 0; i < 1'024; i += 4 ) { - auto payload = create_random_payload( i ); - - auto start = std::chrono::steady_clock::now(); - for ( int i = 0; i < runs; i++ ) - { - koinos::chain::system_call::hash( ctx, std::underlying_type_t< koinos::crypto::multicodec >( code ), payload ); - } - auto stop = std::chrono::steady_clock::now(); - - payload_sizes.push_back( payload.size() ); - hash_times.push_back( std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ).count() / runs ); + auto payload = create_random_payload( i ); + + auto start = std::chrono::steady_clock::now(); + for( int i = 0; i < runs; i++ ) + { + koinos::chain::system_call::hash( ctx, + std::underlying_type_t< koinos::crypto::multicodec >( code ), + payload ); + } + auto stop = std::chrono::steady_clock::now(); + + payload_sizes.push_back( payload.size() ); + hash_times.push_back( std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ).count() / runs ); } return { payload_sizes, hash_times }; - }; - - { - LOG(info) << "Testing sha1..."; - auto [payload_sizes, hash_times] = sample_hash_algorithm( koinos::crypto::multicodec::sha1 ); - auto [b_0, b_1] = lin_reg( payload_sizes, hash_times ); - calls[ "sha1_base" ] = std::max( int64_t(1), int64_t( ceil( b_0 ) ) ); - calls[ "sha1_per_byte" ] = std::max( int64_t(1), int64_t( ceil( b_1 ) ) ); - } - - { - LOG(info) << "Testing sha2_256..."; - auto [payload_sizes, hash_times] = sample_hash_algorithm( koinos::crypto::multicodec::sha2_256 ); - auto [b_0, b_1] = lin_reg( payload_sizes, hash_times ); - calls[ "sha2_256_base" ] = std::max( int64_t(1), int64_t( ceil( b_0 ) ) ); - calls[ "sha2_256_per_byte" ] = std::max( int64_t(1), int64_t( ceil( b_1 ) ) ); - } - - { - LOG(info) << "Testing sha2_512..."; - auto [payload_sizes, hash_times] = sample_hash_algorithm( koinos::crypto::multicodec::sha2_512 ); - auto [b_0, b_1] = lin_reg( payload_sizes, hash_times ); - calls[ "sha2_512_base" ] = std::max( int64_t(1), int64_t( ceil( b_0 ) ) ); - calls[ "sha2_512_per_byte" ] = std::max( int64_t(1), int64_t( ceil( b_1 ) ) ); - } - - { - LOG(info) << "Testing keccak_256..."; - auto [payload_sizes, hash_times] = sample_hash_algorithm( koinos::crypto::multicodec::keccak_256 ); - auto [b_0, b_1] = lin_reg( payload_sizes, hash_times ); - calls[ "keccak_256_base" ] = std::max( int64_t(1), int64_t( ceil( b_0 ) ) ); - calls[ "keccak_256_per_byte" ] = std::max( int64_t(1), int64_t( ceil( b_1 ) ) ); - } - - { - LOG(info) << "Testing ripemd_160..."; - auto [payload_sizes, hash_times] = sample_hash_algorithm( koinos::crypto::multicodec::ripemd_160 ); - auto [b_0, b_1] = lin_reg( payload_sizes, hash_times ); - calls[ "ripemd_160_base" ] = std::max( int64_t(1), int64_t( ceil( b_0 ) ) ); - calls[ "ripemd_160_per_byte" ] = std::max( int64_t(1), int64_t( ceil( b_1 ) ) ); - } - - { - LOG(info) << "Testing event..."; + }; + + { + LOG( info ) << "Testing sha1..."; + auto [ payload_sizes, hash_times ] = sample_hash_algorithm( koinos::crypto::multicodec::sha1 ); + auto [ b_0, b_1 ] = lin_reg( payload_sizes, hash_times ); + calls[ "sha1_base" ] = std::max( int64_t( 1 ), int64_t( ceil( b_0 ) ) ); + calls[ "sha1_per_byte" ] = std::max( int64_t( 1 ), int64_t( ceil( b_1 ) ) ); + } + + { + LOG( info ) << "Testing sha2_256..."; + auto [ payload_sizes, hash_times ] = sample_hash_algorithm( koinos::crypto::multicodec::sha2_256 ); + auto [ b_0, b_1 ] = lin_reg( payload_sizes, hash_times ); + calls[ "sha2_256_base" ] = std::max( int64_t( 1 ), int64_t( ceil( b_0 ) ) ); + calls[ "sha2_256_per_byte" ] = std::max( int64_t( 1 ), int64_t( ceil( b_1 ) ) ); + } + + { + LOG( info ) << "Testing sha2_512..."; + auto [ payload_sizes, hash_times ] = sample_hash_algorithm( koinos::crypto::multicodec::sha2_512 ); + auto [ b_0, b_1 ] = lin_reg( payload_sizes, hash_times ); + calls[ "sha2_512_base" ] = std::max( int64_t( 1 ), int64_t( ceil( b_0 ) ) ); + calls[ "sha2_512_per_byte" ] = std::max( int64_t( 1 ), int64_t( ceil( b_1 ) ) ); + } + + { + LOG( info ) << "Testing keccak_256..."; + auto [ payload_sizes, hash_times ] = sample_hash_algorithm( koinos::crypto::multicodec::keccak_256 ); + auto [ b_0, b_1 ] = lin_reg( payload_sizes, hash_times ); + calls[ "keccak_256_base" ] = std::max( int64_t( 1 ), int64_t( ceil( b_0 ) ) ); + calls[ "keccak_256_per_byte" ] = std::max( int64_t( 1 ), int64_t( ceil( b_1 ) ) ); + } + + { + LOG( info ) << "Testing ripemd_160..."; + auto [ payload_sizes, hash_times ] = sample_hash_algorithm( koinos::crypto::multicodec::ripemd_160 ); + auto [ b_0, b_1 ] = lin_reg( payload_sizes, hash_times ); + calls[ "ripemd_160_base" ] = std::max( int64_t( 1 ), int64_t( ceil( b_0 ) ) ); + calls[ "ripemd_160_per_byte" ] = std::max( int64_t( 1 ), int64_t( ceil( b_1 ) ) ); + } + + { + LOG( info ) << "Testing event..."; std::vector< uint64_t > payload_sizes; std::vector< uint64_t > event_times; @@ -2575,38 +3058,38 @@ BOOST_AUTO_TEST_CASE( thunk_time ) std::vector< std::string > impacted; - uint64_t runs = std::max( uint64_t( 1 ), global_run / 50 ); + uint64_t runs = std::max( uint64_t( 1 ), global_run / 50 ); - for ( int i = 0; i < 50; i++ ) + for( int i = 0; i < 50; i++ ) { - chain::resource_limit_data rld; - rld.set_compute_bandwidth_limit( 100'000'000 ); + chain::resource_limit_data rld; + rld.set_compute_bandwidth_limit( 100'000'000 ); - ctx.resource_meter().set_resource_limit_data( rld ); - auto session = ctx.make_session( 100'000'000 ); + ctx.resource_meter().set_resource_limit_data( rld ); + auto session = ctx.make_session( 100'000'000 ); - auto start = std::chrono::steady_clock::now(); + auto start = std::chrono::steady_clock::now(); - for ( int j = 0; j < runs; j++ ) - { - koinos::chain::system_call::event( ctx, "event", address, impacted ); - } + for( int j = 0; j < runs; j++ ) + { + koinos::chain::system_call::event( ctx, "event", address, impacted ); + } - auto stop = std::chrono::steady_clock::now(); + auto stop = std::chrono::steady_clock::now(); - payload_sizes.push_back( i ); - event_times.push_back( std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ).count() / runs ); + payload_sizes.push_back( i ); + event_times.push_back( std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ).count() / runs ); - impacted.push_back( address ); + impacted.push_back( address ); } - auto [b_0, b_1] = lin_reg( payload_sizes, event_times ); - calls[ "event" ] = std::max( int64_t(1), int64_t( ceil( b_0 ) ) ); - calls[ "event_per_impacted" ] = std::max( int64_t(1), int64_t( ceil( b_1 ) ) ); - } + auto [ b_0, b_1 ] = lin_reg( payload_sizes, event_times ); + calls[ "event" ] = std::max( int64_t( 1 ), int64_t( ceil( b_0 ) ) ); + calls[ "event_per_impacted" ] = std::max( int64_t( 1 ), int64_t( ceil( b_1 ) ) ); + } - { - LOG(info) << "Testing deserialize multihash..."; + { + LOG( info ) << "Testing deserialize multihash..."; std::vector< uint64_t > number_of_hashes; std::vector< uint64_t > deserialize_times; @@ -2617,48 +3100,57 @@ BOOST_AUTO_TEST_CASE( thunk_time ) uint64_t runs = std::max( uint64_t( 1 ), global_run / 20 ); - for ( int i = 0; i < 20; i++ ) + for( int i = 0; i < 20; i++ ) { - chain::resource_limit_data rld; - rld.set_compute_bandwidth_limit( 100'000'000 ); - - ctx.resource_meter().set_resource_limit_data( rld ); - auto session = ctx.make_session( 100'000'000 ); - - auto start = std::chrono::steady_clock::now(); - for ( int j = 0; j < runs; j++ ) - { - std::vector< crypto::multihash > leaves; - leaves.resize( hashes.size() ); - std::transform( std::begin( hashes ), std::end( hashes ), std::begin( leaves ), []( const std::string& s ) { return util::converter::to< crypto::multihash >( s ); } ); - } - auto stop = std::chrono::steady_clock::now(); - - number_of_hashes.push_back( i ); - deserialize_times.push_back( std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ).count() / runs ); - - hashes.push_back( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, create_random_payload( 32 ) ) ) ); + chain::resource_limit_data rld; + rld.set_compute_bandwidth_limit( 100'000'000 ); + + ctx.resource_meter().set_resource_limit_data( rld ); + auto session = ctx.make_session( 100'000'000 ); + + auto start = std::chrono::steady_clock::now(); + for( int j = 0; j < runs; j++ ) + { + std::vector< crypto::multihash > leaves; + leaves.resize( hashes.size() ); + std::transform( std::begin( hashes ), + std::end( hashes ), + std::begin( leaves ), + []( const std::string& s ) + { + return util::converter::to< crypto::multihash >( s ); + } ); + } + auto stop = std::chrono::steady_clock::now(); + + number_of_hashes.push_back( i ); + deserialize_times.push_back( std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ).count() + / runs ); + + hashes.push_back( util::converter::as< std::string >( + crypto::hash( crypto::multicodec::sha2_256, create_random_payload( 32 ) ) ) ); } - auto [b_0, b_1] = lin_reg( number_of_hashes, deserialize_times ); - LOG(info) << b_0 << ", " << b_1; - calls[ "deserialize_multihash_base" ] = std::max( int64_t(1), int64_t( ceil( b_0 ) ) ); - calls[ "deserialize_multihash_per_byte" ] = std::max( int64_t(1), int64_t( ceil( b_1 ) ) ); - } + auto [ b_0, b_1 ] = lin_reg( number_of_hashes, deserialize_times ); + LOG( info ) << b_0 << ", " << b_1; + calls[ "deserialize_multihash_base" ] = std::max( int64_t( 1 ), int64_t( ceil( b_0 ) ) ); + calls[ "deserialize_multihash_per_byte" ] = std::max( int64_t( 1 ), int64_t( ceil( b_1 ) ) ); + } - { - LOG(info) << "Testing verify_merkle_root..."; + { + LOG( info ) << "Testing verify_merkle_root..."; std::vector< crypto::multihash > merkle_leafs; std::vector< std::string > string_leafs; - for ( std::size_t i = 0; i < 20; i++ ) + for( std::size_t i = 0; i < 20; i++ ) { - merkle_leafs.push_back( crypto::hash( koinos::crypto::multicodec::sha2_256, create_random_payload( 32 ) ) ); - string_leafs.push_back( util::converter::as< std::string >( merkle_leafs.back() ) ); + merkle_leafs.push_back( crypto::hash( koinos::crypto::multicodec::sha2_256, create_random_payload( 32 ) ) ); + string_leafs.push_back( util::converter::as< std::string >( merkle_leafs.back() ) ); } - auto merkle_root = util::converter::as< std::string >( crypto::merkle_tree( koinos::crypto::multicodec::sha2_256, merkle_leafs ).root()->hash() ); - int64_t time = 0; + auto merkle_root = util::converter::as< std::string >( + crypto::merkle_tree( koinos::crypto::multicodec::sha2_256, merkle_leafs ).root()->hash() ); + int64_t time = 0; uint64_t runs = std::max( uint64_t( 1 ), global_run / 20 ); chain::resource_limit_data rld; @@ -2668,95 +3160,136 @@ BOOST_AUTO_TEST_CASE( thunk_time ) auto session = ctx.make_session( 10'000'000'000 ); auto start = std::chrono::steady_clock::now(); - for ( int i = 0; i < runs; i++ ) + for( int i = 0; i < runs; i++ ) { - koinos::chain::system_call::verify_merkle_root( ctx, merkle_root, string_leafs ); + koinos::chain::system_call::verify_merkle_root( ctx, merkle_root, string_leafs ); } - auto stop = std::chrono::steady_clock::now(); - time += std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ).count(); + auto stop = std::chrono::steady_clock::now(); + time += std::chrono::duration_cast< std::chrono::nanoseconds >( stop - start ).count(); time /= runs; - time -= ( string_leafs.size() + 1 ) * calls[ "deserialize_multihash_per_byte" ] + calls[ "deserialize_multihash_base" ]; - time -= 21 * ( calls[ "sha2_256_base" ] + 2 * 32 * calls[ "sha2_256_per_byte" ] ); - calls[ "verify_merkle_root" ] = std::max( int64_t(1), int64_t( ceil( time ) ) ); - } - - calls["deserialize_message_per_byte"] = 1; - calls["object_serialization_per_byte"] = 1; - - std::map< std::string, std::vector< std::string > > subcalls; - subcalls[ "process_block_signature" ] = { "get_object", "recover_public_key" }; - subcalls[ "apply_block" ] = { "get_resource_limits", "pre_block_callback", "verify_merkle_root", "hash", "process_block_signature", "put_object", "post_block_callback", "consume_block_resources" }; - subcalls[ "apply_transaction" ] = { "get_object", "verify_merkle_root", "get_account_rc", "pre_transaction_callback", "check_authority", "verify_account_nonce", "set_account_nonce", "post_transaction_callback", "consume_account_rc" }; - subcalls[ "apply_upload_contract_operation" ] = { "check_authority", "hash", "put_object", "put_object" }; - subcalls[ "apply_call_contract_operation" ] = { "call" }; - subcalls[ "apply_set_system_call_operation" ] = { "check_system_authority", "get_object", "get_object", "put_object" }; - subcalls[ "apply_set_system_contract_operation" ] = { "check_system_authority", "get_object", "get_object", "put_object" }; - subcalls[ "call" ] = { "get_object", "get_object" }; - subcalls[ "check_authority" ] = { "get_object", "recover_public_key", "recover_public_key", "recover_public_key" }; - subcalls[ "get_account_nonce" ] = { "get_object" }; - subcalls[ "verify_account_nonce" ] = { "get_account_nonce" }; - subcalls[ "set_account_nonce" ] = { "put_object" }; - subcalls[ "get_account_rc" ] = { "get_object" }; - subcalls[ "get_resource_limits" ] = { "get_object" }; - subcalls[ "check_system_authority" ] = { "get_object", "recover_public_key", "recover_public_key", "recover_public_key" }; - subcalls[ "verify_signature" ] = { "recover_public_key" }; - subcalls[ "get_chain_id" ] = { "get_object" }; - - std::cout << "std::map< std::string, uint64_t > thunk_compute {" << std::endl; - for ( const auto& [ key, value ] : calls ) - { + time -= + ( string_leafs.size() + 1 ) * calls[ "deserialize_multihash_per_byte" ] + calls[ "deserialize_multihash_base" ]; + time -= 21 * ( calls[ "sha2_256_base" ] + 2 * 32 * calls[ "sha2_256_per_byte" ] ); + calls[ "verify_merkle_root" ] = std::max( int64_t( 1 ), int64_t( ceil( time ) ) ); + } + + calls[ "deserialize_message_per_byte" ] = 1; + calls[ "object_serialization_per_byte" ] = 1; + + std::map< std::string, std::vector< std::string > > subcalls; + subcalls[ "process_block_signature" ] = { "get_object", "recover_public_key" }; + subcalls[ "apply_block" ] = { "get_resource_limits", + "pre_block_callback", + "verify_merkle_root", + "hash", + "process_block_signature", + "put_object", + "post_block_callback", + "consume_block_resources" }; + subcalls[ "apply_transaction" ] = { "get_object", + "verify_merkle_root", + "get_account_rc", + "pre_transaction_callback", + "check_authority", + "verify_account_nonce", + "set_account_nonce", + "post_transaction_callback", + "consume_account_rc" }; + subcalls[ "apply_upload_contract_operation" ] = { "check_authority", "hash", "put_object", "put_object" }; + subcalls[ "apply_call_contract_operation" ] = { "call" }; + subcalls[ "apply_set_system_call_operation" ] = { "check_system_authority", + "get_object", + "get_object", + "put_object" }; + subcalls[ "apply_set_system_contract_operation" ] = { "check_system_authority", + "get_object", + "get_object", + "put_object" }; + subcalls[ "call" ] = { "get_object", "get_object" }; + subcalls[ "check_authority" ] = { "get_object", "recover_public_key", "recover_public_key", "recover_public_key" }; + subcalls[ "get_account_nonce" ] = { "get_object" }; + subcalls[ "verify_account_nonce" ] = { "get_account_nonce" }; + subcalls[ "set_account_nonce" ] = { "put_object" }; + subcalls[ "get_account_rc" ] = { "get_object" }; + subcalls[ "get_resource_limits" ] = { "get_object" }; + subcalls[ "check_system_authority" ] = { "get_object", + "recover_public_key", + "recover_public_key", + "recover_public_key" }; + subcalls[ "verify_signature" ] = { "recover_public_key" }; + subcalls[ "get_chain_id" ] = { "get_object" }; + + std::cout << "std::map< std::string, uint64_t > thunk_compute {" << std::endl; + for( const auto& [ key, value ]: calls ) + { auto time = value; auto iter = subcalls.find( key ); - if ( iter != subcalls.end() ) + if( iter != subcalls.end() ) { - auto subs = iter->second; - for ( const auto& element: subs ) - { - auto siter = calls.find( element ); - KOINOS_ASSERT( siter != calls.end(), koinos::exception, "unable to find call timing for ${name}", ("name", element) ); - if ( siter->second > time ) - time = 1; - else - time -= siter->second; - } + auto subs = iter->second; + for( const auto& element: subs ) + { + auto siter = calls.find( element ); + KOINOS_ASSERT( siter != calls.end(), + koinos::exception, + "unable to find call timing for ${name}", + ( "name", element ) ); + if( siter->second > time ) + time = 1; + else + time -= siter->second; + } } uint64_t compute = uint64_t( time * compute_per_nanosecond ); - compute = compute ? compute : 1; + compute = compute ? compute : 1; std::cout << " { \"" << key << "\", " << compute << " }," << std::endl; - } - std::cout << "};" << std::endl; -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + } + std::cout << "};" << std::endl; + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( null_bytes_written_test ) -{ try { - BOOST_TEST_MESSAGE( "Upload the contract" ); - - auto contract_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); - auto contract_address = contract_private_key.get_public_key().to_address_bytes(); - koinos::protocol::transaction trx; - sign_transaction( trx, contract_private_key ); - ctx.set_transaction( trx ); - - koinos::protocol::upload_contract_operation op; - op.set_contract_id( util::converter::as< std::string >( contract_address ) ); - op.set_bytecode( get_null_bytes_written_wasm() ); - - koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); - - auto bytecode_object = koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_bytecode(), op.contract_id() ); - auto meta = util::converter::to< koinos::chain::contract_metadata_object >( koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_metadata(), op.contract_id() ).value() ); - - BOOST_REQUIRE( bytecode_object.exists() ); - BOOST_REQUIRE( bytecode_object.value().size() == op.bytecode().size() ); - BOOST_REQUIRE( std::memcmp( bytecode_object.value().c_str(), op.bytecode().c_str(), op.bytecode().size() ) == 0 ); - BOOST_REQUIRE( meta.hash() == util::converter::as< std::string >( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, bytecode_object.value() ) ) ); - - BOOST_TEST_MESSAGE( "Test executing a contract" ); - - koinos::protocol::call_contract_operation op2; - op2.set_contract_id( op.contract_id() ); - BOOST_CHECK_THROW( koinos::chain::system_call::apply_call_contract_operation( ctx, op2 ), koinos::vm_manager::fizzy::wasm_memory_exception ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + BOOST_TEST_MESSAGE( "Upload the contract" ); + + auto contract_private_key = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); + auto contract_address = contract_private_key.get_public_key().to_address_bytes(); + koinos::protocol::transaction trx; + sign_transaction( trx, contract_private_key ); + ctx.set_transaction( trx ); + + koinos::protocol::upload_contract_operation op; + op.set_contract_id( util::converter::as< std::string >( contract_address ) ); + op.set_bytecode( get_null_bytes_written_wasm() ); + + koinos::chain::system_call::apply_upload_contract_operation( ctx, op ); + + auto bytecode_object = + koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_bytecode(), op.contract_id() ); + auto meta = util::converter::to< koinos::chain::contract_metadata_object >( + koinos::chain::system_call::get_object( ctx, koinos::chain::state::space::contract_metadata(), op.contract_id() ) + .value() ); + + BOOST_REQUIRE( bytecode_object.exists() ); + BOOST_REQUIRE( bytecode_object.value().size() == op.bytecode().size() ); + BOOST_REQUIRE( std::memcmp( bytecode_object.value().c_str(), op.bytecode().c_str(), op.bytecode().size() ) == 0 ); + BOOST_REQUIRE( meta.hash() + == util::converter::as< std::string >( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, bytecode_object.value() ) ) ); + + BOOST_TEST_MESSAGE( "Test executing a contract" ); + + koinos::protocol::call_contract_operation op2; + op2.set_contract_id( op.contract_id() ); + BOOST_CHECK_THROW( koinos::chain::system_call::apply_call_contract_operation( ctx, op2 ), + koinos::vm_manager::fizzy::wasm_memory_exception ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_SUITE_END() From 33a7f2a8522d9482ddaae975f9551d1025bcf77f Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Mon, 4 Mar 2024 12:51:58 +0100 Subject: [PATCH 03/25] Fix static analysis uninitialized variable --- src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp b/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp index d9ee5dd5..128e608b 100644 --- a/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp +++ b/src/koinos/vm_manager/fizzy/fizzy_vm_backend.cpp @@ -103,7 +103,7 @@ class fizzy_runner module_ptr _module = nullptr; FizzyInstance* _instance = nullptr; FizzyExecutionContext* _fizzy_context = nullptr; - int64_t _previous_ticks; + int64_t _previous_ticks = 0; std::exception_ptr _exception; }; From 65eaf6a9d449b17f31e63dc43ad2180fc3580123 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Mon, 4 Mar 2024 12:57:26 +0100 Subject: [PATCH 04/25] Format controller_tests --- tests/controller_test.cpp | 2489 +++++++++++++++++++------------------ 1 file changed, 1303 insertions(+), 1186 deletions(-) diff --git a/tests/controller_test.cpp b/tests/controller_test.cpp index 3ad4be5a..2abeb467 100644 --- a/tests/controller_test.cpp +++ b/tests/controller_test.cpp @@ -9,10 +9,10 @@ #include #include #include -#include #include -#include +#include #include +#include #include #include @@ -30,375 +30,411 @@ using namespace std::string_literals; struct controller_fixture { - controller_fixture() : _controller( 10'000'000, 64'000 ) - { - initialize_logging( "koinos_test", {}, "info" ); - - auto seed = "test seed"s; - _block_signing_private_key = crypto::private_key::regenerate( crypto::hash( koinos::crypto::multicodec::sha2_256, seed.c_str(), seed.size() ) ); - - _state_dir = std::filesystem::temp_directory_path() / boost::filesystem::unique_path().string(); - LOG(info) << "Test temp dir: " << _state_dir.string(); - std::filesystem::create_directory( _state_dir ); - - auto entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::genesis_key ); - entry->set_value( _block_signing_private_key.get_public_key().to_address_bytes() ); - *entry->mutable_space() = chain::state::space::metadata(); - - koinos::chain::resource_limit_data rd; - - rd.set_disk_storage_cost( 10 ); - rd.set_disk_storage_limit( 409'600 ); - - rd.set_network_bandwidth_cost( 5 ); - rd.set_network_bandwidth_limit( 1'048'576 ); - - rd.set_compute_bandwidth_cost( 1 ); - rd.set_compute_bandwidth_limit( 100'000'000 ); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::resource_limit_data ); - entry->set_value( util::converter::as< std::string >( rd ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - koinos::chain::max_account_resources mar; - - mar.set_value( 10'000'000 ); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::max_account_resources ); - entry->set_value( util::converter::as< std::string >( mar ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::protocol_descriptor ); - - // protoc --experimental_allow_proto3_optional --descriptor_set_out=build/koinos_protocol.pb --include_imports `find koinos -name 'protocol.proto'` - std::string protocol_descriptor = util::from_hex< std::string >( "0x0ac33b0a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f120f676f6f676c652e70726f746f627566224d0a1146696c6544657363726970746f7253657412380a0466696c6518012003280b32242e676f6f676c652e70726f746f6275662e46696c6544657363726970746f7250726f746f520466696c6522e4040a1346696c6544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512180a077061636b61676518022001280952077061636b616765121e0a0a646570656e64656e6379180320032809520a646570656e64656e6379122b0a117075626c69635f646570656e64656e6379180a2003280552107075626c6963446570656e64656e637912270a0f7765616b5f646570656e64656e6379180b20032805520e7765616b446570656e64656e637912430a0c6d6573736167655f7479706518042003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520b6d6573736167655479706512410a09656e756d5f7479706518052003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512410a077365727669636518062003280b32272e676f6f676c652e70726f746f6275662e5365727669636544657363726970746f7250726f746f52077365727669636512430a09657874656e73696f6e18072003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12360a076f7074696f6e7318082001280b321c2e676f6f676c652e70726f746f6275662e46696c654f7074696f6e7352076f7074696f6e7312490a10736f757263655f636f64655f696e666f18092001280b321f2e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f520e736f75726365436f6465496e666f12160a0673796e746178180c20012809520673796e74617822b9060a0f44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123b0a056669656c6418022003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f52056669656c6412430a09657874656e73696f6e18062003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12410a0b6e65737465645f7479706518032003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520a6e65737465645479706512410a09656e756d5f7479706518042003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512580a0f657874656e73696f6e5f72616e676518052003280b322f2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e457874656e73696f6e52616e6765520e657874656e73696f6e52616e676512440a0a6f6e656f665f6465636c18082003280b32252e676f6f676c652e70726f746f6275662e4f6e656f6644657363726970746f7250726f746f52096f6e656f664465636c12390a076f7074696f6e7318072001280b321f2e676f6f676c652e70726f746f6275662e4d6573736167654f7074696f6e7352076f7074696f6e7312550a0e72657365727665645f72616e676518092003280b322e2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180a20032809520c72657365727665644e616d651a7a0a0e457874656e73696f6e52616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e6412400a076f7074696f6e7318032001280b32262e676f6f676c652e70726f746f6275662e457874656e73696f6e52616e67654f7074696f6e7352076f7074696f6e731a370a0d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e64227c0a15457874656e73696f6e52616e67654f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c1060a144669656c6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218032001280552066e756d62657212410a056c6162656c18042001280e322b2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e4c6162656c52056c6162656c123e0a047479706518052001280e322a2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e54797065520474797065121b0a09747970655f6e616d651806200128095208747970654e616d65121a0a08657874656e6465651802200128095208657874656e64656512230a0d64656661756c745f76616c7565180720012809520c64656661756c7456616c7565121f0a0b6f6e656f665f696e646578180920012805520a6f6e656f66496e646578121b0a096a736f6e5f6e616d65180a2001280952086a736f6e4e616d6512370a076f7074696f6e7318082001280b321d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7352076f7074696f6e7312270a0f70726f746f335f6f7074696f6e616c181120012808520e70726f746f334f7074696f6e616c22b6020a0454797065120f0a0b545950455f444f55424c451001120e0a0a545950455f464c4f41541002120e0a0a545950455f494e5436341003120f0a0b545950455f55494e5436341004120e0a0a545950455f494e543332100512100a0c545950455f46495845443634100612100a0c545950455f464958454433321007120d0a09545950455f424f4f4c1008120f0a0b545950455f535452494e471009120e0a0a545950455f47524f5550100a12100a0c545950455f4d455353414745100b120e0a0a545950455f4259544553100c120f0a0b545950455f55494e543332100d120d0a09545950455f454e554d100e12110a0d545950455f5346495845443332100f12110a0d545950455f53464958454436341010120f0a0b545950455f53494e5433321011120f0a0b545950455f53494e543634101222430a054c6162656c12120a0e4c4142454c5f4f5054494f4e414c100112120a0e4c4142454c5f5245515549524544100212120a0e4c4142454c5f5245504541544544100322630a144f6e656f6644657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512370a076f7074696f6e7318022001280b321d2e676f6f676c652e70726f746f6275662e4f6e656f664f7074696f6e7352076f7074696f6e7322e3020a13456e756d44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123f0a0576616c756518022003280b32292e676f6f676c652e70726f746f6275662e456e756d56616c756544657363726970746f7250726f746f520576616c756512360a076f7074696f6e7318032001280b321c2e676f6f676c652e70726f746f6275662e456e756d4f7074696f6e7352076f7074696f6e73125d0a0e72657365727665645f72616e676518042003280b32362e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f2e456e756d526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180520032809520c72657365727665644e616d651a3b0a11456e756d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e642283010a18456e756d56616c756544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218022001280552066e756d626572123b0a076f7074696f6e7318032001280b32212e676f6f676c652e70726f746f6275662e456e756d56616c75654f7074696f6e7352076f7074696f6e7322a7010a165365727669636544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123e0a066d6574686f6418022003280b32262e676f6f676c652e70726f746f6275662e4d6574686f6444657363726970746f7250726f746f52066d6574686f6412390a076f7074696f6e7318032001280b321f2e676f6f676c652e70726f746f6275662e536572766963654f7074696f6e7352076f7074696f6e732289020a154d6574686f6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65121d0a0a696e7075745f747970651802200128095209696e70757454797065121f0a0b6f75747075745f74797065180320012809520a6f75747075745479706512380a076f7074696f6e7318042001280b321e2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e7352076f7074696f6e7312300a10636c69656e745f73747265616d696e671805200128083a0566616c7365520f636c69656e7453747265616d696e6712300a107365727665725f73747265616d696e671806200128083a0566616c7365520f73657276657253747265616d696e672291090a0b46696c654f7074696f6e7312210a0c6a6176615f7061636b616765180120012809520b6a6176615061636b61676512300a146a6176615f6f757465725f636c6173736e616d6518082001280952126a6176614f75746572436c6173736e616d6512350a136a6176615f6d756c7469706c655f66696c6573180a200128083a0566616c736552116a6176614d756c7469706c6546696c657312440a1d6a6176615f67656e65726174655f657175616c735f616e645f686173681814200128084202180152196a61766147656e6572617465457175616c73416e6448617368123a0a166a6176615f737472696e675f636865636b5f75746638181b200128083a0566616c736552136a617661537472696e67436865636b5574663812530a0c6f7074696d697a655f666f7218092001280e32292e676f6f676c652e70726f746f6275662e46696c654f7074696f6e732e4f7074696d697a654d6f64653a055350454544520b6f7074696d697a65466f72121d0a0a676f5f7061636b616765180b200128095209676f5061636b61676512350a1363635f67656e657269635f73657276696365731810200128083a0566616c73655211636347656e65726963536572766963657312390a156a6176615f67656e657269635f73657276696365731811200128083a0566616c736552136a61766147656e65726963536572766963657312350a1370795f67656e657269635f73657276696365731812200128083a0566616c73655211707947656e65726963536572766963657312370a147068705f67656e657269635f7365727669636573182a200128083a0566616c7365521270687047656e65726963536572766963657312250a0a646570726563617465641817200128083a0566616c7365520a64657072656361746564122e0a1063635f656e61626c655f6172656e6173181f200128083a0474727565520e6363456e61626c654172656e6173122a0a116f626a635f636c6173735f707265666978182420012809520f6f626a63436c61737350726566697812290a106373686172705f6e616d657370616365182520012809520f6373686172704e616d65737061636512210a0c73776966745f707265666978182720012809520b737769667450726566697812280a107068705f636c6173735f707265666978182820012809520e706870436c61737350726566697812230a0d7068705f6e616d657370616365182920012809520c7068704e616d65737061636512340a167068705f6d657461646174615f6e616d657370616365182c2001280952147068704d657461646174614e616d65737061636512210a0c727562795f7061636b616765182d20012809520b727562795061636b61676512580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e223a0a0c4f7074696d697a654d6f646512090a0553504545441001120d0a09434f44455f53495a45100212100a0c4c4954455f52554e54494d4510032a0908e8071080808080024a040826102722e3020a0e4d6573736167654f7074696f6e73123c0a176d6573736167655f7365745f776972655f666f726d61741801200128083a0566616c736552146d65737361676553657457697265466f726d6174124c0a1f6e6f5f7374616e646172645f64657363726970746f725f6163636573736f721802200128083a0566616c7365521c6e6f5374616e6461726444657363726970746f724163636573736f7212250a0a646570726563617465641803200128083a0566616c7365520a64657072656361746564121b0a096d61705f656e74727918072001280852086d6170456e74727912580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a04080410054a04080510064a04080610074a04080810094a040809100a22e2030a0c4669656c644f7074696f6e7312410a05637479706518012001280e32232e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e43547970653a06535452494e475205637479706512160a067061636b656418022001280852067061636b656412470a066a737479706518062001280e32242e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e4a53547970653a094a535f4e4f524d414c52066a737479706512190a046c617a791805200128083a0566616c736552046c617a7912250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412190a047765616b180a200128083a0566616c736552047765616b12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e222f0a054354797065120a0a06535452494e47100012080a04434f5244100112100a0c535452494e475f5049454345100222350a064a5354797065120d0a094a535f4e4f524d414c1000120d0a094a535f535452494e471001120d0a094a535f4e554d42455210022a0908e8071080808080024a040804100522730a0c4f6e656f664f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c0010a0b456e756d4f7074696f6e73121f0a0b616c6c6f775f616c696173180220012808520a616c6c6f77416c69617312250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a0408051006229e010a10456e756d56616c75654f7074696f6e7312250a0a646570726563617465641801200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e807108080808002229c010a0e536572766963654f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222e0020a0d4d6574686f644f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412710a116964656d706f74656e63795f6c6576656c18222001280e322f2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e732e4964656d706f74656e63794c6576656c3a134944454d504f54454e43595f554e4b4e4f574e52106964656d706f74656e63794c6576656c12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e22500a104964656d706f74656e63794c6576656c12170a134944454d504f54454e43595f554e4b4e4f574e100012130a0f4e4f5f534944455f454646454354531001120e0a0a4944454d504f54454e5410022a0908e807108080808002229a030a13556e696e7465727072657465644f7074696f6e12410a046e616d6518022003280b322d2e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e2e4e616d655061727452046e616d6512290a106964656e7469666965725f76616c7565180320012809520f6964656e74696669657256616c7565122c0a12706f7369746976655f696e745f76616c75651804200128045210706f736974697665496e7456616c7565122c0a126e656761746976655f696e745f76616c756518052001280352106e65676174697665496e7456616c756512210a0c646f75626c655f76616c7565180620012801520b646f75626c6556616c756512210a0c737472696e675f76616c756518072001280c520b737472696e6756616c756512270a0f6167677265676174655f76616c7565180820012809520e61676772656761746556616c75651a4a0a084e616d6550617274121b0a096e616d655f7061727418012002280952086e616d655061727412210a0c69735f657874656e73696f6e180220022808520b6973457874656e73696f6e22a7020a0e536f75726365436f6465496e666f12440a086c6f636174696f6e18012003280b32282e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f2e4c6f636174696f6e52086c6f636174696f6e1ace010a084c6f636174696f6e12160a04706174681801200328054202100152047061746812160a047370616e1802200328054202100152047370616e12290a106c656164696e675f636f6d6d656e7473180320012809520f6c656164696e67436f6d6d656e7473122b0a11747261696c696e675f636f6d6d656e74731804200128095210747261696c696e67436f6d6d656e7473123a0a196c656164696e675f64657461636865645f636f6d6d656e747318062003280952176c656164696e674465746163686564436f6d6d656e747322d1010a1147656e657261746564436f6465496e666f124d0a0a616e6e6f746174696f6e18012003280b322d2e676f6f676c652e70726f746f6275662e47656e657261746564436f6465496e666f2e416e6e6f746174696f6e520a616e6e6f746174696f6e1a6d0a0a416e6e6f746174696f6e12160a047061746818012003280542021001520470617468121f0a0b736f757263655f66696c65180220012809520a736f7572636546696c6512140a05626567696e1803200128055205626567696e12100a03656e641804200128055203656e64427e0a13636f6d2e676f6f676c652e70726f746f627566421044657363726970746f7250726f746f7348015a2d676f6f676c652e676f6c616e672e6f72672f70726f746f6275662f74797065732f64657363726970746f727062f80101a20203475042aa021a476f6f676c652e50726f746f6275662e5265666c656374696f6e0ab5020a146b6f696e6f732f6f7074696f6e732e70726f746f12066b6f696e6f731a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f2a6d0a0a62797465735f74797065120a0a064241534536341000120a0a06424153453538100112070a034845581002120c0a08424c4f434b5f4944100312120a0e5452414e53414354494f4e5f49441004120f0a0b434f4e54524143545f49441005120b0a074144445245535310063a4c0a056274797065121d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7318d086032001280e32122e6b6f696e6f732e62797465735f7479706552056274797065880101422e5a2c6769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f73620670726f746f330aa8190a1e6b6f696e6f732f70726f746f636f6c2f70726f746f636f6c2e70726f746f120f6b6f696e6f732e70726f746f636f6c1a146b6f696e6f732f6f7074696f6e732e70726f746f2290010a0a6576656e745f64617461121a0a0873657175656e636518012001280d520873657175656e6365121c0a06736f7572636518022001280c420480b518055206736f7572636512120a046e616d6518032001280952046e616d6512120a046461746118042001280c52046461746112200a08696d70616374656418052003280c420480b518065208696d706163746564225e0a14636f6e74726163745f63616c6c5f62756e646c6512250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e742292010a1273797374656d5f63616c6c5f746172676574121b0a087468756e6b5f696418012001280d480052077468756e6b496412550a1273797374656d5f63616c6c5f62756e646c6518022001280b32252e6b6f696e6f732e70726f746f636f6c2e636f6e74726163745f63616c6c5f62756e646c654800521073797374656d43616c6c42756e646c6542080a067461726765742294020a1975706c6f61645f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121a0a0862797465636f646518022001280c520862797465636f646512100a03616269180320012809520361626912380a18617574686f72697a65735f63616c6c5f636f6e74726163741804200128085216617574686f72697a657343616c6c436f6e7472616374122a0a11617574686f72697a65735f7573655f7263180520012808520f617574686f72697a65735573655263123c0a1a617574686f72697a65735f75706c6f61645f636f6e74726163741806200128085218617574686f72697a657355706c6f6164436f6e747261637422750a1763616c6c5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e7412120a046172677318032001280c52046172677322710a197365745f73797374656d5f63616c6c5f6f7065726174696f6e12170a0763616c6c5f696418012001280d520663616c6c4964123b0a0674617267657418022001280b32232e6b6f696e6f732e70726f746f636f6c2e73797374656d5f63616c6c5f7461726765745206746172676574226f0a1d7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e7472616374496412270a0f73797374656d5f636f6e7472616374180220012808520e73797374656d436f6e747261637422f1020a096f7065726174696f6e12550a0f75706c6f61645f636f6e747261637418012001280b322a2e6b6f696e6f732e70726f746f636f6c2e75706c6f61645f636f6e74726163745f6f7065726174696f6e4800520e75706c6f6164436f6e7472616374124f0a0d63616c6c5f636f6e747261637418022001280b32282e6b6f696e6f732e70726f746f636f6c2e63616c6c5f636f6e74726163745f6f7065726174696f6e4800520c63616c6c436f6e747261637412540a0f7365745f73797374656d5f63616c6c18032001280b322a2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f63616c6c5f6f7065726174696f6e4800520d73657453797374656d43616c6c12600a137365745f73797374656d5f636f6e747261637418042001280b322e2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e4800521173657453797374656d436f6e747261637442040a026f7022d0010a127472616e73616374696f6e5f68656164657212190a08636861696e5f696418012001280c5207636861696e4964121d0a0872635f6c696d697418022001280442023001520772634c696d697412140a056e6f6e636518032001280c52056e6f6e636512320a156f7065726174696f6e5f6d65726b6c655f726f6f7418042001280c52136f7065726174696f6e4d65726b6c65526f6f74121a0a05706179657218052001280c420480b5180652057061796572121a0a05706179656518062001280c420480b518065205706179656522bc010a0b7472616e73616374696f6e12140a02696418012001280c420480b5180452026964123b0a0668656164657218022001280b32232e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f6865616465725206686561646572123a0a0a6f7065726174696f6e7318032003280b321a2e6b6f696e6f732e70726f746f636f6c2e6f7065726174696f6e520a6f7065726174696f6e73121e0a0a7369676e61747572657318042003280c520a7369676e61747572657322b2030a137472616e73616374696f6e5f7265636569707412140a02696418012001280c420480b5180452026964121a0a05706179657218022001280c420480b518065205706179657212240a0c6d61785f70617965725f726318032001280442023001520a6d617850617965725263121d0a0872635f6c696d697418042001280442023001520772634c696d6974121b0a0772635f75736564180520012804420230015206726355736564122e0a116469736b5f73746f726167655f7573656418062001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641807200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180820012804420230015214636f6d7075746542616e64776964746855736564121a0a0872657665727465641809200128085208726576657274656412330a066576656e7473180a2003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312120a046c6f6773180b2003280952046c6f677322fb010a0c626c6f636b5f68656164657212200a0870726576696f757318012001280c420480b51803520870726576696f7573121a0a0668656967687418022001280442023001520668656967687412200a0974696d657374616d7018032001280442023001520974696d657374616d70123b0a1a70726576696f75735f73746174655f6d65726b6c655f726f6f7418042001280c521770726576696f757353746174654d65726b6c65526f6f7412360a177472616e73616374696f6e5f6d65726b6c655f726f6f7418052001280c52157472616e73616374696f6e4d65726b6c65526f6f7412160a067369676e657218062001280c52067369676e657222b4010a05626c6f636b12140a02696418012001280c420480b518035202696412350a0668656164657218022001280b321d2e6b6f696e6f732e70726f746f636f6c2e626c6f636b5f686561646572520668656164657212400a0c7472616e73616374696f6e7318032003280b321c2e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e520c7472616e73616374696f6e73121c0a097369676e617475726518042001280c52097369676e617475726522b3030a0d626c6f636b5f7265636569707412140a02696418012001280c420480b5180352026964121a0a06686569676874180220012804420230015206686569676874122e0a116469736b5f73746f726167655f7573656418032001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641804200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180520012804420230015214636f6d7075746542616e64776964746855736564122a0a1173746174655f6d65726b6c655f726f6f7418062001280c520f73746174654d65726b6c65526f6f7412330a066576656e747318072003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312570a147472616e73616374696f6e5f726563656970747318082003280b32242e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f7265636569707452137472616e73616374696f6e526563656970747312120a046c6f677318092003280952046c6f677342375a356769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f732f70726f746f636f6c620670726f746f33" ); - entry->set_value( protocol_descriptor ); - *entry->mutable_space() = chain::state::space::metadata(); - - koinos::chain::compute_bandwidth_registry cbr; - - for ( const auto& [ key, value ] : _thunk_compute ) - { - auto centry = cbr.add_entries(); - centry->set_name( key ); - centry->set_compute( value ); - } - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::compute_bandwidth_registry ); - entry->set_value( util::converter::as< std::string >( cbr ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - entry = _genesis_data.add_entries(); - entry->set_key( chain::state::key::block_hash_code ); - entry->set_value( util::converter::as< std::string >( unsigned_varint{ std::underlying_type_t< crypto::multicodec >( crypto::multicodec::sha2_256 ) } ) ); - *entry->mutable_space() = chain::state::space::metadata(); - - _alice_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); - _alice_address = _alice_private_key.get_public_key().to_address_bytes(); - - koinos::chain::object_space alice_space; - alice_space.set_system( false ); - alice_space.set_zone( _alice_address ); - alice_space.set_id( 0 ); - - entry = _genesis_data.add_entries(); - entry->set_key( _alice_address ); - entry->set_value( "alpha bravo charlie delta" ); - *entry->mutable_space() = alice_space; - - _controller.open( _state_dir, _genesis_data, chain::fork_resolution_algorithm::fifo, false ); - } - - virtual ~controller_fixture() - { - boost::log::core::get()->remove_all_sinks(); - std::filesystem::remove_all( _state_dir ); - } - - void set_block_merkle_roots( protocol::block& block, crypto::multicodec code, crypto::digest_size size = crypto::digest_size( 0 ) ) - { - std::vector< crypto::multihash > hashes; - hashes.reserve( block.transactions().size() * 2 ); - - for ( const auto& trx : block.transactions() ) - { - hashes.emplace_back( crypto::hash( code, trx.header(), size ) ); - hashes.emplace_back( crypto::hash( code, trx.signatures(), size ) ); - } - - auto transaction_merkle_tree = crypto::merkle_tree( code, hashes ); - block.mutable_header()->set_transaction_merkle_root( util::converter::as< std::string >( transaction_merkle_tree.root()->hash() ) ); - } - - void sign_block( protocol::block& block, crypto::private_key& block_signing_key ) - { - auto id_mh = crypto::hash( crypto::multicodec::sha2_256, block.header() ); - block.set_signature( util::converter::as< std::string >( block_signing_key.sign_compact( id_mh ) ) ); - } - - void set_transaction_merkle_roots( protocol::transaction& transaction, crypto::multicodec code, crypto::digest_size size = crypto::digest_size( 0 ) ) - { - std::vector< crypto::multihash > operations; - operations.reserve( transaction.operations().size() ); - - for ( const auto& op : transaction.operations() ) - { - operations.emplace_back( crypto::hash( code, op, size ) ); - } - - auto operation_merkle_tree = crypto::merkle_tree( code, operations ); - transaction.mutable_header()->set_operation_merkle_root( util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); - } - - void add_signature( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ) - { - auto id_mh = util::converter::to< crypto::multihash >( transaction.id() ); - transaction.add_signatures( util::converter::as< std::string >( transaction_signing_key.sign_compact( id_mh ) ) ); - } - - void sign_transaction( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ) - { - transaction.mutable_header()->set_payer( transaction_signing_key.get_public_key().to_address_bytes() ); - auto id_mh = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); - transaction.set_id( util::converter::as< std::string >( id_mh ) ); - transaction.clear_signatures(); - transaction.add_signatures( util::converter::as< std::string >( transaction_signing_key.sign_compact( id_mh ) ) ); - } - - chain::controller _controller; - std::filesystem::path _state_dir; - crypto::private_key _block_signing_private_key; - chain::genesis_data _genesis_data; - crypto::private_key _alice_private_key; - std::string _alice_address; - - std::map< std::string, uint64_t > _thunk_compute { - { "apply_block", 16465 }, - { "apply_call_contract_operation", 685 }, - { "apply_set_system_call_operation", 136081 }, - { "apply_set_system_contract_operation", 8692 }, - { "apply_transaction", 12542 }, - { "apply_upload_contract_operation", 3130 }, - { "call", 3573 }, - { "check_authority", 12653 }, - { "check_system_authority", 12750 }, - { "consume_account_rc", 735 }, - { "consume_block_resources", 753 }, - { "deserialize_message_per_byte", 1 }, - { "deserialize_multihash_base", 102 }, - { "deserialize_multihash_per_byte", 404 }, - { "event", 1222 }, - { "event_per_impacted", 101 }, - { "exit", 11636 }, - { "get_account_nonce", 821 }, - { "get_account_rc", 1072 }, - { "get_arguments", 809 }, - { "get_block", 1134 }, - { "get_block_field", 1417 }, - { "get_caller", 825 }, - { "get_chain_id", 1046 }, - { "get_contract_id", 778 }, - { "get_head_info", 2099 }, - { "get_last_irreversible_block", 772 }, - { "get_next_object", 11181 }, - { "get_object", 1054 }, - { "get_operation", 1081 }, - { "get_prev_object", 15445 }, - { "get_resource_limits", 1227 }, - { "get_transaction", 1584 }, - { "get_transaction_field", 1530 }, - { "hash", 1570 }, - { "keccak_256_base", 1406 }, - { "keccak_256_per_byte", 1 }, - { "log", 738 }, - { "object_serialization_per_byte", 1 }, - { "post_block_callback", 741 }, - { "post_transaction_callback", 721 }, - { "pre_block_callback", 730 }, - { "pre_transaction_callback", 729 }, - { "process_block_signature", 4499 }, - { "put_object", 1057 }, - { "recover_public_key", 29630 }, - { "remove_object", 893 }, - { "ripemd_160_base", 1343 }, - { "ripemd_160_per_byte", 1 }, - { "set_account_nonce", 749 }, - { "sha1_base", 1151 }, - { "sha1_per_byte", 1 }, - { "sha2_256_base", 1385 }, - { "sha2_256_per_byte", 1 }, - { "sha2_512_base", 1445 }, - { "sha2_512_per_byte", 1 }, - { "verify_account_nonce", 822 }, - { "verify_merkle_root", 1 }, - { "verify_signature", 762 }, - { "verify_vrf_proof", 144067 }, - }; + controller_fixture(): + _controller( 10'000'000, 64'000 ) + { + initialize_logging( "koinos_test", {}, "info" ); + + auto seed = "test seed"s; + _block_signing_private_key = crypto::private_key::regenerate( + crypto::hash( koinos::crypto::multicodec::sha2_256, seed.c_str(), seed.size() ) ); + + _state_dir = std::filesystem::temp_directory_path() / boost::filesystem::unique_path().string(); + LOG( info ) << "Test temp dir: " << _state_dir.string(); + std::filesystem::create_directory( _state_dir ); + + auto entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::genesis_key ); + entry->set_value( _block_signing_private_key.get_public_key().to_address_bytes() ); + *entry->mutable_space() = chain::state::space::metadata(); + + koinos::chain::resource_limit_data rd; + + rd.set_disk_storage_cost( 10 ); + rd.set_disk_storage_limit( 409'600 ); + + rd.set_network_bandwidth_cost( 5 ); + rd.set_network_bandwidth_limit( 1'048'576 ); + + rd.set_compute_bandwidth_cost( 1 ); + rd.set_compute_bandwidth_limit( 100'000'000 ); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::resource_limit_data ); + entry->set_value( util::converter::as< std::string >( rd ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + koinos::chain::max_account_resources mar; + + mar.set_value( 10'000'000 ); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::max_account_resources ); + entry->set_value( util::converter::as< std::string >( mar ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::protocol_descriptor ); + + // protoc --experimental_allow_proto3_optional --descriptor_set_out=build/koinos_protocol.pb --include_imports `find + // koinos -name 'protocol.proto'` + std::string protocol_descriptor = util::from_hex< std::string >( + "0x0ac33b0a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f120f676f6f676c652e70726f746f627566224d0a1146696c6544657363726970746f7253657412380a0466696c6518012003280b32242e676f6f676c652e70726f746f6275662e46696c6544657363726970746f7250726f746f520466696c6522e4040a1346696c6544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512180a077061636b61676518022001280952077061636b616765121e0a0a646570656e64656e6379180320032809520a646570656e64656e6379122b0a117075626c69635f646570656e64656e6379180a2003280552107075626c6963446570656e64656e637912270a0f7765616b5f646570656e64656e6379180b20032805520e7765616b446570656e64656e637912430a0c6d6573736167655f7479706518042003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520b6d6573736167655479706512410a09656e756d5f7479706518052003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512410a077365727669636518062003280b32272e676f6f676c652e70726f746f6275662e5365727669636544657363726970746f7250726f746f52077365727669636512430a09657874656e73696f6e18072003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12360a076f7074696f6e7318082001280b321c2e676f6f676c652e70726f746f6275662e46696c654f7074696f6e7352076f7074696f6e7312490a10736f757263655f636f64655f696e666f18092001280b321f2e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f520e736f75726365436f6465496e666f12160a0673796e746178180c20012809520673796e74617822b9060a0f44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123b0a056669656c6418022003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f52056669656c6412430a09657874656e73696f6e18062003280b32252e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f5209657874656e73696f6e12410a0b6e65737465645f7479706518032003280b32202e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f520a6e65737465645479706512410a09656e756d5f7479706518042003280b32242e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f5208656e756d5479706512580a0f657874656e73696f6e5f72616e676518052003280b322f2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e457874656e73696f6e52616e6765520e657874656e73696f6e52616e676512440a0a6f6e656f665f6465636c18082003280b32252e676f6f676c652e70726f746f6275662e4f6e656f6644657363726970746f7250726f746f52096f6e656f664465636c12390a076f7074696f6e7318072001280b321f2e676f6f676c652e70726f746f6275662e4d6573736167654f7074696f6e7352076f7074696f6e7312550a0e72657365727665645f72616e676518092003280b322e2e676f6f676c652e70726f746f6275662e44657363726970746f7250726f746f2e526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180a20032809520c72657365727665644e616d651a7a0a0e457874656e73696f6e52616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e6412400a076f7074696f6e7318032001280b32262e676f6f676c652e70726f746f6275662e457874656e73696f6e52616e67654f7074696f6e7352076f7074696f6e731a370a0d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e64227c0a15457874656e73696f6e52616e67654f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c1060a144669656c6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218032001280552066e756d62657212410a056c6162656c18042001280e322b2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e4c6162656c52056c6162656c123e0a047479706518052001280e322a2e676f6f676c652e70726f746f6275662e4669656c6444657363726970746f7250726f746f2e54797065520474797065121b0a09747970655f6e616d651806200128095208747970654e616d65121a0a08657874656e6465651802200128095208657874656e64656512230a0d64656661756c745f76616c7565180720012809520c64656661756c7456616c7565121f0a0b6f6e656f665f696e646578180920012805520a6f6e656f66496e646578121b0a096a736f6e5f6e616d65180a2001280952086a736f6e4e616d6512370a076f7074696f6e7318082001280b321d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7352076f7074696f6e7312270a0f70726f746f335f6f7074696f6e616c181120012808520e70726f746f334f7074696f6e616c22b6020a0454797065120f0a0b545950455f444f55424c451001120e0a0a545950455f464c4f41541002120e0a0a545950455f494e5436341003120f0a0b545950455f55494e5436341004120e0a0a545950455f494e543332100512100a0c545950455f46495845443634100612100a0c545950455f464958454433321007120d0a09545950455f424f4f4c1008120f0a0b545950455f535452494e471009120e0a0a545950455f47524f5550100a12100a0c545950455f4d455353414745100b120e0a0a545950455f4259544553100c120f0a0b545950455f55494e543332100d120d0a09545950455f454e554d100e12110a0d545950455f5346495845443332100f12110a0d545950455f53464958454436341010120f0a0b545950455f53494e5433321011120f0a0b545950455f53494e543634101222430a054c6162656c12120a0e4c4142454c5f4f5054494f4e414c100112120a0e4c4142454c5f5245515549524544100212120a0e4c4142454c5f5245504541544544100322630a144f6e656f6644657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512370a076f7074696f6e7318022001280b321d2e676f6f676c652e70726f746f6275662e4f6e656f664f7074696f6e7352076f7074696f6e7322e3020a13456e756d44657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123f0a0576616c756518022003280b32292e676f6f676c652e70726f746f6275662e456e756d56616c756544657363726970746f7250726f746f520576616c756512360a076f7074696f6e7318032001280b321c2e676f6f676c652e70726f746f6275662e456e756d4f7074696f6e7352076f7074696f6e73125d0a0e72657365727665645f72616e676518042003280b32362e676f6f676c652e70726f746f6275662e456e756d44657363726970746f7250726f746f2e456e756d526573657276656452616e6765520d726573657276656452616e676512230a0d72657365727665645f6e616d65180520032809520c72657365727665644e616d651a3b0a11456e756d526573657276656452616e676512140a0573746172741801200128055205737461727412100a03656e641802200128055203656e642283010a18456e756d56616c756544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d6512160a066e756d62657218022001280552066e756d626572123b0a076f7074696f6e7318032001280b32212e676f6f676c652e70726f746f6275662e456e756d56616c75654f7074696f6e7352076f7074696f6e7322a7010a165365727669636544657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65123e0a066d6574686f6418022003280b32262e676f6f676c652e70726f746f6275662e4d6574686f6444657363726970746f7250726f746f52066d6574686f6412390a076f7074696f6e7318032001280b321f2e676f6f676c652e70726f746f6275662e536572766963654f7074696f6e7352076f7074696f6e732289020a154d6574686f6444657363726970746f7250726f746f12120a046e616d6518012001280952046e616d65121d0a0a696e7075745f747970651802200128095209696e70757454797065121f0a0b6f75747075745f74797065180320012809520a6f75747075745479706512380a076f7074696f6e7318042001280b321e2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e7352076f7074696f6e7312300a10636c69656e745f73747265616d696e671805200128083a0566616c7365520f636c69656e7453747265616d696e6712300a107365727665725f73747265616d696e671806200128083a0566616c7365520f73657276657253747265616d696e672291090a0b46696c654f7074696f6e7312210a0c6a6176615f7061636b616765180120012809520b6a6176615061636b61676512300a146a6176615f6f757465725f636c6173736e616d6518082001280952126a6176614f75746572436c6173736e616d6512350a136a6176615f6d756c7469706c655f66696c6573180a200128083a0566616c736552116a6176614d756c7469706c6546696c657312440a1d6a6176615f67656e65726174655f657175616c735f616e645f686173681814200128084202180152196a61766147656e6572617465457175616c73416e6448617368123a0a166a6176615f737472696e675f636865636b5f75746638181b200128083a0566616c736552136a617661537472696e67436865636b5574663812530a0c6f7074696d697a655f666f7218092001280e32292e676f6f676c652e70726f746f6275662e46696c654f7074696f6e732e4f7074696d697a654d6f64653a055350454544520b6f7074696d697a65466f72121d0a0a676f5f7061636b616765180b200128095209676f5061636b61676512350a1363635f67656e657269635f73657276696365731810200128083a0566616c73655211636347656e65726963536572766963657312390a156a6176615f67656e657269635f73657276696365731811200128083a0566616c736552136a61766147656e65726963536572766963657312350a1370795f67656e657269635f73657276696365731812200128083a0566616c73655211707947656e65726963536572766963657312370a147068705f67656e657269635f7365727669636573182a200128083a0566616c7365521270687047656e65726963536572766963657312250a0a646570726563617465641817200128083a0566616c7365520a64657072656361746564122e0a1063635f656e61626c655f6172656e6173181f200128083a0474727565520e6363456e61626c654172656e6173122a0a116f626a635f636c6173735f707265666978182420012809520f6f626a63436c61737350726566697812290a106373686172705f6e616d657370616365182520012809520f6373686172704e616d65737061636512210a0c73776966745f707265666978182720012809520b737769667450726566697812280a107068705f636c6173735f707265666978182820012809520e706870436c61737350726566697812230a0d7068705f6e616d657370616365182920012809520c7068704e616d65737061636512340a167068705f6d657461646174615f6e616d657370616365182c2001280952147068704d657461646174614e616d65737061636512210a0c727562795f7061636b616765182d20012809520b727562795061636b61676512580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e223a0a0c4f7074696d697a654d6f646512090a0553504545441001120d0a09434f44455f53495a45100212100a0c4c4954455f52554e54494d4510032a0908e8071080808080024a040826102722e3020a0e4d6573736167654f7074696f6e73123c0a176d6573736167655f7365745f776972655f666f726d61741801200128083a0566616c736552146d65737361676553657457697265466f726d6174124c0a1f6e6f5f7374616e646172645f64657363726970746f725f6163636573736f721802200128083a0566616c7365521c6e6f5374616e6461726444657363726970746f724163636573736f7212250a0a646570726563617465641803200128083a0566616c7365520a64657072656361746564121b0a096d61705f656e74727918072001280852086d6170456e74727912580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a04080410054a04080510064a04080610074a04080810094a040809100a22e2030a0c4669656c644f7074696f6e7312410a05637479706518012001280e32232e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e43547970653a06535452494e475205637479706512160a067061636b656418022001280852067061636b656412470a066a737479706518062001280e32242e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e732e4a53547970653a094a535f4e4f524d414c52066a737479706512190a046c617a791805200128083a0566616c736552046c617a7912250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412190a047765616b180a200128083a0566616c736552047765616b12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e222f0a054354797065120a0a06535452494e47100012080a04434f5244100112100a0c535452494e475f5049454345100222350a064a5354797065120d0a094a535f4e4f524d414c1000120d0a094a535f535452494e471001120d0a094a535f4e554d42455210022a0908e8071080808080024a040804100522730a0c4f6e656f664f7074696f6e7312580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222c0010a0b456e756d4f7074696f6e73121f0a0b616c6c6f775f616c696173180220012808520a616c6c6f77416c69617312250a0a646570726563617465641803200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e8071080808080024a0408051006229e010a10456e756d56616c75654f7074696f6e7312250a0a646570726563617465641801200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e807108080808002229c010a0e536572766963654f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e2a0908e80710808080800222e0020a0d4d6574686f644f7074696f6e7312250a0a646570726563617465641821200128083a0566616c7365520a6465707265636174656412710a116964656d706f74656e63795f6c6576656c18222001280e322f2e676f6f676c652e70726f746f6275662e4d6574686f644f7074696f6e732e4964656d706f74656e63794c6576656c3a134944454d504f54454e43595f554e4b4e4f574e52106964656d706f74656e63794c6576656c12580a14756e696e7465727072657465645f6f7074696f6e18e7072003280b32242e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e5213756e696e7465727072657465644f7074696f6e22500a104964656d706f74656e63794c6576656c12170a134944454d504f54454e43595f554e4b4e4f574e100012130a0f4e4f5f534944455f454646454354531001120e0a0a4944454d504f54454e5410022a0908e807108080808002229a030a13556e696e7465727072657465644f7074696f6e12410a046e616d6518022003280b322d2e676f6f676c652e70726f746f6275662e556e696e7465727072657465644f7074696f6e2e4e616d655061727452046e616d6512290a106964656e7469666965725f76616c7565180320012809520f6964656e74696669657256616c7565122c0a12706f7369746976655f696e745f76616c75651804200128045210706f736974697665496e7456616c7565122c0a126e656761746976655f696e745f76616c756518052001280352106e65676174697665496e7456616c756512210a0c646f75626c655f76616c7565180620012801520b646f75626c6556616c756512210a0c737472696e675f76616c756518072001280c520b737472696e6756616c756512270a0f6167677265676174655f76616c7565180820012809520e61676772656761746556616c75651a4a0a084e616d6550617274121b0a096e616d655f7061727418012002280952086e616d655061727412210a0c69735f657874656e73696f6e180220022808520b6973457874656e73696f6e22a7020a0e536f75726365436f6465496e666f12440a086c6f636174696f6e18012003280b32282e676f6f676c652e70726f746f6275662e536f75726365436f6465496e666f2e4c6f636174696f6e52086c6f636174696f6e1ace010a084c6f636174696f6e12160a04706174681801200328054202100152047061746812160a047370616e1802200328054202100152047370616e12290a106c656164696e675f636f6d6d656e7473180320012809520f6c656164696e67436f6d6d656e7473122b0a11747261696c696e675f636f6d6d656e74731804200128095210747261696c696e67436f6d6d656e7473123a0a196c656164696e675f64657461636865645f636f6d6d656e747318062003280952176c656164696e674465746163686564436f6d6d656e747322d1010a1147656e657261746564436f6465496e666f124d0a0a616e6e6f746174696f6e18012003280b322d2e676f6f676c652e70726f746f6275662e47656e657261746564436f6465496e666f2e416e6e6f746174696f6e520a616e6e6f746174696f6e1a6d0a0a416e6e6f746174696f6e12160a047061746818012003280542021001520470617468121f0a0b736f757263655f66696c65180220012809520a736f7572636546696c6512140a05626567696e1803200128055205626567696e12100a03656e641804200128055203656e64427e0a13636f6d2e676f6f676c652e70726f746f627566421044657363726970746f7250726f746f7348015a2d676f6f676c652e676f6c616e672e6f72672f70726f746f6275662f74797065732f64657363726970746f727062f80101a20203475042aa021a476f6f676c652e50726f746f6275662e5265666c656374696f6e0ab5020a146b6f696e6f732f6f7074696f6e732e70726f746f12066b6f696e6f731a20676f6f676c652f70726f746f6275662f64657363726970746f722e70726f746f2a6d0a0a62797465735f74797065120a0a064241534536341000120a0a06424153453538100112070a034845581002120c0a08424c4f434b5f4944100312120a0e5452414e53414354494f4e5f49441004120f0a0b434f4e54524143545f49441005120b0a074144445245535310063a4c0a056274797065121d2e676f6f676c652e70726f746f6275662e4669656c644f7074696f6e7318d086032001280e32122e6b6f696e6f732e62797465735f7479706552056274797065880101422e5a2c6769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f73620670726f746f330aa8190a1e6b6f696e6f732f70726f746f636f6c2f70726f746f636f6c2e70726f746f120f6b6f696e6f732e70726f746f636f6c1a146b6f696e6f732f6f7074696f6e732e70726f746f2290010a0a6576656e745f64617461121a0a0873657175656e636518012001280d520873657175656e6365121c0a06736f7572636518022001280c420480b518055206736f7572636512120a046e616d6518032001280952046e616d6512120a046461746118042001280c52046461746112200a08696d70616374656418052003280c420480b518065208696d706163746564225e0a14636f6e74726163745f63616c6c5f62756e646c6512250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e742292010a1273797374656d5f63616c6c5f746172676574121b0a087468756e6b5f696418012001280d480052077468756e6b496412550a1273797374656d5f63616c6c5f62756e646c6518022001280b32252e6b6f696e6f732e70726f746f636f6c2e636f6e74726163745f63616c6c5f62756e646c654800521073797374656d43616c6c42756e646c6542080a067461726765742294020a1975706c6f61645f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121a0a0862797465636f646518022001280c520862797465636f646512100a03616269180320012809520361626912380a18617574686f72697a65735f63616c6c5f636f6e74726163741804200128085216617574686f72697a657343616c6c436f6e7472616374122a0a11617574686f72697a65735f7573655f7263180520012808520f617574686f72697a65735573655263123c0a1a617574686f72697a65735f75706c6f61645f636f6e74726163741806200128085218617574686f72697a657355706c6f6164436f6e747261637422750a1763616c6c5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e74726163744964121f0a0b656e7472795f706f696e7418022001280d520a656e747279506f696e7412120a046172677318032001280c52046172677322710a197365745f73797374656d5f63616c6c5f6f7065726174696f6e12170a0763616c6c5f696418012001280d520663616c6c4964123b0a0674617267657418022001280b32232e6b6f696e6f732e70726f746f636f6c2e73797374656d5f63616c6c5f7461726765745206746172676574226f0a1d7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e12250a0b636f6e74726163745f696418012001280c420480b51805520a636f6e7472616374496412270a0f73797374656d5f636f6e7472616374180220012808520e73797374656d436f6e747261637422f1020a096f7065726174696f6e12550a0f75706c6f61645f636f6e747261637418012001280b322a2e6b6f696e6f732e70726f746f636f6c2e75706c6f61645f636f6e74726163745f6f7065726174696f6e4800520e75706c6f6164436f6e7472616374124f0a0d63616c6c5f636f6e747261637418022001280b32282e6b6f696e6f732e70726f746f636f6c2e63616c6c5f636f6e74726163745f6f7065726174696f6e4800520c63616c6c436f6e747261637412540a0f7365745f73797374656d5f63616c6c18032001280b322a2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f63616c6c5f6f7065726174696f6e4800520d73657453797374656d43616c6c12600a137365745f73797374656d5f636f6e747261637418042001280b322e2e6b6f696e6f732e70726f746f636f6c2e7365745f73797374656d5f636f6e74726163745f6f7065726174696f6e4800521173657453797374656d436f6e747261637442040a026f7022d0010a127472616e73616374696f6e5f68656164657212190a08636861696e5f696418012001280c5207636861696e4964121d0a0872635f6c696d697418022001280442023001520772634c696d697412140a056e6f6e636518032001280c52056e6f6e636512320a156f7065726174696f6e5f6d65726b6c655f726f6f7418042001280c52136f7065726174696f6e4d65726b6c65526f6f74121a0a05706179657218052001280c420480b5180652057061796572121a0a05706179656518062001280c420480b518065205706179656522bc010a0b7472616e73616374696f6e12140a02696418012001280c420480b5180452026964123b0a0668656164657218022001280b32232e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f6865616465725206686561646572123a0a0a6f7065726174696f6e7318032003280b321a2e6b6f696e6f732e70726f746f636f6c2e6f7065726174696f6e520a6f7065726174696f6e73121e0a0a7369676e61747572657318042003280c520a7369676e61747572657322b2030a137472616e73616374696f6e5f7265636569707412140a02696418012001280c420480b5180452026964121a0a05706179657218022001280c420480b518065205706179657212240a0c6d61785f70617965725f726318032001280442023001520a6d617850617965725263121d0a0872635f6c696d697418042001280442023001520772634c696d6974121b0a0772635f75736564180520012804420230015206726355736564122e0a116469736b5f73746f726167655f7573656418062001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641807200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180820012804420230015214636f6d7075746542616e64776964746855736564121a0a0872657665727465641809200128085208726576657274656412330a066576656e7473180a2003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312120a046c6f6773180b2003280952046c6f677322fb010a0c626c6f636b5f68656164657212200a0870726576696f757318012001280c420480b51803520870726576696f7573121a0a0668656967687418022001280442023001520668656967687412200a0974696d657374616d7018032001280442023001520974696d657374616d70123b0a1a70726576696f75735f73746174655f6d65726b6c655f726f6f7418042001280c521770726576696f757353746174654d65726b6c65526f6f7412360a177472616e73616374696f6e5f6d65726b6c655f726f6f7418052001280c52157472616e73616374696f6e4d65726b6c65526f6f7412160a067369676e657218062001280c52067369676e657222b4010a05626c6f636b12140a02696418012001280c420480b518035202696412350a0668656164657218022001280b321d2e6b6f696e6f732e70726f746f636f6c2e626c6f636b5f686561646572520668656164657212400a0c7472616e73616374696f6e7318032003280b321c2e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e520c7472616e73616374696f6e73121c0a097369676e617475726518042001280c52097369676e617475726522b3030a0d626c6f636b5f7265636569707412140a02696418012001280c420480b5180352026964121a0a06686569676874180220012804420230015206686569676874122e0a116469736b5f73746f726167655f7573656418032001280442023001520f6469736b53746f726167655573656412380a166e6574776f726b5f62616e6477696474685f757365641804200128044202300152146e6574776f726b42616e6477696474685573656412380a16636f6d707574655f62616e6477696474685f75736564180520012804420230015214636f6d7075746542616e64776964746855736564122a0a1173746174655f6d65726b6c655f726f6f7418062001280c520f73746174654d65726b6c65526f6f7412330a066576656e747318072003280b321b2e6b6f696e6f732e70726f746f636f6c2e6576656e745f6461746152066576656e747312570a147472616e73616374696f6e5f726563656970747318082003280b32242e6b6f696e6f732e70726f746f636f6c2e7472616e73616374696f6e5f7265636569707452137472616e73616374696f6e526563656970747312120a046c6f677318092003280952046c6f677342375a356769746875622e636f6d2f6b6f696e6f732f6b6f696e6f732d70726f746f2d676f6c616e672f6b6f696e6f732f70726f746f636f6c620670726f746f33" ); + entry->set_value( protocol_descriptor ); + *entry->mutable_space() = chain::state::space::metadata(); + + koinos::chain::compute_bandwidth_registry cbr; + + for( const auto& [ key, value ]: _thunk_compute ) + { + auto centry = cbr.add_entries(); + centry->set_name( key ); + centry->set_compute( value ); + } + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::compute_bandwidth_registry ); + entry->set_value( util::converter::as< std::string >( cbr ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + entry = _genesis_data.add_entries(); + entry->set_key( chain::state::key::block_hash_code ); + entry->set_value( util::converter::as< std::string >( + unsigned_varint{ std::underlying_type_t< crypto::multicodec >( crypto::multicodec::sha2_256 ) } ) ); + *entry->mutable_space() = chain::state::space::metadata(); + + _alice_private_key = + koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); + _alice_address = _alice_private_key.get_public_key().to_address_bytes(); + + koinos::chain::object_space alice_space; + alice_space.set_system( false ); + alice_space.set_zone( _alice_address ); + alice_space.set_id( 0 ); + + entry = _genesis_data.add_entries(); + entry->set_key( _alice_address ); + entry->set_value( "alpha bravo charlie delta" ); + *entry->mutable_space() = alice_space; + + _controller.open( _state_dir, _genesis_data, chain::fork_resolution_algorithm::fifo, false ); + } + + virtual ~controller_fixture() + { + boost::log::core::get()->remove_all_sinks(); + std::filesystem::remove_all( _state_dir ); + } + + void set_block_merkle_roots( protocol::block& block, + crypto::multicodec code, + crypto::digest_size size = crypto::digest_size( 0 ) ) + { + std::vector< crypto::multihash > hashes; + hashes.reserve( block.transactions().size() * 2 ); + + for( const auto& trx: block.transactions() ) + { + hashes.emplace_back( crypto::hash( code, trx.header(), size ) ); + hashes.emplace_back( crypto::hash( code, trx.signatures(), size ) ); + } + + auto transaction_merkle_tree = crypto::merkle_tree( code, hashes ); + block.mutable_header()->set_transaction_merkle_root( + util::converter::as< std::string >( transaction_merkle_tree.root()->hash() ) ); + } + + void sign_block( protocol::block& block, crypto::private_key& block_signing_key ) + { + auto id_mh = crypto::hash( crypto::multicodec::sha2_256, block.header() ); + block.set_signature( util::converter::as< std::string >( block_signing_key.sign_compact( id_mh ) ) ); + } + + void set_transaction_merkle_roots( protocol::transaction& transaction, + crypto::multicodec code, + crypto::digest_size size = crypto::digest_size( 0 ) ) + { + std::vector< crypto::multihash > operations; + operations.reserve( transaction.operations().size() ); + + for( const auto& op: transaction.operations() ) + { + operations.emplace_back( crypto::hash( code, op, size ) ); + } + + auto operation_merkle_tree = crypto::merkle_tree( code, operations ); + transaction.mutable_header()->set_operation_merkle_root( + util::converter::as< std::string >( operation_merkle_tree.root()->hash() ) ); + } + + void add_signature( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ) + { + auto id_mh = util::converter::to< crypto::multihash >( transaction.id() ); + transaction.add_signatures( util::converter::as< std::string >( transaction_signing_key.sign_compact( id_mh ) ) ); + } + + void sign_transaction( protocol::transaction& transaction, crypto::private_key& transaction_signing_key ) + { + transaction.mutable_header()->set_payer( transaction_signing_key.get_public_key().to_address_bytes() ); + auto id_mh = crypto::hash( crypto::multicodec::sha2_256, transaction.header() ); + transaction.set_id( util::converter::as< std::string >( id_mh ) ); + transaction.clear_signatures(); + transaction.add_signatures( util::converter::as< std::string >( transaction_signing_key.sign_compact( id_mh ) ) ); + } + + chain::controller _controller; + std::filesystem::path _state_dir; + crypto::private_key _block_signing_private_key; + chain::genesis_data _genesis_data; + crypto::private_key _alice_private_key; + std::string _alice_address; + + std::map< std::string, uint64_t > _thunk_compute{ + { "apply_block", 16'465}, + { "apply_call_contract_operation", 685}, + { "apply_set_system_call_operation", 136'081}, + {"apply_set_system_contract_operation", 8'692}, + { "apply_transaction", 12'542}, + { "apply_upload_contract_operation", 3'130}, + { "call", 3'573}, + { "check_authority", 12'653}, + { "check_system_authority", 12'750}, + { "consume_account_rc", 735}, + { "consume_block_resources", 753}, + { "deserialize_message_per_byte", 1}, + { "deserialize_multihash_base", 102}, + { "deserialize_multihash_per_byte", 404}, + { "event", 1'222}, + { "event_per_impacted", 101}, + { "exit", 11'636}, + { "get_account_nonce", 821}, + { "get_account_rc", 1'072}, + { "get_arguments", 809}, + { "get_block", 1'134}, + { "get_block_field", 1'417}, + { "get_caller", 825}, + { "get_chain_id", 1'046}, + { "get_contract_id", 778}, + { "get_head_info", 2'099}, + { "get_last_irreversible_block", 772}, + { "get_next_object", 11'181}, + { "get_object", 1'054}, + { "get_operation", 1'081}, + { "get_prev_object", 15'445}, + { "get_resource_limits", 1'227}, + { "get_transaction", 1'584}, + { "get_transaction_field", 1'530}, + { "hash", 1'570}, + { "keccak_256_base", 1'406}, + { "keccak_256_per_byte", 1}, + { "log", 738}, + { "object_serialization_per_byte", 1}, + { "post_block_callback", 741}, + { "post_transaction_callback", 721}, + { "pre_block_callback", 730}, + { "pre_transaction_callback", 729}, + { "process_block_signature", 4'499}, + { "put_object", 1'057}, + { "recover_public_key", 29'630}, + { "remove_object", 893}, + { "ripemd_160_base", 1'343}, + { "ripemd_160_per_byte", 1}, + { "set_account_nonce", 749}, + { "sha1_base", 1'151}, + { "sha1_per_byte", 1}, + { "sha2_256_base", 1'385}, + { "sha2_256_per_byte", 1}, + { "sha2_512_base", 1'445}, + { "sha2_512_per_byte", 1}, + { "verify_account_nonce", 822}, + { "verify_merkle_root", 1}, + { "verify_signature", 762}, + { "verify_vrf_proof", 144'067}, + }; }; enum token_entry : uint32_t { - name = 0x82a3537f, - symbol = 0xb76a7ca1, - decimals = 0xee80fd2f, - total_supply = 0xb0da3934, - balance_of = 0x5c721497, - transfer = 0x27f576ca, - mint = 0xdc6f17bb + name = 0x82a3537f, + symbol = 0xb76a7ca1, + decimals = 0xee80fd2f, + total_supply = 0xb0da3934, + balance_of = 0x5c721497, + transfer = 0x27f576ca, + mint = 0xdc6f17bb }; BOOST_FIXTURE_TEST_SUITE( controller_tests, controller_fixture ) BOOST_AUTO_TEST_CASE( submission_tests ) -{ try { - using namespace koinos; +{ + try + { + using namespace koinos; - BOOST_TEST_MESSAGE( "Test submit transaction" ); + BOOST_TEST_MESSAGE( "Test submit transaction" ); - auto key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "foobar"s ) ); - rpc::chain::submit_transaction_request trx_req; + auto key = crypto::private_key::regenerate( crypto::hash( crypto::multicodec::sha2_256, "foobar"s ) ); + rpc::chain::submit_transaction_request trx_req; - BOOST_TEST_MESSAGE( "Test submit block" ); - BOOST_TEST_MESSAGE( "Error when first block does not have height of 1" ); + BOOST_TEST_MESSAGE( "Test submit block" ); + BOOST_TEST_MESSAGE( "Error when first block does not have height of 1" ); - rpc::chain::submit_block_request block_req; + rpc::chain::submit_block_request block_req; - auto duration = std::chrono::system_clock::now().time_since_epoch(); - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); - block_req.mutable_block()->mutable_header()->set_height( 2 ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - block_req.mutable_block()->mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + auto duration = std::chrono::system_clock::now().time_since_epoch(); + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); + block_req.mutable_block()->mutable_header()->set_height( 2 ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); + block_req.mutable_block()->mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - BOOST_CHECK_THROW( _controller.submit_block( block_req ), chain::unexpected_height_exception ); + BOOST_CHECK_THROW( _controller.submit_block( block_req ), chain::unexpected_height_exception ); - BOOST_TEST_MESSAGE( "Error when signature does not match" ); + BOOST_TEST_MESSAGE( "Error when signature does not match" ); - auto foo_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( crypto::multicodec::sha2_256, "foo"s ) ); + auto foo_key = + koinos::crypto::private_key::regenerate( koinos::crypto::hash( crypto::multicodec::sha2_256, "foo"s ) ); - block_req.mutable_block()->mutable_header()->set_signer( util::converter::as< std::string >( foo_key.get_public_key().to_address_bytes() ) ); - block_req.mutable_block()->mutable_header()->set_height( 1 ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + block_req.mutable_block()->mutable_header()->set_signer( + util::converter::as< std::string >( foo_key.get_public_key().to_address_bytes() ) ); + block_req.mutable_block()->mutable_header()->set_height( 1 ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), foo_key ); + sign_block( *block_req.mutable_block(), foo_key ); - KOINOS_CHECK_THROW( _controller.submit_block( block_req ), chain::invalid_signature ); + KOINOS_CHECK_THROW( _controller.submit_block( block_req ), chain::invalid_signature ); - BOOST_TEST_MESSAGE( "Error when previous block does not match" ); + BOOST_TEST_MESSAGE( "Error when previous block does not match" ); - block_req.mutable_block()->mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::empty( crypto::multicodec::sha2_256 ) ) ); + block_req.mutable_block()->mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::empty( crypto::multicodec::sha2_256 ) ) ); - set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - BOOST_CHECK_THROW( _controller.submit_block( block_req ), chain::unknown_previous_block_exception ); + BOOST_CHECK_THROW( _controller.submit_block( block_req ), chain::unknown_previous_block_exception ); - BOOST_TEST_MESSAGE( "Error when block timestamp is too far in the future" ); + BOOST_TEST_MESSAGE( "Error when block timestamp is too far in the future" ); - duration = ( std::chrono::system_clock::now() + std::chrono::minutes( 1 ) ).time_since_epoch(); - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); - block_req.mutable_block()->mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + duration = ( std::chrono::system_clock::now() + std::chrono::minutes( 1 ) ).time_since_epoch(); + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); + block_req.mutable_block()->mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - BOOST_CHECK_THROW( _controller.submit_block( block_req ), chain::timestamp_out_of_bounds_exception ); + BOOST_CHECK_THROW( _controller.submit_block( block_req ), chain::timestamp_out_of_bounds_exception ); - duration = std::chrono::system_clock::now().time_since_epoch(); - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); + duration = std::chrono::system_clock::now().time_since_epoch(); + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); - BOOST_TEST_MESSAGE( "Test successful block" ); + BOOST_TEST_MESSAGE( "Test successful block" ); - block_req.mutable_block()->mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + block_req.mutable_block()->mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - auto block_resp = _controller.submit_block( block_req ); + auto block_resp = _controller.submit_block( block_req ); - BOOST_CHECK_EQUAL( 1, block_resp.receipt().height() ); + BOOST_CHECK_EQUAL( 1, block_resp.receipt().height() ); - BOOST_TEST_MESSAGE( "Error when block is too old" ); + BOOST_TEST_MESSAGE( "Error when block is too old" ); - block_req.mutable_block()->mutable_header()->set_previous( block_req.block().id() ); - block_req.mutable_block()->mutable_header()->set_height( 2 ); - block_req.mutable_block()->mutable_header()->set_timestamp( block_req.block().header().timestamp() - 1 ); + block_req.mutable_block()->mutable_header()->set_previous( block_req.block().id() ); + block_req.mutable_block()->mutable_header()->set_height( 2 ); + block_req.mutable_block()->mutable_header()->set_timestamp( block_req.block().header().timestamp() - 1 ); - set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - BOOST_CHECK_THROW( _controller.submit_block( block_req ), chain::timestamp_out_of_bounds_exception ); + BOOST_CHECK_THROW( _controller.submit_block( block_req ), chain::timestamp_out_of_bounds_exception ); - BOOST_TEST_MESSAGE( "Test chain ID retrieval" ); + BOOST_TEST_MESSAGE( "Test chain ID retrieval" ); - BOOST_CHECK_EQUAL( - util::converter::to< crypto::multihash >( _controller.get_chain_id().chain_id() ), - koinos::crypto::hash( crypto::multicodec::sha2_256, _genesis_data ) - ); + BOOST_CHECK_EQUAL( util::converter::to< crypto::multihash >( _controller.get_chain_id().chain_id() ), + koinos::crypto::hash( crypto::multicodec::sha2_256, _genesis_data ) ); - BOOST_TEST_MESSAGE( "Test invalid transaction" ); + BOOST_TEST_MESSAGE( "Test invalid transaction" ); - block_req.mutable_block()->mutable_header()->set_previous( block_req.block().id() ); - block_req.mutable_block()->mutable_header()->set_height( 2 ); - block_req.mutable_block()->mutable_header()->set_timestamp( block_req.block().header().timestamp() + 2 ); + block_req.mutable_block()->mutable_header()->set_previous( block_req.block().id() ); + block_req.mutable_block()->mutable_header()->set_height( 2 ); + block_req.mutable_block()->mutable_header()->set_timestamp( block_req.block().header().timestamp() + 2 ); - auto trx = block_req.mutable_block()->add_transactions(); - chain::value_type nonce_value; - nonce_value.set_uint64_value( 2 ); - trx->mutable_header()->set_rc_limit( 10'000 ); - trx->mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - set_transaction_merkle_roots( *trx, crypto::multicodec::sha2_256 ); + auto trx = block_req.mutable_block()->add_transactions(); + chain::value_type nonce_value; + nonce_value.set_uint64_value( 2 ); + trx->mutable_header()->set_rc_limit( 10'000 ); + trx->mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( *trx, crypto::multicodec::sha2_256 ); - trx->set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, trx->header() ) ) ); + trx->set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, trx->header() ) ) ); - set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - try - { + try + { _controller.submit_block( block_req ); BOOST_REQUIRE( false ); - } - catch ( koinos::exception& e ) - { + } + catch( koinos::exception& e ) + { const auto& j = e.get_json(); BOOST_CHECK( j.find( "transaction_id" ) != j.end() ); - BOOST_CHECK_EQUAL( j["transaction_id"], util::to_hex( trx->id() ) ); - } - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_CHECK_EQUAL( j[ "transaction_id" ], util::to_hex( trx->id() ) ); + } + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( block_irreversibility ) -{ try { - - BOOST_TEST_MESSAGE( "Check block irreversibility" ); +{ + try + { + BOOST_TEST_MESSAGE( "Check block irreversibility" ); - rpc::chain::submit_block_request block_req; + rpc::chain::submit_block_request block_req; - auto head_info_res = _controller.get_head_info(); + auto head_info_res = _controller.get_head_info(); - auto start_time = std::chrono::system_clock::now().time_since_epoch(); - for ( uint64_t i = 1; i <= chain::default_irreversible_threshold; i++ ) - { - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( start_time + std::chrono::milliseconds{ i } ).count() ); + auto start_time = std::chrono::system_clock::now().time_since_epoch(); + for( uint64_t i = 1; i <= chain::default_irreversible_threshold; i++ ) + { + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( start_time + std::chrono::milliseconds{ i } ) + .count() ); block_req.mutable_block()->mutable_header()->set_height( head_info_res.head_topology().height() + 1 ); block_req.mutable_block()->mutable_header()->set_previous( head_info_res.head_topology().id() ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); sign_block( *block_req.mutable_block(), _block_signing_private_key ); _controller.submit_block( block_req ); @@ -406,18 +442,22 @@ BOOST_AUTO_TEST_CASE( block_irreversibility ) head_info_res = _controller.get_head_info(); BOOST_REQUIRE( head_info_res.last_irreversible_block() == 0 ); - } - - start_time = std::chrono::system_clock::now().time_since_epoch(); - for ( uint64_t i = chain::default_irreversible_threshold + 1; i <= chain::default_irreversible_threshold + 3; i++ ) - { - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( start_time + std::chrono::milliseconds{ i } ).count() ); + } + + start_time = std::chrono::system_clock::now().time_since_epoch(); + for( uint64_t i = chain::default_irreversible_threshold + 1; i <= chain::default_irreversible_threshold + 3; i++ ) + { + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( start_time + std::chrono::milliseconds{ i } ) + .count() ); block_req.mutable_block()->mutable_header()->set_height( head_info_res.head_topology().height() + 1 ); block_req.mutable_block()->mutable_header()->set_previous( head_info_res.head_topology().id() ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); sign_block( *block_req.mutable_block(), _block_signing_private_key ); _controller.submit_block( block_req ); @@ -425,85 +465,97 @@ BOOST_AUTO_TEST_CASE( block_irreversibility ) head_info_res = _controller.get_head_info(); BOOST_REQUIRE( head_info_res.last_irreversible_block() == i - chain::default_irreversible_threshold ); - } + } - BOOST_TEST_MESSAGE( "Check parent pre block irreversibility submission" ); + BOOST_TEST_MESSAGE( "Check parent pre block irreversibility submission" ); - head_info_res = _controller.get_head_info(); + head_info_res = _controller.get_head_info(); - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ).count() ); - block_req.mutable_block()->mutable_header()->set_height( head_info_res.last_irreversible_block() - 1 ); - block_req.mutable_block()->mutable_header()->set_previous( "a_random_unknown_id" ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ) + .count() ); + block_req.mutable_block()->mutable_header()->set_height( head_info_res.last_irreversible_block() - 1 ); + block_req.mutable_block()->mutable_header()->set_previous( "a_random_unknown_id" ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); - set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - BOOST_CHECK_THROW( _controller.submit_block( block_req ), koinos::chain::pre_irreversibility_block_exception ); + BOOST_CHECK_THROW( _controller.submit_block( block_req ), koinos::chain::pre_irreversibility_block_exception ); - BOOST_TEST_MESSAGE( "Check parent unknown block at LIB height" ); + BOOST_TEST_MESSAGE( "Check parent unknown block at LIB height" ); - block_req.mutable_block()->mutable_header()->set_height( head_info_res.last_irreversible_block() ); - block_req.mutable_block()->mutable_header()->set_previous( "a_random_unknown_id" ); - set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + block_req.mutable_block()->mutable_header()->set_height( head_info_res.last_irreversible_block() ); + block_req.mutable_block()->mutable_header()->set_previous( "a_random_unknown_id" ); + set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - BOOST_CHECK_THROW( _controller.submit_block( block_req ), koinos::chain::unknown_previous_block_exception ); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_CHECK_THROW( _controller.submit_block( block_req ), koinos::chain::unknown_previous_block_exception ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( fork_heads ) -{ try { - BOOST_TEST_MESSAGE( "Setting up forks and checking heads" ); +{ + try + { + BOOST_TEST_MESSAGE( "Setting up forks and checking heads" ); - rpc::chain::submit_block_request block_req; + rpc::chain::submit_block_request block_req; - uint64_t test_timestamp = 1609459200; + uint64_t test_timestamp = 1'609'459'200; - auto root_head_info = _controller.get_head_info(); - rpc::chain::get_head_info_response head_info; - head_info.CopyFrom( root_head_info ); + auto root_head_info = _controller.get_head_info(); + rpc::chain::get_head_info_response head_info; + head_info.CopyFrom( root_head_info ); - const std::string first_state_merkle_root = _controller.get_head_info().head_state_merkle_root(); - std::string last_state_merkle_root = first_state_merkle_root; - for ( uint64_t i = 1; i <= chain::default_irreversible_threshold; i++ ) - { + const std::string first_state_merkle_root = _controller.get_head_info().head_state_merkle_root(); + std::string last_state_merkle_root = first_state_merkle_root; + for( uint64_t i = 1; i <= chain::default_irreversible_threshold; i++ ) + { block_req.mutable_block()->mutable_header()->set_timestamp( test_timestamp + i ); block_req.mutable_block()->mutable_header()->set_height( head_info.head_topology().height() + 1 ); block_req.mutable_block()->mutable_header()->set_previous( head_info.head_topology().id() ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); sign_block( *block_req.mutable_block(), _block_signing_private_key ); - auto receipt = _controller.submit_block( block_req ).receipt(); + auto receipt = _controller.submit_block( block_req ).receipt(); last_state_merkle_root = receipt.state_merkle_root(); head_info.mutable_head_topology()->set_height( head_info.head_topology().height() + 1 ); head_info.mutable_head_topology()->set_previous( head_info.head_topology().id() ); head_info.mutable_head_topology()->set_id( block_req.block().id() ); - } + } - rpc::chain::get_head_info_response fork_head_info; - fork_head_info.CopyFrom( head_info ); - head_info.CopyFrom( root_head_info ); + rpc::chain::get_head_info_response fork_head_info; + fork_head_info.CopyFrom( head_info ); + head_info.CopyFrom( root_head_info ); - last_state_merkle_root = first_state_merkle_root; - for ( uint64_t i = 1; i <= chain::default_irreversible_threshold; i++ ) - { - block_req.mutable_block()->mutable_header()->set_timestamp( test_timestamp + i + chain::default_irreversible_threshold ); + last_state_merkle_root = first_state_merkle_root; + for( uint64_t i = 1; i <= chain::default_irreversible_threshold; i++ ) + { + block_req.mutable_block()->mutable_header()->set_timestamp( test_timestamp + i + + chain::default_irreversible_threshold ); block_req.mutable_block()->mutable_header()->set_height( head_info.head_topology().height() + 1 ); block_req.mutable_block()->mutable_header()->set_previous( head_info.head_topology().id() ); block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( last_state_merkle_root ); set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); sign_block( *block_req.mutable_block(), _block_signing_private_key ); - auto receipt = _controller.submit_block( block_req ).receipt(); + auto receipt = _controller.submit_block( block_req ).receipt(); last_state_merkle_root = receipt.state_merkle_root(); head_info.mutable_head_topology()->set_height( head_info.head_topology().height() + 1 ); @@ -516,963 +568,1028 @@ BOOST_AUTO_TEST_CASE( fork_heads ) auto topo0 = fork_heads.fork_heads( 0 ); auto topo1 = fork_heads.fork_heads( 1 ); - BOOST_CHECK( ( topo0.height() == fork_head_info.head_topology().height() - && topo0.previous() == fork_head_info.head_topology().previous() - && topo0.id() == fork_head_info.head_topology().id() - && topo1.height() == head_info.head_topology().height() - && topo1.previous() == head_info.head_topology().previous() - && topo1.id() == head_info.head_topology().id() ) - || ( topo1.height() == fork_head_info.head_topology().height() - && topo1.previous() == fork_head_info.head_topology().previous() - && topo1.id() == fork_head_info.head_topology().id() - && topo0.height() == head_info.head_topology().height() - && topo0.previous() == head_info.head_topology().previous() - && topo0.id() == head_info.head_topology().id() ) ); - } - - block_req.mutable_block()->mutable_header()->set_timestamp( test_timestamp + ( 2 * chain::default_irreversible_threshold ) + 1 ); - block_req.mutable_block()->mutable_header()->set_height( head_info.head_topology().height() + 1 ); - block_req.mutable_block()->mutable_header()->set_previous( head_info.head_topology().id() ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( last_state_merkle_root ); - - set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); - - _controller.submit_block( block_req ); - - head_info.mutable_head_topology()->set_height( head_info.head_topology().height() + 1 ); - head_info.mutable_head_topology()->set_previous( head_info.head_topology().id() ); - head_info.mutable_head_topology()->set_id( block_req.block().id() ); - - auto fork_heads = _controller.get_fork_heads(); - - BOOST_REQUIRE_EQUAL( fork_heads.fork_heads_size(), 1 ); - BOOST_CHECK_EQUAL( fork_heads.fork_heads( 0 ).height(), head_info.head_topology().height() ); - BOOST_CHECK_EQUAL( fork_heads.fork_heads( 0 ).previous(), head_info.head_topology().previous() ); - BOOST_CHECK_EQUAL( fork_heads.fork_heads( 0 ).id(), head_info.head_topology().id() ); - - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_CHECK( + ( topo0.height() == fork_head_info.head_topology().height() + && topo0.previous() == fork_head_info.head_topology().previous() + && topo0.id() == fork_head_info.head_topology().id() && topo1.height() == head_info.head_topology().height() + && topo1.previous() == head_info.head_topology().previous() && topo1.id() == head_info.head_topology().id() ) + || ( topo1.height() == fork_head_info.head_topology().height() + && topo1.previous() == fork_head_info.head_topology().previous() + && topo1.id() == fork_head_info.head_topology().id() + && topo0.height() == head_info.head_topology().height() + && topo0.previous() == head_info.head_topology().previous() + && topo0.id() == head_info.head_topology().id() ) ); + } + + block_req.mutable_block()->mutable_header()->set_timestamp( test_timestamp + + ( 2 * chain::default_irreversible_threshold ) + 1 ); + block_req.mutable_block()->mutable_header()->set_height( head_info.head_topology().height() + 1 ); + block_req.mutable_block()->mutable_header()->set_previous( head_info.head_topology().id() ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( last_state_merkle_root ); + + set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); + + _controller.submit_block( block_req ); + + head_info.mutable_head_topology()->set_height( head_info.head_topology().height() + 1 ); + head_info.mutable_head_topology()->set_previous( head_info.head_topology().id() ); + head_info.mutable_head_topology()->set_id( block_req.block().id() ); + + auto fork_heads = _controller.get_fork_heads(); + + BOOST_REQUIRE_EQUAL( fork_heads.fork_heads_size(), 1 ); + BOOST_CHECK_EQUAL( fork_heads.fork_heads( 0 ).height(), head_info.head_topology().height() ); + BOOST_CHECK_EQUAL( fork_heads.fork_heads( 0 ).previous(), head_info.head_topology().previous() ); + BOOST_CHECK_EQUAL( fork_heads.fork_heads( 0 ).id(), head_info.head_topology().id() ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( read_contract_tests ) -{ try { - BOOST_TEST_MESSAGE( "Upload contracts" ); - - auto key1 = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "foobar1"s ) ); - auto key2 = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "foobar2"s ) ); - auto key3 = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "foobar3"s ) ); - - koinos::protocol::transaction trx1; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - - auto op1 = trx1.add_operations()->mutable_upload_contract(); - op1->set_contract_id( util::converter::as< std::string >( key1.get_public_key().to_address_bytes() ) ); - op1->set_bytecode( get_hello_wasm() ); - trx1.mutable_header()->set_rc_limit( 10'000'000 ); - trx1.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx1.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx1, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx1, key1 ); - - // Upload the return test contract - koinos::protocol::transaction trx2; - - auto op2 = trx2.add_operations()->mutable_upload_contract(); - op2->set_contract_id( util::converter::as< std::string >( key2.get_public_key().to_address_bytes() ) ); - op2->set_bytecode( get_contract_return_wasm() ); - trx2.mutable_header()->set_rc_limit( 10'000'000 ); - trx2.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx2.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx2, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx2, key2 ); - - // Upload the db write contract - koinos::protocol::transaction trx3; - - auto op3 = trx3.add_operations()->mutable_upload_contract(); - op3->set_contract_id( util::converter::as< std::string >( key3.get_public_key().to_address_bytes() ) ); - op3->set_bytecode( get_db_write_wasm() ); - trx3.mutable_header()->set_rc_limit( 10'000'000 ); - trx3.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx3.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx3, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx3, key3 ); - - koinos::rpc::chain::submit_block_request block_req; - - auto duration = std::chrono::system_clock::now().time_since_epoch(); - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); - block_req.mutable_block()->mutable_header()->set_height( 1 ); - block_req.mutable_block()->mutable_header()->set_previous( util::converter::as< std::string >( koinos::crypto::multihash::zero( koinos::crypto::multicodec::sha2_256 ) ) ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - *block_req.mutable_block()->add_transactions() = trx1; - *block_req.mutable_block()->add_transactions() = trx2; - *block_req.mutable_block()->add_transactions() = trx3; - - set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); - - _controller.submit_block( block_req ); - - BOOST_TEST_MESSAGE( "Test read contract logs" ); - - koinos::rpc::chain::read_contract_request request; - request.set_contract_id( util::converter::as< std::string >( key1.get_public_key().to_address_bytes() ) ); - request.set_entry_point( 0 ); - - auto response = _controller.read_contract( request ); - - BOOST_REQUIRE( response.result().size() == 0 ); - BOOST_REQUIRE( response.logs( 0 ) == "Greetings from koinos vm" ); - - BOOST_TEST_MESSAGE( "Test read contract return" ); - - request.set_contract_id( util::converter::as< std::string >( key2.get_public_key().to_address_bytes() ) ); - request.set_args( "echo" ); - - response = _controller.read_contract( request ); - BOOST_REQUIRE_EQUAL( response.result(), "echo" ); - - BOOST_TEST_MESSAGE( "Test read contract db write" ); - - request.set_contract_id( util::converter::as< std::string >( key3.get_public_key().to_address_bytes() ) ); - KOINOS_REQUIRE_THROW( _controller.read_contract( request ), chain::read_only_context ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + BOOST_TEST_MESSAGE( "Upload contracts" ); + + auto key1 = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "foobar1"s ) ); + auto key2 = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "foobar2"s ) ); + auto key3 = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "foobar3"s ) ); + + koinos::protocol::transaction trx1; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + + auto op1 = trx1.add_operations()->mutable_upload_contract(); + op1->set_contract_id( util::converter::as< std::string >( key1.get_public_key().to_address_bytes() ) ); + op1->set_bytecode( get_hello_wasm() ); + trx1.mutable_header()->set_rc_limit( 10'000'000 ); + trx1.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx1.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx1, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx1, key1 ); + + // Upload the return test contract + koinos::protocol::transaction trx2; + + auto op2 = trx2.add_operations()->mutable_upload_contract(); + op2->set_contract_id( util::converter::as< std::string >( key2.get_public_key().to_address_bytes() ) ); + op2->set_bytecode( get_contract_return_wasm() ); + trx2.mutable_header()->set_rc_limit( 10'000'000 ); + trx2.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx2.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx2, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx2, key2 ); + + // Upload the db write contract + koinos::protocol::transaction trx3; + + auto op3 = trx3.add_operations()->mutable_upload_contract(); + op3->set_contract_id( util::converter::as< std::string >( key3.get_public_key().to_address_bytes() ) ); + op3->set_bytecode( get_db_write_wasm() ); + trx3.mutable_header()->set_rc_limit( 10'000'000 ); + trx3.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx3.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx3, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx3, key3 ); + + koinos::rpc::chain::submit_block_request block_req; + + auto duration = std::chrono::system_clock::now().time_since_epoch(); + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); + block_req.mutable_block()->mutable_header()->set_height( 1 ); + block_req.mutable_block()->mutable_header()->set_previous( + util::converter::as< std::string >( koinos::crypto::multihash::zero( koinos::crypto::multicodec::sha2_256 ) ) ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); + *block_req.mutable_block()->add_transactions() = trx1; + *block_req.mutable_block()->add_transactions() = trx2; + *block_req.mutable_block()->add_transactions() = trx3; + + set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); + + _controller.submit_block( block_req ); + + BOOST_TEST_MESSAGE( "Test read contract logs" ); + + koinos::rpc::chain::read_contract_request request; + request.set_contract_id( util::converter::as< std::string >( key1.get_public_key().to_address_bytes() ) ); + request.set_entry_point( 0 ); + + auto response = _controller.read_contract( request ); + + BOOST_REQUIRE( response.result().size() == 0 ); + BOOST_REQUIRE( response.logs( 0 ) == "Greetings from koinos vm" ); + + BOOST_TEST_MESSAGE( "Test read contract return" ); + + request.set_contract_id( util::converter::as< std::string >( key2.get_public_key().to_address_bytes() ) ); + request.set_args( "echo" ); + + response = _controller.read_contract( request ); + BOOST_REQUIRE_EQUAL( response.result(), "echo" ); + + BOOST_TEST_MESSAGE( "Test read contract db write" ); + + request.set_contract_id( util::converter::as< std::string >( key3.get_public_key().to_address_bytes() ) ); + KOINOS_REQUIRE_THROW( _controller.read_contract( request ), chain::read_only_context ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( transaction_reversion_test ) -{ try { - BOOST_TEST_MESSAGE( "Upload KOIN contract and attempt to mint to Alice" ); - - auto contract_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); - auto alice_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); - auto alice_address = alice_private_key.get_public_key().to_address_bytes(); - koinos::protocol::transaction trx1; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - - // Upload the KOIN contract - auto op1 = trx1.add_operations()->mutable_upload_contract(); - op1->set_contract_id( util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); - op1->set_bytecode( get_koin_wasm() ); - auto sys_op = trx1.add_operations()->mutable_set_system_contract(); - sys_op->set_contract_id( op1->contract_id() ); - sys_op->set_system_contract( true ); - trx1.mutable_header()->set_rc_limit( 10'000'000 ); - trx1.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx1.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx1, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx1, contract_private_key ); - add_signature( trx1, _block_signing_private_key ); - - koinos::protocol::transaction trx2; - - koinos::contracts::token::mint_arguments mint_arg; - mint_arg.set_to( alice_address ); - mint_arg.set_value( 100 ); - - auto op2 = trx2.add_operations()->mutable_call_contract(); - op2->set_contract_id( op1->contract_id() ); - op2->set_entry_point( token_entry::mint ); - op2->set_args( mint_arg.SerializeAsString() ); - trx2.mutable_header()->set_rc_limit( 10'000'000 ); - trx2.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx2.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx2, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx2, alice_private_key ); - - koinos::rpc::chain::submit_block_request block_req; - - auto duration = std::chrono::system_clock::now().time_since_epoch(); - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); - block_req.mutable_block()->mutable_header()->set_height( 1 ); - block_req.mutable_block()->mutable_header()->set_previous( util::converter::as< std::string >( koinos::crypto::multihash::zero( koinos::crypto::multicodec::sha2_256 ) ) ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - *block_req.mutable_block()->add_transactions() = trx1; - *block_req.mutable_block()->add_transactions() = trx2; - - set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); - - _controller.submit_block( block_req ); - - BOOST_TEST_MESSAGE( "Verify mint did nothing" ); - - koinos::contracts::token::balance_of_arguments bal_args; - bal_args.set_owner( alice_address ); - - koinos::rpc::chain::read_contract_request request; - request.set_contract_id( op1->contract_id() ); - request.set_entry_point( token_entry::balance_of ); - request.set_args( bal_args.SerializeAsString() ); - - auto response = _controller.read_contract( request ); - koinos::contracts::token::balance_of_result bal_ret; - bal_ret.ParseFromString( response.result() ); - - BOOST_REQUIRE_EQUAL( bal_ret.value(), 0 ); - - BOOST_TEST_MESSAGE( "Creating hello contract upload operation" ); - - koinos::protocol::transaction trx3; - - nonce_value.set_uint64_value( 2 ); - - // Upload the hello contract - auto op3 = trx3.add_operations()->mutable_upload_contract(); - op3->set_contract_id( util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); - op3->set_bytecode( get_hello_wasm() ); - trx3.mutable_header()->set_rc_limit( 10'000'000 ); - trx3.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx3.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx3, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx3, contract_private_key ); - - BOOST_TEST_MESSAGE( "Creating forever contract upload operation" ); - - auto forever_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "forever"s ) ); - - koinos::protocol::transaction trx4; - - nonce_value.set_uint64_value( 1 ); - - // Upload the hello contract - auto op4 = trx4.add_operations()->mutable_upload_contract(); - op4->set_contract_id( util::converter::as< std::string >( forever_private_key.get_public_key().to_address_bytes() ) ); - op4->set_bytecode( get_forever_wasm() ); - trx4.mutable_header()->set_rc_limit( 10'000'000 ); - trx4.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx4.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx4, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx4, forever_private_key ); - - BOOST_TEST_MESSAGE( "Creating operation that calls both contracts" ); - - koinos::protocol::transaction trx5; - - nonce_value.set_uint64_value( 2 ); - - auto op5 = trx5.add_operations()->mutable_call_contract(); - op5->set_contract_id( op3->contract_id() ); - op5->set_entry_point( 0x00 ); +{ + try + { + BOOST_TEST_MESSAGE( "Upload KOIN contract and attempt to mint to Alice" ); + + auto contract_private_key = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); + auto alice_private_key = + koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); + auto alice_address = alice_private_key.get_public_key().to_address_bytes(); + koinos::protocol::transaction trx1; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + + // Upload the KOIN contract + auto op1 = trx1.add_operations()->mutable_upload_contract(); + op1->set_contract_id( + util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); + op1->set_bytecode( get_koin_wasm() ); + auto sys_op = trx1.add_operations()->mutable_set_system_contract(); + sys_op->set_contract_id( op1->contract_id() ); + sys_op->set_system_contract( true ); + trx1.mutable_header()->set_rc_limit( 10'000'000 ); + trx1.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx1.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx1, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx1, contract_private_key ); + add_signature( trx1, _block_signing_private_key ); + + koinos::protocol::transaction trx2; + + koinos::contracts::token::mint_arguments mint_arg; + mint_arg.set_to( alice_address ); + mint_arg.set_value( 100 ); + + auto op2 = trx2.add_operations()->mutable_call_contract(); + op2->set_contract_id( op1->contract_id() ); + op2->set_entry_point( token_entry::mint ); + op2->set_args( mint_arg.SerializeAsString() ); + trx2.mutable_header()->set_rc_limit( 10'000'000 ); + trx2.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx2.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx2, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx2, alice_private_key ); + + koinos::rpc::chain::submit_block_request block_req; + + auto duration = std::chrono::system_clock::now().time_since_epoch(); + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); + block_req.mutable_block()->mutable_header()->set_height( 1 ); + block_req.mutable_block()->mutable_header()->set_previous( + util::converter::as< std::string >( koinos::crypto::multihash::zero( koinos::crypto::multicodec::sha2_256 ) ) ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); + *block_req.mutable_block()->add_transactions() = trx1; + *block_req.mutable_block()->add_transactions() = trx2; + + set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); + + _controller.submit_block( block_req ); + + BOOST_TEST_MESSAGE( "Verify mint did nothing" ); + + koinos::contracts::token::balance_of_arguments bal_args; + bal_args.set_owner( alice_address ); + + koinos::rpc::chain::read_contract_request request; + request.set_contract_id( op1->contract_id() ); + request.set_entry_point( token_entry::balance_of ); + request.set_args( bal_args.SerializeAsString() ); + + auto response = _controller.read_contract( request ); + koinos::contracts::token::balance_of_result bal_ret; + bal_ret.ParseFromString( response.result() ); + + BOOST_REQUIRE_EQUAL( bal_ret.value(), 0 ); + + BOOST_TEST_MESSAGE( "Creating hello contract upload operation" ); + + koinos::protocol::transaction trx3; + + nonce_value.set_uint64_value( 2 ); + + // Upload the hello contract + auto op3 = trx3.add_operations()->mutable_upload_contract(); + op3->set_contract_id( + util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); + op3->set_bytecode( get_hello_wasm() ); + trx3.mutable_header()->set_rc_limit( 10'000'000 ); + trx3.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx3.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx3, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx3, contract_private_key ); + + BOOST_TEST_MESSAGE( "Creating forever contract upload operation" ); + + auto forever_private_key = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "forever"s ) ); + + koinos::protocol::transaction trx4; + + nonce_value.set_uint64_value( 1 ); + + // Upload the hello contract + auto op4 = trx4.add_operations()->mutable_upload_contract(); + op4->set_contract_id( + util::converter::as< std::string >( forever_private_key.get_public_key().to_address_bytes() ) ); + op4->set_bytecode( get_forever_wasm() ); + trx4.mutable_header()->set_rc_limit( 10'000'000 ); + trx4.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx4.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx4, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx4, forever_private_key ); + + BOOST_TEST_MESSAGE( "Creating operation that calls both contracts" ); + + koinos::protocol::transaction trx5; - auto op6 = trx5.add_operations()->mutable_call_contract(); - op6->set_contract_id( op4->contract_id() ); - op6->set_entry_point( 0x00 ); + nonce_value.set_uint64_value( 2 ); - trx5.mutable_header()->set_rc_limit( 10'000'000 ); - trx5.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx5.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx5, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx5, alice_private_key ); + auto op5 = trx5.add_operations()->mutable_call_contract(); + op5->set_contract_id( op3->contract_id() ); + op5->set_entry_point( 0x00 ); - BOOST_TEST_MESSAGE( "Constructing block" ); + auto op6 = trx5.add_operations()->mutable_call_contract(); + op6->set_contract_id( op4->contract_id() ); + op6->set_entry_point( 0x00 ); - koinos::rpc::chain::submit_block_request block_req2; + trx5.mutable_header()->set_rc_limit( 10'000'000 ); + trx5.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx5.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx5, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx5, alice_private_key ); - auto duration2 = std::chrono::system_clock::now().time_since_epoch(); - block_req2.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( duration2 ).count() ); - block_req2.mutable_block()->mutable_header()->set_height( 2 ); - block_req2.mutable_block()->mutable_header()->set_previous( block_req.block().id() ); - block_req2.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - *block_req2.mutable_block()->add_transactions() = trx3; - *block_req2.mutable_block()->add_transactions() = trx4; - *block_req2.mutable_block()->add_transactions() = trx5; + BOOST_TEST_MESSAGE( "Constructing block" ); - set_block_merkle_roots( *block_req2.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req2.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, block_req2.block().header() ) ) ); - sign_block( *block_req2.mutable_block(), _block_signing_private_key ); + koinos::rpc::chain::submit_block_request block_req2; - BOOST_TEST_MESSAGE( "Submitting block" ); + auto duration2 = std::chrono::system_clock::now().time_since_epoch(); + block_req2.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( duration2 ).count() ); + block_req2.mutable_block()->mutable_header()->set_height( 2 ); + block_req2.mutable_block()->mutable_header()->set_previous( block_req.block().id() ); + block_req2.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); + *block_req2.mutable_block()->add_transactions() = trx3; + *block_req2.mutable_block()->add_transactions() = trx4; + *block_req2.mutable_block()->add_transactions() = trx5; - auto resp = _controller.submit_block( block_req2 ); + set_block_merkle_roots( *block_req2.mutable_block(), koinos::crypto::multicodec::sha2_256 ); + block_req2.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, block_req2.block().header() ) ) ); + sign_block( *block_req2.mutable_block(), _block_signing_private_key ); + BOOST_TEST_MESSAGE( "Submitting block" ); - BOOST_TEST_MESSAGE( "Ensuring transaction(0) succeeded" ); + auto resp = _controller.submit_block( block_req2 ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(0).id(), trx3.id() ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(0).reverted(), false ); + BOOST_TEST_MESSAGE( "Ensuring transaction(0) succeeded" ); - BOOST_TEST_MESSAGE( "Ensuring transaction(1) succeeded" ); + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 0 ).id(), trx3.id() ); + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 0 ).reverted(), false ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(1).id(), trx4.id() ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(1).reverted(), false ); + BOOST_TEST_MESSAGE( "Ensuring transaction(1) succeeded" ); - BOOST_TEST_MESSAGE( "Ensuring transaction(2) was reverted and the log still exists on the receipt" ); + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 1 ).id(), trx4.id() ); + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 1 ).reverted(), false ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(2).id(), trx5.id() ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(2).reverted(), true ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(2).logs().size(), 2 ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(2).logs(0), "Greetings from koinos vm" ); - BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts(2).logs(1), "transaction reverted: insufficient rc" ); + BOOST_TEST_MESSAGE( "Ensuring transaction(2) was reverted and the log still exists on the receipt" ); -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 2 ).id(), trx5.id() ); + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 2 ).reverted(), true ); + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 2 ).logs().size(), 2 ); + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 2 ).logs( 0 ), "Greetings from koinos vm" ); + BOOST_REQUIRE_EQUAL( resp.receipt().transaction_receipts( 2 ).logs( 1 ), "transaction reverted: insufficient rc" ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( receipt_test ) -{ try { - BOOST_TEST_MESSAGE( "Submit block with KOIN contract upload and attempted mint" ); - - auto rc_limit1 = 10'000'000; - auto rc_limit2 = 9'000'000; - - auto contract_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); - auto alice_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); - auto alice_address = alice_private_key.get_public_key().to_address_bytes(); - koinos::protocol::transaction trx1; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); - - // Upload the KOIN contract - auto op1 = trx1.add_operations()->mutable_upload_contract(); - op1->set_contract_id( util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); - op1->set_bytecode( get_koin_wasm() ); - auto sys_op = trx1.add_operations()->mutable_set_system_contract(); - sys_op->set_contract_id( op1->contract_id() ); - sys_op->set_system_contract( true ); - trx1.mutable_header()->set_rc_limit( rc_limit1 ); - trx1.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx1.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx1, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx1, contract_private_key ); - add_signature( trx1, _block_signing_private_key ); - - koinos::protocol::transaction trx2; - - koinos::contracts::token::mint_arguments mint_arg; - mint_arg.set_to( alice_address ); - mint_arg.set_value( 100 ); - - auto op2 = trx2.add_operations()->mutable_call_contract(); - op2->set_contract_id( op1->contract_id() ); - op2->set_entry_point( token_entry::mint ); - op2->set_args( mint_arg.SerializeAsString() ); - trx2.mutable_header()->set_rc_limit( rc_limit2 ); - trx2.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - trx2.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - set_transaction_merkle_roots( trx2, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx2, alice_private_key ); - - koinos::rpc::chain::submit_block_request block_req; - - auto duration = std::chrono::system_clock::now().time_since_epoch(); - block_req.mutable_block()->mutable_header()->set_timestamp( std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); - block_req.mutable_block()->mutable_header()->set_height( 1 ); - block_req.mutable_block()->mutable_header()->set_previous( util::converter::as< std::string >( koinos::crypto::multihash::zero( koinos::crypto::multicodec::sha2_256 ) ) ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - *block_req.mutable_block()->add_transactions() = trx1; - *block_req.mutable_block()->add_transactions() = trx2; - - set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); - - auto rld = _controller.get_resource_limits( koinos::rpc::chain::get_resource_limits_request() ); - - koinos::rpc::chain::get_account_rc_request rc_req; - - rc_req.set_account( util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); - uint64_t max_payer1 = _controller.get_account_rc( rc_req ).rc(); - - rc_req.set_account( util::converter::as< std::string >( alice_private_key.get_public_key().to_address_bytes() ) ); - uint64_t max_payer2 = _controller.get_account_rc( rc_req ).rc(); - - auto block_resp = _controller.submit_block( block_req ); - - BOOST_TEST_MESSAGE( "Check the resulting block receipt" ); - - LOG(debug) << block_resp; - - BOOST_REQUIRE_EQUAL( block_resp.receipt().id(), block_req.block().id() ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts_size(), 2 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().events_size(), 0 ); - BOOST_REQUIRE( - block_resp.receipt().disk_storage_used() >= - block_resp.receipt().transaction_receipts( 0 ).disk_storage_used() + - block_resp.receipt().transaction_receipts( 1 ).disk_storage_used() ); - - BOOST_REQUIRE( - block_resp.receipt().network_bandwidth_used() >= - block_resp.receipt().transaction_receipts( 0 ).network_bandwidth_used() + - block_resp.receipt().transaction_receipts( 1 ).network_bandwidth_used() ); - - BOOST_REQUIRE( - block_resp.receipt().compute_bandwidth_used() >= - block_resp.receipt().transaction_receipts( 0 ).compute_bandwidth_used() + - block_resp.receipt().transaction_receipts( 1 ).compute_bandwidth_used() ); - - uint64_t rc1 = 0; - rc1 += block_resp.receipt().transaction_receipts( 0 ).disk_storage_used() * rld.resource_limit_data().disk_storage_cost(); - rc1 += block_resp.receipt().transaction_receipts( 0 ).compute_bandwidth_used() * rld.resource_limit_data().compute_bandwidth_cost(); - rc1 += block_resp.receipt().transaction_receipts( 0 ).network_bandwidth_used() * rld.resource_limit_data().network_bandwidth_cost(); - - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).id(), trx1.id() ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).rc_limit(), rc_limit1 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).rc_used(), rc1 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).payer(), util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).max_payer_rc(), max_payer1 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).reverted(), false ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).events_size(), 1 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).state_delta_entries_size(), 4 ); - - uint64_t rc2 = 0; - rc2 += block_resp.receipt().transaction_receipts( 1 ).disk_storage_used() * rld.resource_limit_data().disk_storage_cost(); - rc2 += block_resp.receipt().transaction_receipts( 1 ).compute_bandwidth_used() * rld.resource_limit_data().compute_bandwidth_cost(); - rc2 += block_resp.receipt().transaction_receipts( 1 ).network_bandwidth_used() * rld.resource_limit_data().network_bandwidth_cost(); - - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).id(), trx2.id() ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).rc_limit(), rc_limit2 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).rc_used(), rc2 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).payer(), util::converter::as< std::string >( alice_private_key.get_public_key().to_address_bytes() ) ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).max_payer_rc(), max_payer2 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).reverted(), true ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).events_size(), 0 ); - BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).state_delta_entries_size(), 5 ); - - LOG(debug) << block_resp; - - auto rc_limit3 = 8'000'000; - - koinos::protocol::transaction trx3; - nonce_value.set_uint64_value( 2 ); - - koinos::contracts::token::transfer_arguments xfer_arg; - xfer_arg.set_from( alice_address ); - xfer_arg.set_to( contract_private_key.get_public_key().to_address_bytes() ); - xfer_arg.set_value( 0 ); - - auto op3 = trx3.add_operations()->mutable_call_contract(); - op3->set_contract_id( op1->contract_id() ); - op3->set_entry_point( token_entry::transfer ); - op3->set_args( xfer_arg.SerializeAsString() ); - trx3.mutable_header()->set_rc_limit( rc_limit3 ); - trx3.mutable_header()->set_nonce( util::converter::as< std::string>( nonce_value ) ); - trx3.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - set_transaction_merkle_roots( trx3, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( trx3, alice_private_key ); - - LOG(info) << util::to_base58( alice_private_key.get_public_key().to_address_bytes() ); - - koinos::rpc::chain::submit_transaction_request tx_req; - *tx_req.mutable_transaction() = trx3; - - rld = _controller.get_resource_limits( koinos::rpc::chain::get_resource_limits_request() ); - - rc_req.set_account( util::converter::as< std::string >( alice_private_key.get_public_key().to_address_bytes() ) ); - - uint64_t max_payer3 = _controller.get_account_rc( rc_req ).rc(); - - auto tx_resp = _controller.submit_transaction( tx_req ); - - uint64_t rc3 = 0; - rc3 += tx_resp.receipt().disk_storage_used() * rld.resource_limit_data().disk_storage_cost(); - rc3 += tx_resp.receipt().compute_bandwidth_used() * rld.resource_limit_data().compute_bandwidth_cost(); - rc3 += tx_resp.receipt().network_bandwidth_used() * rld.resource_limit_data().network_bandwidth_cost(); - - BOOST_TEST_MESSAGE( "Check the resulting transaction receipt" ); - - BOOST_REQUIRE_EQUAL( tx_resp.receipt().id(), trx3.id() ); - BOOST_REQUIRE_EQUAL( tx_resp.receipt().rc_limit(), rc_limit3 ); - BOOST_REQUIRE_EQUAL( tx_resp.receipt().rc_used(), rc3 ); - BOOST_REQUIRE_EQUAL( tx_resp.receipt().payer(), util::converter::as< std::string >( alice_private_key.get_public_key().to_address_bytes() ) ); - BOOST_REQUIRE_EQUAL( tx_resp.receipt().max_payer_rc(), max_payer3 ); - BOOST_REQUIRE_EQUAL( tx_resp.receipt().reverted(), false ); - BOOST_REQUIRE_EQUAL( tx_resp.receipt().events_size(), 1 ); - BOOST_REQUIRE_EQUAL( tx_resp.receipt().state_delta_entries_size(), 3 ); - - LOG(debug) << tx_resp.receipt(); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + BOOST_TEST_MESSAGE( "Submit block with KOIN contract upload and attempted mint" ); + + auto rc_limit1 = 10'000'000; + auto rc_limit2 = 9'000'000; + + auto contract_private_key = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "contract"s ) ); + auto alice_private_key = + koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "alice"s ) ); + auto alice_address = alice_private_key.get_public_key().to_address_bytes(); + koinos::protocol::transaction trx1; + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); + + // Upload the KOIN contract + auto op1 = trx1.add_operations()->mutable_upload_contract(); + op1->set_contract_id( + util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); + op1->set_bytecode( get_koin_wasm() ); + auto sys_op = trx1.add_operations()->mutable_set_system_contract(); + sys_op->set_contract_id( op1->contract_id() ); + sys_op->set_system_contract( true ); + trx1.mutable_header()->set_rc_limit( rc_limit1 ); + trx1.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx1.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx1, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx1, contract_private_key ); + add_signature( trx1, _block_signing_private_key ); + + koinos::protocol::transaction trx2; + + koinos::contracts::token::mint_arguments mint_arg; + mint_arg.set_to( alice_address ); + mint_arg.set_value( 100 ); + + auto op2 = trx2.add_operations()->mutable_call_contract(); + op2->set_contract_id( op1->contract_id() ); + op2->set_entry_point( token_entry::mint ); + op2->set_args( mint_arg.SerializeAsString() ); + trx2.mutable_header()->set_rc_limit( rc_limit2 ); + trx2.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + trx2.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + set_transaction_merkle_roots( trx2, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx2, alice_private_key ); + + koinos::rpc::chain::submit_block_request block_req; + + auto duration = std::chrono::system_clock::now().time_since_epoch(); + block_req.mutable_block()->mutable_header()->set_timestamp( + std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count() ); + block_req.mutable_block()->mutable_header()->set_height( 1 ); + block_req.mutable_block()->mutable_header()->set_previous( + util::converter::as< std::string >( koinos::crypto::multihash::zero( koinos::crypto::multicodec::sha2_256 ) ) ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); + *block_req.mutable_block()->add_transactions() = trx1; + *block_req.mutable_block()->add_transactions() = trx2; + + set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); + + auto rld = _controller.get_resource_limits( koinos::rpc::chain::get_resource_limits_request() ); + + koinos::rpc::chain::get_account_rc_request rc_req; + + rc_req.set_account( + util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); + uint64_t max_payer1 = _controller.get_account_rc( rc_req ).rc(); + + rc_req.set_account( util::converter::as< std::string >( alice_private_key.get_public_key().to_address_bytes() ) ); + uint64_t max_payer2 = _controller.get_account_rc( rc_req ).rc(); + + auto block_resp = _controller.submit_block( block_req ); + + BOOST_TEST_MESSAGE( "Check the resulting block receipt" ); + + LOG( debug ) << block_resp; + + BOOST_REQUIRE_EQUAL( block_resp.receipt().id(), block_req.block().id() ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts_size(), 2 ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().events_size(), 0 ); + BOOST_REQUIRE( block_resp.receipt().disk_storage_used() + >= block_resp.receipt().transaction_receipts( 0 ).disk_storage_used() + + block_resp.receipt().transaction_receipts( 1 ).disk_storage_used() ); + + BOOST_REQUIRE( block_resp.receipt().network_bandwidth_used() + >= block_resp.receipt().transaction_receipts( 0 ).network_bandwidth_used() + + block_resp.receipt().transaction_receipts( 1 ).network_bandwidth_used() ); + + BOOST_REQUIRE( block_resp.receipt().compute_bandwidth_used() + >= block_resp.receipt().transaction_receipts( 0 ).compute_bandwidth_used() + + block_resp.receipt().transaction_receipts( 1 ).compute_bandwidth_used() ); + + uint64_t rc1 = 0; + rc1 += block_resp.receipt().transaction_receipts( 0 ).disk_storage_used() + * rld.resource_limit_data().disk_storage_cost(); + rc1 += block_resp.receipt().transaction_receipts( 0 ).compute_bandwidth_used() + * rld.resource_limit_data().compute_bandwidth_cost(); + rc1 += block_resp.receipt().transaction_receipts( 0 ).network_bandwidth_used() + * rld.resource_limit_data().network_bandwidth_cost(); + + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).id(), trx1.id() ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).rc_limit(), rc_limit1 ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).rc_used(), rc1 ); + BOOST_REQUIRE_EQUAL( + block_resp.receipt().transaction_receipts( 0 ).payer(), + util::converter::as< std::string >( contract_private_key.get_public_key().to_address_bytes() ) ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).max_payer_rc(), max_payer1 ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).reverted(), false ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).events_size(), 1 ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 0 ).state_delta_entries_size(), 4 ); + + uint64_t rc2 = 0; + rc2 += block_resp.receipt().transaction_receipts( 1 ).disk_storage_used() + * rld.resource_limit_data().disk_storage_cost(); + rc2 += block_resp.receipt().transaction_receipts( 1 ).compute_bandwidth_used() + * rld.resource_limit_data().compute_bandwidth_cost(); + rc2 += block_resp.receipt().transaction_receipts( 1 ).network_bandwidth_used() + * rld.resource_limit_data().network_bandwidth_cost(); + + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).id(), trx2.id() ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).rc_limit(), rc_limit2 ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).rc_used(), rc2 ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).payer(), + util::converter::as< std::string >( alice_private_key.get_public_key().to_address_bytes() ) ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).max_payer_rc(), max_payer2 ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).reverted(), true ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).events_size(), 0 ); + BOOST_REQUIRE_EQUAL( block_resp.receipt().transaction_receipts( 1 ).state_delta_entries_size(), 5 ); + + LOG( debug ) << block_resp; + + auto rc_limit3 = 8'000'000; + + koinos::protocol::transaction trx3; + nonce_value.set_uint64_value( 2 ); + + koinos::contracts::token::transfer_arguments xfer_arg; + xfer_arg.set_from( alice_address ); + xfer_arg.set_to( contract_private_key.get_public_key().to_address_bytes() ); + xfer_arg.set_value( 0 ); + + auto op3 = trx3.add_operations()->mutable_call_contract(); + op3->set_contract_id( op1->contract_id() ); + op3->set_entry_point( token_entry::transfer ); + op3->set_args( xfer_arg.SerializeAsString() ); + trx3.mutable_header()->set_rc_limit( rc_limit3 ); + trx3.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + trx3.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + set_transaction_merkle_roots( trx3, koinos::crypto::multicodec::sha2_256 ); + sign_transaction( trx3, alice_private_key ); + + LOG( info ) << util::to_base58( alice_private_key.get_public_key().to_address_bytes() ); + + koinos::rpc::chain::submit_transaction_request tx_req; + *tx_req.mutable_transaction() = trx3; + + rld = _controller.get_resource_limits( koinos::rpc::chain::get_resource_limits_request() ); + + rc_req.set_account( util::converter::as< std::string >( alice_private_key.get_public_key().to_address_bytes() ) ); + + uint64_t max_payer3 = _controller.get_account_rc( rc_req ).rc(); + + auto tx_resp = _controller.submit_transaction( tx_req ); + + uint64_t rc3 = 0; + rc3 += tx_resp.receipt().disk_storage_used() * rld.resource_limit_data().disk_storage_cost(); + rc3 += tx_resp.receipt().compute_bandwidth_used() * rld.resource_limit_data().compute_bandwidth_cost(); + rc3 += tx_resp.receipt().network_bandwidth_used() * rld.resource_limit_data().network_bandwidth_cost(); + + BOOST_TEST_MESSAGE( "Check the resulting transaction receipt" ); + + BOOST_REQUIRE_EQUAL( tx_resp.receipt().id(), trx3.id() ); + BOOST_REQUIRE_EQUAL( tx_resp.receipt().rc_limit(), rc_limit3 ); + BOOST_REQUIRE_EQUAL( tx_resp.receipt().rc_used(), rc3 ); + BOOST_REQUIRE_EQUAL( tx_resp.receipt().payer(), + util::converter::as< std::string >( alice_private_key.get_public_key().to_address_bytes() ) ); + BOOST_REQUIRE_EQUAL( tx_resp.receipt().max_payer_rc(), max_payer3 ); + BOOST_REQUIRE_EQUAL( tx_resp.receipt().reverted(), false ); + BOOST_REQUIRE_EQUAL( tx_resp.receipt().events_size(), 1 ); + BOOST_REQUIRE_EQUAL( tx_resp.receipt().state_delta_entries_size(), 3 ); + + LOG( debug ) << tx_resp.receipt(); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( system_call_override_test ) -{ try { - BOOST_TEST_MESSAGE( "Upload a contract that calls the log system call" ); - koinos::chain::value_type nonce_value; - - auto random_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, std::string( "alpha" ) ) ); - - auto contract_address = random_private_key.get_public_key().to_address_bytes(); - - koinos::protocol::upload_contract_operation upload_contract_op; - upload_contract_op.set_contract_id( contract_address ); - upload_contract_op.set_bytecode( get_hello_wasm() ); - - koinos::protocol::transaction transaction; - transaction.mutable_header()->set_payer( random_private_key.get_public_key().to_address_bytes() ); - nonce_value.set_uint64_value( 1 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - transaction.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - *transaction.add_operations()->mutable_upload_contract() = upload_contract_op; - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, random_private_key ); - - auto block_time = std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ).count(); - koinos::protocol::block block; - block.mutable_header()->set_height( 1 ); - block.mutable_header()->set_signer( _block_signing_private_key.get_public_key().to_address_bytes() ); - block.mutable_header()->set_timestamp( block_time ); - block.mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - block.mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - *block.add_transactions() = transaction; - set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); - block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); - sign_block( block, _block_signing_private_key ); - - koinos::rpc::chain::submit_block_request block_request; - *block_request.mutable_block() = block; - - _controller.submit_block( block_request ); - - BOOST_TEST_MESSAGE( "Read contract that calls the log system call" ); - - koinos::rpc::chain::read_contract_request contract_request; - contract_request.set_contract_id( contract_address ); - auto contract_response = _controller.read_contract( contract_request ); - - BOOST_REQUIRE_EQUAL( contract_response.logs( 0 ), "Greetings from koinos vm" ); - - auto random_private_key2 = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, std::string( "bravo" ) ) ); - - BOOST_TEST_MESSAGE( "Upload a contract that preprends log messages" ); - - auto contract_address2 = random_private_key2.get_public_key().to_address_bytes(); - - koinos::protocol::upload_contract_operation upload_contract_op2; - upload_contract_op2.set_contract_id( contract_address2 ); - upload_contract_op2.set_bytecode( get_syscall_override_wasm() ); - - transaction.Clear(); - transaction.mutable_header()->set_payer( random_private_key2.get_public_key().to_address_bytes() ); - nonce_value.set_uint64_value( 1 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - transaction.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - *transaction.add_operations()->mutable_upload_contract() = upload_contract_op2; - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, random_private_key2 ); - - auto previous_id = block.id(); - - block.Clear(); - block.mutable_header()->set_height( 2 ); - block.mutable_header()->set_signer( _block_signing_private_key.get_public_key().to_address_bytes() ); - block.mutable_header()->set_timestamp( ++block_time ); - block.mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - block.mutable_header()->set_previous( previous_id ); - *block.add_transactions() = transaction; - set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); - block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); - sign_block( block, _block_signing_private_key ); - - block_request.Clear(); - *block_request.mutable_block() = block; - - _controller.submit_block( block_request ); - - BOOST_TEST_MESSAGE( "Set contract as a system call override, call it in the same transaction" ); - - koinos::protocol::set_system_contract_operation system_contract_op; - system_contract_op.set_contract_id( contract_address2 ); - system_contract_op.set_system_contract( true ); - - koinos::protocol::set_system_call_operation set_op; - set_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); - set_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( contract_address2 ); - set_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); - - koinos::protocol::call_contract_operation call_op; - call_op.set_contract_id( contract_address ); - - transaction.Clear(); - transaction.mutable_header()->set_payer( _block_signing_private_key.get_public_key().to_address_bytes() ); - nonce_value.set_uint64_value( 1 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - transaction.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - *transaction.add_operations()->mutable_set_system_contract() = system_contract_op; - *transaction.add_operations()->mutable_set_system_call() = set_op; - *transaction.add_operations()->mutable_call_contract() = call_op; - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, _block_signing_private_key ); - - previous_id = block.id(); - - block.Clear(); - block.mutable_header()->set_height( 3 ); - block.mutable_header()->set_signer( _block_signing_private_key.get_public_key().to_address_bytes() ); - block.mutable_header()->set_timestamp( ++block_time ); - block.mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - block.mutable_header()->set_previous( previous_id ); - *block.add_transactions() = transaction; - set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); - block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); - sign_block( block, _block_signing_private_key ); - - block_request.Clear(); - *block_request.mutable_block() = block; - - auto block_response = _controller.submit_block( block_request ); - - BOOST_TEST_MESSAGE( "Ensure log behavior did not change during block application" ); - - BOOST_REQUIRE( block_response.receipt().transaction_receipts_size() >= 1 ); - BOOST_REQUIRE( block_response.receipt().transaction_receipts( 0 ).logs_size() >= 1 ); - BOOST_REQUIRE_EQUAL( block_response.receipt().transaction_receipts( 0 ).logs( 0 ), "Greetings from koinos vm" ); - - transaction.Clear(); - transaction.mutable_header()->set_payer( _block_signing_private_key.get_public_key().to_address_bytes() ); - nonce_value.set_uint64_value( 2 ); - transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - transaction.mutable_header()->set_rc_limit( 1'000'000 ); - transaction.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); - *transaction.add_operations()->mutable_call_contract() = call_op; - set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); - sign_transaction( transaction, _block_signing_private_key ); - - previous_id = block.id(); - - block.Clear(); - block.mutable_header()->set_height( 4 ); - block.mutable_header()->set_signer( _block_signing_private_key.get_public_key().to_address_bytes() ); - block.mutable_header()->set_timestamp( ++block_time ); - block.mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - block.mutable_header()->set_previous( previous_id ); - *block.add_transactions() = transaction; - set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); - block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); - sign_block( block, _block_signing_private_key ); - - block_request.Clear(); - *block_request.mutable_block() = block; - - block_response = _controller.submit_block( block_request ); - - BOOST_TEST_MESSAGE( "Ensure log behavior changed during subsequent block application" ); - - BOOST_REQUIRE_EQUAL( block_response.receipt().transaction_receipts( 0 ).logs( 0 ), "test: Greetings from koinos vm" ); - - BOOST_TEST_MESSAGE( "Ensure log behavior changed during read contract" ); - - contract_request.Clear(); - contract_request.set_contract_id( contract_address ); - contract_response = _controller.read_contract( contract_request ); - - BOOST_REQUIRE_EQUAL( contract_response.logs( 0 ), "test: Greetings from koinos vm" ); - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } +{ + try + { + BOOST_TEST_MESSAGE( "Upload a contract that calls the log system call" ); + koinos::chain::value_type nonce_value; + + auto random_private_key = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, std::string( "alpha" ) ) ); + + auto contract_address = random_private_key.get_public_key().to_address_bytes(); + + koinos::protocol::upload_contract_operation upload_contract_op; + upload_contract_op.set_contract_id( contract_address ); + upload_contract_op.set_bytecode( get_hello_wasm() ); + + koinos::protocol::transaction transaction; + transaction.mutable_header()->set_payer( random_private_key.get_public_key().to_address_bytes() ); + nonce_value.set_uint64_value( 1 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + transaction.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + *transaction.add_operations()->mutable_upload_contract() = upload_contract_op; + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, random_private_key ); + + auto block_time = + std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch() ) + .count(); + koinos::protocol::block block; + block.mutable_header()->set_height( 1 ); + block.mutable_header()->set_signer( _block_signing_private_key.get_public_key().to_address_bytes() ); + block.mutable_header()->set_timestamp( block_time ); + block.mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block.mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + *block.add_transactions() = transaction; + set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); + block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); + sign_block( block, _block_signing_private_key ); + + koinos::rpc::chain::submit_block_request block_request; + *block_request.mutable_block() = block; + + _controller.submit_block( block_request ); + + BOOST_TEST_MESSAGE( "Read contract that calls the log system call" ); + + koinos::rpc::chain::read_contract_request contract_request; + contract_request.set_contract_id( contract_address ); + auto contract_response = _controller.read_contract( contract_request ); + + BOOST_REQUIRE_EQUAL( contract_response.logs( 0 ), "Greetings from koinos vm" ); + + auto random_private_key2 = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, std::string( "bravo" ) ) ); + + BOOST_TEST_MESSAGE( "Upload a contract that preprends log messages" ); + + auto contract_address2 = random_private_key2.get_public_key().to_address_bytes(); + + koinos::protocol::upload_contract_operation upload_contract_op2; + upload_contract_op2.set_contract_id( contract_address2 ); + upload_contract_op2.set_bytecode( get_syscall_override_wasm() ); + + transaction.Clear(); + transaction.mutable_header()->set_payer( random_private_key2.get_public_key().to_address_bytes() ); + nonce_value.set_uint64_value( 1 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + transaction.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + *transaction.add_operations()->mutable_upload_contract() = upload_contract_op2; + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, random_private_key2 ); + + auto previous_id = block.id(); + + block.Clear(); + block.mutable_header()->set_height( 2 ); + block.mutable_header()->set_signer( _block_signing_private_key.get_public_key().to_address_bytes() ); + block.mutable_header()->set_timestamp( ++block_time ); + block.mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block.mutable_header()->set_previous( previous_id ); + *block.add_transactions() = transaction; + set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); + block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); + sign_block( block, _block_signing_private_key ); + + block_request.Clear(); + *block_request.mutable_block() = block; + + _controller.submit_block( block_request ); + + BOOST_TEST_MESSAGE( "Set contract as a system call override, call it in the same transaction" ); + + koinos::protocol::set_system_contract_operation system_contract_op; + system_contract_op.set_contract_id( contract_address2 ); + system_contract_op.set_system_contract( true ); + + koinos::protocol::set_system_call_operation set_op; + set_op.set_call_id( std::underlying_type_t< chain::system_call_id >( chain::system_call_id::log ) ); + set_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( contract_address2 ); + set_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0 ); + + koinos::protocol::call_contract_operation call_op; + call_op.set_contract_id( contract_address ); + + transaction.Clear(); + transaction.mutable_header()->set_payer( _block_signing_private_key.get_public_key().to_address_bytes() ); + nonce_value.set_uint64_value( 1 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + transaction.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + *transaction.add_operations()->mutable_set_system_contract() = system_contract_op; + *transaction.add_operations()->mutable_set_system_call() = set_op; + *transaction.add_operations()->mutable_call_contract() = call_op; + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, _block_signing_private_key ); + + previous_id = block.id(); + + block.Clear(); + block.mutable_header()->set_height( 3 ); + block.mutable_header()->set_signer( _block_signing_private_key.get_public_key().to_address_bytes() ); + block.mutable_header()->set_timestamp( ++block_time ); + block.mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block.mutable_header()->set_previous( previous_id ); + *block.add_transactions() = transaction; + set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); + block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); + sign_block( block, _block_signing_private_key ); + + block_request.Clear(); + *block_request.mutable_block() = block; + + auto block_response = _controller.submit_block( block_request ); + + BOOST_TEST_MESSAGE( "Ensure log behavior did not change during block application" ); + + BOOST_REQUIRE( block_response.receipt().transaction_receipts_size() >= 1 ); + BOOST_REQUIRE( block_response.receipt().transaction_receipts( 0 ).logs_size() >= 1 ); + BOOST_REQUIRE_EQUAL( block_response.receipt().transaction_receipts( 0 ).logs( 0 ), "Greetings from koinos vm" ); + + transaction.Clear(); + transaction.mutable_header()->set_payer( _block_signing_private_key.get_public_key().to_address_bytes() ); + nonce_value.set_uint64_value( 2 ); + transaction.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + transaction.mutable_header()->set_rc_limit( 1'000'000 ); + transaction.mutable_header()->set_chain_id( _controller.get_chain_id().chain_id() ); + *transaction.add_operations()->mutable_call_contract() = call_op; + set_transaction_merkle_roots( transaction, crypto::multicodec::sha2_256 ); + sign_transaction( transaction, _block_signing_private_key ); + + previous_id = block.id(); + + block.Clear(); + block.mutable_header()->set_height( 4 ); + block.mutable_header()->set_signer( _block_signing_private_key.get_public_key().to_address_bytes() ); + block.mutable_header()->set_timestamp( ++block_time ); + block.mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block.mutable_header()->set_previous( previous_id ); + *block.add_transactions() = transaction; + set_block_merkle_roots( block, crypto::multicodec::sha2_256 ); + block.set_id( util::converter::as< std::string >( crypto::hash( crypto::multicodec::sha2_256, block.header() ) ) ); + sign_block( block, _block_signing_private_key ); + + block_request.Clear(); + *block_request.mutable_block() = block; + + block_response = _controller.submit_block( block_request ); + + BOOST_TEST_MESSAGE( "Ensure log behavior changed during subsequent block application" ); + + BOOST_REQUIRE_EQUAL( block_response.receipt().transaction_receipts( 0 ).logs( 0 ), + "test: Greetings from koinos vm" ); + + BOOST_TEST_MESSAGE( "Ensure log behavior changed during read contract" ); + + contract_request.Clear(); + contract_request.set_contract_id( contract_address ); + contract_response = _controller.read_contract( contract_request ); + + BOOST_REQUIRE_EQUAL( contract_response.logs( 0 ), "test: Greetings from koinos vm" ); + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_CASE( invoke_system_call_test ) -{ try { - rpc::chain::invoke_system_call_response syscall_response; - rpc::chain::submit_block_response block_response; +{ + try + { + rpc::chain::invoke_system_call_response syscall_response; + rpc::chain::submit_block_response block_response; + + koinos::rpc::chain::invoke_system_call_request syscall_req; - koinos::rpc::chain::invoke_system_call_request syscall_req; + BOOST_TEST_MESSAGE( "Read get_contract_id (system)" ); - BOOST_TEST_MESSAGE( "Read get_contract_id (system)" ); + syscall_req.set_id( chain::system_call_id::get_contract_id ); - syscall_req.set_id( chain::system_call_id::get_contract_id ); + syscall_response = _controller.invoke_system_call( syscall_req ); - syscall_response = _controller.invoke_system_call( syscall_req ); + koinos::chain::get_contract_id_result contract_id_result; - koinos::chain::get_contract_id_result contract_id_result; + contract_id_result.ParseFromString( syscall_response.value() ); - contract_id_result.ParseFromString( syscall_response.value() ); + BOOST_REQUIRE_EQUAL( contract_id_result.value(), koinos::chain::constants::system ); - BOOST_REQUIRE_EQUAL( contract_id_result.value(), koinos::chain::constants::system ); + BOOST_TEST_MESSAGE( "Read get_contract_id (user)" ); - BOOST_TEST_MESSAGE( "Read get_contract_id (user)" ); + syscall_req.set_id( chain::system_call_id::get_contract_id ); + syscall_req.mutable_caller_data()->set_caller_privilege( koinos::chain::privilege::user_mode ); + syscall_req.mutable_caller_data()->set_caller( _alice_address ); - syscall_req.set_id( chain::system_call_id::get_contract_id ); - syscall_req.mutable_caller_data()->set_caller_privilege( koinos::chain::privilege::user_mode ); - syscall_req.mutable_caller_data()->set_caller( _alice_address ); + syscall_response = _controller.invoke_system_call( syscall_req ); - syscall_response = _controller.invoke_system_call( syscall_req ); + contract_id_result.ParseFromString( syscall_response.value() ); - contract_id_result.ParseFromString( syscall_response.value() ); + BOOST_REQUIRE_EQUAL( contract_id_result.value(), _alice_address ); - BOOST_REQUIRE_EQUAL( contract_id_result.value(), _alice_address ); + syscall_req.Clear(); - syscall_req.Clear(); + BOOST_TEST_MESSAGE( "Read get_object (system)" ); - BOOST_TEST_MESSAGE( "Read get_object (system)" ); + koinos::chain::get_object_arguments get_object_args; - koinos::chain::get_object_arguments get_object_args; + *get_object_args.mutable_space() = chain::state::space::metadata(); + get_object_args.set_key( chain::state::key::compute_bandwidth_registry ); - *get_object_args.mutable_space() = chain::state::space::metadata(); - get_object_args.set_key( chain::state::key::compute_bandwidth_registry ); + syscall_req.set_name( chain::system_call_id_Name( chain::system_call_id::get_object ) ); + *syscall_req.mutable_args() = get_object_args.SerializeAsString(); - syscall_req.set_name( chain::system_call_id_Name( chain::system_call_id::get_object ) ); - *syscall_req.mutable_args() = get_object_args.SerializeAsString(); + syscall_response = _controller.invoke_system_call( syscall_req ); - syscall_response = _controller.invoke_system_call( syscall_req ); + koinos::chain::get_object_result res; - koinos::chain::get_object_result res; + res.ParseFromString( syscall_response.value() ); - res.ParseFromString( syscall_response.value() ); + koinos::chain::compute_bandwidth_registry registry; - koinos::chain::compute_bandwidth_registry registry; + koinos::chain::database_object obj = res.value(); - koinos::chain::database_object obj = res.value(); + registry.ParseFromString( obj.value() ); - registry.ParseFromString( obj.value() ); + BOOST_REQUIRE_EQUAL( registry.entries().size(), _thunk_compute.size() ); - BOOST_REQUIRE_EQUAL( registry.entries().size(), _thunk_compute.size() ); - for ( auto const &entry : registry.entries() ) - { + for( const auto& entry: registry.entries() ) + { BOOST_REQUIRE_EQUAL( _thunk_compute[ entry.name() ], entry.compute() ); - } + } - BOOST_TEST_MESSAGE( "Read get_object (user)" ); + BOOST_TEST_MESSAGE( "Read get_object (user)" ); - koinos::chain::object_space alice_space; - alice_space.set_system( false ); - alice_space.set_zone( _alice_address ); - alice_space.set_id( 0 ); + koinos::chain::object_space alice_space; + alice_space.set_system( false ); + alice_space.set_zone( _alice_address ); + alice_space.set_id( 0 ); - *get_object_args.mutable_space() = alice_space; - get_object_args.set_key( _alice_address ); + *get_object_args.mutable_space() = alice_space; + get_object_args.set_key( _alice_address ); - syscall_req.set_name( chain::system_call_id_Name( chain::system_call_id::get_object ) ); - *syscall_req.mutable_args() = get_object_args.SerializeAsString(); + syscall_req.set_name( chain::system_call_id_Name( chain::system_call_id::get_object ) ); + *syscall_req.mutable_args() = get_object_args.SerializeAsString(); - try - { + try + { _controller.invoke_system_call( syscall_req ); BOOST_FAIL( "Expected reversion exception to be thrown" ); - } - catch ( const koinos::chain::reversion_exception& e ) - { + } + catch( const koinos::chain::reversion_exception& e ) + { BOOST_REQUIRE_EQUAL( e.get_code(), koinos::chain::reversion ); BOOST_REQUIRE_EQUAL( e.get_message(), "privileged code can only access system space" ); - } - catch ( ... ) - { + } + catch( ... ) + { BOOST_FAIL( "An unexpected exception was thrown" ); - } + } - syscall_req.mutable_caller_data()->set_caller_privilege( koinos::chain::privilege::user_mode ); - syscall_req.mutable_caller_data()->set_caller( _alice_address ); + syscall_req.mutable_caller_data()->set_caller_privilege( koinos::chain::privilege::user_mode ); + syscall_req.mutable_caller_data()->set_caller( _alice_address ); - syscall_response = _controller.invoke_system_call( syscall_req ); + syscall_response = _controller.invoke_system_call( syscall_req ); - res.ParseFromString( syscall_response.value() ); + res.ParseFromString( syscall_response.value() ); - BOOST_REQUIRE_EQUAL( res.value().value(), "alpha bravo charlie delta" ); + BOOST_REQUIRE_EQUAL( res.value().value(), "alpha bravo charlie delta" ); - syscall_req.Clear(); + syscall_req.Clear(); - BOOST_TEST_MESSAGE( "Write put_object (system)" ); + BOOST_TEST_MESSAGE( "Write put_object (system)" ); - koinos::chain::put_object_arguments put_object_args; + koinos::chain::put_object_arguments put_object_args; - *put_object_args.mutable_space() = chain::state::space::metadata(); - put_object_args.set_key( chain::state::key::compute_bandwidth_registry ); - *put_object_args.mutable_obj() = std::string( "junk" ); + *put_object_args.mutable_space() = chain::state::space::metadata(); + put_object_args.set_key( chain::state::key::compute_bandwidth_registry ); + *put_object_args.mutable_obj() = std::string( "junk" ); - syscall_req.set_name( chain::system_call_id_Name( chain::system_call_id::put_object ) ); - *syscall_req.mutable_args() = put_object_args.SerializeAsString(); + syscall_req.set_name( chain::system_call_id_Name( chain::system_call_id::put_object ) ); + *syscall_req.mutable_args() = put_object_args.SerializeAsString(); - BOOST_REQUIRE_THROW( _controller.invoke_system_call( syscall_req ), koinos::chain::read_only_context_exception ); + BOOST_REQUIRE_THROW( _controller.invoke_system_call( syscall_req ), koinos::chain::read_only_context_exception ); - BOOST_TEST_MESSAGE( "Write put_object (user)" ); + BOOST_TEST_MESSAGE( "Write put_object (user)" ); - *put_object_args.mutable_space() = alice_space; - put_object_args.set_key( _alice_address ); - *put_object_args.mutable_obj() = std::string( "junk" ); + *put_object_args.mutable_space() = alice_space; + put_object_args.set_key( _alice_address ); + *put_object_args.mutable_obj() = std::string( "junk" ); - syscall_req.set_name( chain::system_call_id_Name( chain::system_call_id::put_object ) ); - *syscall_req.mutable_args() = put_object_args.SerializeAsString(); + syscall_req.set_name( chain::system_call_id_Name( chain::system_call_id::put_object ) ); + *syscall_req.mutable_args() = put_object_args.SerializeAsString(); - BOOST_REQUIRE_THROW( _controller.invoke_system_call( syscall_req ), koinos::chain::read_only_context_exception ); + BOOST_REQUIRE_THROW( _controller.invoke_system_call( syscall_req ), koinos::chain::read_only_context_exception ); - BOOST_TEST_MESSAGE( "Setup system call overrides" ); + BOOST_TEST_MESSAGE( "Setup system call overrides" ); - rpc::chain::submit_block_request block_req; + rpc::chain::submit_block_request block_req; - auto duration = std::chrono::system_clock::now().time_since_epoch(); - auto timestamp = std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count(); - block_req.mutable_block()->mutable_header()->set_timestamp( timestamp ); - block_req.mutable_block()->mutable_header()->set_height( 1 ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); - block_req.mutable_block()->mutable_header()->set_previous( util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); + auto duration = std::chrono::system_clock::now().time_since_epoch(); + auto timestamp = std::chrono::duration_cast< std::chrono::milliseconds >( duration ).count(); + block_req.mutable_block()->mutable_header()->set_timestamp( timestamp ); + block_req.mutable_block()->mutable_header()->set_height( 1 ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); + block_req.mutable_block()->mutable_header()->set_previous( + util::converter::as< std::string >( crypto::multihash::zero( crypto::multicodec::sha2_256 ) ) ); - koinos::protocol::transaction tx; + koinos::protocol::transaction tx; - auto random_private_key = koinos::crypto::private_key::regenerate( koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "syscall_rpc"s ) ); - auto contract_address = random_private_key.get_public_key().to_address_bytes(); + auto random_private_key = koinos::crypto::private_key::regenerate( + koinos::crypto::hash( koinos::crypto::multicodec::sha2_256, "syscall_rpc"s ) ); + auto contract_address = random_private_key.get_public_key().to_address_bytes(); - koinos::protocol::upload_contract_operation upload_op; - upload_op.set_contract_id( util::converter::as< std::string >( contract_address ) ); - upload_op.set_bytecode( get_syscall_rpc_wasm() ); + koinos::protocol::upload_contract_operation upload_op; + upload_op.set_contract_id( util::converter::as< std::string >( contract_address ) ); + upload_op.set_bytecode( get_syscall_rpc_wasm() ); - *tx.add_operations()->mutable_upload_contract() = upload_op; + *tx.add_operations()->mutable_upload_contract() = upload_op; - koinos::chain::value_type nonce_value; - nonce_value.set_uint64_value( 1 ); + koinos::chain::value_type nonce_value; + nonce_value.set_uint64_value( 1 ); - tx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - tx.mutable_header()->set_rc_limit( 10'000'000 ); - tx.mutable_header()->set_chain_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ) ) ); - tx.mutable_header()->set_payer( contract_address ); + tx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + tx.mutable_header()->set_rc_limit( 10'000'000 ); + tx.mutable_header()->set_chain_id( + util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ) ) ); + tx.mutable_header()->set_payer( contract_address ); - set_transaction_merkle_roots( tx, koinos::crypto::multicodec::sha2_256 ); + set_transaction_merkle_roots( tx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( tx, random_private_key ); - add_signature( tx, _block_signing_private_key ); + sign_transaction( tx, random_private_key ); + add_signature( tx, _block_signing_private_key ); - *block_req.mutable_block()->add_transactions() = tx; + *block_req.mutable_block()->add_transactions() = tx; - set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); + set_block_merkle_roots( *block_req.mutable_block(), crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + koinos::crypto::hash( crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - block_response = _controller.submit_block( block_req ); - for ( const auto& log : block_response.receipt().transaction_receipts(0).logs() ) - { - LOG(info) << log; - } + block_response = _controller.submit_block( block_req ); + for( const auto& log: block_response.receipt().transaction_receipts( 0 ).logs() ) + { + LOG( info ) << log; + } - block_req.mutable_block()->mutable_header()->set_timestamp( timestamp + 1 ); - block_req.mutable_block()->mutable_header()->set_height( _controller.get_head_info().head_topology().height() + 1 ); - block_req.mutable_block()->mutable_header()->set_previous( _controller.get_head_info().head_topology().id() ); - block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( _controller.get_head_info().head_state_merkle_root() ); + block_req.mutable_block()->mutable_header()->set_timestamp( timestamp + 1 ); + block_req.mutable_block()->mutable_header()->set_height( _controller.get_head_info().head_topology().height() + 1 ); + block_req.mutable_block()->mutable_header()->set_previous( _controller.get_head_info().head_topology().id() ); + block_req.mutable_block()->mutable_header()->set_previous_state_merkle_root( + _controller.get_head_info().head_state_merkle_root() ); - block_req.mutable_block()->clear_transactions(); + block_req.mutable_block()->clear_transactions(); - koinos::protocol::set_system_contract_operation set_system_op; - set_system_op.set_contract_id( upload_op.contract_id() ); - set_system_op.set_system_contract( true ); + koinos::protocol::set_system_contract_operation set_system_op; + set_system_op.set_contract_id( upload_op.contract_id() ); + set_system_op.set_system_contract( true ); - // success - koinos::protocol::set_system_call_operation set_syscall_op; - set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( 20001 ) ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x01 ); + // success + koinos::protocol::set_system_call_operation set_syscall_op; + set_syscall_op.set_call_id( std::underlying_type_t< chain::system_call_id >( 20'001 ) ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x01 ); - // failure - koinos::protocol::set_system_call_operation set_syscall_op2; - set_syscall_op2.set_call_id( std::underlying_type_t< chain::system_call_id >( 20002 ) ); - set_syscall_op2.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op2.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x02 ); + // failure + koinos::protocol::set_system_call_operation set_syscall_op2; + set_syscall_op2.set_call_id( std::underlying_type_t< chain::system_call_id >( 20'002 ) ); + set_syscall_op2.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op2.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x02 ); - // reversion - koinos::protocol::set_system_call_operation set_syscall_op3; - set_syscall_op3.set_call_id( std::underlying_type_t< chain::system_call_id >( 20003 ) ); - set_syscall_op3.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op3.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x03 ); + // reversion + koinos::protocol::set_system_call_operation set_syscall_op3; + set_syscall_op3.set_call_id( std::underlying_type_t< chain::system_call_id >( 20'003 ) ); + set_syscall_op3.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op3.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x03 ); - // write - koinos::protocol::set_system_call_operation set_syscall_op4; - set_syscall_op4.set_call_id( std::underlying_type_t< chain::system_call_id >( 20004 ) ); - set_syscall_op4.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); - set_syscall_op4.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x04 ); + // write + koinos::protocol::set_system_call_operation set_syscall_op4; + set_syscall_op4.set_call_id( std::underlying_type_t< chain::system_call_id >( 20'004 ) ); + set_syscall_op4.mutable_target()->mutable_system_call_bundle()->set_contract_id( upload_op.contract_id() ); + set_syscall_op4.mutable_target()->mutable_system_call_bundle()->set_entry_point( 0x04 ); - tx.Clear(); - *tx.add_operations()->mutable_set_system_contract() = set_system_op; - *tx.add_operations()->mutable_set_system_call() = set_syscall_op; - *tx.add_operations()->mutable_set_system_call() = set_syscall_op2; - *tx.add_operations()->mutable_set_system_call() = set_syscall_op3; - *tx.add_operations()->mutable_set_system_call() = set_syscall_op4; + tx.Clear(); + *tx.add_operations()->mutable_set_system_contract() = set_system_op; + *tx.add_operations()->mutable_set_system_call() = set_syscall_op; + *tx.add_operations()->mutable_set_system_call() = set_syscall_op2; + *tx.add_operations()->mutable_set_system_call() = set_syscall_op3; + *tx.add_operations()->mutable_set_system_call() = set_syscall_op4; - nonce_value.set_uint64_value( 1 ); + nonce_value.set_uint64_value( 1 ); - tx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); - tx.mutable_header()->set_rc_limit( 10'000'000 ); - tx.mutable_header()->set_chain_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ) ) ); - tx.mutable_header()->set_payer( _block_signing_private_key.get_public_key().to_address_bytes() ); + tx.mutable_header()->set_nonce( util::converter::as< std::string >( nonce_value ) ); + tx.mutable_header()->set_rc_limit( 10'000'000 ); + tx.mutable_header()->set_chain_id( + util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, _genesis_data ) ) ); + tx.mutable_header()->set_payer( _block_signing_private_key.get_public_key().to_address_bytes() ); - set_transaction_merkle_roots( tx, koinos::crypto::multicodec::sha2_256 ); + set_transaction_merkle_roots( tx, koinos::crypto::multicodec::sha2_256 ); - sign_transaction( tx, _block_signing_private_key ); + sign_transaction( tx, _block_signing_private_key ); - *block_req.mutable_block()->add_transactions() = tx; + *block_req.mutable_block()->add_transactions() = tx; - set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); - block_req.mutable_block()->set_id( util::converter::as< std::string >( crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); - sign_block( *block_req.mutable_block(), _block_signing_private_key ); + set_block_merkle_roots( *block_req.mutable_block(), koinos::crypto::multicodec::sha2_256 ); + block_req.mutable_block()->set_id( util::converter::as< std::string >( + crypto::hash( koinos::crypto::multicodec::sha2_256, block_req.block().header() ) ) ); + sign_block( *block_req.mutable_block(), _block_signing_private_key ); - block_response = _controller.submit_block( block_req ); - for ( const auto& log : block_response.receipt().transaction_receipts(0).logs() ) - { - LOG(info) << log; - } + block_response = _controller.submit_block( block_req ); + for( const auto& log: block_response.receipt().transaction_receipts( 0 ).logs() ) + { + LOG( info ) << log; + } + BOOST_TEST_MESSAGE( "System call echo" ); - BOOST_TEST_MESSAGE( "System call echo" ); + koinos::chain::error_data arg_errdata, errdata; + *arg_errdata.mutable_message() = "audentes fortuna iuvat"; - koinos::chain::error_data arg_errdata, errdata; - *arg_errdata.mutable_message() = "audentes fortuna iuvat"; + syscall_req.set_id( 20'001 ); + *syscall_req.mutable_args() = arg_errdata.SerializeAsString(); - syscall_req.set_id( 20001 ); - *syscall_req.mutable_args() = arg_errdata.SerializeAsString(); + syscall_response = _controller.invoke_system_call( syscall_req ); - syscall_response = _controller.invoke_system_call( syscall_req ); + errdata.ParseFromString( syscall_response.value() ); - errdata.ParseFromString( syscall_response.value() ); + BOOST_REQUIRE_EQUAL( errdata.message(), arg_errdata.message() ); - BOOST_REQUIRE_EQUAL( errdata.message(), arg_errdata.message() ); + BOOST_TEST_MESSAGE( "System call failure" ); - BOOST_TEST_MESSAGE( "System call failure" ); + syscall_req.set_id( 20'002 ); - syscall_req.set_id( 20002 ); - - try - { + try + { _controller.invoke_system_call( syscall_req ); BOOST_FAIL( "Expected failure exception to be thrown" ); - } - catch ( const koinos::chain::failure_exception& e ) - { + } + catch( const koinos::chain::failure_exception& e ) + { BOOST_REQUIRE_EQUAL( e.get_code(), koinos::chain::failure ); BOOST_REQUIRE_EQUAL( e.get_message(), "failure" ); - } - catch ( ... ) - { + } + catch( ... ) + { BOOST_FAIL( "An unexpected exception was thrown" ); - } + } - BOOST_TEST_MESSAGE( "System call reversion" ); + BOOST_TEST_MESSAGE( "System call reversion" ); - syscall_req.set_id( 20003 ); + syscall_req.set_id( 20'003 ); - try - { + try + { _controller.invoke_system_call( syscall_req ); BOOST_FAIL( "Expected reversion exception to be thrown" ); - } - catch ( const koinos::chain::reversion_exception& e ) - { + } + catch( const koinos::chain::reversion_exception& e ) + { BOOST_REQUIRE_EQUAL( e.get_code(), koinos::chain::reversion ); BOOST_REQUIRE_EQUAL( e.get_message(), "reversion" ); - } - catch ( ... ) - { + } + catch( ... ) + { BOOST_FAIL( "An unexpected exception was thrown" ); - } + } - BOOST_TEST_MESSAGE( "System call write" ); + BOOST_TEST_MESSAGE( "System call write" ); - syscall_req.set_id( 20004 ); + syscall_req.set_id( 20'004 ); - try - { + try + { _controller.invoke_system_call( syscall_req ); BOOST_FAIL( "Expected reversion exception to be thrown" ); - } - catch ( const koinos::chain::reversion_exception& e ) - { + } + catch( const koinos::chain::reversion_exception& e ) + { BOOST_REQUIRE_EQUAL( e.get_code(), koinos::chain::read_only_context ); BOOST_REQUIRE_EQUAL( e.get_message(), "cannot put object during read only call" ); - } - catch ( ... ) - { + } + catch( ... ) + { BOOST_FAIL( "An unexpected exception was thrown" ); - } - -} KOINOS_CATCH_LOG_AND_RETHROW(info) } + } + } + KOINOS_CATCH_LOG_AND_RETHROW( info ) +} BOOST_AUTO_TEST_SUITE_END() From 6b9d54614ee91f1a8fd6acc6ccfe102f50975079 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Mon, 4 Mar 2024 13:27:31 +0100 Subject: [PATCH 05/25] Avoid linting a false positive, add information regarding the issue --- src/koinos/chain/proto_utils.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/koinos/chain/proto_utils.cpp b/src/koinos/chain/proto_utils.cpp index 518453df..77c8faf5 100644 --- a/src/koinos/chain/proto_utils.cpp +++ b/src/koinos/chain/proto_utils.cpp @@ -176,7 +176,13 @@ value_type get_nested_field_value( execution_context& context, ( "type", parent_message.GetTypeName() ) ); std::vector< std::string > field_path; - boost::split( field_path, field_name, boost::is_any_of( "." ) ); + + // The following line fails static analysis and is reportedly a false-positive. + // See the following issue reports: + // * https://github.com/boostorg/algorithm/issues/63 + // * https://bugs.llvm.org/show_bug.cgi?id=44247 + // * https://bugs.llvm.org/show_bug.cgi?id=41141 + boost::split( field_path, field_name, boost::is_any_of( "." ) ); // NOLINT const google::protobuf::Reflection* reflection = parent_message.GetReflection(); const google::protobuf::Message* message = &parent_message; From 735b2c7e9ab053b82c7af93d182c8628a0a43c45 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Mon, 4 Mar 2024 14:45:48 +0100 Subject: [PATCH 06/25] Move test wasm into the tools directory --- {wasm => tools/wasm}/build.sh | 0 {wasm => tools/wasm}/tests/authorize.cpp | 0 {wasm => tools/wasm}/tests/benchmark.cpp | 0 {wasm => tools/wasm}/tests/build_koinos_contract.sh | 0 {wasm => tools/wasm}/tests/call.cpp | 0 {wasm => tools/wasm}/tests/contract_return.cpp | 0 {wasm => tools/wasm}/tests/db_write.cpp | 0 {wasm => tools/wasm}/tests/echo.cpp | 0 {wasm => tools/wasm}/tests/empty_contract.cpp | 0 {wasm => tools/wasm}/tests/exit.cpp | 0 {wasm => tools/wasm}/tests/forever.cpp | 0 {wasm => tools/wasm}/tests/get_arguments_override.cpp | 0 {wasm => tools/wasm}/tests/hello.cpp | 0 {wasm => tools/wasm}/tests/null_bytes_written.cpp | 0 {wasm => tools/wasm}/tests/stack/call_contract.cpp | 0 {wasm => tools/wasm}/tests/stack/call_system_call.cpp | 0 {wasm => tools/wasm}/tests/stack/call_system_call2.cpp | 0 {wasm => tools/wasm}/tests/stack/stack_assertion.cpp | 0 {wasm => tools/wasm}/tests/stack/system_from_system.cpp | 0 {wasm => tools/wasm}/tests/stack/system_from_user.cpp | 0 {wasm => tools/wasm}/tests/stack/user_from_system.cpp | 0 {wasm => tools/wasm}/tests/stack/user_from_user.cpp | 0 {wasm => tools/wasm}/tests/syscall_override.cpp | 0 {wasm => tools/wasm}/tests/syscall_rpc.cpp | 0 24 files changed, 0 insertions(+), 0 deletions(-) rename {wasm => tools/wasm}/build.sh (100%) rename {wasm => tools/wasm}/tests/authorize.cpp (100%) rename {wasm => tools/wasm}/tests/benchmark.cpp (100%) rename {wasm => tools/wasm}/tests/build_koinos_contract.sh (100%) rename {wasm => tools/wasm}/tests/call.cpp (100%) rename {wasm => tools/wasm}/tests/contract_return.cpp (100%) rename {wasm => tools/wasm}/tests/db_write.cpp (100%) rename {wasm => tools/wasm}/tests/echo.cpp (100%) rename {wasm => tools/wasm}/tests/empty_contract.cpp (100%) rename {wasm => tools/wasm}/tests/exit.cpp (100%) rename {wasm => tools/wasm}/tests/forever.cpp (100%) rename {wasm => tools/wasm}/tests/get_arguments_override.cpp (100%) rename {wasm => tools/wasm}/tests/hello.cpp (100%) rename {wasm => tools/wasm}/tests/null_bytes_written.cpp (100%) rename {wasm => tools/wasm}/tests/stack/call_contract.cpp (100%) rename {wasm => tools/wasm}/tests/stack/call_system_call.cpp (100%) rename {wasm => tools/wasm}/tests/stack/call_system_call2.cpp (100%) rename {wasm => tools/wasm}/tests/stack/stack_assertion.cpp (100%) rename {wasm => tools/wasm}/tests/stack/system_from_system.cpp (100%) rename {wasm => tools/wasm}/tests/stack/system_from_user.cpp (100%) rename {wasm => tools/wasm}/tests/stack/user_from_system.cpp (100%) rename {wasm => tools/wasm}/tests/stack/user_from_user.cpp (100%) rename {wasm => tools/wasm}/tests/syscall_override.cpp (100%) rename {wasm => tools/wasm}/tests/syscall_rpc.cpp (100%) diff --git a/wasm/build.sh b/tools/wasm/build.sh similarity index 100% rename from wasm/build.sh rename to tools/wasm/build.sh diff --git a/wasm/tests/authorize.cpp b/tools/wasm/tests/authorize.cpp similarity index 100% rename from wasm/tests/authorize.cpp rename to tools/wasm/tests/authorize.cpp diff --git a/wasm/tests/benchmark.cpp b/tools/wasm/tests/benchmark.cpp similarity index 100% rename from wasm/tests/benchmark.cpp rename to tools/wasm/tests/benchmark.cpp diff --git a/wasm/tests/build_koinos_contract.sh b/tools/wasm/tests/build_koinos_contract.sh similarity index 100% rename from wasm/tests/build_koinos_contract.sh rename to tools/wasm/tests/build_koinos_contract.sh diff --git a/wasm/tests/call.cpp b/tools/wasm/tests/call.cpp similarity index 100% rename from wasm/tests/call.cpp rename to tools/wasm/tests/call.cpp diff --git a/wasm/tests/contract_return.cpp b/tools/wasm/tests/contract_return.cpp similarity index 100% rename from wasm/tests/contract_return.cpp rename to tools/wasm/tests/contract_return.cpp diff --git a/wasm/tests/db_write.cpp b/tools/wasm/tests/db_write.cpp similarity index 100% rename from wasm/tests/db_write.cpp rename to tools/wasm/tests/db_write.cpp diff --git a/wasm/tests/echo.cpp b/tools/wasm/tests/echo.cpp similarity index 100% rename from wasm/tests/echo.cpp rename to tools/wasm/tests/echo.cpp diff --git a/wasm/tests/empty_contract.cpp b/tools/wasm/tests/empty_contract.cpp similarity index 100% rename from wasm/tests/empty_contract.cpp rename to tools/wasm/tests/empty_contract.cpp diff --git a/wasm/tests/exit.cpp b/tools/wasm/tests/exit.cpp similarity index 100% rename from wasm/tests/exit.cpp rename to tools/wasm/tests/exit.cpp diff --git a/wasm/tests/forever.cpp b/tools/wasm/tests/forever.cpp similarity index 100% rename from wasm/tests/forever.cpp rename to tools/wasm/tests/forever.cpp diff --git a/wasm/tests/get_arguments_override.cpp b/tools/wasm/tests/get_arguments_override.cpp similarity index 100% rename from wasm/tests/get_arguments_override.cpp rename to tools/wasm/tests/get_arguments_override.cpp diff --git a/wasm/tests/hello.cpp b/tools/wasm/tests/hello.cpp similarity index 100% rename from wasm/tests/hello.cpp rename to tools/wasm/tests/hello.cpp diff --git a/wasm/tests/null_bytes_written.cpp b/tools/wasm/tests/null_bytes_written.cpp similarity index 100% rename from wasm/tests/null_bytes_written.cpp rename to tools/wasm/tests/null_bytes_written.cpp diff --git a/wasm/tests/stack/call_contract.cpp b/tools/wasm/tests/stack/call_contract.cpp similarity index 100% rename from wasm/tests/stack/call_contract.cpp rename to tools/wasm/tests/stack/call_contract.cpp diff --git a/wasm/tests/stack/call_system_call.cpp b/tools/wasm/tests/stack/call_system_call.cpp similarity index 100% rename from wasm/tests/stack/call_system_call.cpp rename to tools/wasm/tests/stack/call_system_call.cpp diff --git a/wasm/tests/stack/call_system_call2.cpp b/tools/wasm/tests/stack/call_system_call2.cpp similarity index 100% rename from wasm/tests/stack/call_system_call2.cpp rename to tools/wasm/tests/stack/call_system_call2.cpp diff --git a/wasm/tests/stack/stack_assertion.cpp b/tools/wasm/tests/stack/stack_assertion.cpp similarity index 100% rename from wasm/tests/stack/stack_assertion.cpp rename to tools/wasm/tests/stack/stack_assertion.cpp diff --git a/wasm/tests/stack/system_from_system.cpp b/tools/wasm/tests/stack/system_from_system.cpp similarity index 100% rename from wasm/tests/stack/system_from_system.cpp rename to tools/wasm/tests/stack/system_from_system.cpp diff --git a/wasm/tests/stack/system_from_user.cpp b/tools/wasm/tests/stack/system_from_user.cpp similarity index 100% rename from wasm/tests/stack/system_from_user.cpp rename to tools/wasm/tests/stack/system_from_user.cpp diff --git a/wasm/tests/stack/user_from_system.cpp b/tools/wasm/tests/stack/user_from_system.cpp similarity index 100% rename from wasm/tests/stack/user_from_system.cpp rename to tools/wasm/tests/stack/user_from_system.cpp diff --git a/wasm/tests/stack/user_from_user.cpp b/tools/wasm/tests/stack/user_from_user.cpp similarity index 100% rename from wasm/tests/stack/user_from_user.cpp rename to tools/wasm/tests/stack/user_from_user.cpp diff --git a/wasm/tests/syscall_override.cpp b/tools/wasm/tests/syscall_override.cpp similarity index 100% rename from wasm/tests/syscall_override.cpp rename to tools/wasm/tests/syscall_override.cpp diff --git a/wasm/tests/syscall_rpc.cpp b/tools/wasm/tests/syscall_rpc.cpp similarity index 100% rename from wasm/tests/syscall_rpc.cpp rename to tools/wasm/tests/syscall_rpc.cpp From b9219bb877d601f1f4783cf6dc7b372efa5f2ae7 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Mon, 4 Mar 2024 17:16:05 +0100 Subject: [PATCH 07/25] Fix indentation of test CMakeLists.txt --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7544c0fc..b42fc37a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -35,6 +35,6 @@ koinos_add_format(TARGET chain_tests) koinos_coverage( EXECUTABLE - chain_tests + chain_tests EXCLUDE "tests/*") From c78de8b9b470c863c770bdcae70d21dcd2a5a97c Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Mon, 4 Mar 2024 17:16:15 +0100 Subject: [PATCH 08/25] Update README.md --- README.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5c1b7154..1f49e9a1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,80 @@ # Koinos Chain -[![Build Status](https://app.travis-ci.com/koinos/koinos-chain.svg?branch=master)](https://app.travis-ci.com/koinos/koinos-chain) [![Coverage Status](https://coveralls.io/repos/github/koinos/koinos-chain/badge.svg?branch=master)](https://coveralls.io/github/koinos/koinos-chain?branch=master) -The home of Koinos. A next generation, scalable, smart contract platform. More info to come! +This program implements the chain microservice, the enforcement of consensus, for the Koinos Blockchain Framework. + +### Project Structure + +This project's structure follows the [Pitchfork](https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs) specification. + +``` +├── build/ # An ephemeral directory for building the project. Not checked in, but excluded via .gitignore. +├── include/ # Contains all public headers for the Koinos Chain. +├── src/ # Contains all source code and private headers for Koinos Chain. +├── tools/ # Contains additional tooling for Koinos Chain, primarily WASM test code. +└── tests/ # Contains tests for Koinos Chain. +``` + +### Building + +Koinos Chain's build process is configured using CMake. Additionally, all dependencies are managed through Hunter, a CMake drive package manager for C/C++. This means that all dependencies are downloaded and built during configuration rather than relying on system installed libraries. + +``` +mkdir build +cd build +cmake -D CMAKE_BUILD_TYPE=Release .. +cmake --build . --config Release --parallel +``` + +You can optionally run static analysis with Clang-Tidy during the build process. Static analysis is checked in CI and is required to pass before merging pull requests. + +``` +cmake -D CMAKE_BUILD_TYPE=Debug -D STATIC_ANALYSIS=ON .. +``` + +### Testing + +Tests are built by default as target `chain_tests`. You can building them specifically with: + +``` +cmake --build . --config Release --parallel --target chain_tests +``` + +Tests can be invoked from the tests directiory within the build directory. + +``` +cd tests +./chain_tests +``` + +Tests can also be ran in parallel using CTest. + +``` +cd tests +ctest -j +``` + +You can also generate a coverage report. + +``` +cmake -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON .. +cmake --build . --config Debug --parallel 3 --target coverage +``` + +You can run tests in different sanitizer profiles. Those profiles are None (Default), Address, Stack, and Thread. Currently, these are only known to work with clang, but may work with gcc with additional environment configuration. + +``` +cmake -D CMAKE_BUILD_TYPE=Debug -D SANITIZER=Address .. +cmake --build . --config Debug --parallel --target chain_tests +cd tests +ctest -j +``` + +### Formatting + +Formatting of the source code is enforced by ClangFormat. If ClangFormat is installed, build targets will be automatically generated. You can review the library's code style by uploading the included `.clang-format` to https://clang-format-configurator.site/. + +You can build `format.check` to check formattting and `format.fix` to attempt to automatically fix formatting. It is recommended to check and manually fix formatting as automatic formatting can unintentionally change code. + +### Contributing + +As an open source project, contributions are welcome and appreciated. Before contributing, please read our [Contribution Guidelines](CONTRIBUTING.md). From 00f6df89712538850a665e8e35a00b77c860059f Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Mon, 4 Mar 2024 20:56:11 +0100 Subject: [PATCH 09/25] Bump Koinos CMake, add Docker and integration test builds, update Dockerfile --- .travis.yml | 33 +++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- Dockerfile | 28 ++++++++++++---------------- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab2dc5e9..ebae3942 100644 --- a/.travis.yml +++ b/.travis.yml @@ -110,6 +110,39 @@ jobs: - cd tests - ctest -j3 --output-on-failure + - name: "Docker and Integration Tests" + os: linux + dist: jammy + env: + - DOCKER_ORG=koinos + - DOCKER_REPO=$TRAVIS_REPO_SLUG + - TAG=`if [ $TRAVIS_BRANCH == "main" ]; then echo -n latest; else echo -n $TRAVIS_BRANCH; fi` + - CHAIN_TAG=$TAG + install: + - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + - sudo chmod +x /usr/local/bin/docker-compose + - eval "$(gimme 1.18.1)" + - source ~/.gimme/envs/go1.18.1.env + - git clone https://github.com/koinos/koinos-integration-tests.git + - pushd koinos-integration-tests + - go get ./... + - popd + before_script: + - cp -R ~/.ccache ./ccache + - docker build . -t build --target builder + - docker build . -t $DOCKER_ORG/$DOCKER_REPO:$TAG + - docker run -td --name extract-ccache build + - docker cp extract-ccache:/build/.ccache ~/.ccache + script: + - pushd koinos-integration-tests + #- ./run.sh + after_success: + - | + if [ "$TRAVIS_PULL_REQUEST_BRANCH" == "" ]; then + echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin + docker push $DOCKER_ORG/$DOCKER_REPO:$TAG + fi + notifications: slack: secure: jA1UWnXRjaqTxqPDNhQhZXAk7mC7xLAuI6NLSFPh+ybYv+goM1wefZp6IkdX5u1EHB0UCF4jbmczQxjVEhvBCBx8sy9DmxFICfjDtbsEnHksRsROpKPePF4DTwZMsjKn5+oPF7fBHr0ShzpdcZ7rmbFWQnfXI6Bin6znDV6xd8XNV5jI26FAaL0eIQd/+bjKHpDCDRzu2MJY44+Awpf0tbdwfWqj9EZ9SHl1wMsyvp1BSOlOtErEiv0EUWjmM1VTE2nPYzn2N7YoRv6nwtTpqJ+Y1xgm0mJ0DtV39xyo4+AhyxJAoJqkjkrP5AIepUyz+1o+m/4j/98FjfTi3JugMOzWAJqiAyWLVJG74W7Zs3h+M+W+eRSDhMfybgwEWz2+IFrP0Re9C7XI+KGLLAZ734lzESNKs6grisIRnk226YawffeDMJ/zT1uyWs3VIw9TuXI/0SnSnE+Gno0Xbho37jTT1lqRHsrMRzbC44rF+dBqMJE+m70naHj9MrR+0fHNGct19X73nDadIJeJNlMdV5OgddxLvCZL7RsD8c1MDQDWrASfConS6P/TPVsYeLxia3uSl8NoXwSRX7+j91bQnI0YFzpgKyJdYE2WtNJULgqOTftKr+7orzMqMqjBNdlRhsB7Yh6pepKWbLX1N1N3UoDhtia9JoWz04vQcq2l42w= diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e4fbe36..7d33aa88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ include(FetchContent) FetchContent_Declare( koinos_cmake GIT_REPOSITORY https://github.com/koinos/koinos-cmake.git - GIT_TAG bf62292ba053f8871dc8aefd524ca8037317a166) + GIT_TAG 113f07791c56b292bbcb10164b759daa68a74121) FetchContent_MakeAvailable(koinos_cmake) include("${koinos_cmake_SOURCE_DIR}/Koinos.cmake") diff --git a/Dockerfile b/Dockerfile index 31194347..339ee49f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:latest as builder +FROM alpine:3.18 as builder RUN apk update && \ apk add \ @@ -10,22 +10,18 @@ RUN apk update && \ libgmpxx \ cmake \ make \ - git \ - perl \ - python3 \ - py3-pip \ - py3-setuptools && \ - pip3 install --user dataclasses_json Jinja2 importlib_resources pluginbase gitpython + git -ADD . /koinos-chain -WORKDIR /koinos-chain +ADD . /build +WORKDIR /build -ENV CC=/usr/lib/ccache/bin/gcc -ENV CXX=/usr/lib/ccache/bin/g++ +ENV CC=gcc +ENV CXX=g++ +ENV CMAKE_C_COMPILER_LAUNCHER=ccache +ENV CMAKE_CXX_COMPILER_LAUNCHER=ccache +ENV CCACHE_DIR /build/.ccache -RUN mkdir -p /koinos-chain/.ccache && \ - ln -s /koinos-chain/.ccache $HOME/.ccache && \ - git submodule update --init --recursive && \ +RUN git submodule update --init --recursive && \ cmake -DCMAKE_BUILD_TYPE=Release . && \ cmake --build . --config Release --parallel @@ -34,5 +30,5 @@ RUN apk update && \ apk add \ musl \ libstdc++ -COPY --from=builder /koinos-chain/programs/koinos_chain/koinos_chain /usr/local/bin -ENTRYPOINT [ "/usr/local/bin/koinos_chain" ] +COPY --from=builder /build/src/koinos_chain /usr/local/bin +ENTRYPOINT [ "/usr/local/bin/koinos_chain" ] \ No newline at end of file From c24b2a7bc436adcb9963500dfd696f160b9fdf2c Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Mon, 4 Mar 2024 18:52:13 -0700 Subject: [PATCH 10/25] Run docker info --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ebae3942..aac93452 100644 --- a/.travis.yml +++ b/.travis.yml @@ -129,6 +129,7 @@ jobs: - popd before_script: - cp -R ~/.ccache ./ccache + - docker info - docker build . -t build --target builder - docker build . -t $DOCKER_ORG/$DOCKER_REPO:$TAG - docker run -td --name extract-ccache build From e6fda37dea0dc30927ce1319a5d00bbcd556c239 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Mon, 4 Mar 2024 21:38:53 -0700 Subject: [PATCH 11/25] Limit parallelism in docker build --- .travis.yml | 1 - Dockerfile | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index aac93452..ebae3942 100644 --- a/.travis.yml +++ b/.travis.yml @@ -129,7 +129,6 @@ jobs: - popd before_script: - cp -R ~/.ccache ./ccache - - docker info - docker build . -t build --target builder - docker build . -t $DOCKER_ORG/$DOCKER_REPO:$TAG - docker run -td --name extract-ccache build diff --git a/Dockerfile b/Dockerfile index 339ee49f..f40bf22d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,7 @@ ENV CCACHE_DIR /build/.ccache RUN git submodule update --init --recursive && \ cmake -DCMAKE_BUILD_TYPE=Release . && \ - cmake --build . --config Release --parallel + cmake --build . --config Release --parallel 3 FROM alpine:latest RUN apk update && \ From 58381863245a773209b62a1e2069bd4eb40dd1fd Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 15:27:14 +0100 Subject: [PATCH 12/25] Use TRAVIS_REPO_SLUG for Docker build --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ebae3942..de1fa1ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -114,8 +114,6 @@ jobs: os: linux dist: jammy env: - - DOCKER_ORG=koinos - - DOCKER_REPO=$TRAVIS_REPO_SLUG - TAG=`if [ $TRAVIS_BRANCH == "main" ]; then echo -n latest; else echo -n $TRAVIS_BRANCH; fi` - CHAIN_TAG=$TAG install: @@ -130,7 +128,7 @@ jobs: before_script: - cp -R ~/.ccache ./ccache - docker build . -t build --target builder - - docker build . -t $DOCKER_ORG/$DOCKER_REPO:$TAG + - docker build . -t $TRAVIS_REPO_SLUG:$TAG - docker run -td --name extract-ccache build - docker cp extract-ccache:/build/.ccache ~/.ccache script: @@ -140,7 +138,7 @@ jobs: - | if [ "$TRAVIS_PULL_REQUEST_BRANCH" == "" ]; then echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin - docker push $DOCKER_ORG/$DOCKER_REPO:$TAG + docker push $TRAVIS_REPO_SLUG:$TAG fi notifications: From 1c6afecf529698d4443a5488324bc9f10631346c Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 15:59:15 +0100 Subject: [PATCH 13/25] Check for master branch instead of main --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index de1fa1ee..48361e57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -114,7 +114,7 @@ jobs: os: linux dist: jammy env: - - TAG=`if [ $TRAVIS_BRANCH == "main" ]; then echo -n latest; else echo -n $TRAVIS_BRANCH; fi` + - TAG=`if [ $TRAVIS_BRANCH == "master" ]; then echo -n latest; else echo -n $TRAVIS_BRANCH; fi` - CHAIN_TAG=$TAG install: - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose From d6733930103d9d81879850c553e289f11c44f3cb Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 16:01:02 +0100 Subject: [PATCH 14/25] Use docker service provided by travis --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 48361e57..38965f17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ language: c++ +services: + - docker + cache: ccache: true @@ -117,8 +120,6 @@ jobs: - TAG=`if [ $TRAVIS_BRANCH == "master" ]; then echo -n latest; else echo -n $TRAVIS_BRANCH; fi` - CHAIN_TAG=$TAG install: - - sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - - sudo chmod +x /usr/local/bin/docker-compose - eval "$(gimme 1.18.1)" - source ~/.gimme/envs/go1.18.1.env - git clone https://github.com/koinos/koinos-integration-tests.git From c96acd02301e2e1f797b096d36215ac85ae6afcf Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 17:22:38 +0100 Subject: [PATCH 15/25] Specify golang and docker for integration test builds --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 38965f17..7a6766db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,5 @@ language: c++ -services: - - docker - cache: ccache: true @@ -116,12 +113,15 @@ jobs: - name: "Docker and Integration Tests" os: linux dist: jammy + language: go + go: + - 1.18.x + services: + - docker env: - TAG=`if [ $TRAVIS_BRANCH == "master" ]; then echo -n latest; else echo -n $TRAVIS_BRANCH; fi` - CHAIN_TAG=$TAG install: - - eval "$(gimme 1.18.1)" - - source ~/.gimme/envs/go1.18.1.env - git clone https://github.com/koinos/koinos-integration-tests.git - pushd koinos-integration-tests - go get ./... From 083f2ef9547db765182e2dacee26a754d242b5aa Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 17:53:05 +0100 Subject: [PATCH 16/25] Try grabbing golang without golang language --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7a6766db..8b743324 100644 --- a/.travis.yml +++ b/.travis.yml @@ -113,7 +113,6 @@ jobs: - name: "Docker and Integration Tests" os: linux dist: jammy - language: go go: - 1.18.x services: From 84c012b8477a424b741b7ecc5db530c6f68e070f Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 18:19:49 +0100 Subject: [PATCH 17/25] Use cleaner conditional for pull requests, print golang version --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8b743324..c5f3fd43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -123,6 +123,7 @@ jobs: install: - git clone https://github.com/koinos/koinos-integration-tests.git - pushd koinos-integration-tests + - go version - go get ./... - popd before_script: @@ -136,7 +137,7 @@ jobs: #- ./run.sh after_success: - | - if [ "$TRAVIS_PULL_REQUEST_BRANCH" == "" ]; then + if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin docker push $TRAVIS_REPO_SLUG:$TAG fi From c3422dcb26ae3cbc7c14f59fa301d6963bbd9171 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 18:35:26 +0100 Subject: [PATCH 18/25] Request golang 1.19 to test --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c5f3fd43..4876db68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -114,7 +114,7 @@ jobs: os: linux dist: jammy go: - - 1.18.x + - 1.19.x services: - docker env: From df7104db4adeb3ca9eaac3edd1d6093c09977ff8 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 18:55:27 +0100 Subject: [PATCH 19/25] Use package manager version of golang --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4876db68..73c41fb3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ addons: - ruby - gcc-12 - g++-12 + - golang-go env: global: @@ -113,8 +114,6 @@ jobs: - name: "Docker and Integration Tests" os: linux dist: jammy - go: - - 1.19.x services: - docker env: @@ -123,7 +122,6 @@ jobs: install: - git clone https://github.com/koinos/koinos-integration-tests.git - pushd koinos-integration-tests - - go version - go get ./... - popd before_script: From 45203ea5e8bb3ae28310198eedff7422ff359b84 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Tue, 5 Mar 2024 19:11:29 +0100 Subject: [PATCH 20/25] Remove gitmodules --- .gitmodules | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29b..00000000 From 326b2889a1fb1595a1281a968b9220d7c7a13233 Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Wed, 6 Mar 2024 19:30:33 +0100 Subject: [PATCH 21/25] Move all headers to source directory --- CMakeLists.txt | 2 +- README.md | 1 - src/CMakeLists.txt | 52 +++++++------------ {include => src}/koinos/chain/chronicler.hpp | 0 {include => src}/koinos/chain/constants.hpp | 0 {include => src}/koinos/chain/controller.hpp | 0 {include => src}/koinos/chain/exceptions.hpp | 0 .../koinos/chain/execution_context.hpp | 0 {include => src}/koinos/chain/host_api.hpp | 0 {include => src}/koinos/chain/indexer.hpp | 0 {include => src}/koinos/chain/proto_utils.hpp | 0 .../koinos/chain/resource_meter.hpp | 0 {include => src}/koinos/chain/session.hpp | 0 {include => src}/koinos/chain/state.hpp | 0 .../koinos/chain/system_calls.hpp | 0 .../koinos/chain/thunk_dispatcher.hpp | 0 {include => src}/koinos/chain/thunk_utils.hpp | 0 {include => src}/koinos/chain/types.hpp | 0 .../koinos/vm_manager/exceptions.hpp | 0 .../koinos/vm_manager/fizzy/exceptions.hpp | 0 .../vm_manager/fizzy/fizzy_vm_backend.hpp | 0 .../koinos/vm_manager/fizzy/module_cache.hpp | 0 .../koinos/vm_manager/host_api.hpp | 0 .../koinos/vm_manager/vm_backend.hpp | 0 24 files changed, 21 insertions(+), 34 deletions(-) rename {include => src}/koinos/chain/chronicler.hpp (100%) rename {include => src}/koinos/chain/constants.hpp (100%) rename {include => src}/koinos/chain/controller.hpp (100%) rename {include => src}/koinos/chain/exceptions.hpp (100%) rename {include => src}/koinos/chain/execution_context.hpp (100%) rename {include => src}/koinos/chain/host_api.hpp (100%) rename {include => src}/koinos/chain/indexer.hpp (100%) rename {include => src}/koinos/chain/proto_utils.hpp (100%) rename {include => src}/koinos/chain/resource_meter.hpp (100%) rename {include => src}/koinos/chain/session.hpp (100%) rename {include => src}/koinos/chain/state.hpp (100%) rename {include => src}/koinos/chain/system_calls.hpp (100%) rename {include => src}/koinos/chain/thunk_dispatcher.hpp (100%) rename {include => src}/koinos/chain/thunk_utils.hpp (100%) rename {include => src}/koinos/chain/types.hpp (100%) rename {include => src}/koinos/vm_manager/exceptions.hpp (100%) rename {include => src}/koinos/vm_manager/fizzy/exceptions.hpp (100%) rename {include => src}/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp (100%) rename {include => src}/koinos/vm_manager/fizzy/module_cache.hpp (100%) rename {include => src}/koinos/vm_manager/host_api.hpp (100%) rename {include => src}/koinos/vm_manager/vm_backend.hpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d33aa88..62f5abfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ include("${koinos_cmake_SOURCE_DIR}/Koinos.cmake") project(koinos_chain VERSION 1.2.0 - DESCRIPTION "The Koinos chain" + DESCRIPTION "Koinos Chain microservice" LANGUAGES CXX C) koinos_define_version() diff --git a/README.md b/README.md index 1f49e9a1..eedc8676 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ This project's structure follows the [Pitchfork](https://api.csswg.org/bikeshed/ ``` ├── build/ # An ephemeral directory for building the project. Not checked in, but excluded via .gitignore. -├── include/ # Contains all public headers for the Koinos Chain. ├── src/ # Contains all source code and private headers for Koinos Chain. ├── tools/ # Contains additional tooling for Koinos Chain, primarily WASM test code. └── tests/ # Contains tests for Koinos Chain. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 599838ca..49c98bdb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,3 @@ -# libkoinos_chain - add_library(chain koinos/chain/chronicler.cpp koinos/chain/controller.cpp @@ -13,22 +11,21 @@ add_library(chain koinos/chain/system_calls.cpp koinos/chain/thunk_dispatcher.cpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/chronicler.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/constants.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/controller.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/exceptions.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/execution_context.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/host_api.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/indexer.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/proto_utils.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/resource_meter.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/session.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/state.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/system_calls.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/thunk_dispatcher.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/thunk_utils.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/chain/types.hpp -) + koinos/chain/chronicler.hpp + koinos/chain/constants.hpp + koinos/chain/controller.hpp + koinos/chain/exceptions.hpp + koinos/chain/execution_context.hpp + koinos/chain/host_api.hpp + koinos/chain/indexer.hpp + koinos/chain/proto_utils.hpp + koinos/chain/resource_meter.hpp + koinos/chain/session.hpp + koinos/chain/state.hpp + koinos/chain/system_calls.hpp + koinos/chain/thunk_dispatcher.hpp + koinos/chain/thunk_utils.hpp + koinos/chain/types.hpp) target_link_libraries( chain @@ -44,23 +41,19 @@ target_link_libraries( target_include_directories( chain PUBLIC - $ - $) + $) koinos_add_format(TARGET chain) -# libkoinos_vm_manager - add_library(vm_manager koinos/vm_manager/host_api.cpp koinos/vm_manager/vm_backend.cpp koinos/vm_manager/fizzy/fizzy_vm_backend.cpp koinos/vm_manager/fizzy/module_cache.cpp - ${PROJECT_SOURCE_DIR}/include/koinos/vm_manager/fizzy/exceptions.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp - ${PROJECT_SOURCE_DIR}/include/koinos/vm_manager/fizzy/module_cache.hpp -) + koinos/vm_manager/fizzy/exceptions.hpp + koinos/vm_manager/fizzy/fizzy_vm_backend.hpp + koinos/vm_manager/fizzy/module_cache.hpp) target_link_libraries( vm_manager @@ -73,13 +66,10 @@ target_link_libraries( target_include_directories( vm_manager PUBLIC - $ - $) + $) koinos_add_format(TARGET vm_manager) -# koinos_chain - add_executable(koinos_chain koinos_chain.cpp) target_link_libraries( koinos_chain @@ -90,8 +80,6 @@ target_link_libraries( koinos_add_format(TARGET koinos_chain) -# koinos_vm_driver - add_executable(koinos_vm_driver koinos_vm_driver.cpp) target_link_libraries( koinos_vm_driver diff --git a/include/koinos/chain/chronicler.hpp b/src/koinos/chain/chronicler.hpp similarity index 100% rename from include/koinos/chain/chronicler.hpp rename to src/koinos/chain/chronicler.hpp diff --git a/include/koinos/chain/constants.hpp b/src/koinos/chain/constants.hpp similarity index 100% rename from include/koinos/chain/constants.hpp rename to src/koinos/chain/constants.hpp diff --git a/include/koinos/chain/controller.hpp b/src/koinos/chain/controller.hpp similarity index 100% rename from include/koinos/chain/controller.hpp rename to src/koinos/chain/controller.hpp diff --git a/include/koinos/chain/exceptions.hpp b/src/koinos/chain/exceptions.hpp similarity index 100% rename from include/koinos/chain/exceptions.hpp rename to src/koinos/chain/exceptions.hpp diff --git a/include/koinos/chain/execution_context.hpp b/src/koinos/chain/execution_context.hpp similarity index 100% rename from include/koinos/chain/execution_context.hpp rename to src/koinos/chain/execution_context.hpp diff --git a/include/koinos/chain/host_api.hpp b/src/koinos/chain/host_api.hpp similarity index 100% rename from include/koinos/chain/host_api.hpp rename to src/koinos/chain/host_api.hpp diff --git a/include/koinos/chain/indexer.hpp b/src/koinos/chain/indexer.hpp similarity index 100% rename from include/koinos/chain/indexer.hpp rename to src/koinos/chain/indexer.hpp diff --git a/include/koinos/chain/proto_utils.hpp b/src/koinos/chain/proto_utils.hpp similarity index 100% rename from include/koinos/chain/proto_utils.hpp rename to src/koinos/chain/proto_utils.hpp diff --git a/include/koinos/chain/resource_meter.hpp b/src/koinos/chain/resource_meter.hpp similarity index 100% rename from include/koinos/chain/resource_meter.hpp rename to src/koinos/chain/resource_meter.hpp diff --git a/include/koinos/chain/session.hpp b/src/koinos/chain/session.hpp similarity index 100% rename from include/koinos/chain/session.hpp rename to src/koinos/chain/session.hpp diff --git a/include/koinos/chain/state.hpp b/src/koinos/chain/state.hpp similarity index 100% rename from include/koinos/chain/state.hpp rename to src/koinos/chain/state.hpp diff --git a/include/koinos/chain/system_calls.hpp b/src/koinos/chain/system_calls.hpp similarity index 100% rename from include/koinos/chain/system_calls.hpp rename to src/koinos/chain/system_calls.hpp diff --git a/include/koinos/chain/thunk_dispatcher.hpp b/src/koinos/chain/thunk_dispatcher.hpp similarity index 100% rename from include/koinos/chain/thunk_dispatcher.hpp rename to src/koinos/chain/thunk_dispatcher.hpp diff --git a/include/koinos/chain/thunk_utils.hpp b/src/koinos/chain/thunk_utils.hpp similarity index 100% rename from include/koinos/chain/thunk_utils.hpp rename to src/koinos/chain/thunk_utils.hpp diff --git a/include/koinos/chain/types.hpp b/src/koinos/chain/types.hpp similarity index 100% rename from include/koinos/chain/types.hpp rename to src/koinos/chain/types.hpp diff --git a/include/koinos/vm_manager/exceptions.hpp b/src/koinos/vm_manager/exceptions.hpp similarity index 100% rename from include/koinos/vm_manager/exceptions.hpp rename to src/koinos/vm_manager/exceptions.hpp diff --git a/include/koinos/vm_manager/fizzy/exceptions.hpp b/src/koinos/vm_manager/fizzy/exceptions.hpp similarity index 100% rename from include/koinos/vm_manager/fizzy/exceptions.hpp rename to src/koinos/vm_manager/fizzy/exceptions.hpp diff --git a/include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp b/src/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp similarity index 100% rename from include/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp rename to src/koinos/vm_manager/fizzy/fizzy_vm_backend.hpp diff --git a/include/koinos/vm_manager/fizzy/module_cache.hpp b/src/koinos/vm_manager/fizzy/module_cache.hpp similarity index 100% rename from include/koinos/vm_manager/fizzy/module_cache.hpp rename to src/koinos/vm_manager/fizzy/module_cache.hpp diff --git a/include/koinos/vm_manager/host_api.hpp b/src/koinos/vm_manager/host_api.hpp similarity index 100% rename from include/koinos/vm_manager/host_api.hpp rename to src/koinos/vm_manager/host_api.hpp diff --git a/include/koinos/vm_manager/vm_backend.hpp b/src/koinos/vm_manager/vm_backend.hpp similarity index 100% rename from include/koinos/vm_manager/vm_backend.hpp rename to src/koinos/vm_manager/vm_backend.hpp From c7dac2b98d6d5ccdee502e185d9fe1fb0983a9cf Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Wed, 6 Mar 2024 20:25:16 +0100 Subject: [PATCH 22/25] Turn off clang-format for certain areas of code --- src/koinos_chain.cpp | 108 ++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 74 deletions(-) diff --git a/src/koinos_chain.cpp b/src/koinos_chain.cpp index f416b6f2..3649c362 100644 --- a/src/koinos_chain.cpp +++ b/src/koinos_chain.cpp @@ -91,41 +91,26 @@ int main( int argc, char** argv ) try { program_options::options_description options; - options.add_options()( HELP_OPTION ",h", "Print this help message and exit" )( VERSION_OPTION ",v", - "Print version string and exit" )( - BASEDIR_OPTION ",d", - program_options::value< std::string >()->default_value( util::get_default_base_directory().string() ), - "Koinos base directory" )( AMQP_OPTION ",a", program_options::value< std::string >(), "AMQP server URL" )( - LOG_LEVEL_OPTION ",l", - program_options::value< std::string >(), - "The log filtering level" )( INSTANCE_ID_OPTION ",i", - program_options::value< std::string >(), - "An ID that uniquely identifies the instance" )( - JOBS_OPTION ",j", - program_options::value< uint64_t >(), - "The number of worker jobs" )( READ_COMPUTE_BANDWITH_LIMIT_OPTION ",b", - program_options::value< uint64_t >(), - "The compute bandwidth when reading contracts via the API" )( - GENESIS_DATA_FILE_OPTION ",g", - program_options::value< std::string >(), - "The genesis data file" )( - STATEDIR_OPTION, - program_options::value< std::string >(), - "The location of the blockchain state files (absolute path or relative to basedir/chain)" )( - RESET_OPTION, - program_options::value< bool >(), - "Reset the database" )( - FORK_ALGORITHM_OPTION ",f", - program_options::value< std::string >(), - "The fork resolution algorithm to use. Can be 'fifo', 'pob', or 'block-time'. (Default: 'fifo')" )( - LOG_DIR_OPTION, - program_options::value< std::string >(), - "The logging directory" )( LOG_COLOR_OPTION, program_options::value< bool >(), "Log color toggle" )( - LOG_DATETIME_OPTION, - program_options::value< bool >(), - "Log datetime on console toggle" )( SYSTEM_CALL_BUFFER_SIZE_OPTION, - program_options::value< uint32_t >(), - "System call RPC invocation buffer size" ); + + // clang-format off + options.add_options() + ( HELP_OPTION ",h" , "Print this help message and exit" ) + ( VERSION_OPTION ",v" , "Print version string and exit" ) + ( BASEDIR_OPTION ",d" , program_options::value< std::string >()->default_value( util::get_default_base_directory().string() ), "Koinos base directory" ) + ( AMQP_OPTION ",a" , program_options::value< std::string >(), "AMQP server URL" ) + ( LOG_LEVEL_OPTION ",l" , program_options::value< std::string >(), "The log filtering level" ) + ( INSTANCE_ID_OPTION ",i" , program_options::value< std::string >(), "An ID that uniquely identifies the instance" ) + ( JOBS_OPTION ",j" , program_options::value< uint64_t >() , "The number of worker jobs" ) + ( READ_COMPUTE_BANDWITH_LIMIT_OPTION ",b", program_options::value< uint64_t >() , "The compute bandwidth when reading contracts via the API" ) + ( GENESIS_DATA_FILE_OPTION ",g" , program_options::value< std::string >(), "The genesis data file" ) + ( STATEDIR_OPTION , program_options::value< std::string >(), "The location of the blockchain state files (absolute path or relative to basedir/chain)" ) + ( RESET_OPTION , program_options::value< bool >() , "Reset the database" ) + ( FORK_ALGORITHM_OPTION ",f" , program_options::value< std::string >(), "The fork resolution algorithm to use. Can be 'fifo', 'pob', or 'block-time'. (Default: 'fifo')" ) + ( LOG_DIR_OPTION , program_options::value< std::string >(), "The logging directory" ) + ( LOG_COLOR_OPTION , program_options::value< bool >() , "Log color toggle" ) + ( LOG_DATETIME_OPTION , program_options::value< bool >() , "Log datetime on console toggle" ) + ( SYSTEM_CALL_BUFFER_SIZE_OPTION , program_options::value< uint32_t >() , "System call RPC invocation buffer size" ); + // clang-format on program_options::variables_map args; program_options::store( program_options::parse_command_line( argc, argv, options ), args ); @@ -165,46 +150,21 @@ int main( int argc, char** argv ) chain_config = config[ util::service::chain ]; } - amqp_url = util::get_option< std::string >( AMQP_OPTION, AMQP_DEFAULT, args, chain_config, global_config ); - log_level = - util::get_option< std::string >( LOG_LEVEL_OPTION, LOG_LEVEL_DEFAULT, args, chain_config, global_config ); - log_dir = util::get_option< std::string >( LOG_DIR_OPTION, LOG_DIR_DEFAULT, args, chain_config, global_config ); - log_color = util::get_option< bool >( LOG_COLOR_OPTION, LOG_COLOR_DEFAULT, args, chain_config, global_config ); - log_datetime = - util::get_option< bool >( LOG_DATETIME_OPTION, LOG_DATETIME_DEFAULT, args, chain_config, global_config ); - instance_id = util::get_option< std::string >( INSTANCE_ID_OPTION, - util::random_alphanumeric( 5 ), - args, - chain_config, - global_config ); - statedir = std::filesystem::path( - util::get_option< std::string >( STATEDIR_OPTION, STATEDIR_DEFAULT, args, chain_config, global_config ) ); - genesis_data_file = std::filesystem::path( util::get_option< std::string >( GENESIS_DATA_FILE_OPTION, - GENESIS_DATA_FILE_DEFAULT, - args, - chain_config, - global_config ) ); + // clang-format off + amqp_url = util::get_option< std::string >( AMQP_OPTION, AMQP_DEFAULT, args, chain_config, global_config ); + log_level = util::get_option< std::string >( LOG_LEVEL_OPTION, LOG_LEVEL_DEFAULT, args, chain_config, global_config ); + log_dir = util::get_option< std::string >( LOG_DIR_OPTION, LOG_DIR_DEFAULT, args, chain_config, global_config ); + log_color = util::get_option< bool >( LOG_COLOR_OPTION, LOG_COLOR_DEFAULT, args, chain_config, global_config ); + log_datetime = util::get_option< bool >( LOG_DATETIME_OPTION, LOG_DATETIME_DEFAULT, args, chain_config, global_config ); + instance_id = util::get_option< std::string >( INSTANCE_ID_OPTION, util::random_alphanumeric( 5 ), args, chain_config, global_config ); + statedir = std::filesystem::path( util::get_option< std::string >( STATEDIR_OPTION, STATEDIR_DEFAULT, args, chain_config, global_config ) ); + genesis_data_file = std::filesystem::path( util::get_option< std::string >( GENESIS_DATA_FILE_OPTION, GENESIS_DATA_FILE_DEFAULT, args, chain_config, global_config ) ); reset = util::get_option< bool >( RESET_OPTION, false, args, chain_config, global_config ); - jobs = util::get_option< uint64_t >( JOBS_OPTION, - std::max( JOBS_DEFAULT, uint64_t( std::thread::hardware_concurrency() ) ), - args, - chain_config, - global_config ); - read_compute_limit = util::get_option< uint64_t >( READ_COMPUTE_BANDWITH_LIMIT_OPTION, - READ_COMPUTE_BANDWITH_LIMIT_DEFAULT, - args, - chain_config, - global_config ); - fork_algorithm_option = util::get_option< std::string >( FORK_ALGORITHM_OPTION, - FORK_ALGORITHM_DEFAULT, - args, - chain_config, - global_config ); - syscall_bufsize = util::get_option< uint32_t >( SYSTEM_CALL_BUFFER_SIZE_OPTION, - SYSTEM_CALL_BUFFER_SIZE_DEFAULT, - args, - chain_config, - global_config ); + jobs = util::get_option< uint64_t >( JOBS_OPTION, std::max( JOBS_DEFAULT, uint64_t( std::thread::hardware_concurrency() ) ), args, chain_config, global_config ); + read_compute_limit = util::get_option< uint64_t >( READ_COMPUTE_BANDWITH_LIMIT_OPTION, READ_COMPUTE_BANDWITH_LIMIT_DEFAULT, args, chain_config, global_config ); + fork_algorithm_option = util::get_option< std::string >( FORK_ALGORITHM_OPTION, FORK_ALGORITHM_DEFAULT, args, chain_config, global_config ); + syscall_bufsize = util::get_option< uint32_t >( SYSTEM_CALL_BUFFER_SIZE_OPTION, SYSTEM_CALL_BUFFER_SIZE_DEFAULT, args, chain_config, global_config ); + // clang-format on std::optional< std::filesystem::path > logdir_path; if( !log_dir.empty() ) From e8dd3e7357e693f8baba25a56e2a253e7069bb8b Mon Sep 17 00:00:00 2001 From: Steve Gerbino Date: Fri, 8 Mar 2024 15:25:52 +0100 Subject: [PATCH 23/25] Enable integration tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 73c41fb3..79aeda1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -132,7 +132,7 @@ jobs: - docker cp extract-ccache:/build/.ccache ~/.ccache script: - pushd koinos-integration-tests - #- ./run.sh + - ./run.sh after_success: - | if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then From aa63ee945166c010aa1858189e822a9178c6f854 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Mon, 11 Mar 2024 08:09:02 -0700 Subject: [PATCH 24/25] Remove workflows --- .github/workflows/add_issue_to_project.yml | 19 ---------------- .github/workflows/add_pr_to_project.yml | 17 --------------- .github/workflows/add_to_project.yml | 21 ------------------ .github/workflows/close_issues.yml | 25 ---------------------- 4 files changed, 82 deletions(-) delete mode 100644 .github/workflows/add_issue_to_project.yml delete mode 100644 .github/workflows/add_pr_to_project.yml delete mode 100644 .github/workflows/add_to_project.yml delete mode 100644 .github/workflows/close_issues.yml diff --git a/.github/workflows/add_issue_to_project.yml b/.github/workflows/add_issue_to_project.yml deleted file mode 100644 index e8f4b836..00000000 --- a/.github/workflows/add_issue_to_project.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Assign issue to project - -on: - issues: - types: [opened] - -jobs: - assign_to_project: - runs-on: ubuntu-latest - name: Assign issue to project - steps: - - - name: Assign issue with `bug` or `enhancement` label to project - uses: actions/add-to-project@v0.4.0 - with: - project-url: https://github.com/orgs/koinos/projects/6 - github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }} - labeled: bug, enhancement - label-operator: OR diff --git a/.github/workflows/add_pr_to_project.yml b/.github/workflows/add_pr_to_project.yml deleted file mode 100644 index 31c6c972..00000000 --- a/.github/workflows/add_pr_to_project.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Assign pull request to project - -on: - pull_request: - types: [opened] - -jobs: - assign_to_project: - runs-on: ubuntu-latest - name: Assign pull request to project - steps: - - - name: Assign pull request to project - uses: actions/add-to-project@v0.4.0 - with: - project-url: https://github.com/orgs/koinos/projects/6 - github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }} diff --git a/.github/workflows/add_to_project.yml b/.github/workflows/add_to_project.yml deleted file mode 100644 index c987ae4e..00000000 --- a/.github/workflows/add_to_project.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Auto assign to project - -on: - issues: - types: [opened] - pull_request: - types: [opened] - -jobs: - assign_to_project: - runs-on: ubuntu-latest - name: Assign issue/pull request to project - steps: - - - name: Assign issues with `bug` or `enhancement` label to project - uses: actions/add-to-project@v0.4.0 - with: - project-url: https://github.com/orgs/koinos/projects/6 - github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }} - labeled: bug, enhancement - label-operator: OR diff --git a/.github/workflows/close_issues.yml b/.github/workflows/close_issues.yml deleted file mode 100644 index 78ff5a31..00000000 --- a/.github/workflows/close_issues.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Close inactive issues - -on: - schedule: - - cron: "0 0 * * *" # Run every day at midnight - -jobs: - close-issues: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: actions/stale@v7 - with: - exempt-issue-labels: "story,task,research" - days-before-stale: 30 - days-before-close: 14 - stale-issue-label: "stale" - stale-pr-label: "stale" - stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." - close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." - stale-pr-message: "This pull request is stale because it has been open for 30 days with no activity." - close-pr-message: "This pull request was closed because it has been inactive for 14 days since being marked as stale." - repo-token: ${{ secrets.ISSUE_MANAGEMENT_TOKEN }} From de4994f75295a7e8c6eb76d042e06e5f2dbbb28e Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Mon, 11 Mar 2024 15:06:16 -0600 Subject: [PATCH 25/25] Bump koinos-cmake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62f5abfb..ce7f18e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ include(FetchContent) FetchContent_Declare( koinos_cmake GIT_REPOSITORY https://github.com/koinos/koinos-cmake.git - GIT_TAG 113f07791c56b292bbcb10164b759daa68a74121) + GIT_TAG 0c8433a118eb4cd5a86bb7ac4708a38db8166801) FetchContent_MakeAvailable(koinos_cmake) include("${koinos_cmake_SOURCE_DIR}/Koinos.cmake")