From 9509dd7cb30b58ad4adf023e62e6d5a65ce243dd Mon Sep 17 00:00:00 2001 From: Thaipanda Date: Fri, 1 May 2020 13:26:38 +0800 Subject: [PATCH 01/25] check llvm version >= 7 and install automatically --- CMakeLists.txt | 4 ++-- eosio_build.sh | 16 ++++++++-------- scripts/eosio_build_amazon.sh | 20 ++++++++++++++++---- scripts/eosio_build_centos.sh | 22 +++++++++++++++++----- scripts/eosio_build_fedora.sh | 20 ++++++++++++++++---- scripts/eosio_build_ubuntu.sh | 23 ++++++++++++++++++----- 6 files changed, 77 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6b16e4958c..fd82178bd72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,8 +55,8 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") add_compile_options(-fdiagnostics-color=always) endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) - message(FATAL_ERROR "Clang version must be at least 6.0!") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) + message(FATAL_ERROR "Clang version must be at least 7.0!") endif() endif() diff --git a/eosio_build.sh b/eosio_build.sh index 3db66b5e66b..7969c261cac 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -63,7 +63,7 @@ fi START_MAKE=true TIME_BEGIN=$( date -u +%s ) - VERSION=1.2 + VERSION=3.0.7 txtbld=$(tput bold) bldred=${txtbld}$(tput setaf 1) @@ -174,7 +174,7 @@ MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm export CMAKE=${HOME}/opt/cmake/bin/cmake - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "CentOS Linux") FILE="${SOURCE_DIR}/scripts/eosio_build_centos.sh" @@ -183,14 +183,14 @@ MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm export CMAKE=${HOME}/opt/cmake/bin/cmake - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "elementary OS") FILE="${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh" CXX_COMPILER=clang++ C_COMPILER=clang MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "Fedora") FILE="${SOURCE_DIR}/scripts/eosio_build_fedora.sh" @@ -204,21 +204,21 @@ CXX_COMPILER=clang++ C_COMPILER=clang MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "Ubuntu") FILE="${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh" CXX_COMPILER=clang++ C_COMPILER=clang MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "Debian GNU/Linux") FILE=${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh CXX_COMPILER=clang++ C_COMPILER=clang MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; *) printf "\\n\\tUnsupported Linux Distribution. Exiting now.\\n\\n" @@ -274,7 +274,7 @@ -DENABLE_COVERAGE_TESTING="${ENABLE_COVERAGE_TESTING}" -DBUILD_DOXYGEN="${DOXYGEN}" \ -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ -DCMAKE_INSTALL_PREFIX="/usr/local/eosio" ${LOCAL_CMAKE_FLAGS} "${SOURCE_DIR}" \ - -DENABLE_TOOLS=OFF + -DENABLE_TOOLS=OFF then printf "\\n\\t>>>>>>>>>>>>>>>>>>>> CMAKE building BOSCore has exited with the above error.\\n\\n" exit -1 diff --git a/scripts/eosio_build_amazon.sh b/scripts/eosio_build_amazon.sh index a6dac190959..1ccab5fbbe3 100644 --- a/scripts/eosio_build_amazon.sh +++ b/scripts/eosio_build_amazon.sh @@ -535,8 +535,20 @@ fi printf "\\tMongo C++ driver found at /usr/local/lib64/libmongocxx-static.a.\\n" fi - printf "\\n\\tChecking LLVM with WASM support.\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then + printf "\\n\\tChecking for LLVM with WASM support.\\n" + CLANG_INSTALL=false + if ! type clang > /dev/null ; then + CLANG_INSTALL=true + echo "Failed to find clang, it will install automatically." + else + CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1) + if [ "${CLANG_V}" -lt 7 ] ; then + echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically." + CLANG_INSTALL=true + fi + fi + + if [ $CLANG_INSTALL == true ]; then printf "\\tInstalling LLVM & WASM.\\n" if ! cd "${TEMP_DIR}" then @@ -556,7 +568,7 @@ fi printf "\\n\\tExiting now.\\n" exit 1; fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git + if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/llvm.git then printf "\\tUnable to clone llvm repo @ https://github.com/llvm-mirror/llvm.git.\\n" printf "\\tExiting now.\\n\\n" @@ -568,7 +580,7 @@ fi printf "\\n\\tExiting now.\\n" exit 1; fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git + if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/clang.git then printf "\\tUnable to clone clang repo @ https://github.com/llvm-mirror/clang.git.\\n" printf "\\tExiting now.\\n\\n" diff --git a/scripts/eosio_build_centos.sh b/scripts/eosio_build_centos.sh index f392fe5ef53..347fb0f1031 100644 --- a/scripts/eosio_build_centos.sh +++ b/scripts/eosio_build_centos.sh @@ -610,8 +610,20 @@ mongodconf printf "\\n" - printf "\\tChecking LLVM with WASM support installation...\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then + printf "\\n\\tChecking for LLVM with WASM support.\\n" + CLANG_INSTALL=false + if ! type clang > /dev/null ; then + CLANG_INSTALL=true + echo "Failed to find clang, it will install automatically." + else + CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1) + if [ "${CLANG_V}" -lt 7 ] ; then + echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically." + CLANG_INSTALL=true + fi + fi + + if [ $CLANG_INSTALL == true ]; then printf "\\tInstalling LLVM with WASM...\\n" if ! cd "${TEMP_DIR}"; then printf "\\t!! Unable to enter directory %s !!\\n" "${TEMP_DIR}" @@ -629,7 +641,7 @@ mongodconf exit 1; fi LLVMURL="https://github.com/llvm-mirror/llvm.git" - if ! git clone --depth 1 --single-branch --branch release_40 "${LLVMURL}"; then + if ! git clone --depth 1 --single-branch --branch release_90 "${LLVMURL}"; then printf "\\t!! Unable to clone llvm repo from ${LLVMURL} !!\\n" printf "\\tExiting now.\\n" exit 1; @@ -641,7 +653,7 @@ mongodconf exit 1; fi CLANGURL="https://github.com/llvm-mirror/clang.git" - if ! git clone --depth 1 --single-branch --branch release_40 "${CLANGURL}"; then + if ! git clone --depth 1 --single-branch --branch release_90 "${CLANGURL}"; then printf "\\t!! Unable to clone clang repo from ${CLANGURL} !!\\n" printf "\\tExiting now.\\n" exit 1; @@ -663,7 +675,7 @@ mongodconf exit 1; fi if ! "${CMAKE}" -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="${HOME}/opt/wasm" \ - -DLLVM_TARGETS_TO_BUILD="host" -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="WebAssembly" \ + -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="WebAssembly" \ -DLLVM_ENABLE_RTTI=1 -DCMAKE_BUILD_TYPE="Release" ..; then printf "\\t!! CMake has exited with the above error !!\\n" printf "\\tExiting now.\\n" diff --git a/scripts/eosio_build_fedora.sh b/scripts/eosio_build_fedora.sh index ca201600116..91dc16506dd 100644 --- a/scripts/eosio_build_fedora.sh +++ b/scripts/eosio_build_fedora.sh @@ -394,8 +394,20 @@ printf "\\tMongo C++ driver found at /usr/local/lib64/libmongocxx-static.a.\\n" fi - printf "\\n\\tChecking LLVM with WASM support installation.\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then + printf "\\n\\tChecking for LLVM with WASM support.\\n" + CLANG_INSTALL=false + if ! type clang > /dev/null ; then + CLANG_INSTALL=true + echo "Failed to find clang, it will install automatically." + else + CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1) + if [ "${CLANG_V}" -lt 7 ] ; then + echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically." + CLANG_INSTALL=true + fi + fi + + if [ $CLANG_INSTALL == true ]; then printf "\\tInstalling LLVM & WASM\\n" if ! cd "${TEMP_DIR}" then @@ -415,7 +427,7 @@ printf "\\n\\tExiting now.\\n" exit 1; fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git + if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/llvm.git then printf "\\tUnable to clone llvm repo @ https://github.com/llvm-mirror/llvm.git.\\n" printf "\\n\\tExiting now.\\n" @@ -439,7 +451,7 @@ printf "\\n\\tExiting now.\\n" exit 1; fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git + if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/clang.git then printf "\\tUnable to clone clang repo @ https://github.com/llvm-mirror/clang.git.\\n" printf "\\n\\tExiting now.\\n" diff --git a/scripts/eosio_build_ubuntu.sh b/scripts/eosio_build_ubuntu.sh index c5ca90528b7..f63340753d7 100644 --- a/scripts/eosio_build_ubuntu.sh +++ b/scripts/eosio_build_ubuntu.sh @@ -421,19 +421,31 @@ mongodconf else printf "\\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\\n" fi - + printf "\\n\\tChecking for LLVM with WASM support.\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then + CLANG_INSTALL=false + if ! type clang > /dev/null ; then + CLANG_INSTALL=true + echo "Failed to find clang, it will install automatically." + else + CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1) + if [ "${CLANG_V}" -lt 7 ] ; then + echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically." + CLANG_INSTALL=true + fi + fi + + if [ $CLANG_INSTALL == true ]; then # Build LLVM and clang with WASM support: printf "\\tInstalling LLVM with WASM\\n" if ! cd "${TEMP_DIR}" - then + then printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" printf "\\n\\tExiting now.\\n" exit 1; fi if ! mkdir "${TEMP_DIR}/llvm-compiler" 2>/dev/null - then + then printf "\\n\\tUnable to create directory %s/llvm-compiler.\\n" "${TEMP_DIR}" printf "\\n\\tExiting now.\\n" exit 1; @@ -480,7 +492,8 @@ mongodconf printf "\\n\\tExiting now.\\n" exit 1; fi - if ! cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="${HOME}/opt/wasm" -DLLVM_TARGETS_TO_BUILD= \ + # Refer : https://llvm.org/docs/CMake.html + if ! cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="${HOME}/opt/wasm" -DLLVM_ENABLE_RTTI=1 \ -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../ then printf "\\tError compiling LLVM and clang with EXPERIMENTAL WASM support.0\\n" From c9e6641ac9e85cd13b68c55e6e27bbbe7c4088c7 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Tue, 5 May 2020 15:42:09 +0800 Subject: [PATCH 02/25] Remove bytes in flight --- plugins/http_plugin/http_plugin.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/http_plugin/http_plugin.cpp b/plugins/http_plugin/http_plugin.cpp index f6672720ec8..0e434ffe6d9 100644 --- a/plugins/http_plugin/http_plugin.cpp +++ b/plugins/http_plugin/http_plugin.cpp @@ -283,7 +283,11 @@ namespace eosio { if( bytes_in_flight > max_bytes_in_flight ) { dlog( "503 - too many bytes in flight: ${bytes}", ("bytes", bytes_in_flight.load()) ); - error_results results{websocketpp::http::status_code::too_many_requests, "Busy", error_results::error_info()}; + error_results::error_info ei; + ei.code = websocketpp::http::status_code::too_many_requests; + ei.name = "Busy"; + ei.what = "Too many bytes in flight: " + std::to_string( bytes_in_flight ); + error_results results{websocketpp::http::status_code::too_many_requests, "Busy", ei}; con->set_body( fc::json::to_string( results )); con->set_status( websocketpp::http::status_code::too_many_requests ); return; @@ -294,7 +298,6 @@ namespace eosio { auto handler_itr = url_handlers.find( resource ); if( handler_itr != url_handlers.end()) { con->defer_http_response(); - bytes_in_flight += body.size(); handler_itr->second( resource, body, [&bytes_in_flight = this->bytes_in_flight, con]( int code, fc::variant response_body ) { std::string json = fc::json::to_string( response_body ); response_body.clear(); From a7e215854b457134ebaa5f72a12bc26779bf6540 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Mon, 11 May 2020 13:31:15 +0800 Subject: [PATCH 03/25] Upgrade: name apply context transaction context and plugins --- CMakeLists.txt | 4 +- libraries/CMakeLists.txt | 2 +- libraries/chain/CMakeLists.txt | 1 + libraries/chain/apply_context.cpp | 211 ++++--- libraries/chain/authorization_manager.cpp | 2 +- libraries/chain/controller.cpp | 6 +- libraries/chain/eosio_contract.cpp | 25 +- .../include/eosio/chain/abi_serializer.hpp | 1 - .../include/eosio/chain/apply_context.hpp | 102 ++- .../chain/include/eosio/chain/config.hpp | 31 +- .../eosio/chain/contract_table_objects.hpp | 20 +- .../chain/include/eosio/chain/exceptions.hpp | 4 + libraries/chain/include/eosio/chain/name.hpp | 122 ++-- libraries/chain/include/eosio/chain/trace.hpp | 65 +- .../eosio/chain/transaction_context.hpp | 79 +-- .../include/eosio/chain/webassembly/wabt.hpp | 2 +- .../include/eosio/chain/webassembly/wavm.hpp | 596 ------------------ libraries/chain/name.cpp | 24 +- libraries/chain/trace.cpp | 37 ++ libraries/chain/transaction_context.cpp | 377 ++++++----- libraries/chain/wasm_interface.cpp | 126 ++-- plugins/chain_plugin/chain_plugin.cpp | 92 +-- .../eosio/chain_plugin/chain_plugin.hpp | 13 +- .../history_api_plugin/history_api_plugin.cpp | 1 - plugins/history_plugin/history_plugin.cpp | 159 +---- plugins/kafka_plugin/kafka.cpp | 20 +- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 4 +- plugins/notify_plugin/notify_plugin.cpp | 21 +- plugins/producer_plugin/producer_plugin.cpp | 12 +- .../state_history_log.hpp | 461 +++++++------- .../state_history_plugin.hpp | 47 ++ .../state_history_serialization.hpp | 274 +++++--- .../state_history_plugin.cpp | 130 ++-- .../state_history_plugin_abi.cpp | 91 ++- .../txn_test_gen_plugin.cpp | 18 +- tests/Cluster.py | 2 +- 36 files changed, 1396 insertions(+), 1786 deletions(-) create mode 100644 libraries/chain/trace.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fd82178bd72..3d5d4cb077c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -249,8 +249,8 @@ add_subdirectory( libraries ) add_subdirectory( plugins ) add_subdirectory( programs ) add_subdirectory( scripts ) -add_subdirectory( unittests ) -add_subdirectory( tests ) +#add_subdirectory( unittests ) +#add_subdirectory( tests ) add_subdirectory( tools ) add_subdirectory( debian ) diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 788e6194973..58583d1ed01 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -5,7 +5,7 @@ add_subdirectory( chainbase ) add_subdirectory( wasm-jit ) add_subdirectory( appbase ) add_subdirectory( chain ) -add_subdirectory( testing ) +#add_subdirectory( testing ) #turn tools&tests off; not needed for library build set(BUILD_TESTS OFF CACHE BOOL "Build GTest-based tests") diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 4ab7dceebee..dbd7de4985b 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -95,6 +95,7 @@ add_library( eosio_chain # global_property_object.cpp # # contracts/chain_initializer.cpp + trace.cpp protocol_state_object.cpp genesis_intrinsics.cpp whitelisted_intrinsics.cpp diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 5a35eafd29a..56ec3fbc375 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -30,79 +30,99 @@ static inline void print_debug(account_name receiver, const action_trace& ar) { } } -void apply_context::exec_one( action_trace& trace ) +apply_context::apply_context(controller& con, transaction_context& trx_ctx, uint32_t action_ordinal, uint32_t depth) +:control(con) +,db(con.mutable_db()) +,trx_context(trx_ctx) +,recurse_depth(depth) +,first_receiver_action_ordinal(action_ordinal) +,action_ordinal(action_ordinal) +,idx64(*this) +,idx128(*this) +,idx256(*this) +,idx_double(*this) +,idx_long_double(*this) +{ + action_trace& trace = trx_ctx.get_action_trace(action_ordinal); + act = &trace.act; + receiver = trace.receiver; + context_free = trace.context_free; +} + +void apply_context::exec_one() { auto start = fc::time_point::now(); action_receipt r; r.receiver = receiver; - r.act_digest = digest_type::hash(act); - - trace.trx_id = trx_context.id; - trace.block_num = control.pending_block_state()->block_num; - trace.block_time = control.pending_block_time(); - trace.producer_block_id = control.pending_producer_block_id(); - trace.act = act; - trace.context_free = context_free; - - const auto& p = control.get_dynamic_global_properties(); - global_action_sequence = p.global_action_sequence + 1; + r.act_digest = digest_type::hash(*act); const auto& cfg = control.get_global_properties().configuration; const account_metadata_object* receiver_account = nullptr; try { try { receiver_account = &db.get( receiver ); - privileged = receiver_account->is_privileged(); - auto native = control.find_apply_handler( receiver, act.account, act.name ); + privileged = receiver_account->is_privileged(); + auto native = control.find_apply_handler( receiver, act->account, act->name ); if( native ) { if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); - control.check_action_list( act.account, act.name ); + control.check_action_list( act->account, act->name ); } (*native)( *this ); } - if( receiver_account->code_hash != digest_type() && - !(act.account == config::system_account_name && act.name == N( setcode ) && - receiver == config::system_account_name) ) { + if( ( receiver_account->code_hash != digest_type() ) && + ( !( act->account == config::system_account_name + && act->name == N( setcode ) + && receiver == config::system_account_name ) +// || control.is_builtin_activated( builtin_protocol_feature_t::forward_setcode ) + ) + ) { if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); - control.check_action_list( act.account, act.name ); + control.check_action_list( act->account, act->name ); } try { control.get_wasm_interface().apply( receiver_account->code_hash, receiver_account->vm_type, receiver_account->vm_version, *this ); } catch( const wasm_exit& ) {} } - } FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output.str()) ) + } FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output) ) } catch( fc::exception& e ) { - trace.receipt = r; // fill with known data - trace.except = e; - finalize_trace( trace, start ); - throw; + action_trace& trace = trx_context.get_action_trace( action_ordinal ); + /// TODO +// trace.error_code = controller::convert_exception_to_error_code( e ); + trace.except = e; + finalize_trace( trace, start ); + throw; } + // Note: It should not be possible for receiver_account to be invalidated because: + // * a pointer to an object in a chainbase index is not invalidated if other objects in that index are modified, removed, or added; + // * a pointer to an object in a chainbase index is not invalidated if the fields of that object are modified; + // * and, the *receiver_account object itself cannot be removed because accounts cannot be deleted in EOSIO. + r.global_sequence = next_global_sequence(); - r.recv_sequence = next_recv_sequence( receiver ); + r.recv_sequence = next_recv_sequence( *receiver_account ); const account_metadata_object* first_receiver_account = nullptr; - if( act.account == receiver ) { + if( act->account == receiver ) { first_receiver_account = receiver_account; } else { - first_receiver_account = &db.get(act.account); + first_receiver_account = &db.get(act->account); } r.code_sequence = first_receiver_account->code_sequence; // could be modified by action execution above r.abi_sequence = first_receiver_account->abi_sequence; // could be modified by action execution above - - for( const auto& auth : act.authorization ) { + for( const auto& auth : act->authorization ) { r.auth_sequence[auth.actor] = next_auth_sequence( auth.actor ); } + action_trace& trace = trx_context.get_action_trace( action_ordinal ); trace.receipt = r; - trx_context.executed.emplace_back( move(r) ); + trx_context.executed.emplace_back( std::move(r) ); finalize_trace( trace, start ); @@ -116,20 +136,19 @@ void apply_context::finalize_trace( action_trace& trace, const fc::time_point& s trace.account_ram_deltas = std::move( _account_ram_deltas ); _account_ram_deltas.clear(); - trace.console = _pending_console_output.str(); - reset_console(); + trace.console = std::move( _pending_console_output ); + _pending_console_output.clear(); trace.elapsed = fc::time_point::now() - start; } -void apply_context::exec( action_trace& trace ) +void apply_context::exec() { - _notified.push_back(receiver); - exec_one( trace ); + _notified.emplace_back( receiver, action_ordinal ); + exec_one(); for( uint32_t i = 1; i < _notified.size(); ++i ) { - receiver = _notified[i]; - trace.inline_traces.emplace_back( ); - exec_one( trace.inline_traces.back() ); + std::tie( receiver, action_ordinal ) = _notified[i]; + exec_one(); } if( _cfa_inline_actions.size() > 0 || _inline_actions.size() > 0 ) { @@ -137,14 +156,12 @@ void apply_context::exec( action_trace& trace ) transaction_exception, "max inline action depth per transaction reached" ); } - for( const auto& inline_action : _cfa_inline_actions ) { - trace.inline_traces.emplace_back(); - trx_context.dispatch_action( trace.inline_traces.back(), inline_action, inline_action.account, true, recurse_depth + 1 ); + for( uint32_t ordinal : _cfa_inline_actions ) { + trx_context.execute_action( ordinal, recurse_depth + 1 ); } - for( const auto& inline_action : _inline_actions ) { - trace.inline_traces.emplace_back(); - trx_context.dispatch_action( trace.inline_traces.back(), inline_action, inline_action.account, false, recurse_depth + 1 ); + for( uint32_t ordinal : _inline_actions ) { + trx_context.execute_action( ordinal, recurse_depth + 1 ); } } /// exec() @@ -154,9 +171,8 @@ bool apply_context::is_account( const account_name& account )const { } void apply_context::require_authorization( const account_name& account ) { - for( uint32_t i=0; i < act.authorization.size(); i++ ) { - if( act.authorization[i].actor == account ) { - used_authorizations[i] = true; + for( uint32_t i=0; i < act->authorization.size(); i++ ) { + if( act->authorization[i].actor == account ) { return; } } @@ -164,7 +180,7 @@ void apply_context::require_authorization( const account_name& account ) { } bool apply_context::has_authorization( const account_name& account )const { - for( const auto& auth : act.authorization ) + for( const auto& auth : act->authorization ) if( auth.actor == account ) return true; return false; @@ -172,10 +188,9 @@ bool apply_context::has_authorization( const account_name& account )const { void apply_context::require_authorization(const account_name& account, const permission_name& permission) { - for( uint32_t i=0; i < act.authorization.size(); i++ ) - if( act.authorization[i].actor == account ) { - if( act.authorization[i].permission == permission ) { - used_authorizations[i] = true; + for( uint32_t i=0; i < act->authorization.size(); i++ ) + if( act->authorization[i].actor == account ) { + if( act->authorization[i].permission == permission ) { return; } } @@ -184,15 +199,18 @@ void apply_context::require_authorization(const account_name& account, } bool apply_context::has_recipient( account_name code )const { - for( auto a : _notified ) - if( a == code ) + for( const auto& p : _notified ) + if( p.first == code ) return true; return false; } void apply_context::require_recipient( account_name recipient ) { if( !has_recipient(recipient) ) { - _notified.push_back(recipient); + _notified.emplace_back( + recipient, + schedule_action( action_ordinal, recipient, false ) + ); } } @@ -222,7 +240,7 @@ void apply_context::execute_inline( action&& a ) { bool disallow_send_to_self_bypass = false; // eventually set to whether the appropriate protocol feature has been activated bool send_to_self = (a.account == receiver); - bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act.account) && control.is_producing_block()); + bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act->account) && control.is_producing_block()); flat_set inherited_authorizations; if( inherit_parent_authorizations ) { @@ -239,7 +257,7 @@ void apply_context::execute_inline( action&& a ) { if( enforce_actor_whitelist_blacklist ) actors.insert( auth.actor ); - if( inherit_parent_authorizations && std::find(act.authorization.begin(), act.authorization.end(), auth) != act.authorization.end() ) { + if( inherit_parent_authorizations && std::find(act->authorization.begin(), act->authorization.end(), auth) != act->authorization.end() ) { inherited_authorizations.insert( auth ); } } @@ -283,7 +301,10 @@ void apply_context::execute_inline( action&& a ) { } } - _inline_actions.emplace_back( move(a) ); + auto inline_receiver = a.account; + _inline_actions.emplace_back( + schedule_action( std::move(a), inline_receiver, false ) + ); } void apply_context::execute_context_free_inline( action&& a ) { @@ -294,14 +315,16 @@ void apply_context::execute_context_free_inline( action&& a ) { EOS_ASSERT( a.authorization.size() == 0, action_validate_exception, "context-free actions cannot have authorizations" ); - _cfa_inline_actions.emplace_back( move(a) ); + + auto inline_receiver = a.account; + _cfa_inline_actions.emplace_back( + schedule_action( std::move(a), inline_receiver, true ) + ); } void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ) { EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" ); - trx.expiration = control.pending_block_time() + fc::microseconds(999'999); // Rounds up to nearest second (makes expiration check unnecessary) - trx.set_reference_block(control.head_block_id()); // No TaPoS check necessary bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block() && !control.sender_avoids_whitelist_blacklist_enforcement( receiver ); @@ -406,7 +429,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a }); } - EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act.account) || (receiver == payer) || privileged, + EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act->account) || (receiver == payer) || privileged, subjective_block_production_exception, "Cannot charge RAM to other accounts during notify." ); add_ram_usage( payer, (config::billable_size_v + trx_size) ); } @@ -421,6 +444,26 @@ bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, acc return gto; } +uint32_t apply_context::schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free ) +{ + uint32_t scheduled_action_ordinal = trx_context.schedule_action( ordinal_of_action_to_schedule, + receiver, context_free, + action_ordinal, first_receiver_action_ordinal ); + + act = &trx_context.get_action_trace( action_ordinal ).act; + return scheduled_action_ordinal; +} + +uint32_t apply_context::schedule_action( action&& act_to_schedule, account_name receiver, bool context_free ) +{ + uint32_t scheduled_action_ordinal = trx_context.schedule_action( std::move(act_to_schedule), + receiver, context_free, + action_ordinal, first_receiver_action_ordinal ); + + act = &trx_context.get_action_trace( action_ordinal ).act; + return scheduled_action_ordinal; +} + const table_id_object* apply_context::find_table( name code, name scope, name table ) { return db.find(boost::make_tuple(code, scope, table)); } @@ -456,11 +499,6 @@ vector apply_context::get_active_producers() const { return accounts; } -void apply_context::reset_console() { - _pending_console_output = std::ostringstream(); - _pending_console_output.setf( std::ios::scientific, std::ios::floatfield ); -} - bytes apply_context::get_packed_transaction() { auto r = fc::raw::pack( static_cast(trx_context.trx) ); return r; @@ -469,7 +507,7 @@ bytes apply_context::get_packed_transaction() { void apply_context::update_db_usage( const account_name& payer, int64_t delta ) { if( delta > 0 ) { if( !(privileged || payer == account_name(receiver)) ) { - EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act.account), + EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act->account), subjective_block_production_exception, "Cannot charge RAM to other accounts during notify." ); require_authorization( payer ); } @@ -519,11 +557,11 @@ int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t b return copy_size; } -int apply_context::db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { +int apply_context::db_store_i64( name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { return db_store_i64( receiver, scope, table, payer, id, buffer, buffer_size); } -int apply_context::db_store_i64( uint64_t code, uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { +int apply_context::db_store_i64( name code, name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { // require_write_lock( scope ); const auto& tab = find_or_create_table( code, scope, table, payer ); auto tableid = tab.id; @@ -659,7 +697,7 @@ int apply_context::db_previous_i64( int iterator, uint64_t& primary ) { return keyval_cache.add(*itr); } -int apply_context::db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { +int apply_context::db_find_i64( name code, name scope, name table, uint64_t id ) { //require_read_lock( code, scope ); // redundant? const auto* tab = find_table( code, scope, table ); @@ -673,7 +711,7 @@ int apply_context::db_find_i64( uint64_t code, uint64_t scope, uint64_t table, u return keyval_cache.add( *obj ); } -int apply_context::db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { +int apply_context::db_lowerbound_i64( name code, name scope, name table, uint64_t id ) { //require_read_lock( code, scope ); // redundant? const auto* tab = find_table( code, scope, table ); @@ -689,7 +727,7 @@ int apply_context::db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t ta return keyval_cache.add( *itr ); } -int apply_context::db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { +int apply_context::db_upperbound_i64( name code, name scope, name table, uint64_t id ) { //require_read_lock( code, scope ); // redundant? const auto* tab = find_table( code, scope, table ); @@ -705,7 +743,7 @@ int apply_context::db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t ta return keyval_cache.add( *itr ); } -int apply_context::db_end_i64( uint64_t code, uint64_t scope, uint64_t table ) { +int apply_context::db_end_i64( name code, name scope, name table ) { //require_read_lock( code, scope ); // redundant? const auto* tab = find_table( code, scope, table ); @@ -722,19 +760,18 @@ uint64_t apply_context::next_global_sequence() { return p.global_action_sequence; } -uint64_t apply_context::next_recv_sequence( account_name receiver ) { - const auto& rs = db.get( receiver ); - db.modify( rs, [&]( auto& mrs ) { - ++mrs.recv_sequence; +uint64_t apply_context::next_recv_sequence( const account_metadata_object& receiver_account ) { + db.modify( receiver_account, [&]( auto& ra ) { + ++ra.recv_sequence; }); - return rs.recv_sequence; + return receiver_account.recv_sequence; } uint64_t apply_context::next_auth_sequence( account_name actor ) { - const auto& rs = db.get( actor ); - db.modify( rs, [&](auto& mrs ){ - ++mrs.auth_sequence; + const auto& amo = db.get( actor ); + db.modify( amo, [&](auto& am ){ + ++am.auth_sequence; }); - return rs.auth_sequence; + return amo.auth_sequence; } void apply_context::add_ram_usage( account_name account, int64_t ram_delta ) { @@ -746,5 +783,13 @@ void apply_context::add_ram_usage( account_name account, int64_t ram_delta ) { } } +action_name apply_context::get_sender() const { + const action_trace& trace = trx_context.get_action_trace( action_ordinal ); + if (trace.creator_action_ordinal > 0) { + const action_trace& creator_trace = trx_context.get_action_trace( trace.creator_action_ordinal ); + return creator_trace.receiver; + } + return action_name(); +} } } /// eosio::chain diff --git a/libraries/chain/authorization_manager.cpp b/libraries/chain/authorization_manager.cpp index e69f7129121..fd60e8baa99 100644 --- a/libraries/chain/authorization_manager.cpp +++ b/libraries/chain/authorization_manager.cpp @@ -238,7 +238,7 @@ namespace eosio { namespace chain { auto link = _db.find(key); // If no specific link found, check for a contract-wide default if (link == nullptr) { - boost::get<2>(key) = ""; + boost::get<2>(key) = {}; link = _db.find(key); } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index dfe210a5f90..e6d8a636952 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -213,7 +213,8 @@ struct controller_impl { { #define SET_APP_HANDLER( receiver, contract, action) \ - set_apply_handler( #receiver, #contract, #action, &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) ) + set_apply_handler( account_name(#receiver), account_name(#contract), action_name(#action), \ + &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) ) SET_APP_HANDLER( eosio, eosio, newaccount ); SET_APP_HANDLER( eosio, eosio, setcode ); @@ -1104,8 +1105,7 @@ struct controller_impl { try { trx_context.init_for_implicit_trx(); trx_context.published = gtrx.published; - trx_context.trace->action_traces.emplace_back(); - trx_context.dispatch_action( trx_context.trace->action_traces.back(), etrx.actions.back(), gtrx.sender ); + trx_context.execute_action( trx_context.schedule_action( etrx.actions.back(), gtrx.sender, false, 0, 0 ), 0 ); trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful auto restore = make_block_restore_point(); diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index 3e925d175da..fa16ea56dfb 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -68,7 +69,7 @@ void validate_authority_precondition( const apply_context& context, const author * This method is called assuming precondition_system_newaccount succeeds a */ void apply_eosio_newaccount(apply_context& context) { - auto create = context.act.data_as(); + auto create = context.get_action().data_as(); try { context.require_authorization(create.creator); // context.require_write_lock( config::eosio_auth_scope ); @@ -129,7 +130,7 @@ void apply_eosio_setcode(apply_context& context) { const auto& cfg = context.control.get_global_properties().configuration; auto& db = context.db; - auto act = context.act.data_as(); + auto act = context.get_action().data_as(); context.require_authorization(act.account); EOS_ASSERT( act.vmtype == 0, invalid_contract_vm_type, "code should be 0" ); @@ -201,7 +202,7 @@ void apply_eosio_setcode(apply_context& context) { void apply_eosio_setabi(apply_context& context) { auto& db = context.db; - auto act = context.act.data_as(); + auto act = context.get_action().data_as(); context.require_authorization(act.account); @@ -220,9 +221,9 @@ void apply_eosio_setabi(apply_context& context) { } }); - const auto& account_sequence = db.get(act.account); - db.modify( account_sequence, [&]( auto& aso ) { - aso.abi_sequence += 1; + const auto& account_metadata = db.get(act.account); + db.modify( account_metadata, [&]( auto& a ) { + a.abi_sequence += 1; }); if (new_size != old_size) { @@ -232,7 +233,7 @@ void apply_eosio_setabi(apply_context& context) { void apply_eosio_updateauth(apply_context& context) { - auto update = context.act.data_as(); + auto update = context.get_action().data_as(); context.require_authorization(update.account); // only here to mark the single authority on this action as used auto& authorization = context.control.get_mutable_authorization_manager(); @@ -297,7 +298,7 @@ void apply_eosio_updateauth(apply_context& context) { void apply_eosio_deleteauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); - auto remove = context.act.data_as(); + auto remove = context.get_action().data_as(); context.require_authorization(remove.account); // only here to mark the single authority on this action as used EOS_ASSERT(remove.permission != config::active_name, action_validate_exception, "Cannot delete active authority"); @@ -313,7 +314,7 @@ void apply_eosio_deleteauth(apply_context& context) { auto range = index.equal_range(boost::make_tuple(remove.account, remove.permission)); EOS_ASSERT(range.first == range.second, action_validate_exception, "Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.", - ("code", string(range.first->code))("type", string(range.first->message_type))); + ("code", range.first->code)("type", range.first->message_type)); } const auto& permission = authorization.get_permission({remove.account, remove.permission}); @@ -328,7 +329,7 @@ void apply_eosio_deleteauth(apply_context& context) { void apply_eosio_linkauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); - auto requirement = context.act.data_as(); + auto requirement = context.get_action().data_as(); try { EOS_ASSERT(!requirement.requirement.empty(), action_validate_exception, "Required permission cannot be empty"); @@ -377,7 +378,7 @@ void apply_eosio_unlinkauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); auto& db = context.db; - auto unlink = context.act.data_as(); + auto unlink = context.get_action().data_as(); context.require_authorization(unlink.account); // only here to mark the single authority on this action as used @@ -393,7 +394,7 @@ void apply_eosio_unlinkauth(apply_context& context) { } void apply_eosio_canceldelay(apply_context& context) { - auto cancel = context.act.data_as(); + auto cancel = context.get_action().data_as(); context.require_authorization(cancel.canceling_auth.actor); // only here to mark the single authority on this action as used const auto& trx_id = cancel.trx_id; diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 06b9d2bb761..769e685bb4d 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -240,7 +240,6 @@ namespace impl { std::is_same::value || std::is_same::value || std::is_same::value || - std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 6272636deab..c9cdb527bae 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -71,7 +71,8 @@ class apply_context { void remove( int iterator ) { EOS_ASSERT( iterator != -1, invalid_table_iterator, "invalid iterator" ); EOS_ASSERT( iterator >= 0, table_operation_not_permitted, "cannot call remove on end iterators" ); - EOS_ASSERT( iterator < _iterator_to_object.size(), invalid_table_iterator, "iterator out of range" ); + EOS_ASSERT( (size_t)iterator < _iterator_to_object.size(), invalid_table_iterator, "iterator out of range" ); + auto obj_ptr = _iterator_to_object[iterator]; if( !obj_ptr ) return; _iterator_to_object[iterator] = nullptr; @@ -183,7 +184,7 @@ class apply_context { // context.require_write_lock( scope ); - const auto& tab = context.find_or_create_table( context.receiver, scope, table, payer ); + const auto& tab = context.find_or_create_table( context.receiver, name(scope), name(table), payer ); const auto& obj = context.db.create( [&]( auto& o ){ o.t_id = tab.id; @@ -247,7 +248,7 @@ class apply_context { } int find_secondary( uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_const_type secondary, uint64_t& primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -261,7 +262,7 @@ class apply_context { } int lowerbound_secondary( uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t& primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -278,7 +279,7 @@ class apply_context { } int upperbound_secondary( uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t& primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -295,7 +296,7 @@ class apply_context { } int end_secondary( uint64_t code, uint64_t scope, uint64_t table ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; return itr_cache.cache_table( *tab ); @@ -349,7 +350,7 @@ class apply_context { } int find_primary( uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -362,7 +363,7 @@ class apply_context { } int lowerbound_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if (!tab) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -376,7 +377,7 @@ class apply_context { } int upperbound_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if ( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -451,35 +452,23 @@ class apply_context { /// Constructor public: - apply_context(controller& con, transaction_context& trx_ctx, const action& a, uint32_t depth=0) - :control(con) - ,db(con.mutable_db()) - ,trx_context(trx_ctx) - ,act(a) - ,receiver(act.account) - ,used_authorizations(act.authorization.size(), false) - ,recurse_depth(depth) - ,idx64(*this) - ,idx128(*this) - ,idx256(*this) - ,idx_double(*this) - ,idx_long_double(*this) - { - reset_console(); - } - + apply_context(controller& con, transaction_context& trx_ctx, uint32_t action_ordinal, uint32_t depth=0); /// Execution methods: public: - void exec_one( action_trace& trace ); - void exec( action_trace& trace ); + void exec_one(); + void exec(); void execute_inline( action&& a ); void execute_context_free_inline( action&& a ); void schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ); bool cancel_deferred_transaction( const uint128_t& sender_id, account_name sender ); bool cancel_deferred_transaction( const uint128_t& sender_id ) { return cancel_deferred_transaction(sender_id, receiver); } + protected: + uint32_t schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free ); + uint32_t schedule_action( action&& act_to_schedule, account_name receiver, bool context_free ); + /// Authorization methods: public: @@ -516,23 +505,8 @@ class apply_context { /// Console methods: public: - void reset_console(); - std::ostringstream& get_console_stream() { return _pending_console_output; } - const std::ostringstream& get_console_stream()const { return _pending_console_output; } - - template - void console_append(T val) { - _pending_console_output << val; - } - - template - void console_append(T val, Ts ...rest) { - console_append(val); - console_append(rest...); - }; - - inline void console_append_formatted(const string& fmt, const variant_object& vo) { - console_append(fc::format_string(fmt, vo)); + void console_append( const string& val ) { + _pending_console_output += val; } /// Database methods: @@ -540,16 +514,16 @@ class apply_context { void update_db_usage( const account_name& payer, int64_t delta ); - int db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); + int db_store_i64( name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); void db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size ); void db_remove_i64( int iterator ); int db_get_i64( int iterator, char* buffer, size_t buffer_size ); int db_next_i64( int iterator, uint64_t& primary ); int db_previous_i64( int iterator, uint64_t& primary ); - int db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ); - int db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ); - int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ); - int db_end_i64( uint64_t code, uint64_t scope, uint64_t table ); + int db_find_i64( name code, name scope, name table, uint64_t id ); + int db_lowerbound_i64( name code, name scope, name table, uint64_t id ); + int db_upperbound_i64( name code, name scope, name table, uint64_t id ); + int db_end_i64( name code, name scope, name table ); private: @@ -557,19 +531,20 @@ class apply_context { const table_id_object& find_or_create_table( name code, name scope, name table, const account_name &payer ); void remove_table( const table_id_object& tid ); - int db_store_i64( uint64_t code, uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); + int db_store_i64( name code, name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); /// Misc methods: public: + int get_action( uint32_t type, uint32_t index, char* buffer, size_t buffer_size )const; int get_context_free_data( uint32_t index, char* buffer, size_t buffer_size )const; vector get_active_producers() const; bytes get_packed_transaction(); uint64_t next_global_sequence(); - uint64_t next_recv_sequence( account_name receiver ); + uint64_t next_recv_sequence( const account_metadata_object& receiver_account ); uint64_t next_auth_sequence( account_name actor ); void add_ram_usage( account_name account, int64_t ram_delta ); @@ -578,7 +553,9 @@ class apply_context { bool is_context_free()const { return context_free; } bool is_privileged()const { return privileged; } action_name get_receiver()const { return receiver; } - const action& get_action()const { return act; } + const action& get_action()const { return *act; } + + action_name get_sender() const; /// Fields: public: @@ -586,15 +563,18 @@ class apply_context { controller& control; chainbase::database& db; ///< database where state is stored transaction_context& trx_context; ///< transaction context in which the action is running - const action& act; ///< message being applied + + private: + const action* act = nullptr; ///< action being applied + // act pointer may be invalidated on call to trx_context.schedule_action account_name receiver; ///< the code that is currently running - vector used_authorizations; ///< Parallel to act.authorization; tracks which permissions have been used while processing the message uint32_t recurse_depth; ///< how deep inline actions can recurse + uint32_t first_receiver_action_ordinal = 0; + uint32_t action_ordinal = 0; bool privileged = false; bool context_free = false; - bool used_context_free_api = false; - uint64_t global_action_sequence = 0; + public: generic_index idx64; generic_index idx128; generic_index idx256; @@ -604,10 +584,10 @@ class apply_context { private: iterator_cache keyval_cache; - vector _notified; ///< keeps track of new accounts to be notifed of current message - vector _inline_actions; ///< queued inline messages - vector _cfa_inline_actions; ///< queued inline messages - std::ostringstream _pending_console_output; + vector< std::pair > _notified; ///< keeps track of new accounts to be notifed of current message + vector _inline_actions; ///< action_ordinals of queued inline actions + vector _cfa_inline_actions; ///< action_ordinals of queued inline context-free actions + std::string _pending_console_output; flat_set _account_ram_deltas; ///< flat_set of account_delta so json is an array of objects //bytes _cached_trx; diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 3f44522498b..8c7a854a3df 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -26,26 +26,26 @@ const static auto default_state_guard_size = 128*1024*1024ll; const static auto checkpoints_filename = "checkpoints.dat"; - -const static uint64_t system_account_name = N(eosio); -const static uint64_t null_account_name = N(eosio.null); -const static uint64_t producers_account_name = N(eosio.prods); +const static name system_account_name { N(eosio) }; +const static name null_account_name { N(eosio.null) }; +const static name producers_account_name { N(eosio.prods) }; // Active permission of producers account requires greater than 2/3 of the producers to authorize -const static uint64_t majority_producers_permission_name = N(prod.major); // greater than 1/2 of producers needed to authorize -const static uint64_t minority_producers_permission_name = N(prod.minor); // greater than 1/3 of producers needed to authorize0 +const static name majority_producers_permission_name { N(prod.major) }; // greater than 1/2 of producers needed to authorize +const static name minority_producers_permission_name { N(prod.minor) }; // greater than 1/3 of producers needed to authorize0 -const static uint64_t eosio_auth_scope = N(eosio.auth); -const static uint64_t eosio_all_scope = N(eosio.all); +const static name eosio_auth_scope { N(eosio.auth) }; +const static name eosio_all_scope { N(eosio.all) }; -const static uint64_t active_name = N(active); -const static uint64_t owner_name = N(owner); -const static uint64_t eosio_any_name = N(eosio.any); -const static uint64_t eosio_code_name = N(eosio.code); +const static name active_name { N(active) }; +const static name owner_name { N(owner) }; +const static name eosio_any_name { N(eosio.any) }; +const static name eosio_code_name { N(eosio.code) }; const static int block_interval_ms = 500; const static int block_interval_us = block_interval_ms*1000; const static uint64_t block_timestamp_epoch = 946684800000ll; // epoch is year 2000. +const static uint32_t genesis_num_supported_key_types = 2; /** Percentages are fixed point with a denominator of 10,000 */ const static int percent_100 = 10000; @@ -55,7 +55,7 @@ static const uint32_t account_cpu_usage_average_window_ms = 24*60*60*1000l; static const uint32_t account_net_usage_average_window_ms = 24*60*60*1000l; static const uint32_t block_cpu_usage_average_window_ms = 60*1000l; static const uint32_t block_size_average_window_ms = 60*1000l; -const static uint32_t genesis_num_supported_key_types = 2; +static const uint32_t maximum_elastic_resource_multiplier = 1000; //const static uint64_t default_max_storage_size = 10 * 1024; //const static uint32_t default_max_trx_runtime = 10*1000; @@ -77,6 +77,7 @@ const static uint32_t default_max_block_cpu_usage = 200'000; / const static uint32_t default_target_block_cpu_usage_pct = 10 * percent_1; const static uint32_t default_max_transaction_cpu_usage = 3*default_max_block_cpu_usage/4; /// max trx cpu usage in microseconds const static uint32_t default_min_transaction_cpu_usage = 100; /// min trx cpu usage in microseconds (10000 TPS equiv) +const static uint32_t default_subjective_cpu_leeway_us = 31000; /// default subjective cpu leeway in microseconds const static uint32_t default_max_trx_lifetime = 60*60; // 1 hour const static uint32_t default_deferred_trx_expiration_window = 10*60; // 10 minutes @@ -85,7 +86,9 @@ const static uint32_t default_max_inline_action_size = 4 * 1024; // const static uint16_t default_max_inline_action_depth = 4; const static uint16_t default_max_auth_depth = 6; const static uint32_t default_sig_cpu_bill_pct = 50 * percent_1; // billable percentage of signature recovery +const static uint32_t default_block_cpu_effort_pct = 80 * percent_1; // percentage of block time used for producing block const static uint16_t default_controller_thread_pool_size = 2; +const static uint32_t default_max_variable_signature_length = 16384u; const static uint32_t min_net_usage_delta_between_base_and_max_for_trx = 10*1024; // Should be large enough to allow recovery from badly set blockchain parameters without a hard fork @@ -101,7 +104,7 @@ const static uint32_t setcode_ram_bytes_multiplier = 10; ///< multip const static uint32_t hashing_checktime_block_size = 10*1024; /// call checktime from hashing intrinsic once per this number of bytes const static eosio::chain::wasm_interface::vm_type default_wasm_runtime = eosio::chain::wasm_interface::vm_type::wabt; -const static uint32_t default_abi_serializer_max_time_ms = 15*1000; ///< default deadline for abi serialization methods +const static uint32_t default_abi_serializer_max_time_us = 15*1000; ///< default deadline for abi serialization methods /** * The number of sequential blocks produced by a single producer diff --git a/libraries/chain/include/eosio/chain/contract_table_objects.hpp b/libraries/chain/include/eosio/chain/contract_table_objects.hpp index dc6b25b0501..fb02fb5e1e0 100644 --- a/libraries/chain/include/eosio/chain/contract_table_objects.hpp +++ b/libraries/chain/include/eosio/chain/contract_table_objects.hpp @@ -20,9 +20,9 @@ namespace eosio { namespace chain { OBJECT_CTOR(table_id_object) id_type id; - account_name code; - scope_name scope; - table_name table; + account_name code; //< code should not be changed within a chainbase modifier lambda + scope_name scope; //< scope should not be changed within a chainbase modifier lambda + table_name table; //< table should not be changed within a chainbase modifier lambda account_name payer; uint32_t count = 0; /// the number of elements in the table }; @@ -59,9 +59,9 @@ namespace eosio { namespace chain { static const int number_of_keys = 1; id_type id; - table_id t_id; - uint64_t primary_key; - account_name payer = 0; + table_id t_id; //< t_id should not be changed within a chainbase modifier lambda + uint64_t primary_key; //< primary_key should not be changed within a chainbase modifier lambda + account_name payer; shared_blob value; }; @@ -90,10 +90,10 @@ namespace eosio { namespace chain { typedef SecondaryKey secondary_key_type; typename chainbase::object::id_type id; - table_id t_id; - uint64_t primary_key; - account_name payer = 0; - SecondaryKey secondary_key; + table_id t_id; //< t_id should not be changed within a chainbase modifier lambda + uint64_t primary_key; //< primary_key should not be changed within a chainbase modifier lambda + account_name payer; + SecondaryKey secondary_key; //< secondary_key should not be changed within a chainbase modifier lambda }; diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 5c295192a1d..68d3d93b156 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -70,6 +70,10 @@ namespace eosio { namespace chain { + enum class system_error_code : uint64_t { + generic_system_error = 10000000000000000000ULL, + contract_restricted_error_code, //< contract used an error code reserved for system usage + }; FC_DECLARE_EXCEPTION( chain_exception, 3000000, "blockchain exception" ) /** diff --git a/libraries/chain/include/eosio/chain/name.hpp b/libraries/chain/include/eosio/chain/name.hpp index 52a100b5c00..eef06b81ece 100644 --- a/libraries/chain/include/eosio/chain/name.hpp +++ b/libraries/chain/include/eosio/chain/name.hpp @@ -3,9 +3,16 @@ #include #include -namespace eosio { namespace chain { - using std::string; +namespace eosio::chain { + struct name; +} +namespace fc { + class variant; + void to_variant(const eosio::chain::name& c, fc::variant& v); + void from_variant(const fc::variant& v, eosio::chain::name& check); +} // fc +namespace eosio::chain { static constexpr uint64_t char_to_symbol( char c ) { if( c >= 'a' && c <= 'z' ) return (c - 'a') + 6; @@ -14,102 +21,83 @@ namespace eosio { namespace chain { return 0; } - // Each char of the string is encoded into 5-bit chunk and left-shifted - // to its 5-bit slot starting with the highest slot for the first char. - // The 13th char, if str is long enough, is encoded into 4-bit chunk - // and placed in the lowest 4 bits. 64 = 12 * 5 + 4 - static constexpr uint64_t string_to_name( const char* str ) - { - uint64_t name = 0; + static constexpr uint64_t string_to_uint64_t( std::string_view str ) { + uint64_t n = 0; int i = 0; for ( ; str[i] && i < 12; ++i) { - // NOTE: char_to_symbol() returns char type, and without this explicit - // expansion to uint64 type, the compilation fails at the point of usage - // of string_to_name(), where the usage requires constant (compile time) expression. - name |= (char_to_symbol(str[i]) & 0x1f) << (64 - 5 * (i + 1)); - } + // NOTE: char_to_symbol() returns char type, and without this explicit + // expansion to uint64 type, the compilation fails at the point of usage + // of string_to_name(), where the usage requires constant (compile time) expression. + n |= (char_to_symbol(str[i]) & 0x1f) << (64 - 5 * (i + 1)); + } // The for-loop encoded up to 60 high bits into uint64 'name' variable, // if (strlen(str) > 12) then encode str[12] into the low (remaining) // 4 bits of 'name' if (i == 12) - name |= char_to_symbol(str[12]) & 0x0F; - return name; + n |= char_to_symbol(str[12]) & 0x0F; + return n; } -#define N(X) eosio::chain::string_to_name(#X) - + /// Immutable except for fc::from_variant. struct name { + private: uint64_t value = 0; - bool empty()const { return 0 == value; } - bool good()const { return !empty(); } - - name( const char* str ) { set(str); } - name( const string& str ) { set( str.c_str() ); } - void set( const char* str ); + friend struct fc::reflector; + friend void fc::from_variant(const fc::variant& v, eosio::chain::name& check); - template - name( T v ):value(v){} - name(){} + void set( std::string_view str ); - explicit operator string()const; + public: + constexpr bool empty()const { return 0 == value; } + constexpr bool good()const { return !empty(); } - string to_string() const { return string(*this); } - constexpr uint64_t to_uint64_t()const { return value; } + explicit name( std::string_view str ) { set( str ); } + constexpr explicit name( uint64_t v ) : value(v) {} + constexpr name() = default; - name& operator=( uint64_t v ) { - value = v; - return *this; - } - - name& operator=( const string& n ) { - value = name(n).value; - return *this; - } - name& operator=( const char* n ) { - value = name(n).value; - return *this; - } + std::string to_string()const; + constexpr uint64_t to_uint64_t()const { return value; } friend std::ostream& operator << ( std::ostream& out, const name& n ) { - return out << string(n); + return out << n.to_string(); } - friend bool operator < ( const name& a, const name& b ) { return a.value < b.value; } - friend bool operator <= ( const name& a, const name& b ) { return a.value <= b.value; } - friend bool operator > ( const name& a, const name& b ) { return a.value > b.value; } - friend bool operator >=( const name& a, const name& b ) { return a.value >= b.value; } - friend bool operator == ( const name& a, const name& b ) { return a.value == b.value; } + friend constexpr bool operator < ( const name& a, const name& b ) { return a.value < b.value; } + friend constexpr bool operator > ( const name& a, const name& b ) { return a.value > b.value; } + friend constexpr bool operator <= ( const name& a, const name& b ) { return a.value <= b.value; } + friend constexpr bool operator >= ( const name& a, const name& b ) { return a.value >= b.value; } + friend constexpr bool operator == ( const name& a, const name& b ) { return a.value == b.value; } + friend constexpr bool operator != ( const name& a, const name& b ) { return a.value != b.value; } - friend bool operator == ( const name& a, uint64_t b ) { return a.value == b; } - friend bool operator != ( const name& a, uint64_t b ) { return a.value != b; } + friend constexpr bool operator == ( const name& a, uint64_t b ) { return a.value == b; } + friend constexpr bool operator != ( const name& a, uint64_t b ) { return a.value != b; } - friend bool operator != ( const name& a, const name& b ) { return a.value != b.value; } - - operator bool()const { return value; } - operator uint64_t()const { return value; } - operator unsigned __int128()const { return value; } + constexpr explicit operator bool()const { return value != 0; } }; -} } // eosio::chain + // Each char of the string is encoded into 5-bit chunk and left-shifted + // to its 5-bit slot starting with the highest slot for the first char. + // The 13th char, if str is long enough, is encoded into 4-bit chunk + // and placed in the lowest 4 bits. 64 = 12 * 5 + 4 + static constexpr name string_to_name( std::string_view str ) + { + return name( string_to_uint64_t( str ) ); + } + +#define N(X) eosio::chain::string_to_name(#X) + +} // eosio::chain namespace std { template<> struct hash : private hash { typedef eosio::chain::name argument_type; - typedef typename hash::result_type result_type; - result_type operator()(const argument_type& name) const noexcept + size_t operator()(const argument_type& name) const noexcept { - return hash::operator()(name.value); + return hash::operator()(name.to_uint64_t()); } }; }; -namespace fc { - class variant; - void to_variant(const eosio::chain::name& c, fc::variant& v); - void from_variant(const fc::variant& v, eosio::chain::name& check); -} // fc - - FC_REFLECT( eosio::chain::name, (value) ) diff --git a/libraries/chain/include/eosio/chain/trace.hpp b/libraries/chain/include/eosio/chain/trace.hpp index 58de120bdd8..a7a069bde38 100644 --- a/libraries/chain/include/eosio/chain/trace.hpp +++ b/libraries/chain/include/eosio/chain/trace.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ #pragma once #include @@ -20,33 +16,36 @@ namespace eosio { namespace chain { friend bool operator<( const account_delta& lhs, const account_delta& rhs ) { return lhs.account < rhs.account; } }; - struct base_action_trace { - base_action_trace( const action_receipt& r ):receipt(r){} - base_action_trace(){} - - action_receipt receipt; - action act; - bool context_free = false; - fc::microseconds elapsed; - string console; + struct transaction_trace; + using transaction_trace_ptr = std::shared_ptr; - transaction_id_type trx_id; ///< the transaction that generated this action - uint32_t block_num = 0; - block_timestamp_type block_time; + struct action_trace { + action_trace( const transaction_trace& trace, const action& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ); + action_trace( const transaction_trace& trace, action&& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ); + action_trace(){} + + fc::unsigned_int action_ordinal; + fc::unsigned_int creator_action_ordinal; + fc::unsigned_int closest_unnotified_ancestor_action_ordinal; + fc::optional receipt; + action_name receiver; + action act; + bool context_free = false; + fc::microseconds elapsed; + string console; + transaction_id_type trx_id; ///< the transaction that generated this action + uint32_t block_num = 0; + block_timestamp_type block_time; fc::optional producer_block_id; flat_set account_ram_deltas; fc::optional except; + fc::optional error_code; }; - struct action_trace : public base_action_trace { - using base_action_trace::base_action_trace; - - vector inline_traces; - }; - - struct transaction_trace; - using transaction_trace_ptr = std::shared_ptr; - struct transaction_trace { transaction_id_type id; uint32_t block_num = 0; @@ -56,10 +55,12 @@ namespace eosio { namespace chain { fc::microseconds elapsed; uint64_t net_usage = 0; bool scheduled = false; - vector action_traces; ///< disposable + vector action_traces; + fc::optional account_ram_delta; transaction_trace_ptr failed_dtrx_trace; fc::optional except; + fc::optional error_code; std::exception_ptr except_ptr; }; @@ -68,13 +69,11 @@ namespace eosio { namespace chain { FC_REFLECT( eosio::chain::account_delta, (account)(delta) ) -FC_REFLECT( eosio::chain::base_action_trace, - (receipt)(act)(context_free)(elapsed)(console)(trx_id) - (block_num)(block_time)(producer_block_id)(account_ram_deltas)(except) ) - -FC_REFLECT_DERIVED( eosio::chain::action_trace, - (eosio::chain::base_action_trace), (inline_traces) ) +FC_REFLECT( eosio::chain::action_trace, + (action_ordinal)(creator_action_ordinal)(closest_unnotified_ancestor_action_ordinal)(receipt) + (receiver)(act)(context_free)(elapsed)(console)(trx_id)(block_num)(block_time) + (producer_block_id)(account_ram_deltas)(except)(error_code) ) FC_REFLECT( eosio::chain::transaction_trace, (id)(block_num)(block_time)(producer_block_id) (receipt)(elapsed)(net_usage)(scheduled) - (action_traces)(failed_dtrx_trace)(except) ) + (action_traces)(account_ram_delta)(failed_dtrx_trace)(except)(error_code) ) diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index 0d627c6613b..cbbca9b5b1e 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -6,40 +6,27 @@ namespace eosio { namespace chain { - struct transaction_checktime_timer { - public: - transaction_checktime_timer() = delete; - transaction_checktime_timer(const transaction_checktime_timer&) = delete; - transaction_checktime_timer(transaction_checktime_timer&&) = default; - ~transaction_checktime_timer(); - - void start(fc::time_point tp); - void stop(); - - /* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or - on any particular thread. Only a single callback can be registered at once; trying to register more will - result in an exception. Use nullptr to disable a previously set callback. */ - void set_expiration_callback(void(*func)(void*), void* user); - - std::atomic_bool& expired; - private: - platform_timer& _timer; - - transaction_checktime_timer(platform_timer& timer); - friend controller_impl; - }; - - struct deadline_timer { - deadline_timer(); - ~deadline_timer(); + struct transaction_checktime_timer { + public: + transaction_checktime_timer() = delete; + transaction_checktime_timer(const transaction_checktime_timer&) = delete; + transaction_checktime_timer(transaction_checktime_timer&&) = default; + ~transaction_checktime_timer(); void start(fc::time_point tp); void stop(); - static volatile sig_atomic_t expired; + /* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or + on any particular thread. Only a single callback can be registered at once; trying to register more will + result in an exception. Use nullptr to disable a previously set callback. */ + void set_expiration_callback(void(*func)(void*), void* user); + + std::atomic_bool& expired; private: - static void timer_expired(int); - static bool initialized; + platform_timer& _timer; + + transaction_checktime_timer(platform_timer& timer); + friend controller_impl; }; class transaction_context { @@ -51,8 +38,8 @@ namespace eosio { namespace chain { transaction_context( controller& c, const signed_transaction& t, const transaction_id_type& trx_id, - transaction_checktime_timer&& timer, - fc::time_point start = fc::time_point::now() ); + transaction_checktime_timer&& timer, + fc::time_point start = fc::time_point::now() ); void init_for_implicit_trx( uint64_t initial_net_usage = 0 ); @@ -89,14 +76,30 @@ namespace eosio { namespace chain { void add_ram_usage( account_name account, int64_t ram_delta ); - void dispatch_action( action_trace& trace, const action& a, account_name receiver, bool context_free = false, uint32_t recurse_depth = 0 ); - inline void dispatch_action( action_trace& trace, const action& a, bool context_free = false ) { - dispatch_action(trace, a, a.account, context_free); - }; + action_trace& get_action_trace( uint32_t action_ordinal ); + const action_trace& get_action_trace( uint32_t action_ordinal )const; + + /** invalidates any action_trace references returned by get_action_trace */ + uint32_t schedule_action( const action& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal ); + + /** invalidates any action_trace references returned by get_action_trace */ + uint32_t schedule_action( action&& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal ); + + /** invalidates any action_trace references returned by get_action_trace */ + uint32_t schedule_action( uint32_t action_ordinal, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal ); + + void execute_action( uint32_t action_ordinal, uint32_t recurse_depth ); + void schedule_transaction(); void record_transaction( const transaction_id_type& id, fc::time_point_sec expire ); - void validate_cpu_usage_to_bill( int64_t u, bool check_minimum = true )const; + void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const; + void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, bool estimate )const; + + void disallow_transaction_extensions( const char* error_msg )const; /// Fields: public: @@ -130,7 +133,7 @@ namespace eosio { namespace chain { transaction_checktime_timer transaction_timer; - private: + private: bool is_initialized = false; @@ -150,8 +153,6 @@ namespace eosio { namespace chain { fc::time_point pseudo_start; fc::microseconds billed_time; fc::microseconds billing_timer_duration_limit; - - deadline_timer _deadline_timer; }; } } diff --git a/libraries/chain/include/eosio/chain/webassembly/wabt.hpp b/libraries/chain/include/eosio/chain/webassembly/wabt.hpp index 49cbfef05c1..ae403ce3ed3 100644 --- a/libraries/chain/include/eosio/chain/webassembly/wabt.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/wabt.hpp @@ -190,7 +190,7 @@ inline auto convert_native_to_literal(const wabt_apply_instance_vars&, const dou inline auto convert_native_to_literal(const wabt_apply_instance_vars&, const name &val) { TypedValue tv(Type::I64); - tv.set_i64(val.value); + tv.set_i64(val.to_uint64_t()); return tv; } diff --git a/libraries/chain/include/eosio/chain/webassembly/wavm.hpp b/libraries/chain/include/eosio/chain/webassembly/wavm.hpp index 16ff8dd96cd..7dde4a443bd 100644 --- a/libraries/chain/include/eosio/chain/webassembly/wavm.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/wavm.hpp @@ -145,600 +145,6 @@ struct wasm_function_type_provider { #define __INTRINSIC_NAME(LABEL, SUFFIX) LABEL##SUFFIX #define _INTRINSIC_NAME(LABEL, SUFFIX) __INTRINSIC_NAME(LABEL,SUFFIX) -#ifdef EOSIO_WAVM_RUNTIME_ENABLED - -/** - * class to represent an in-wasm-memory array - * it is a hint to the transcriber that the next parameter will - * be a size (in Ts) and that the pair are validated together - * This triggers the template specialization of intrinsic_invoker_impl - * @tparam T - */ -template -inline array_ptr array_ptr_impl (running_instance_context& ctx, U32 ptr, size_t length) -{ - MemoryInstance* mem = ctx.memory; - if (!mem) - Runtime::causeException(Exception::Cause::accessViolation); - - size_t mem_total = IR::numBytesPerPage * Runtime::getMemoryNumPages(mem); - if (ptr >= mem_total || length > (mem_total - ptr) / sizeof(T)) - Runtime::causeException(Exception::Cause::accessViolation); - - T* ret_ptr = (T*)(getMemoryBaseAddress(mem) + ptr); - - return array_ptr((T*)(getMemoryBaseAddress(mem) + ptr)); -} - -/** - * class to represent an in-wasm-memory char array that must be null terminated - */ -inline null_terminated_ptr null_terminated_ptr_impl(running_instance_context& ctx, U32 ptr) -{ - MemoryInstance* mem = ctx.memory; - if(!mem) - Runtime::causeException(Exception::Cause::accessViolation); - - char *value = (char*)(getMemoryBaseAddress(mem) + ptr); - const char* p = value; - const char* const top_of_memory = (char*)(getMemoryBaseAddress(mem) + IR::numBytesPerPage*Runtime::getMemoryNumPages(mem)); - while(p < top_of_memory) - if(*p++ == '\0') - return null_terminated_ptr(value); - - Runtime::causeException(Exception::Cause::accessViolation); -} - - -/** - * template that maps native types to WASM VM types - * @tparam T the native type - */ -template -struct native_to_wasm { - using type = void; -}; - -/** - * specialization for mapping pointers to int32's - */ -template -struct native_to_wasm { - using type = I32; -}; - -/** - * Mappings for native types - */ -template<> -struct native_to_wasm { - using type = F32; -}; -template<> -struct native_to_wasm { - using type = F64; -}; -template<> -struct native_to_wasm { - using type = I32; -}; -template<> -struct native_to_wasm { - using type = I32; -}; -template<> -struct native_to_wasm { - using type = I64; -}; -template<> -struct native_to_wasm { - using type = I64; -}; -template<> -struct native_to_wasm { - using type = I32; -}; -template<> -struct native_to_wasm { - using type = I64; -}; -template<> -struct native_to_wasm { - using type = I64; -}; -template<> -struct native_to_wasm { - using type = I32; -}; - -template<> -struct native_to_wasm { - using type = I32; -}; - -// convenience alias -template -using native_to_wasm_t = typename native_to_wasm::type; - -template -inline auto convert_native_to_wasm(const running_instance_context& ctx, T val) { - return native_to_wasm_t(val); -} - -inline auto convert_native_to_wasm(const running_instance_context& ctx, const name &val) { - return native_to_wasm_t(val.value); -} - -inline auto convert_native_to_wasm(const running_instance_context& ctx, const fc::time_point_sec& val) { - return native_to_wasm_t(val.sec_since_epoch()); -} - -inline auto convert_native_to_wasm(running_instance_context& ctx, char* ptr) { - MemoryInstance* mem = ctx.memory; - if(!mem) - Runtime::causeException(Exception::Cause::accessViolation); - char* base = (char*)getMemoryBaseAddress(mem); - char* top_of_memory = base + IR::numBytesPerPage*Runtime::getMemoryNumPages(mem); - if(ptr < base || ptr >= top_of_memory) - Runtime::causeException(Exception::Cause::accessViolation); - return (U32)(ptr - base); -} - -template -inline auto convert_wasm_to_native(native_to_wasm_t val) { - return T(val); -} - -/** - * Forward declaration of the invoker type which transcribes arguments to/from a native method - * and injects the appropriate checks - * - * @tparam Ret - the return type of the native function - * @tparam NativeParameters - a std::tuple of the remaining native parameters to transcribe - * @tparam WasmParameters - a std::tuple of the transribed parameters - */ -template -struct intrinsic_invoker_impl; - -/** - * Specialization for the fully transcribed signature - * @tparam Ret - the return type of the native function - * @tparam Translated - the arguments to the wasm function - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_method_type = Ret (*)(running_instance_context &, Translated...); - - template - static native_to_wasm_t invoke(Translated... translated) { - try { - return convert_native_to_wasm(the_running_instance_context, Method(the_running_instance_context, translated...)); - } - catch(...) { - Platform::immediately_exit(std::current_exception()); - } - } - - template - static const auto fn() { - return invoke; - } -}; - -/** - * specialization of the fully transcribed signature for void return values - * @tparam Translated - the arguments to the wasm function - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_method_type = void_type (*)(running_instance_context &, Translated...); - - template - static void invoke(Translated... translated) { - try { - Method(the_running_instance_context, translated...); - } - catch(...) { - Platform::immediately_exit(std::current_exception()); - } - } - - template - static const auto fn() { - return invoke; - } -}; - -/** - * Sepcialization for transcribing a simple type in the native method signature - * @tparam Ret - the return type of the native method - * @tparam Input - the type of the native parameter to transcribe - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using translated_type = native_to_wasm_t; - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret (*)(running_instance_context &, Input, Inputs..., Translated...); - - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, translated_type last) { - auto native = convert_wasm_to_native(last); - return Then(ctx, native, rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a array_ptr type in the native method signature - * This type transcribes into 2 wasm parameters: a pointer and byte length and checks the validity of that memory - * range before dispatching to the native method - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, uint32_t, Inputs...>, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret(*)(running_instance_context&, array_ptr, uint32_t, Inputs..., Translated...); - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr, I32 size) -> std::enable_if_t::value, Ret> { - static_assert(!std::is_pointer::value, "Currently don't support array of pointers"); - const auto length = size_t(size); - T* base = array_ptr_impl(ctx, (U32)ptr, length); - if ( reinterpret_cast(base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned array of const values" ); - std::vector > copy(length > 0 ? length : 1); - T* copy_ptr = ©[0]; - memcpy( (void*)copy_ptr, (void*)base, length * sizeof(T) ); - return Then(ctx, static_cast>(copy_ptr), length, rest..., translated...); - } - return Then(ctx, static_cast>(base), length, rest..., translated...); - }; - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr, I32 size) -> std::enable_if_t::value, Ret> { - static_assert(!std::is_pointer::value, "Currently don't support array of pointers"); - const auto length = size_t(size); - T* base = array_ptr_impl(ctx, (U32)ptr, length); - if ( reinterpret_cast(base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned array of values" ); - std::vector > copy(length > 0 ? length : 1); - T* copy_ptr = ©[0]; - memcpy( (void*)copy_ptr, (void*)base, length * sizeof(T) ); - Ret ret = Then(ctx, static_cast>(copy_ptr), length, rest..., translated...); - memcpy( (void*)base, (void*)copy_ptr, length * sizeof(T) ); - return ret; - } - return Then(ctx, static_cast>(base), length, rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a null_terminated_ptr type in the native method signature - * This type transcribes 1 wasm parameters: a char pointer which is validated to contain - * a null value before the end of the allocated memory. - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret(*)(running_instance_context&, null_terminated_ptr, Inputs..., Translated...); - - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) { - return Then(ctx, null_terminated_ptr_impl(ctx, (U32)ptr), rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a pair of array_ptr types in the native method signature that share size - * This type transcribes into 3 wasm parameters: 2 pointers and byte length and checks the validity of those memory - * ranges before dispatching to the native method - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, array_ptr, uint32_t, Inputs...>, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret(*)(running_instance_context&, array_ptr, array_ptr, uint32_t, Inputs..., Translated...); - - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr_t, I32 ptr_u, I32 size) { - static_assert(std::is_same, char>::value && std::is_same, char>::value, "Currently only support array of (const)chars"); - const auto length = size_t(size); - return Then(ctx, array_ptr_impl(ctx, (U32)ptr_t, length), array_ptr_impl(ctx, (U32)ptr_u, length), length, rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing memset parameters - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, int, uint32_t>, std::tuple<>> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret(*)(running_instance_context&, array_ptr, int, uint32_t); - - template - static Ret translate_one(running_instance_context& ctx, I32 ptr, I32 value, I32 size) { - const auto length = size_t(size); - return Then(ctx, array_ptr_impl(ctx, (U32)ptr, length), value, length); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a pointer type in the native method signature - * This type transcribes into an int32 pointer checks the validity of that memory - * range before dispatching to the native method - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret (*)(running_instance_context&, T *, Inputs..., Translated...); - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t::value, Ret> { - T* base = array_ptr_impl(ctx, (U32)ptr, 1); - if ( reinterpret_cast(base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned const pointer" ); - std::remove_const_t copy; - T* copy_ptr = © - memcpy( (void*)copy_ptr, (void*)base, sizeof(T) ); - return Then(ctx, copy_ptr, rest..., translated...); - } - return Then(ctx, base, rest..., translated...); - }; - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t::value, Ret> { - T* base = array_ptr_impl(ctx, (U32)ptr, 1); - if ( reinterpret_cast(base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned pointer" ); - std::remove_const_t copy; - T* copy_ptr = © - memcpy( (void*)copy_ptr, (void*)base, sizeof(T) ); - Ret ret = Then(ctx, copy_ptr, rest..., translated...); - memcpy( (void*)base, (void*)copy_ptr, sizeof(T) ); - return ret; - } - return Then(ctx, base, rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a reference to a name which can be passed as a native value - * This type transcribes into a native type which is loaded by value into a - * variable on the stack and then passed by reference to the intrinsic. - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple >>; - using then_type = Ret (*)(running_instance_context&, const name&, Inputs..., Translated...); - - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, native_to_wasm_t wasm_value) { - auto value = name(wasm_value); - return Then(ctx, value, rest..., translated...); - } - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a reference type in the native method signature - * This type transcribes into an int32 pointer checks the validity of that memory - * range before dispatching to the native method - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret (*)(running_instance_context &, T &, Inputs..., Translated...); - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t::value, Ret> { - // references cannot be created for null pointers - EOS_ASSERT((U32)ptr != 0, wasm_exception, "references cannot be created for null pointers"); - MemoryInstance* mem = ctx.memory; - if(!mem || (U32)ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem)) - Runtime::causeException(Exception::Cause::accessViolation); - T &base = *(T*)(getMemoryBaseAddress(mem)+(U32)ptr); - if ( reinterpret_cast(&base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned const reference" ); - std::remove_const_t copy; - T* copy_ptr = © - memcpy( (void*)copy_ptr, (void*)&base, sizeof(T) ); - return Then(ctx, *copy_ptr, rest..., translated...); - } - return Then(ctx, base, rest..., translated...); - } - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t::value, Ret> { - // references cannot be created for null pointers - EOS_ASSERT((U32)ptr != 0, wasm_exception, "reference cannot be created for null pointers"); - MemoryInstance* mem = ctx.memory; - if(!mem || (U32)ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem)) - Runtime::causeException(Exception::Cause::accessViolation); - T &base = *(T*)(getMemoryBaseAddress(mem)+(U32)ptr); - if ( reinterpret_cast(&base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned reference" ); - std::remove_const_t copy; - T* copy_ptr = © - memcpy( (void*)copy_ptr, (void*)&base, sizeof(T) ); - Ret ret = Then(ctx, *copy_ptr, rest..., translated...); - memcpy( (void*)&base, (void*)copy_ptr, sizeof(T) ); - return ret; - } - return Then(ctx, base, rest..., translated...); - } - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * forward declaration of a wrapper class to call methods of the class - */ -template -struct intrinsic_function_invoker { - using impl = intrinsic_invoker_impl, std::tuple<>>; - - template - static Ret wrapper(running_instance_context& ctx, Params... params) { - class_from_wasm::value(*ctx.apply_ctx).checktime(); - return (class_from_wasm::value(*ctx.apply_ctx).*Method)(params...); - } - - template - static const WasmSig *fn() { - auto fn = impl::template fn>(); - static_assert(std::is_same::value, - "Intrinsic function signature does not match the ABI"); - return fn; - } -}; - -template -struct intrinsic_function_invoker { - using impl = intrinsic_invoker_impl, std::tuple<>>; - - template - static void_type wrapper(running_instance_context& ctx, Params... params) { - class_from_wasm::value(*ctx.apply_ctx).checktime(); - (class_from_wasm::value(*ctx.apply_ctx).*Method)(params...); - return void_type(); - } - - template - static const WasmSig *fn() { - auto fn = impl::template fn>(); - static_assert(std::is_same::value, - "Intrinsic function signature does not match the ABI"); - return fn; - } -}; - -template -struct void_ret_wrapper { - using type = T; -}; - -template<> -struct void_ret_wrapper { - using type = char; -}; - -template -using void_ret_wrapper_t = typename void_ret_wrapper::type; - -template -struct intrinsic_function_invoker_wrapper; - -template -struct intrinsic_function_invoker_wrapper { - static_assert( !(std::is_pointer_v && alignof(std::remove_pointer_t>) != 1) && - !(std::is_lvalue_reference_v && alignof(std::remove_reference_t>) != 1), - "intrinsics should only return a reference or pointer with single byte alignment"); - using type = intrinsic_function_invoker; -}; - -template -struct intrinsic_function_invoker_wrapper { - static_assert( !(std::is_pointer_v && alignof(std::remove_pointer_t>) != 1) && - !(std::is_lvalue_reference_v && alignof(std::remove_reference_t>) != 1), - "intrinsics should only return a reference or pointer with single byte alignment"); - using type = intrinsic_function_invoker; -}; - -template -struct intrinsic_function_invoker_wrapper { - static_assert( !(std::is_pointer_v && alignof(std::remove_pointer_t>) != 1) && - !(std::is_lvalue_reference_v && alignof(std::remove_reference_t>) != 1), - "intrinsics should only return a reference or pointer with single byte alignment"); - using type = intrinsic_function_invoker; -}; - -template -struct intrinsic_function_invoker_wrapper { - static_assert( !(std::is_pointer_v && alignof(std::remove_pointer_t>) != 1) && - !(std::is_lvalue_reference_v && alignof(std::remove_reference_t>) != 1), - "intrinsics should only return a reference or pointer with single byte alignment"); - using type = intrinsic_function_invoker; -}; - -#define _REGISTER_WAVM_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\ - static Intrinsics::Function _INTRINSIC_NAME(__intrinsic_fn, __COUNTER__) (\ - MOD "." NAME,\ - eosio::chain::webassembly::wavm::wasm_function_type_provider::type(),\ - (void *)eosio::chain::webassembly::wavm::intrinsic_function_invoker_wrapper::type::fn<&CLS::METHOD>()\ - ); - -#else - #define _REGISTER_WAVM_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\ static Intrinsics::Function _INTRINSIC_NAME(__intrinsic_fn, __COUNTER__) (\ MOD "." NAME,\ @@ -746,6 +152,4 @@ struct intrinsic_function_invoker_wrapper #include -namespace eosio { namespace chain { +namespace eosio::chain { - void name::set( const char* str ) { - const auto len = strnlen(str, 14); - EOS_ASSERT(len <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name", string(str))); - value = string_to_name(str); - EOS_ASSERT(to_string() == string(str), name_type_exception, + void name::set( std::string_view str ) { + const auto len = str.size(); + EOS_ASSERT(len <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name", std::string(str))); + value = string_to_uint64_t(str); + EOS_ASSERT(to_string() == str, name_type_exception, "Name not properly normalized (name: ${name}, normalized: ${normalized}) ", - ("name", string(str))("normalized", to_string())); + ("name", std::string(str))("normalized", to_string())); } // keep in sync with name::to_string() in contract definition for name - name::operator string()const { + std::string name::to_string()const { static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz"; - string str(13,'.'); + std::string str(13,'.'); uint64_t tmp = value; for( uint32_t i = 0; i <= 12; ++i ) { @@ -32,9 +32,9 @@ namespace eosio { namespace chain { return str; } -} } /// eosio::chain +} // eosio::chain namespace fc { - void to_variant(const eosio::chain::name& c, fc::variant& v) { v = std::string(c); } - void from_variant(const fc::variant& v, eosio::chain::name& check) { check = v.get_string(); } + void to_variant(const eosio::chain::name& c, fc::variant& v) { v = c.to_string(); } + void from_variant(const fc::variant& v, eosio::chain::name& check) { check.set( v.get_string() ); } } // fc diff --git a/libraries/chain/trace.cpp b/libraries/chain/trace.cpp new file mode 100644 index 00000000000..7ce555d8a11 --- /dev/null +++ b/libraries/chain/trace.cpp @@ -0,0 +1,37 @@ +#include + +namespace eosio { namespace chain { + +action_trace::action_trace( + const transaction_trace& trace, const action& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal +) +:action_ordinal( action_ordinal ) +,creator_action_ordinal( creator_action_ordinal ) +,closest_unnotified_ancestor_action_ordinal( closest_unnotified_ancestor_action_ordinal ) +,receiver( receiver ) +,act( act ) +,context_free( context_free ) +,trx_id( trace.id ) +,block_num( trace.block_num ) +,block_time( trace.block_time ) +,producer_block_id( trace.producer_block_id ) +{} + +action_trace::action_trace( + const transaction_trace& trace, action&& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal +) +:action_ordinal( action_ordinal ) +,creator_action_ordinal( creator_action_ordinal ) +,closest_unnotified_ancestor_action_ordinal( closest_unnotified_ancestor_action_ordinal ) +,receiver( receiver ) +,act( std::move(act) ) +,context_free( context_free ) +,trx_id( trace.id ) +,block_num( trace.block_num ) +,block_time( trace.block_time ) +,producer_block_id( trace.producer_block_id ) +{} + +} } // eosio::chain diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 619afb2ce19..8018440bda6 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -21,158 +21,33 @@ namespace eosio { namespace chain { -namespace bacc = boost::accumulators; - - struct deadline_timer_verify { - deadline_timer_verify() { - //keep longest first in list. You're effectively going to take test_intervals[0]*sizeof(test_intervals[0]) - //time to do the the "calibration" - int test_intervals[] = {50000, 10000, 5000, 1000, 500, 100, 50, 10}; - - struct sigaction act; - sigemptyset(&act.sa_mask); - act.sa_handler = timer_hit; - act.sa_flags = 0; - if(sigaction(SIGALRM, &act, NULL)) - return; - - sigset_t alrm; - sigemptyset(&alrm); - sigaddset(&alrm, SIGALRM); - int dummy; - - for(int& interval : test_intervals) { - unsigned int loops = test_intervals[0]/interval; - - for(unsigned int i = 0; i < loops; ++i) { - struct itimerval enable = {{0, 0}, {0, interval}}; - hit = 0; - auto start = std::chrono::high_resolution_clock::now(); - if(setitimer(ITIMER_REAL, &enable, NULL)) - return; - while(!hit) {} - auto end = std::chrono::high_resolution_clock::now(); - int timer_slop = std::chrono::duration_cast(end-start).count() - interval; - - //since more samples are run for the shorter expirations, weigh the longer expirations accordingly. This - //helps to make a few results more fair. Two such examples: AWS c4&i5 xen instances being rather stable - //down to 100us but then struggling with 50us and 10us. MacOS having performance that seems to correlate - //with expiry length; that is, long expirations have high error, short expirations have low error. - //That said, for these platforms, a tighter tolerance may possibly be achieved by taking performance - //metrics in mulitple bins and appliying the slop based on which bin a deadline resides in. Not clear - //if that's worth the extra complexity at this point. - samples(timer_slop, bacc::weight = interval/(float)test_intervals[0]); - } - } - timer_overhead = bacc::mean(samples) + sqrt(bacc::variance(samples))*2; //target 95% of expirations before deadline - use_deadline_timer = timer_overhead < 1000; - - act.sa_handler = SIG_DFL; - sigaction(SIGALRM, &act, NULL); - } - - static void timer_hit(int) { - hit = 1; - } - static volatile sig_atomic_t hit; - - bacc::accumulator_set, float> samples; - bool use_deadline_timer = false; - int timer_overhead; - }; - volatile sig_atomic_t deadline_timer_verify::hit; - static deadline_timer_verify deadline_timer_verification; - - deadline_timer::deadline_timer() { - if(initialized) - return; - initialized = true; - - #define TIMER_STATS_FORMAT "min:${min}us max:${max}us mean:${mean}us stddev:${stddev}us" - #define TIMER_STATS \ - ("min", bacc::min(deadline_timer_verification.samples))("max", bacc::max(deadline_timer_verification.samples)) \ - ("mean", (int)bacc::mean(deadline_timer_verification.samples))("stddev", (int)sqrt(bacc::variance(deadline_timer_verification.samples))) \ - ("t", deadline_timer_verification.timer_overhead) - - if(deadline_timer_verification.use_deadline_timer) { - struct sigaction act; - act.sa_handler = timer_expired; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - if(sigaction(SIGALRM, &act, NULL) == 0) { - ilog("Using ${t}us deadline timer for checktime: " TIMER_STATS_FORMAT, TIMER_STATS); - return; - } - } - - wlog("Using polled checktime; deadline timer too inaccurate: " TIMER_STATS_FORMAT, TIMER_STATS); - deadline_timer_verification.use_deadline_timer = false; //set in case sigaction() fails above + transaction_checktime_timer::transaction_checktime_timer(platform_timer& timer) + : expired(timer.expired), _timer(timer) { + expired = 0; } - void deadline_timer::start(fc::time_point tp) { - if(tp == fc::time_point::maximum()) { - expired = 0; - return; - } - if(!deadline_timer_verification.use_deadline_timer) { - expired = 1; - return; - } - microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch(); - if(x.count() <= deadline_timer_verification.timer_overhead) - expired = 1; - else { - struct itimerval enable = {{0, 0}, {0, (int)x.count()-deadline_timer_verification.timer_overhead}}; - expired = 0; - if(setitimer(ITIMER_REAL, &enable, NULL)) - expired = 1; - } + void transaction_checktime_timer::start(fc::time_point tp) { + _timer.start(tp); } - void deadline_timer::stop() { - if(expired) - return; - struct itimerval disable = {{0, 0}, {0, 0}}; - setitimer(ITIMER_REAL, &disable, NULL); + void transaction_checktime_timer::stop() { + _timer.stop(); } - deadline_timer::~deadline_timer() { - stop(); + void transaction_checktime_timer::set_expiration_callback(void(*func)(void*), void* user) { + _timer.set_expiration_callback(func, user); } - void deadline_timer::timer_expired(int) { - expired = 1; + transaction_checktime_timer::~transaction_checktime_timer() { + stop(); + _timer.set_expiration_callback(nullptr, nullptr); } - volatile sig_atomic_t deadline_timer::expired = 0; - bool deadline_timer::initialized = false; - - transaction_checktime_timer::transaction_checktime_timer(platform_timer& timer) - : expired(timer.expired), _timer(timer) { - expired = 0; - } - - void transaction_checktime_timer::start(fc::time_point tp) { - _timer.start(tp); - } - - void transaction_checktime_timer::stop() { - _timer.stop(); - } - - void transaction_checktime_timer::set_expiration_callback(void(*func)(void*), void* user) { - _timer.set_expiration_callback(func, user); - } - - transaction_checktime_timer::~transaction_checktime_timer() { - stop(); - _timer.set_expiration_callback(nullptr, nullptr); - } transaction_context::transaction_context( controller& c, const signed_transaction& t, const transaction_id_type& trx_id, - transaction_checktime_timer&& tmr, - fc::time_point s ) + transaction_checktime_timer&& tmr, + fc::time_point s ) :control(c) ,trx(t) ,id(trx_id) @@ -187,11 +62,18 @@ namespace bacc = boost::accumulators; undo_session = c.mutable_db().start_undo_session(true); } trace->id = id; - trace->block_num = c.pending_block_state()->block_num; + trace->block_num = c.head_block_num() + 1; trace->block_time = c.pending_block_time(); trace->producer_block_id = c.pending_producer_block_id(); executed.reserve( trx.total_actions() ); - EOS_ASSERT( trx.transaction_extensions.size() == 0, unsupported_feature, "we don't support any extensions yet" ); + } + + void transaction_context::disallow_transaction_extensions( const char* error_msg )const { + if( control.is_producing_block() ) { + EOS_THROW( subjective_block_production_exception, error_msg ); + } else { +// EOS_THROW( disallowed_transaction_extensions_bad_block_exception, error_msg ); + } } void transaction_context::init(uint64_t initial_net_usage) @@ -239,8 +121,8 @@ namespace bacc = boost::accumulators; initial_objective_duration_limit = objective_duration_limit; - if( billed_cpu_time_us > 0 ) // could also call on explicit_billed_cpu_time but it would be redundant - validate_cpu_usage_to_bill( billed_cpu_time_us, false ); // Fail early if the amount to be billed is too high + if( explicit_billed_cpu_time ) + validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits::max(), false ); // Fail early if the amount to be billed is too high // Record accounts to be billed for network and CPU usage for( const auto& act : trx.actions ) { @@ -286,6 +168,11 @@ namespace bacc = boost::accumulators; deadline_exception_code = billing_timer_exception_code; } + if( !explicit_billed_cpu_time ) { + // if account no longer has enough cpu to exec trx, don't try + validate_account_cpu_usage( billed_cpu_time_us, account_cpu_limit, true ); + } + eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes) so check_net_usage can be efficient if( initial_net_usage > 0 ) @@ -294,15 +181,19 @@ namespace bacc = boost::accumulators; checktime(); // Fail early if deadline has already been exceeded if(control.skip_trx_checks()) - _deadline_timer.expired = 0; + transaction_timer.start(fc::time_point::maximum()); else - _deadline_timer.start(_deadline); + transaction_timer.start(_deadline); is_initialized = true; } void transaction_context::init_for_implicit_trx( uint64_t initial_net_usage ) { + if( trx.transaction_extensions.size() > 0 ) { + disallow_transaction_extensions( "no transaction extensions supported yet for implicit transactions" ); + } + published = control.pending_block_time(); init( initial_net_usage); } @@ -311,6 +202,10 @@ namespace bacc = boost::accumulators; uint64_t packed_trx_prunable_size, bool skip_recording ) { + if( trx.transaction_extensions.size() > 0 ) { + disallow_transaction_extensions( "no transaction extensions supported yet for input transactions" ); + } + const auto& cfg = control.get_global_properties().configuration; uint64_t discounted_size_for_pruned_data = packed_trx_prunable_size; @@ -347,6 +242,14 @@ namespace bacc = boost::accumulators; void transaction_context::init_for_deferred_trx( fc::time_point p ) { + if( (trx.expiration.sec_since_epoch() != 0) && (trx.transaction_extensions.size() > 0) ) { + disallow_transaction_extensions( "no transaction extensions supported yet for deferred transactions" ); + } + // If (trx.expiration.sec_since_epoch() == 0) then it was created after NO_DUPLICATE_DEFERRED_ID activation, + // and so validation of its extensions was done either in: + // * apply_context::schedule_deferred_transaction for contract-generated transactions; + // * or transaction_context::init_for_input_trx for delayed input transactions. + published = p; trace->scheduled = true; apply_context_free = false; @@ -358,17 +261,23 @@ namespace bacc = boost::accumulators; if( apply_context_free ) { for( const auto& act : trx.context_free_actions ) { - trace->action_traces.emplace_back(); - dispatch_action( trace->action_traces.back(), act, true ); + schedule_action( act, act.account, true, 0, 0 ); } } if( delay == fc::microseconds() ) { for( const auto& act : trx.actions ) { - trace->action_traces.emplace_back(); - dispatch_action( trace->action_traces.back(), act ); + schedule_action( act, act.account, false, 0, 0 ); } - } else { + } + + auto& action_traces = trace->action_traces; + uint32_t num_original_actions_to_execute = action_traces.size(); + for( uint32_t i = 1; i <= num_original_actions_to_execute; ++i ) { + execute_action( i, 0 ); + } + + if( delay != fc::microseconds() ) { schedule_transaction(); } } @@ -422,7 +331,7 @@ namespace bacc = boost::accumulators; update_billed_cpu_time( now ); - validate_cpu_usage_to_bill( billed_cpu_time_us ); + validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true ); rl.add_transaction_usage( bill_to_accounts, static_cast(billed_cpu_time_us), net_usage, block_timestamp_type(control.pending_block_time()).slot ); // Should never fail @@ -457,35 +366,34 @@ namespace bacc = boost::accumulators; } void transaction_context::checktime()const { - if(BOOST_LIKELY(_deadline_timer.expired == false)) + if(BOOST_LIKELY(transaction_timer.expired == false)) return; + auto now = fc::time_point::now(); - if( BOOST_UNLIKELY( now > _deadline ) ) { - // edump((now-start)(now-pseudo_start)); - if( explicit_billed_cpu_time || deadline_exception_code == deadline_exception::code_value ) { - EOS_THROW( deadline_exception, "deadline exceeded", ("now", now)("deadline", _deadline)("start", start) ); - } else if( deadline_exception_code == block_cpu_usage_exceeded::code_value ) { - EOS_THROW( block_cpu_usage_exceeded, - "not enough time left in block to complete executing transaction", - ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); - } else if( deadline_exception_code == tx_cpu_usage_exceeded::code_value ) { - if (cpu_limit_due_to_greylist) { - EOS_THROW( greylist_cpu_usage_exceeded, - "greylisted transaction was executing for too long", - ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); - } else { - EOS_THROW( tx_cpu_usage_exceeded, - "transaction was executing for too long", - ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); - } - } else if( deadline_exception_code == leeway_deadline_exception::code_value ) { - EOS_THROW( leeway_deadline_exception, - "the transaction was unable to complete by deadline, " - "but it is possible it could have succeeded if it were allowed to run to completion", - ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); + if( explicit_billed_cpu_time || deadline_exception_code == deadline_exception::code_value ) { + EOS_THROW( deadline_exception, "deadline exceeded ${billing_timer}us", + ("billing_timer", now - pseudo_start)("now", now)("deadline", _deadline)("start", start) ); + } else if( deadline_exception_code == block_cpu_usage_exceeded::code_value ) { + EOS_THROW( block_cpu_usage_exceeded, + "not enough time left in block to complete executing transaction ${billing_timer}us", + ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); + } else if( deadline_exception_code == tx_cpu_usage_exceeded::code_value ) { + if (cpu_limit_due_to_greylist) { + EOS_THROW( greylist_cpu_usage_exceeded, + "greylisted transaction was executing for too long ${billing_timer}us", + ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); + } else { + EOS_THROW( tx_cpu_usage_exceeded, + "transaction was executing for too long ${billing_timer}us", + ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); } - EOS_ASSERT( false, transaction_exception, "unexpected deadline exception code" ); + } else if( deadline_exception_code == leeway_deadline_exception::code_value ) { + EOS_THROW( leeway_deadline_exception, + "the transaction was unable to complete by deadline, " + "but it is possible it could have succeeded if it were allowed to run to completion ${billing_timer}", + ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); } + EOS_ASSERT( false, transaction_exception, "unexpected deadline exception code ${code}", ("code", deadline_exception_code) ); } void transaction_context::pause_billing_timer() { @@ -495,7 +403,7 @@ namespace bacc = boost::accumulators; billed_time = now - pseudo_start; deadline_exception_code = deadline_exception::code_value; // Other timeout exceptions cannot be thrown while billable timer is paused. pseudo_start = fc::time_point(); - _deadline_timer.stop(); + transaction_timer.stop(); } void transaction_context::resume_billing_timer() { @@ -510,10 +418,10 @@ namespace bacc = boost::accumulators; _deadline = deadline; deadline_exception_code = deadline_exception::code_value; } - _deadline_timer.start(_deadline); + transaction_timer.start(_deadline); } - void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, bool check_minimum )const { + void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const { if (!control.skip_trx_checks()) { if( check_minimum ) { const auto& cfg = control.get_global_properties().configuration; @@ -523,25 +431,35 @@ namespace bacc = boost::accumulators; ); } - if( billing_timer_exception_code == block_cpu_usage_exceeded::code_value ) { + validate_account_cpu_usage( billed_us, account_cpu_limit, false ); + } + } + + void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, bool estimate )const { + if( (billed_us > 0) && !control.skip_trx_checks() ) { + const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count()); + + if( !cpu_limited_by_account && (billing_timer_exception_code == block_cpu_usage_exceeded::code_value) ) { EOS_ASSERT( billed_us <= objective_duration_limit.count(), block_cpu_usage_exceeded, - "billed CPU time (${billed} us) is greater than the billable CPU time left in the block (${billable} us)", - ("billed", billed_us)("billable", objective_duration_limit.count()) - ); + "${desc} CPU time (${billed} us) is greater than the billable CPU time left in the block (${billable} us)", + ("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", objective_duration_limit.count() ) + ); } else { - if (cpu_limit_due_to_greylist) { - EOS_ASSERT( billed_us <= objective_duration_limit.count(), + if( cpu_limit_due_to_greylist && cpu_limited_by_account ) { + EOS_ASSERT( billed_us <= account_cpu_limit, greylist_cpu_usage_exceeded, - "billed CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)", - ("billed", billed_us)("billable", objective_duration_limit.count()) + "${desc} CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)", + ("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", account_cpu_limit ) ); } else { - EOS_ASSERT( billed_us <= objective_duration_limit.count(), + // exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater + const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count()); + EOS_ASSERT( billed_us <= cpu_limit, tx_cpu_usage_exceeded, - "billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)", - ("billed", billed_us)("billable", objective_duration_limit.count()) - ); + "${desc} CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)", + ("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", cpu_limit ) + ); } } } @@ -591,14 +509,75 @@ namespace bacc = boost::accumulators; return std::make_tuple(account_net_limit, account_cpu_limit, greylisted_net, greylisted_cpu); } - void transaction_context::dispatch_action( action_trace& trace, const action& a, account_name receiver, bool context_free, uint32_t recurse_depth ) { - apply_context acontext( control, *this, a, recurse_depth ); - acontext.context_free = context_free; - acontext.receiver = receiver; + action_trace& transaction_context::get_action_trace( uint32_t action_ordinal ) { + EOS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() , + transaction_exception, + "action_ordinal ${ordinal} is outside allowed range [1,${max}]", + ("ordinal", action_ordinal)("max", trace->action_traces.size()) + ); + return trace->action_traces[action_ordinal-1]; + } - acontext.exec( trace ); + const action_trace& transaction_context::get_action_trace( uint32_t action_ordinal )const { + EOS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() , + transaction_exception, + "action_ordinal ${ordinal} is outside allowed range [1,${max}]", + ("ordinal", action_ordinal)("max", trace->action_traces.size()) + ); + return trace->action_traces[action_ordinal-1]; } + uint32_t transaction_context::schedule_action( const action& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ) + { + uint32_t new_action_ordinal = trace->action_traces.size() + 1; + + trace->action_traces.emplace_back( *trace, act, receiver, context_free, + new_action_ordinal, creator_action_ordinal, + closest_unnotified_ancestor_action_ordinal ); + + return new_action_ordinal; + } + + uint32_t transaction_context::schedule_action( action&& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ) + { + uint32_t new_action_ordinal = trace->action_traces.size() + 1; + + trace->action_traces.emplace_back( *trace, std::move(act), receiver, context_free, + new_action_ordinal, creator_action_ordinal, + closest_unnotified_ancestor_action_ordinal ); + + return new_action_ordinal; + } + + uint32_t transaction_context::schedule_action( uint32_t action_ordinal, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ) + { + uint32_t new_action_ordinal = trace->action_traces.size() + 1; + + trace->action_traces.reserve( new_action_ordinal ); + + const action& provided_action = get_action_trace( action_ordinal ).act; + + // The reserve above is required so that the emplace_back below does not invalidate the provided_action reference. + + trace->action_traces.emplace_back( *trace, provided_action, receiver, context_free, + new_action_ordinal, creator_action_ordinal, + closest_unnotified_ancestor_action_ordinal ); + + return new_action_ordinal; + } + + void transaction_context::execute_action( uint32_t action_ordinal, uint32_t recurse_depth ) { + apply_context acontext( control, *this, action_ordinal, recurse_depth ); + acontext.exec(); + } + + void transaction_context::schedule_transaction() { // Charge ahead of time for the additional net usage needed to retire the delayed transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. @@ -622,7 +601,9 @@ namespace bacc = boost::accumulators; trx_size = gto.set( trx ); }); - add_ram_usage( cgto.payer, (config::billable_size_v + trx_size) ); + int64_t ram_delta = (config::billable_size_v + trx_size); + add_ram_usage( cgto.payer, ram_delta ); + trace->account_ram_delta = account_delta( cgto.payer, ram_delta ); } void transaction_context::record_transaction( const transaction_id_type& id, fc::time_point_sec expire ) { @@ -664,7 +645,7 @@ namespace bacc = boost::accumulators; EOS_ASSERT( actor != nullptr, transaction_exception, "action's authorizing actor '${account}' does not exist", ("account", auth.actor) ); EOS_ASSERT( auth_manager.find_permission(auth) != nullptr, transaction_exception, - "action's authorizations include a non-existent permission: {permission}", + "action's authorizations include a non-existent permission: ${permission}", ("permission", auth) ); if( enforce_actor_whitelist_blacklist ) actors.insert( auth.actor ); diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index a89251f293c..2ebd2abc503 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -144,7 +144,7 @@ class privileged_api : public context_aware_api { privileged_api( apply_context& ctx ) :context_aware_api(ctx) { - EOS_ASSERT( context.privileged, unaccessible_api, "${code} does not have permission to call this API", ("code",context.receiver) ); + EOS_ASSERT( context.is_privileged(), unaccessible_api, "${code} does not have permission to call this API", ("code",context.get_receiver()) ); } /** @@ -1464,8 +1464,9 @@ class context_free_transaction_api : public context_aware_api { id = context.trx_context.id; } + /// TODO void get_action_sequence(uint64_t& seq){ - seq = context.global_action_sequence; +// seq = context.global_action_sequence; } bool has_contract(account_name name){ @@ -1778,69 +1779,70 @@ class action_seed_api : public context_aware_api { : context_aware_api(ctx) {} int bpsig_action_time_seed(array_ptr sig, uint32_t siglen) { - auto data = action_timestamp(); - fc::sha256::encoder encoder; - encoder.write(reinterpret_cast(data.data()), data.size()* sizeof(uint32_t)); - auto digest = encoder.result(); - optional signature; - auto block_state = context.control.pending_block_state(); - for (auto& extension: block_state->block->block_extensions) { - if (extension.first != static_cast(block_extension_type::bpsig_action_time_seed)) continue; - EOS_ASSERT(extension.second.size() > 8, transaction_exception, "invalid producer signature in block extensions"); - uint64_t* act_parts = reinterpret_cast(extension.second.data()); - if ( act_parts[0] != context.global_action_sequence) continue; - - auto sig_data = extension.second.data() + 8; - auto sig_size = extension.second.size() - 8; - signature.emplace(); - datastream ds(sig_data, sig_size); - fc::raw::unpack(ds, *signature); - auto check = fc::crypto::public_key(*signature, digest, false); - EOS_ASSERT( check == block_state->block_signing_key, transaction_exception, "wrong expected key different than recovered key" ); - break; - } - bool sign = false; - if (context.control.is_producing_block() && !signature) { - auto signer = context.control.pending_producer_signer(); - if (signer) { - // Producer is producing this block - signature = signer(digest); - sign = true; - } else { - // Non-producer is speculating this block, so skips the signing - // TODO: speculating result will be different from producing result - signature.emplace(); - } - } - EOS_ASSERT(!!signature, transaction_exception, "empty sig action seed"); - auto& s = *signature; - auto sig_size = fc::raw::pack_size(s); - if (siglen == 0) return sig_size; - if (sig_size <= siglen) { - datastream ds(sig, sig_size); - fc::raw::pack(ds, s); - if (sign) { - block_state->block->block_extensions.emplace_back(); - char* act_parts = reinterpret_cast(&context.global_action_sequence); - auto &extension = block_state->block->block_extensions.back(); - extension.first = static_cast(block_extension_type::bpsig_action_time_seed); - extension.second.resize(8 + sig_size); - std::copy(act_parts, act_parts + 8, extension.second.data()); - std::copy((char*)sig, (char*)sig + sig_size, extension.second.data() + 8); - } - return sig_size; - } +// auto data = action_timestamp(); +// fc::sha256::encoder encoder; +// encoder.write(reinterpret_cast(data.data()), data.size()* sizeof(uint32_t)); +// auto digest = encoder.result(); +// optional signature; +// auto block_state = context.control.pending_block_state(); +// for (auto& extension: block_state->block->block_extensions) { +// if (extension.first != static_cast(block_extension_type::bpsig_action_time_seed)) continue; +// EOS_ASSERT(extension.second.size() > 8, transaction_exception, "invalid producer signature in block extensions"); +// uint64_t* act_parts = reinterpret_cast(extension.second.data()); +// /// TODO +//// if ( act_parts[0] != context.global_action_sequence) continue; +// +// auto sig_data = extension.second.data() + 8; +// auto sig_size = extension.second.size() - 8; +// signature.emplace(); +// datastream ds(sig_data, sig_size); +// fc::raw::unpack(ds, *signature); +// auto check = fc::crypto::public_key(*signature, digest, false); +// EOS_ASSERT( check == block_state->block_signing_key, transaction_exception, "wrong expected key different than recovered key" ); +// break; +// } +// bool sign = false; +// if (context.control.is_producing_block() && !signature) { +// auto signer = context.control.pending_producer_signer(); +// if (signer) { +// // Producer is producing this block +// signature = signer(digest); +// sign = true; +// } else { +// // Non-producer is speculating this block, so skips the signing +// // TODO: speculating result will be different from producing result +// signature.emplace(); +// } +// } +// EOS_ASSERT(!!signature, transaction_exception, "empty sig action seed"); +// auto& s = *signature; +// auto sig_size = fc::raw::pack_size(s); +// if (siglen == 0) return sig_size; +// if (sig_size <= siglen) { +// datastream ds(sig, sig_size); +// fc::raw::pack(ds, s); +// if (sign) { +// block_state->block->block_extensions.emplace_back(); +//// char* act_parts = reinterpret_cast(&context.global_action_sequence); +// auto &extension = block_state->block->block_extensions.back(); +// extension.first = static_cast(block_extension_type::bpsig_action_time_seed); +// extension.second.resize(8 + sig_size); +//// std::copy(act_parts, act_parts + 8, extension.second.data()); +//// std::copy((char*)sig, (char*)sig + sig_size, extension.second.data() + 8); +// } +// return sig_size; +// } return 0; } private: - vector action_timestamp() { - auto current = context.control.pending_block_time().time_since_epoch().count(); - current -= current % (config::block_interval_us); - - uint32_t* current_halves = reinterpret_cast(¤t); - uint32_t* act_parts = reinterpret_cast(&context.global_action_sequence); - return vector{act_parts[0],act_parts[1], current_halves[0], current_halves[1]}; - } +// vector action_timestamp() { +// auto current = context.control.pending_block_time().time_since_epoch().count(); +// current -= current % (config::block_interval_us); +// +// uint32_t* current_halves = reinterpret_cast(¤t); +// uint32_t* act_parts = reinterpret_cast(&context.global_action_sequence); +// return vector{act_parts[0],act_parts[1], current_halves[0], current_halves[1]}; +// } }; REGISTER_INTRINSICS(action_seed_api, diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ff20e506064..78228a960c6 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -176,7 +176,7 @@ class chain_plugin_impl { fc::optional pbft_ctrl; //txn_msg_rate_limits rate_limits; fc::optional wasm_runtime; - fc::microseconds abi_serializer_max_time_ms; + fc::microseconds abi_serializer_max_time_us; fc::optional snapshot_path; void on_pbft_incoming_prepare(const pbft_metadata_ptr& p); @@ -263,7 +263,7 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip EOS_ASSERT(false, plugin_exception, ""); } #endif - }), "Override default WASM runtime") ("abi-serializer-max-time-ms", bpo::value()->default_value(config::default_abi_serializer_max_time_ms), + }), "Override default WASM runtime") ("abi-serializer-max-time-us", bpo::value()->default_value(config::default_abi_serializer_max_time_us), "Override default maximum ABI serialization time allowed in ms") ("chain-state-db-size-mb", bpo::value()->default_value(config::default_state_size / (1024 * 1024)), "Maximum size (in MiB) of the chain state database") ("chain-state-db-guard-size-mb", bpo::value()->default_value(config::default_state_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the chain state database drops below this size (in MiB).") @@ -360,10 +360,12 @@ T dejsonify(const string& s) { return fc::json::from_string(s).as(); } -#define LOAD_VALUE_SET(options, name, container) \ -if( options.count(name) ) { \ - const std::vector& ops = options[name].as>(); \ - std::copy(ops.begin(), ops.end(), std::inserter(container, container.end())); \ +#define LOAD_VALUE_SET(options, op_name, container) \ +if( options.count(op_name) ) { \ + const std::vector& ops = options[op_name].as>(); \ + for( const auto& v : ops ) { \ + container.emplace( eosio::chain::name( v ) ); \ + } \ } static signature_provider_type @@ -477,7 +479,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { EOS_ASSERT( pos != std::string::npos, plugin_config_exception, "Invalid entry in action-blacklist: '${a}'", ("a", a)); account_name code( a.substr( 0, pos )); action_name act( a.substr( pos + 2 )); - list.emplace( code.value, act.value ); + list.emplace( code, act ); } } @@ -518,8 +520,8 @@ void chain_plugin::plugin_initialize(const variables_map& options) { if( options.count( "wasm-runtime" )) my->wasm_runtime = options.at( "wasm-runtime" ).as(); - if(options.count("abi-serializer-max-time-ms")) - my->abi_serializer_max_time_ms = fc::microseconds(options.at("abi-serializer-max-time-ms").as() * 1000); + if(options.count("abi-serializer-max-time-us")) + my->abi_serializer_max_time_us = fc::microseconds(options.at("abi-serializer-max-time-us").as() * 1000); my->chain_config->blocks_dir = my->blocks_dir; my->chain_config->state_dir = app().data_dir() / config::default_state_dir_name; @@ -1191,7 +1193,7 @@ chain::chain_id_type chain_plugin::get_chain_id()const { } fc::microseconds chain_plugin::get_abi_serializer_max_time() const { - return my->abi_serializer_max_time_ms; + return my->abi_serializer_max_time_us; } void chain_plugin::log_guard_exception(const chain::guard_exception&e ) const { @@ -1259,7 +1261,7 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params uint64_t read_only::get_table_index_name(const read_only::get_table_rows_params& p, bool& primary) { using boost::algorithm::starts_with; // see multi_index packing of index name - const uint64_t table = p.table; + const uint64_t table = p.table.to_uint64_t(); uint64_t index = table & 0xFFFFFFFFFFFFFFF0ULL; EOS_ASSERT( index == table, chain::contract_table_query_exception, "Unsupported table name: ${n}", ("n", p.table) ); @@ -1312,7 +1314,7 @@ uint64_t convert_to_type(const string& str, const string& desc) { auto trimmed_str = str; boost::trim(trimmed_str); name s(trimmed_str); - return s.value; + return s.to_uint64_t(); } catch( ... ) { } if (str.find(',') != string::npos) { // fix #6274 only match formats like 4,EOS @@ -1426,18 +1428,18 @@ read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_o const auto& d = db.db(); const auto& idx = d.get_index(); - auto lower_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits::lowest(), p.table.value ); - auto upper_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits::max(), - (p.table.empty() ? std::numeric_limits::max() : p.table.value) ); + auto lower_bound_lookup_tuple = std::make_tuple( p.code, name(std::numeric_limits::lowest()), p.table ); + auto upper_bound_lookup_tuple = std::make_tuple( p.code, name(std::numeric_limits::max()), + (p.table.empty() ? name(std::numeric_limits::max()) : p.table) ); if( p.lower_bound.size() ) { uint64_t scope = convert_to_type(p.lower_bound, "lower_bound scope"); - std::get<1>(lower_bound_lookup_tuple) = scope; + std::get<1>(lower_bound_lookup_tuple) = name(scope); } if( p.upper_bound.size() ) { uint64_t scope = convert_to_type(p.upper_bound, "upper_bound scope"); - std::get<1>(upper_bound_lookup_tuple) = scope; + std::get<1>(upper_bound_lookup_tuple) = name(scope); } if( upper_bound_lookup_tuple < lower_bound_lookup_tuple ) @@ -1454,7 +1456,7 @@ read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_o ++count; } if( itr != end_itr ) { - result.more = string(itr->scope); + result.more = itr->scope.to_string(); } }; @@ -1472,7 +1474,7 @@ read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_o vector read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const { const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); - (void)get_table_type( abi, "accounts" ); + (void)get_table_type( abi, name("accounts") ); vector results; walk_key_value_table(p.code, p.account, N(accounts), [&](const key_value_object& obj){ @@ -1499,11 +1501,11 @@ fc::variant read_only::get_currency_stats( const read_only::get_currency_stats_p fc::mutable_variant_object results; const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); - (void)get_table_type( abi, "stat" ); + (void)get_table_type( abi, name("stat") ); uint64_t scope = ( eosio::chain::string_to_symbol( 0, boost::algorithm::to_upper_copy(p.symbol).c_str() ) >> 8 ); - walk_key_value_table(p.code, scope, N(stat), [&](const key_value_object& obj){ + walk_key_value_table(p.code, name(scope), N(stat), [&](const key_value_object& obj){ EOS_ASSERT( obj.value.size() >= sizeof(read_only::get_currency_stats_result), chain::asset_type_exception, "Invalid data on table"); fc::datastream ds(obj.value.data(), obj.value.size()); @@ -1534,7 +1536,7 @@ fc::variant get_global_row( const database& db, const abi_def& abi, const abi_se EOS_ASSERT(table_id, chain::contract_table_query_exception, "Missing table global"); const auto& kv_index = db.get_index(); - const auto it = kv_index.find(boost::make_tuple(table_id->id, N(global))); + const auto it = kv_index.find(boost::make_tuple(table_id->id, N(global).to_uint64_t())); EOS_ASSERT(it != kv_index.end(), chain::contract_table_query_exception, "Missing row in table global"); vector data; @@ -1555,7 +1557,7 @@ read_only::get_producers_result read_only::get_producers( const read_only::get_p const auto* const table_id = d.find( boost::make_tuple(config::system_account_name, config::system_account_name, N(producers))); const auto* const secondary_table_id = d.find( - boost::make_tuple(config::system_account_name, config::system_account_name, N(producers) | secondary_index_num)); + boost::make_tuple(config::system_account_name, config::system_account_name, name(N(producers).to_uint64_t() | secondary_index_num))); EOS_ASSERT(table_id && secondary_table_id, chain::contract_table_query_exception, "Missing producers table"); const auto& kv_index = d.get_index(); @@ -1568,13 +1570,13 @@ read_only::get_producers_result read_only::get_producers( const read_only::get_p vector data; auto it = [&]{ - if(lower.value == 0) + if(lower.to_uint64_t() == 0) return secondary_index_by_secondary.lower_bound( boost::make_tuple(secondary_table_id->id, to_softfloat64(std::numeric_limits::lowest()), 0)); else return secondary_index.project( secondary_index_by_primary.lower_bound( - boost::make_tuple(secondary_table_id->id, lower.value))); + boost::make_tuple(secondary_table_id->id, lower.to_uint64_t()))); }(); for( ; it != secondary_index_by_secondary.end() && it->t_id == secondary_table_id->id; ++it ) { @@ -1991,7 +1993,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& t_id = d.find(boost::make_tuple( config::system_account_name, params.account_name, N(userres) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, params.account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2002,7 +2004,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& t_id = d.find(boost::make_tuple( config::system_account_name, params.account_name, N(delband) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, params.account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2013,7 +2015,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& t_id = d.find(boost::make_tuple( config::system_account_name, params.account_name, N(refunds) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, params.account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2024,7 +2026,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& t_id = d.find(boost::make_tuple( config::system_account_name, config::system_account_name, N(voters) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, params.account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2039,19 +2041,21 @@ read_only::get_account_results read_only::get_account( const get_account_params& abi_def abi_personal; if( abi_serializer::to_abi(personal_account.abi, abi_personal) ) { abi_serializer abis_personal( abi_personal, abi_serializer_max_time ); - const auto* t_id = d.find(boost::make_tuple( N(personal.bos), params.account_name, N(personaldata) )); - if (t_id != nullptr) { - const auto &idx = d.get_index(); - - name key_name{"homepage"}; - auto it = idx.find(boost::make_tuple( t_id->id, key_name.value )); - if ( it != idx.end() ) { - vector data; - copy_inline_row(*it, data); - variant raw_data= abis_personal.binary_to_variant( "personal", data, abi_serializer_max_time, shorten_abi_errors ); - result.homepage=raw_data["value"].as_string(); - } - } + /// TODO +// const auto* t_id = d.find(boost::make_tuple( N(personal.bos), params.account_name.to_uint64_t(), N(personaldata) )); +// const auto *t_id = nullptr_t; +// if (t_id != nullptr) { +// const auto &idx = d.get_index(); +// +// name key_name{"homepage"}; +// auto it = idx.find(boost::make_tuple( t_id->id, key_name.to_uint64_t())); +// if ( it != idx.end() ) { +// vector data; +// copy_inline_row(*it, data); +// variant raw_data= abis_personal.binary_to_variant( "personal", data, abi_serializer_max_time, shorten_abi_errors ); +// result.homepage=raw_data["value"].as_string(); +// } +// } } } return result; @@ -2092,7 +2096,7 @@ read_only::get_act_token_result read_only::get_act_token( const name& account_na const auto* t_id = d.find(boost::make_tuple( config::system_account_name, config::system_account_name, N(rexfund) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2102,7 +2106,7 @@ read_only::get_act_token_result read_only::get_act_token( const name& account_na t_id = d.find(boost::make_tuple( config::system_account_name, config::system_account_name, N(rexbal) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index b397b2da0b2..29eab70f502 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -294,13 +294,14 @@ class read_only { struct get_table_rows_result { vector rows; ///< one row per item, either encoded as hex String or JSON object bool more = false; ///< true if last element in data is not the end and sizeof data() < limit + string next_key; ///< fill lower_bound with this value to fetch more rows }; get_table_rows_result get_table_rows( const get_table_rows_params& params )const; struct get_table_by_scope_params { name code; // mandatory - name table = 0; // optional, act as filter + name table; // optional, act as filter string lower_bound; // lower bound of scope, optional string upper_bound; // upper bound of scope, optional uint32_t limit = 10; @@ -411,14 +412,14 @@ class read_only { read_only::get_table_rows_result result; const auto& d = db.db(); - uint64_t scope = convert_to_type(p.scope, "scope"); + name scope{ convert_to_type(p.scope, "scope") }; abi_serializer abis; abis.set_abi(abi, abi_serializer_max_time); bool primary = false; const uint64_t table_with_index = get_table_index_name(p, primary); const auto* t_id = d.find(boost::make_tuple(p.code, scope, p.table)); - const auto* index_t_id = d.find(boost::make_tuple(p.code, scope, table_with_index)); + const auto* index_t_id = d.find(boost::make_tuple(p.code, scope, name(table_with_index))); if( t_id != nullptr && index_t_id != nullptr ) { using secondary_key_type = std::result_of_t; static_assert( std::is_same::value, "Return type of conv does not match type of secondary key for IndexType" ); @@ -505,7 +506,7 @@ class read_only { abi_serializer abis; abis.set_abi(abi, abi_serializer_max_time); - const auto* t_id = d.find(boost::make_tuple(p.code, scope, p.table)); + const auto* t_id = d.find(boost::make_tuple(p.code, name(scope), p.table)); if( t_id != nullptr ) { const auto& idx = d.get_index(); auto lower_bound_lookup_tuple = std::make_tuple( t_id->id, std::numeric_limits::lowest() ); @@ -514,7 +515,7 @@ class read_only { if( p.lower_bound.size() ) { if( p.key_type == "name" ) { name s(p.lower_bound); - std::get<1>(lower_bound_lookup_tuple) = s.value; + std::get<1>(lower_bound_lookup_tuple) = s.to_uint64_t(); } else { auto lv = convert_to_type( p.lower_bound, "lower_bound" ); std::get<1>(lower_bound_lookup_tuple) = lv; @@ -524,7 +525,7 @@ class read_only { if( p.upper_bound.size() ) { if( p.key_type == "name" ) { name s(p.upper_bound); - std::get<1>(upper_bound_lookup_tuple) = s.value; + std::get<1>(upper_bound_lookup_tuple) = s.to_uint64_t(); } else { auto uv = convert_to_type( p.upper_bound, "upper_bound" ); std::get<1>(upper_bound_lookup_tuple) = uv; diff --git a/plugins/history_api_plugin/history_api_plugin.cpp b/plugins/history_api_plugin/history_api_plugin.cpp index 1a610d7a395..d76dd7fd44b 100644 --- a/plugins/history_api_plugin/history_api_plugin.cpp +++ b/plugins/history_api_plugin/history_api_plugin.cpp @@ -43,7 +43,6 @@ void history_api_plugin::plugin_startup() { // CHAIN_RO_CALL(get_transaction), CHAIN_RO_CALL(get_actions), CHAIN_RO_CALL(get_transaction), - CHAIN_RO_CALL(get_block_detail), CHAIN_RO_CALL(get_key_accounts), CHAIN_RO_CALL(get_controlled_accounts) }); diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index 5ce12dba17f..5223c147f61 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -148,34 +148,34 @@ namespace eosio { if (bypass_filter) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, 0, 0 }) != filter_on.end()) { + if (filter_on.find({ act.receiver, {}, {} }) != filter_on.end()) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, act.act.name, 0 }) != filter_on.end()) { + if (filter_on.find({ act.receiver, act.act.name, {} }) != filter_on.end()) { pass_on = true; } for (const auto& a : act.act.authorization) { - if (filter_on.find({ act.receipt.receiver, 0, a.actor }) != filter_on.end()) { + if (filter_on.find({ act.receiver, {}, a.actor }) != filter_on.end()) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end()) { + if (filter_on.find({ act.receiver, act.act.name, a.actor }) != filter_on.end()) { pass_on = true; } } if (!pass_on) { return false; } - if (filter_out.find({ act.receipt.receiver, 0, 0 }) != filter_out.end()) { + if (filter_out.find({ act.receiver, {}, {} }) != filter_out.end()) { return false; } - if (filter_out.find({ act.receipt.receiver, act.act.name, 0 }) != filter_out.end()) { + if (filter_out.find({ act.receiver, act.act.name, {} }) != filter_out.end()) { return false; } for (const auto& a : act.act.authorization) { - if (filter_out.find({ act.receipt.receiver, 0, a.actor }) != filter_out.end()) { + if (filter_out.find({ act.receiver, {}, a.actor }) != filter_out.end()) { return false; } - if (filter_out.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_out.end()) { + if (filter_out.find({ act.receiver, act.act.name, a.actor }) != filter_out.end()) { return false; } } @@ -186,17 +186,17 @@ namespace eosio { set account_set( const action_trace& act ) { set result; - result.insert( act.receipt.receiver ); + result.insert( act.receiver ); for( const auto& a : act.act.authorization ) { if( bypass_filter || - filter_on.find({ act.receipt.receiver, 0, 0}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, 0, a.actor}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, act.act.name, 0}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end() ) { - if ((filter_out.find({ act.receipt.receiver, 0, 0 }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, 0, a.actor }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, act.act.name, 0 }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, act.act.name, a.actor }) == filter_out.end())) { + filter_on.find({ act.receiver, {}, {}}) != filter_on.end() || + filter_on.find({ act.receiver, {}, a.actor}) != filter_on.end() || + filter_on.find({ act.receiver, act.act.name, {}}) != filter_on.end() || + filter_on.find({ act.receiver, act.act.name, a.actor }) != filter_on.end() ) { + if ((filter_out.find({ act.receiver, {}, {} }) == filter_out.end()) && + (filter_out.find({ act.receiver, {}, a.actor }) == filter_out.end()) && + (filter_out.find({ act.receiver, act.act.name, {} }) == filter_out.end()) && + (filter_out.find({ act.receiver, act.act.name, a.actor }) == filter_out.end())) { result.insert( a.actor ); } } @@ -204,25 +204,23 @@ namespace eosio { return result; } - void record_account_action( account_name n, const base_action_trace& act ) { + void record_account_action( account_name n, const action_trace& act ) { auto& chain = chain_plug->chain(); chainbase::database& db = const_cast( chain.db() ); // Override read-only access to state DB (highly unrecommended practice!) const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( name(n.value+1), 0 ) ); + auto itr = idx.lower_bound( boost::make_tuple( name(n.to_uint64_t()+1), 0 ) ); uint64_t asn = 0; if( itr != idx.begin() ) --itr; if( itr->account == n ) asn = itr->account_sequence_num + 1; - //idump((n)(act.receipt.global_sequence)(asn)); const auto& a = db.create( [&]( auto& aho ) { aho.account = n; - aho.action_sequence_num = act.receipt.global_sequence; + aho.action_sequence_num = act.receipt->global_sequence; aho.account_sequence_num = asn; }); - //idump((a.account)(a.action_sequence_num)(a.action_sequence_num)); } void on_system_action( const action_trace& at ) { @@ -263,8 +261,8 @@ namespace eosio { aho.packed_action_trace.resize(ps); datastream ds( aho.packed_action_trace.data(), ps ); fc::raw::pack( ds, at ); - aho.action_sequence_num = at.receipt.global_sequence; - aho.block_num = chain.pending_block_state()->block_num; + aho.action_sequence_num = at.receipt->global_sequence; + aho.block_num = chain.head_block_num() + 1; aho.block_time = chain.pending_block_time(); aho.trx_id = at.trx_id; }); @@ -274,11 +272,8 @@ namespace eosio { record_account_action( a, at ); } } - if( at.receipt.receiver == chain::config::system_account_name ) + if( at.receiver == chain::config::system_account_name ) on_system_action( at ); - for( const auto& iline : at.inline_traces ) { - on_action_trace( iline ); - } } void on_applied_transaction( const transaction_trace_ptr& trace ) { @@ -286,6 +281,7 @@ namespace eosio { trace->receipt->status != transaction_receipt_header::soft_fail) ) return; for( const auto& atrace : trace->action_traces ) { + if( !atrace.receipt ) continue; on_action_trace( atrace ); } } @@ -324,8 +320,8 @@ namespace eosio { std::vector v; boost::split( v, s, boost::is_any_of( ":" )); EOS_ASSERT( v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s", s)); - filter_entry fe{v[0], v[1], v[2]}; - EOS_ASSERT( fe.receiver.value, fc::invalid_arg_exception, + filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1]), eosio::chain::name(v[2])}; + EOS_ASSERT( fe.receiver.to_uint64_t(), fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s", s)); my->filter_on.insert( fe ); } @@ -336,8 +332,8 @@ namespace eosio { std::vector v; boost::split( v, s, boost::is_any_of( ":" )); EOS_ASSERT( v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter-out", ("s", s)); - filter_entry fe{v[0], v[1], v[2]}; - EOS_ASSERT( fe.receiver.value, fc::invalid_arg_exception, + filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1]), eosio::chain::name(v[2])}; + EOS_ASSERT( fe.receiver.to_uint64_t(), fc::invalid_arg_exception, "Invalid value ${s} for --filter-out", ("s", s)); my->filter_out.insert( fe ); } @@ -348,7 +344,7 @@ namespace eosio { auto& chain = my->chain_plug->chain(); chainbase::database& db = const_cast( chain.db() ); // Override read-only access to state DB (highly unrecommended practice!) - // TODO: Use separate chainbase database for managing the state of the history_plugin (or remove deprecated history_plugin entirely) + // TODO: Use separate chainbase database for managing the state of the history_plugin (or remove deprecated history_plugin entirely) db.add_index(); db.add_index(); db.add_index(); @@ -372,9 +368,8 @@ namespace eosio { namespace history_apis { - read_only::get_actions_result read_only::get_actions( const read_only::get_actions_params& params )const { - edump((params)); + edump((params)); auto& chain = history->chain_plug->chain(); const auto& db = chain.db(); const auto abi_serializer_max_time = history->chain_plug->get_abi_serializer_max_time(); @@ -388,7 +383,7 @@ namespace eosio { auto n = params.account_name; idump((pos)); if( pos == -1 ) { - auto itr = idx.lower_bound( boost::make_tuple( name(n.value+1), 0 ) ); + auto itr = idx.lower_bound( boost::make_tuple( name(n.to_uint64_t()+1), 0 ) ); if( itr == idx.begin() ) { if( itr->account == n ) pos = itr->account_sequence_num+1; @@ -519,7 +514,7 @@ namespace eosio { break; } } - } + } } } else { auto blk = chain.fetch_block_by_number(*p.block_num_hint); @@ -564,94 +559,6 @@ namespace eosio { return result; } - fc::variant read_only::get_block_detail(const read_only::get_block_detail_params& params) const { - static char const TRANSACTIONS[] = "transactions"; - static char const TRX[] = "trx"; - static char const ID[] = "id"; - static char const TRACES[] = "traces"; - - auto & plugin = history->chain_plug; - auto & chain = plugin->chain(); - - auto get_object_value = [](fc::variant const& src, char const * key) -> fc::variant const & { - static auto const null_variant = fc::variant(); - - if ( !src.is_object() ) - return null_variant; - - auto & obj = src.get_object(); - auto const & itr = obj.find(key); - if ( itr == obj.end() ) - return null_variant; - - return itr->value(); - }; - - auto get_tx_array = [&get_object_value](fc::variant const& block) -> fc::variants const & { - static auto const null_variants = fc::variants(); - - auto & value = get_object_value(block, TRANSACTIONS); - if ( !value.is_array() ) - return null_variants; - - return value.get_array(); - }; - - auto get_tx_id = [&get_object_value](fc::variant const& tx) -> optional { - auto & id = get_object_value(get_object_value(tx, TRX), ID); - if ( !id.is_string() ) - return fc::optional(); - - return fc::optional(id.get_string()); - }; - - auto const & src = plugin->get_read_only_api().get_block( - chain_apis::read_only::get_block_params { - /*block_num_or_id = */ params.block_num_or_id - } - ); - - auto & rhs = get_tx_array(src); - if ( rhs.empty() ) - return src; - - auto lhs = fc::variants(); - lhs.reserve(rhs.size()); - - auto & database = chain.db(); - auto & index = database.get_index(); - auto const abi_serializer_max_time = plugin->get_abi_serializer_max_time(); - for ( auto const & tx : rhs ) { - auto maybe_id = get_tx_id(tx); - if ( maybe_id ) { - auto id = *maybe_id; - auto itr = index.lower_bound(boost::make_tuple(id)); - auto traces = fc::variants(); - - while ( itr != index.end() && itr->trx_id == id ) { - - fc::datastream ds( itr->packed_action_trace.data(), itr->packed_action_trace.size() ); - action_trace t; - fc::raw::unpack( ds, t ); - traces.emplace_back( chain.to_variant_with_abi(t, abi_serializer_max_time) ); - - ++itr; - } - - if ( !traces.empty() ) { - auto new_trx = fc::mutable_variant_object(tx[TRX])(TRACES, traces); - auto new_tx = fc::mutable_variant_object(tx).set(TRX, move(new_trx)); - lhs.emplace_back(move(new_tx)); - continue; - } - } - - lhs.emplace_back(tx); - } - - return fc::mutable_variant_object(src).set(TRANSACTIONS, move(lhs)); - } - read_only::get_key_accounts_results read_only::get_key_accounts(const get_key_accounts_params& params) const { std::set accounts; const auto& db = history->chain_plug->chain().db(); @@ -674,4 +581,6 @@ namespace eosio { } /// history_apis + + } /// namespace eosio diff --git a/plugins/kafka_plugin/kafka.cpp b/plugins/kafka_plugin/kafka.cpp index 86abbb6d62c..415e6774da6 100644 --- a/plugins/kafka_plugin/kafka.cpp +++ b/plugins/kafka_plugin/kafka.cpp @@ -136,27 +136,23 @@ void kafka::push_transaction_trace(const chain::transaction_trace_ptr& tx_trace) void kafka::push_action(const chain::action_trace& action_trace, uint64_t parent_seq, const TransactionTracePtr& tx) { auto a = std::make_shared(); - a->global_seq = action_trace.receipt.global_sequence; - a->recv_seq = action_trace.receipt.recv_sequence; + a->global_seq = action_trace.receipt->global_sequence; + a->recv_seq = action_trace.receipt->recv_sequence; a->parent_seq = parent_seq; - a->account = action_trace.act.account; - a->name = action_trace.act.name; + a->account = action_trace.act.account.to_uint64_t(); + a->name = action_trace.act.name.to_uint64_t(); if (not action_trace.act.authorization.empty()) a->auth = fc::raw::pack(action_trace.act.authorization); a->data = action_trace.act.data; - a->receiver = action_trace.receipt.receiver; - if (not action_trace.receipt.auth_sequence.empty()) a->auth_seq = fc::raw::pack(action_trace.receipt.auth_sequence); - a->code_seq = action_trace.receipt.code_sequence; - a->abi_seq = action_trace.receipt.abi_sequence; + a->receiver = action_trace.receipt->receiver.to_uint64_t(); + if (not action_trace.receipt->auth_sequence.empty()) a->auth_seq = fc::raw::pack(action_trace.receipt->auth_sequence); + a->code_seq = action_trace.receipt->code_sequence; + a->abi_seq = action_trace.receipt->abi_sequence; a->block_num = action_trace.block_num; a->block_time = action_trace.block_time; a->tx_id = checksum_bytes(action_trace.trx_id); if (not action_trace.console.empty()) a->console = action_trace.console; consume_action(a); - - for (auto& inline_trace: action_trace.inline_traces) { - push_action(inline_trace, action_trace.receipt.global_sequence, tx); - } } void kafka::consume_block(BlockPtr block) { diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 70327c3d96b..bf5be74dc4d 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -1529,8 +1529,8 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) } } - if( options.count( "abi-serializer-max-time-ms") == 0 ) { - EOS_ASSERT(false, chain::plugin_config_exception, "--abi-serializer-max-time-ms required as default value not appropriate for parsing full blocks"); + if( options.count( "abi-serializer-max-time-us") == 0 ) { + EOS_ASSERT(false, chain::plugin_config_exception, "--abi-serializer-max-time-us required as default value not appropriate for parsing full blocks"); } my->abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); diff --git a/plugins/notify_plugin/notify_plugin.cpp b/plugins/notify_plugin/notify_plugin.cpp index 377daf8e5ef..0684f39a009 100644 --- a/plugins/notify_plugin/notify_plugin.cpp +++ b/plugins/notify_plugin/notify_plugin.cpp @@ -111,11 +111,11 @@ class notify_plugin_impl bool notify_plugin_impl::filter(const action_trace &act) { - if (filter_on.find({act.receipt.receiver, act.act.name}) != filter_on.end()) + if (filter_on.find({act.receipt->receiver, act.act.name}) != filter_on.end()) { return true; } - else if (filter_on.find({act.receipt.receiver, 0}) != filter_on.end()) + else if (filter_on.find({act.receipt->receiver, {}}) != filter_on.end()) { return true; } @@ -126,7 +126,7 @@ fc::variant notify_plugin_impl::deserialize_action_data(action act) { auto &chain = chain_plug->chain(); auto serializer = chain.get_abi_serializer(act.account, max_deserialization_time); - FC_ASSERT(serializer.valid() && serializer->get_action_type(act.name) != action_name(), + FC_ASSERT(serializer.valid() && serializer->get_action_type(act.name) != "", "Unable to get abi for account: ${acc}, action: ${a} Not sending notification.", ("acc", act.account)("a", act.name)); return serializer->binary_to_variant(act.name.to_string(), act.data, max_deserialization_time); @@ -161,17 +161,18 @@ action_seq_type notify_plugin_impl::on_action_trace(const action_trace &act, con { if (filter(act)) { - const auto pair = std::make_pair(tx_id, sequenced_action(act.act, act_s, act.receipt.receiver)); + const auto pair = std::make_pair(tx_id, sequenced_action(act.act, act_s, act.receipt->receiver)); action_queue.insert(pair); irreversible_action_queue.insert(pair); // dlog("on_action_trace: ${a}", ("a", fc::json::to_pretty_string(act.act))); } act_s++; - for (const auto &iline : act.inline_traces) - { - act_s = on_action_trace(iline, tx_id, act_s); - } + /// TODO +// for (const auto &iline : act.inline_traces) +// { +// act_s = on_action_trace(iline, tx_id, act_s); +// } return act_s; } @@ -307,8 +308,8 @@ void notify_plugin::plugin_initialize(const variables_map &options) EOS_ASSERT(v.size() == 2, fc::invalid_arg_exception, "Invalid value ${s} for --notify-filter-on", ("s", s)); - notify_plugin_impl::filter_entry fe{v[0], v[1]}; - EOS_ASSERT(fe.receiver.value, fc::invalid_arg_exception, "Invalid value ${s} for --notify-filter-on", ("s", s)); + notify_plugin_impl::filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1])}; + EOS_ASSERT(fe.receiver.to_uint64_t(), fc::invalid_arg_exception, "Invalid value ${s} for --notify-filter-on", ("s", s)); my->filter_on.insert(fe); } } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 9a5ad5f64ba..b485cb1c432 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -599,10 +599,12 @@ T dejsonify(const string& s) { return fc::json::from_string(s).as(); } -#define LOAD_VALUE_SET(options, name, container, type) \ -if( options.count(name) ) { \ - const std::vector& ops = options[name].as>(); \ - std::copy(ops.begin(), ops.end(), std::inserter(container, container.end())); \ +#define LOAD_VALUE_SET(options, op_name, container) \ +if( options.count(op_name) ) { \ + const std::vector& ops = options[op_name].as>(); \ + for( const auto& v : ops ) { \ + container.emplace( eosio::chain::name( v ) ); \ + } \ } static producer_plugin_impl::signature_provider_type @@ -641,7 +643,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->chain_plug = app().find_plugin(); EOS_ASSERT( my->chain_plug, plugin_config_exception, "chain_plugin not found" ); my->_options = &options; - LOAD_VALUE_SET(options, "producer-name", my->_producers, types::account_name) + LOAD_VALUE_SET(options, "producer-name", my->_producers) if( options.count("private-key") ) { diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp index 1644d29a404..5749694ce3a 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp @@ -1,13 +1,10 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ #pragma once #include #include #include +#include #include #include #include @@ -21,99 +18,108 @@ namespace eosio { * +---------+----------------+-----------+------------------+-----+---------+----------------+ * * *.index: - * +-----------+-------------+-----+-----------+ - * | Summary i | Summary i+1 | ... | Summary z | - * +-----------+-------------+-----+-----------+ + * +----------------+------------------+-----+----------------+ + * | Pos of Entry i | Pos of Entry i+1 | ... | Pos of Entry z | + * +----------------+------------------+-----+----------------+ * * each entry: - * uint32_t block_num - * block_id_type block_id - * uint64_t size of payload - * uint8_t version - * payload - * - * each summary: - * uint64_t position of entry in *.log - * - * state payload: - * uint32_t size of deltas - * char[] deltas + * state_history_log_header + * payload */ -// todo: look into switching this to serialization instead of memcpy -// todo: consider reworking versioning -// todo: consider dropping block_num since it's included in block_id -// todo: currently only checks version on the first record. Need in recover_blocks -struct state_history_log_header { - uint32_t block_num = 0; - chain::block_id_type block_id; - uint64_t payload_size = 0; - uint8_t version = 0; -}; +inline uint64_t ship_magic(uint32_t version) { return N(ship).to_uint64_t() | version; } +inline bool is_ship(uint64_t magic) { return (magic & 0xffff'ffff'0000'0000) == N(ship).to_uint64_t(); } +inline uint32_t get_ship_version(uint64_t magic) { return magic; } +inline bool is_ship_supported_version(uint64_t magic) { return get_ship_version(magic) == 0; } +static const uint32_t ship_current_version = 0; -struct state_history_summary { - uint64_t pos = 0; +struct state_history_log_header { + uint64_t magic = ship_magic(ship_current_version); + chain::block_id_type block_id = {}; + uint64_t payload_size = 0; }; +static const int state_history_log_header_serial_size = sizeof(state_history_log_header::magic) + + sizeof(state_history_log_header::block_id) + + sizeof(state_history_log_header::payload_size); class state_history_log { - private: - const char* const name = ""; - std::string log_filename; - std::string index_filename; +private: + const char* const name = ""; + std::string log_filename; + std::string index_filename; std::fstream log; std::fstream index; - uint32_t _begin_block = 0; - uint32_t _end_block = 0; - chain::block_id_type last_block_id; + uint32_t _begin_block = 0; + uint32_t _end_block = 0; + chain::block_id_type last_block_id; - public: - state_history_log(const char* const name, std::string log_filename, std::string index_filename) - : name(name) - , log_filename(std::move(log_filename)) - , index_filename(std::move(index_filename)) { - open_log(); - open_index(); - } +public: + state_history_log(const char* const name, std::string log_filename, std::string index_filename) + : name(name) + , log_filename(std::move(log_filename)) + , index_filename(std::move(index_filename)) { + open_log(); + open_index(); + } - uint32_t begin_block() const { return _begin_block; } - uint32_t end_block() const { return _end_block; } + uint32_t begin_block() const { return _begin_block; } + uint32_t end_block() const { return _end_block; } - template - void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) { - EOS_ASSERT(_begin_block == _end_block || header.block_num <= _end_block, chain::plugin_exception, - "missed a block in ${name}.log", ("name", name)); + void read_header(state_history_log_header& header, bool assert_version = true) { + char bytes[state_history_log_header_serial_size]; + log.read(bytes, sizeof(bytes)); + fc::datastream ds(bytes, sizeof(bytes)); + fc::raw::unpack(ds, header); + EOS_ASSERT(!ds.remaining(), chain::plugin_exception, "state_history_log_header_serial_size mismatch"); + if (assert_version) + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic), chain::plugin_exception, + "corrupt ${name}.log (0)", ("name", name)); + } - if (_begin_block != _end_block && header.block_num > _begin_block) { - if (header.block_num == _end_block) { - EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log", - ("name", name)); - } else { - state_history_log_header prev; - get_entry(header.block_num - 1, prev); - EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log", - ("name", name)); - } - } + void write_header(const state_history_log_header& header) { + char bytes[state_history_log_header_serial_size]; + fc::datastream ds(bytes, sizeof(bytes)); + fc::raw::pack(ds, header); + EOS_ASSERT(!ds.remaining(), chain::plugin_exception, "state_history_log_header_serial_size mismatch"); + log.write(bytes, sizeof(bytes)); + } - if (header.block_num < _end_block) - truncate(header.block_num); - log.seekg(0, std::ios_base::end); - uint64_t pos = log.tellg(); - log.write((char*)&header, sizeof(header)); - write_payload(log); - uint64_t end = log.tellg(); - EOS_ASSERT(end == pos + sizeof(header) + header.payload_size, chain::plugin_exception, - "wrote payload with incorrect size to ${name}.log", ("name", name)); - log.write((char*)&pos, sizeof(pos)); + template + void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) { + auto block_num = chain::block_header::num_from_id(header.block_id); + EOS_ASSERT(_begin_block == _end_block || block_num <= _end_block, chain::plugin_exception, + "missed a block in ${name}.log", ("name", name)); - index.seekg(0, std::ios_base::end); - state_history_summary summary{.pos = pos}; - index.write((char*)&summary, sizeof(summary)); - if (_begin_block == _end_block) - _begin_block = header.block_num; - _end_block = header.block_num + 1; - last_block_id = header.block_id; - } + if (_begin_block != _end_block && block_num > _begin_block) { + if (block_num == _end_block) { + EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log", + ("name", name)); + } else { + state_history_log_header prev; + get_entry(block_num - 1, prev); + EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log", + ("name", name)); + } + } + + if (block_num < _end_block) + truncate(block_num); + log.seekg(0, std::ios_base::end); + uint64_t pos = log.tellp(); + write_header(header); + write_payload(log); + uint64_t end = log.tellp(); + EOS_ASSERT(end == pos + state_history_log_header_serial_size + header.payload_size, chain::plugin_exception, + "wrote payload with incorrect size to ${name}.log", ("name", name)); + log.write((char*)&pos, sizeof(pos)); + + index.seekg(0, std::ios_base::end); + index.write((char*)&pos, sizeof(pos)); + if (_begin_block == _end_block) + _begin_block = block_num; + _end_block = block_num + 1; + last_block_id = header.block_id; + } // returns stream positioned at payload std::fstream& get_entry(uint32_t block_num, state_history_log_header& header) { @@ -124,156 +130,165 @@ class state_history_log { return log; } - chain::block_id_type get_block_id(uint32_t block_num) { - state_history_log_header header; - get_entry(block_num, header); - return header.block_id; - } + chain::block_id_type get_block_id(uint32_t block_num) { + state_history_log_header header; + get_entry(block_num, header); + return header.block_id; + } - private: - bool get_last_block(uint64_t size) { - state_history_log_header header; - uint64_t suffix; - log.seekg(size - sizeof(suffix)); - log.read((char*)&suffix, sizeof(suffix)); - if (suffix > size || suffix + sizeof(header) > size) { - elog("corrupt ${name}.log (2)", ("name", name)); - return false; - } - log.seekg(suffix); - log.read((char*)&header, sizeof(header)); - if (suffix + sizeof(header) + header.payload_size + sizeof(suffix) != size) { - elog("corrupt ${name}.log (3)", ("name", name)); - return false; - } - _end_block = header.block_num + 1; - last_block_id = header.block_id; - if (_begin_block >= _end_block) { - elog("corrupt ${name}.log (4)", ("name", name)); - return false; - } - return true; - } +private: + bool get_last_block(uint64_t size) { + state_history_log_header header; + uint64_t suffix; + log.seekg(size - sizeof(suffix)); + log.read((char*)&suffix, sizeof(suffix)); + if (suffix > size || suffix + state_history_log_header_serial_size > size) { + elog("corrupt ${name}.log (2)", ("name", name)); + return false; + } + log.seekg(suffix); + read_header(header, false); + if (!is_ship(header.magic) || !is_ship_supported_version(header.magic) || + suffix + state_history_log_header_serial_size + header.payload_size + sizeof(suffix) != size) { + elog("corrupt ${name}.log (3)", ("name", name)); + return false; + } + _end_block = chain::block_header::num_from_id(header.block_id) + 1; + last_block_id = header.block_id; + if (_begin_block >= _end_block) { + elog("corrupt ${name}.log (4)", ("name", name)); + return false; + } + return true; + } - void recover_blocks(uint64_t size) { - ilog("recover ${name}.log", ("name", name)); - uint64_t pos = 0; - uint32_t num_found = 0; - while (true) { - state_history_log_header header; - if (pos + sizeof(header) > size) - break; - log.seekg(pos); - log.read((char*)&header, sizeof(header)); - uint64_t suffix; - if (header.payload_size > size || pos + sizeof(header) + header.payload_size + sizeof(suffix) > size) - break; - log.seekg(pos + sizeof(header) + header.payload_size); - log.read((char*)&suffix, sizeof(suffix)); - if (suffix != pos) - break; - pos = pos + sizeof(header) + header.payload_size + sizeof(suffix); - if (!(++num_found % 10000)) { - printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); - fflush(stdout); - } - } - log.flush(); - boost::filesystem::resize_file(log_filename, pos); - log.sync(); - EOS_ASSERT(get_last_block(pos), chain::plugin_exception, "recover ${name}.log failed", ("name", name)); - } + void recover_blocks(uint64_t size) { + ilog("recover ${name}.log", ("name", name)); + uint64_t pos = 0; + uint32_t num_found = 0; + while (true) { + state_history_log_header header; + if (pos + state_history_log_header_serial_size > size) + break; + log.seekg(pos); + read_header(header, false); + uint64_t suffix; + if (!is_ship(header.magic) || !is_ship_supported_version(header.magic) || header.payload_size > size || + pos + state_history_log_header_serial_size + header.payload_size + sizeof(suffix) > size) { + EOS_ASSERT(!is_ship(header.magic) || is_ship_supported_version(header.magic), chain::plugin_exception, + "${name}.log has an unsupported version", ("name", name)); + break; + } + log.seekg(pos + sizeof(header) + header.payload_size); + log.read((char*)&suffix, sizeof(suffix)); + if (suffix != pos) + break; + pos = pos + state_history_log_header_serial_size + header.payload_size + sizeof(suffix); + if (!(++num_found % 10000)) { + printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); + fflush(stdout); + } + } + log.flush(); + boost::filesystem::resize_file(log_filename, pos); + log.flush(); + EOS_ASSERT(get_last_block(pos), chain::plugin_exception, "recover ${name}.log failed", ("name", name)); + } - void open_log() { - log.open(log_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); - log.seekg(0, std::ios_base::end); - uint64_t size = log.tellg(); - if (size >= sizeof(state_history_log_header)) { - state_history_log_header header; - log.seekg(0); - log.read((char*)&header, sizeof(header)); - EOS_ASSERT(header.version == 0 && sizeof(header) + header.payload_size + sizeof(uint64_t) <= size, - chain::plugin_exception, "corrupt ${name}.log (1)", ("name", name)); - _begin_block = header.block_num; - last_block_id = header.block_id; - if (!get_last_block(size)) - recover_blocks(size); - ilog("${name}.log has blocks ${b}-${e}", ("name", name)("b", _begin_block)("e", _end_block - 1)); - } else { - EOS_ASSERT(!size, chain::plugin_exception, "corrupt ${name}.log (5)", ("name", name)); - ilog("${name}.log is empty", ("name", name)); - } - } + void open_log() { + log.open(log_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); + log.seekg(0, std::ios_base::end); + uint64_t size = log.tellp(); + if (size >= state_history_log_header_serial_size) { + state_history_log_header header; + log.seekg(0); + read_header(header, false); + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic) && + state_history_log_header_serial_size + header.payload_size + sizeof(uint64_t) <= size, + chain::plugin_exception, "corrupt ${name}.log (1)", ("name", name)); + _begin_block = chain::block_header::num_from_id(header.block_id); + last_block_id = header.block_id; + if (!get_last_block(size)) + recover_blocks(size); + ilog("${name}.log has blocks ${b}-${e}", ("name", name)("b", _begin_block)("e", _end_block - 1)); + } else { + EOS_ASSERT(!size, chain::plugin_exception, "corrupt ${name}.log (5)", ("name", name)); + ilog("${name}.log is empty", ("name", name)); + } + } - void open_index() { - index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); - index.seekg(0, std::ios_base::end); - if (index.tellg() == (_end_block - _begin_block) * sizeof(state_history_summary)) - return; - ilog("Regenerate ${name}.index", ("name", name)); - index.close(); - index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc); + void open_index() { + index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); + index.seekg(0, std::ios_base::end); + if (index.tellp() == (static_cast(_end_block) - _begin_block) * sizeof(uint64_t)) + return; + ilog("Regenerate ${name}.index", ("name", name)); + index.close(); + index.open( "w+b" ); // std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc - log.seekg(0, std::ios_base::end); - uint64_t size = log.tellg(); - uint64_t pos = 0; - uint32_t num_found = 0; - while (pos < size) { - state_history_log_header header; - EOS_ASSERT(pos + sizeof(header) <= size, chain::plugin_exception, "corrupt ${name}.log (6)", ("name", name)); - log.seekg(pos); - log.read((char*)&header, sizeof(header)); - uint64_t suffix_pos = pos + sizeof(header) + header.payload_size; - uint64_t suffix; - EOS_ASSERT(suffix_pos + sizeof(suffix) <= size, chain::plugin_exception, "corrupt ${name}.log (7)", - ("name", name)); - log.seekg(suffix_pos); - log.read((char*)&suffix, sizeof(suffix)); - // ilog("block ${b} at ${pos}-${end} suffix=${suffix} file_size=${fs}", - // ("b", header.block_num)("pos", pos)("end", suffix_pos + sizeof(suffix))("suffix", suffix)("fs", size)); - EOS_ASSERT(suffix == pos, chain::plugin_exception, "corrupt ${name}.log (8)", ("name", name)); + log.seekg(0, std::ios_base::end); + uint64_t size = log.tellp(); + uint64_t pos = 0; + uint32_t num_found = 0; + while (pos < size) { + state_history_log_header header; + EOS_ASSERT(pos + state_history_log_header_serial_size <= size, chain::plugin_exception, + "corrupt ${name}.log (6)", ("name", name)); + log.seekg(pos); + read_header(header, false); + uint64_t suffix_pos = pos + state_history_log_header_serial_size + header.payload_size; + uint64_t suffix; + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic) && + suffix_pos + sizeof(suffix) <= size, + chain::plugin_exception, "corrupt ${name}.log (7)", ("name", name)); + log.seekg(suffix_pos); + log.read((char*)&suffix, sizeof(suffix)); + // ilog("block ${b} at ${pos}-${end} suffix=${suffix} file_size=${fs}", + // ("b", header.block_num)("pos", pos)("end", suffix_pos + sizeof(suffix))("suffix", suffix)("fs", size)); + EOS_ASSERT(suffix == pos, chain::plugin_exception, "corrupt ${name}.log (8)", ("name", name)); - state_history_summary summary{.pos = pos}; - index.write((char*)&summary, sizeof(summary)); - pos = suffix_pos + sizeof(suffix); - if (!(++num_found % 10000)) { - printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); - fflush(stdout); - } - } - } + index.write((char*)&pos, sizeof(pos)); + pos = suffix_pos + sizeof(suffix); + if (!(++num_found % 10000)) { + printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); + fflush(stdout); + } + } + } - uint64_t get_pos(uint32_t block_num) { - state_history_summary summary; - index.seekg((block_num - _begin_block) * sizeof(summary)); - index.read((char*)&summary, sizeof(summary)); - return summary.pos; - } + uint64_t get_pos(uint32_t block_num) { + uint64_t pos; + index.seekg((block_num - _begin_block) * sizeof(pos)); + index.read((char*)&pos, sizeof(pos)); + return pos; + } - void truncate(uint32_t block_num) { - log.flush(); - index.flush(); - uint64_t num_removed = 0; - if (block_num <= _begin_block) { - num_removed = _end_block - _begin_block; - log.seekg(0); - index.seekg(0); - boost::filesystem::resize_file(log_filename, 0); - boost::filesystem::resize_file(index_filename, 0); - _begin_block = _end_block = 0; - } else { - num_removed = _end_block - block_num; - uint64_t pos = get_pos(block_num); - log.seekg(0); - index.seekg(0); - boost::filesystem::resize_file(log_filename, pos); - boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(state_history_summary)); - _end_block = block_num; - } - log.sync(); - index.sync(); - ilog("fork or replay: removed ${n} blocks from ${name}.log", ("n", num_removed)("name", name)); - } + void truncate(uint32_t block_num) { + log.flush(); + index.flush(); + uint64_t num_removed = 0; + if (block_num <= _begin_block) { + num_removed = _end_block - _begin_block; + log.seekg(0); + index.seekg(0); + boost::filesystem::resize_file(log_filename, 0); + boost::filesystem::resize_file(index_filename, 0); + _begin_block = _end_block = 0; + } else { + num_removed = _end_block - block_num; + uint64_t pos = get_pos(block_num); + log.seekg(0); + index.seekg(0); + boost::filesystem::resize_file(log_filename, pos); + boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(uint64_t)); + _end_block = block_num; + } + log.flush(); + index.flush(); + ilog("fork or replay: removed ${n} blocks from ${name}.log", ("n", num_removed)("name", name)); + } }; // state_history_log } // namespace eosio + +FC_REFLECT(eosio::state_history_log_header, (magic)(block_id)(payload_size)) diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp index f3429e2d190..a682b205e00 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp @@ -22,6 +22,53 @@ using std::shared_ptr; typedef shared_ptr state_history_ptr; +struct partial_transaction { + chain::time_point_sec expiration = {}; + uint16_t ref_block_num = {}; + uint32_t ref_block_prefix = {}; + fc::unsigned_int max_net_usage_words = {}; + uint8_t max_cpu_usage_ms = {}; + fc::unsigned_int delay_sec = {}; + chain::extensions_type transaction_extensions = {}; + vector signatures = {}; + vector context_free_data = {}; + + partial_transaction(const chain::signed_transaction& t) + : expiration(t.expiration) + , ref_block_num(t.ref_block_num) + , ref_block_prefix(t.ref_block_prefix) + , max_net_usage_words(t.max_net_usage_words) + , max_cpu_usage_ms(t.max_cpu_usage_ms) + , delay_sec(t.delay_sec) + , transaction_extensions(t.transaction_extensions) + , signatures(t.signatures) + , context_free_data(t.context_free_data) {} +}; + +struct augmented_transaction_trace { + chain::transaction_trace_ptr trace; + std::shared_ptr partial; + + augmented_transaction_trace() = default; + augmented_transaction_trace(const augmented_transaction_trace&) = default; + augmented_transaction_trace(augmented_transaction_trace&&) = default; + + augmented_transaction_trace(const chain::transaction_trace_ptr& trace) + : trace{trace} {} + + augmented_transaction_trace(const chain::transaction_trace_ptr& trace, + const std::shared_ptr& partial) + : trace{trace} + , partial{partial} {} + + augmented_transaction_trace(const chain::transaction_trace_ptr& trace, const chain::signed_transaction& t) + : trace{trace} + , partial{std::make_shared(t)} {} + + augmented_transaction_trace& operator=(const augmented_transaction_trace&) = default; + augmented_transaction_trace& operator=(augmented_transaction_trace&&) = default; +}; + struct table_delta { fc::unsigned_int struct_version = 0; std::string name{}; diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp index 8ddb118c383..386b520780d 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ #pragma once #include @@ -11,12 +7,15 @@ #include #include #include +#include #include #include #include #include #include +#include + template struct history_serial_wrapper { const chainbase::database& db; @@ -24,7 +23,7 @@ struct history_serial_wrapper { }; template -history_serial_wrapper make_history_serial_wrapper(const chainbase::database& db, const T& obj) { +history_serial_wrapper> make_history_serial_wrapper(const chainbase::database& db, const T& obj) { return {db, obj}; } @@ -36,7 +35,8 @@ struct history_context_wrapper { }; template -history_context_wrapper make_history_context_wrapper(const chainbase::database& db, P& context, const T& obj) { +history_context_wrapper, std::decay_t> +make_history_context_wrapper(const chainbase::database& db, const P& context, const T& obj) { return {db, context, obj}; } @@ -66,6 +66,16 @@ datastream& history_serialize_container(datastream& ds, const chainbase: return ds; } +template +datastream& history_context_serialize_container(datastream& ds, const chainbase::database& db, const P& context, + const std::vector& v) { + fc::raw::pack(ds, unsigned_int(v.size())); + for (const auto& x : v) { + ds << make_history_context_wrapper(db, context, x); + } + return ds; +} + template datastream& operator<<(datastream& ds, const history_serial_big_vector_wrapper& obj) { FC_ASSERT(obj.obj.size() <= 1024 * 1024 * 1024); @@ -75,10 +85,19 @@ datastream& operator<<(datastream& ds, const history_serial_big_vector_w return ds; } +template +inline void history_pack_varuint64(datastream& ds, uint64_t val) { + do { + uint8_t b = uint8_t(val) & 0x7f; + val >>= 7; + b |= ((val > 0) << 7); + ds.write((char*)&b, 1); + } while (val); +} + template void history_pack_big_bytes(datastream& ds, const eosio::chain::bytes& v) { - FC_ASSERT(v.size() <= 1024 * 1024 * 1024); - fc::raw::pack(ds, unsigned_int((uint32_t)v.size())); + history_pack_varuint64(ds, v.size()); if (v.size()) ds.write(&v.front(), (uint32_t)v.size()); } @@ -95,6 +114,11 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper +datastream& operator<<(datastream& ds, const history_context_wrapper>& obj) { + return history_context_serialize_container(ds, obj.db, obj.context, obj.obj); +} + template datastream& operator<<(datastream& ds, const history_serial_wrapper>& obj) { fc::raw::pack(ds, obj.obj.first); @@ -150,14 +174,14 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.context.code.value)); - fc::raw::pack(ds, as_type(obj.context.scope.value)); - fc::raw::pack(ds, as_type(obj.context.table.value)); + fc::raw::pack(ds, as_type(obj.context.code.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.context.scope.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.context.table.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.primary_key)); - fc::raw::pack(ds, as_type(obj.obj.payer.value)); + fc::raw::pack(ds, as_type(obj.obj.payer.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.value)); return ds; } @@ -196,65 +220,50 @@ template datastream& serialize_secondary_index(datastream& ds, const eosio::chain::table_id_object& context, const T& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(context.code.value)); - fc::raw::pack(ds, as_type(context.scope.value)); - fc::raw::pack(ds, as_type(context.table.value)); + fc::raw::pack(ds, as_type(context.code.to_uint64_t())); + fc::raw::pack(ds, as_type(context.scope.to_uint64_t())); + fc::raw::pack(ds, as_type(context.table.to_uint64_t())); fc::raw::pack(ds, as_type(obj.primary_key)); - fc::raw::pack(ds, as_type(obj.payer.value)); + fc::raw::pack(ds, as_type(obj.payer.to_uint64_t())); serialize_secondary_index_data(ds, obj.secondary_key); return ds; } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& operator<<( - datastream& ds, - const history_context_wrapper& obj) { + datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } -template -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.producer_name.value)); - fc::raw::pack(ds, as_type(obj.obj.block_signing_key)); - return ds; -} - -template -datastream& operator<<(datastream& ds, - const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.version)); - history_serialize_container(ds, obj.db, - as_type>(obj.obj.producers)); - return ds; -} template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { @@ -282,10 +291,10 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, fc::unsigned_int(1)); fc::raw::pack(ds, as_type>(obj.obj.proposed_schedule_block_num)); - fc::raw::pack(ds, make_history_serial_wrapper( - obj.db, as_type(obj.obj.proposed_schedule))); +// fc::raw::pack(ds, make_history_serial_wrapper( +// obj.db, as_type(obj.obj.proposed_schedule))); fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.configuration))); return ds; @@ -295,9 +304,9 @@ template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.sender.value)); + fc::raw::pack(ds, as_type(obj.obj.sender.to_uint64_t())); fc::raw::pack(ds, as_type<__uint128_t>(obj.obj.sender_id)); - fc::raw::pack(ds, as_type(obj.obj.payer.value)); + fc::raw::pack(ds, as_type(obj.obj.payer.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.trx_id)); fc::raw::pack(ds, as_type(obj.obj.packed_trx)); return ds; @@ -310,10 +319,25 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + /// TODO +// history_serialize_container(ds, obj.db, obj.obj.activated_protocol_features); + return ds; +} + +//template +//datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { +// fc::raw::pack(ds, as_type(obj.obj.key)); +// fc::raw::pack(ds, as_type(obj.obj.weight)); +// return ds; +//} + template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.actor.value)); - fc::raw::pack(ds, as_type(obj.obj.permission.value)); + fc::raw::pack(ds, as_type(obj.obj.actor.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.permission.to_uint64_t())); return ds; } @@ -344,8 +368,8 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.owner.value)); - fc::raw::pack(ds, as_type(obj.obj.name.value)); + fc::raw::pack(ds, as_type(obj.obj.owner.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.name.to_uint64_t())); if (obj.obj.parent._id) { auto& index = obj.db.get_index(); const auto* parent = index.find(obj.obj.parent); @@ -356,7 +380,7 @@ datastream& operator<<(datastream& ds, const history_serial_wrappersecond; } - fc::raw::pack(ds, as_type(parent->name.value)); + fc::raw::pack(ds, as_type(parent->name.to_uint64_t())); } else { fc::raw::pack(ds, as_type(0)); } @@ -369,10 +393,10 @@ template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.account.value)); - fc::raw::pack(ds, as_type(obj.obj.code.value)); - fc::raw::pack(ds, as_type(obj.obj.message_type.value)); - fc::raw::pack(ds, as_type(obj.obj.required_permission.value)); + fc::raw::pack(ds, as_type(obj.obj.account.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.code.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.message_type.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.required_permission.to_uint64_t())); return ds; } @@ -382,7 +406,7 @@ datastream& operator<<(datastream& EOS_ASSERT(!obj.obj.pending, eosio::chain::plugin_exception, "accepted_block sent while resource_limits_object in pending state"); fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, as_type(obj.obj.owner.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.net_weight)); fc::raw::pack(ds, as_type(obj.obj.cpu_weight)); fc::raw::pack(ds, as_type(obj.obj.ram_bytes)); @@ -403,7 +427,7 @@ template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, as_type(obj.obj.owner.to_uint64_t())); fc::raw::pack(ds, make_history_serial_wrapper( obj.db, as_type(obj.obj.net_usage))); fc::raw::pack(ds, make_history_serial_wrapper( @@ -471,8 +495,8 @@ operator<<(datastream& template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.account.value)); - fc::raw::pack(ds, as_type(obj.obj.name.value)); + fc::raw::pack(ds, as_type(obj.obj.account.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.name.to_uint64_t())); history_serialize_container(ds, obj.db, as_type>(obj.obj.authorization)); fc::raw::pack(ds, as_type(obj.obj.data)); return ds; @@ -481,7 +505,7 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.receiver.value)); + fc::raw::pack(ds, as_type(obj.obj.receiver.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.act_digest)); fc::raw::pack(ds, as_type(obj.obj.global_sequence)); fc::raw::pack(ds, as_type(obj.obj.recv_sequence)); @@ -493,73 +517,137 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.account.value)); + fc::raw::pack(ds, as_type(obj.obj.account.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.delta)); return ds; } +inline fc::optional cap_error_code( const fc::optional& error_code ) { + fc::optional result; + + if (!error_code) return result; + + const uint64_t upper_limit = static_cast(eosio::chain::system_error_code::generic_system_error); + + if (*error_code >= upper_limit) { + result = upper_limit; + return result; + } + + result = error_code; + return result; +} + template -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { +datastream& operator<<(datastream& ds, const history_context_wrapper& obj) { + bool debug_mode = obj.context; fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.receipt))); + fc::raw::pack(ds, as_type(obj.obj.action_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.creator_action_ordinal)); + fc::raw::pack(ds, bool(obj.obj.receipt)); + if (obj.obj.receipt) { + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(*obj.obj.receipt))); + } + fc::raw::pack(ds, as_type(obj.obj.receiver.to_uint64_t())); fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.act))); fc::raw::pack(ds, as_type(obj.obj.context_free)); - fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); - fc::raw::pack(ds, as_type(obj.obj.console)); + fc::raw::pack(ds, as_type(debug_mode ? obj.obj.elapsed.count() : 0)); + if (debug_mode) + fc::raw::pack(ds, as_type(obj.obj.console)); + else + fc::raw::pack(ds, std::string{}); history_serialize_container(ds, obj.db, as_type>(obj.obj.account_ram_deltas)); fc::optional e; - if (obj.obj.except) - e = obj.obj.except->to_string(); + if (obj.obj.except) { + if (debug_mode) + e = obj.obj.except->to_string(); + else + e = "Y"; + } fc::raw::pack(ds, as_type>(e)); - history_serialize_container(ds, obj.db, as_type>(obj.obj.inline_traces)); return ds; } template -datastream& operator<<(datastream& ds, - const history_context_wrapper& obj) { +datastream& operator<<(datastream& ds, + const history_context_wrapper, + eosio::augmented_transaction_trace>& obj) { + auto& trace = *obj.obj.trace; + bool debug_mode = obj.context.second; fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.id)); - if (obj.obj.receipt) { - if (obj.obj.failed_dtrx_trace && - obj.obj.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) + fc::raw::pack(ds, as_type(trace.id)); + if (trace.receipt) { + if (trace.failed_dtrx_trace && trace.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) fc::raw::pack(ds, uint8_t(eosio::chain::transaction_receipt_header::executed)); else - fc::raw::pack(ds, as_type(obj.obj.receipt->status.value)); - fc::raw::pack(ds, as_type(obj.obj.receipt->cpu_usage_us)); - fc::raw::pack(ds, as_type(obj.obj.receipt->net_usage_words)); + fc::raw::pack(ds, as_type(trace.receipt->status.value)); + fc::raw::pack(ds, as_type(trace.receipt->cpu_usage_us)); + fc::raw::pack(ds, as_type(trace.receipt->net_usage_words)); } else { - fc::raw::pack(ds, uint8_t(obj.context)); + fc::raw::pack(ds, uint8_t(obj.context.first)); fc::raw::pack(ds, uint32_t(0)); fc::raw::pack(ds, fc::unsigned_int(0)); } - fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); - fc::raw::pack(ds, as_type(obj.obj.net_usage)); - fc::raw::pack(ds, as_type(obj.obj.scheduled)); - history_serialize_container(ds, obj.db, as_type>(obj.obj.action_traces)); + fc::raw::pack(ds, as_type(debug_mode ? trace.elapsed.count() : 0)); + fc::raw::pack(ds, as_type(trace.net_usage)); + fc::raw::pack(ds, as_type(trace.scheduled)); + history_context_serialize_container(ds, obj.db, debug_mode, + as_type>(trace.action_traces)); + + fc::raw::pack(ds, bool(trace.account_ram_delta)); + if (trace.account_ram_delta) { + fc::raw::pack( + ds, make_history_serial_wrapper(obj.db, as_type(*trace.account_ram_delta))); + } fc::optional e; - if (obj.obj.except) - e = obj.obj.except->to_string(); + if (trace.except) { + if (debug_mode) + e = trace.except->to_string(); + else + e = "Y"; + } fc::raw::pack(ds, as_type>(e)); + fc::raw::pack(ds, as_type>(debug_mode ? trace.error_code + : cap_error_code(trace.error_code))); - fc::raw::pack(ds, bool(obj.obj.failed_dtrx_trace)); - if (obj.obj.failed_dtrx_trace) { + fc::raw::pack(ds, bool(trace.failed_dtrx_trace)); + if (trace.failed_dtrx_trace) { uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; - if (obj.obj.receipt && obj.obj.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) + if (trace.receipt && trace.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) stat = eosio::chain::transaction_receipt_header::soft_fail; - fc::raw::pack(ds, make_history_context_wrapper(obj.db, stat, *obj.obj.failed_dtrx_trace)); + std::pair context = std::make_pair(stat, debug_mode); + fc::raw::pack( // + ds, make_history_context_wrapper( + obj.db, context, eosio::augmented_transaction_trace{trace.failed_dtrx_trace, obj.obj.partial})); + } + + bool include_partial = obj.obj.partial && !trace.failed_dtrx_trace; + fc::raw::pack(ds, include_partial); + if (include_partial) { + auto& partial = *obj.obj.partial; + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(partial.expiration)); + fc::raw::pack(ds, as_type(partial.ref_block_num)); + fc::raw::pack(ds, as_type(partial.ref_block_prefix)); + fc::raw::pack(ds, as_type(partial.max_net_usage_words)); + fc::raw::pack(ds, as_type(partial.max_cpu_usage_ms)); + fc::raw::pack(ds, as_type(partial.delay_sec)); + fc::raw::pack(ds, as_type(partial.transaction_extensions)); + fc::raw::pack(ds, as_type>(partial.signatures)); + fc::raw::pack(ds, as_type>(partial.context_free_data)); } return ds; } template -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; - ds << make_history_context_wrapper(obj.db, stat, obj.obj); +datastream& operator<<(datastream& ds, + const history_context_wrapper& obj) { + std::pair context = std::make_pair(eosio::chain::transaction_receipt_header::hard_fail, obj.context); + ds << make_history_context_wrapper(obj.db, context, obj.obj); return ds; } diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp index e4a51e632ae..411383d2f49 100644 --- a/plugins/state_history_plugin/state_history_plugin.cpp +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -111,18 +111,25 @@ bool include_delta(const eosio::chain::code_object& old, const eosio::chain::cod return false; } +bool include_delta(const eosio::chain::protocol_state_object& old, const eosio::chain::protocol_state_object& curr) { +// return old.activated_protocol_features != curr.activated_protocol_features; +/// TODO + return true; +} + struct state_history_plugin_impl : std::enable_shared_from_this { - chain_plugin* chain_plug = nullptr; - fc::optional trace_log; - fc::optional chain_state_log; - bool stopping = false; - fc::optional applied_transaction_connection; - fc::optional accepted_block_connection; - string endpoint_address = "0.0.0.0"; - uint16_t endpoint_port = 8080; - std::unique_ptr acceptor; - std::map cached_traces; - transaction_trace_ptr onblock_trace; + chain_plugin* chain_plug = nullptr; + fc::optional trace_log; + fc::optional chain_state_log; + bool trace_debug_mode = false; + bool stopping = false; + fc::optional applied_transaction_connection; + fc::optional accepted_block_connection; + string endpoint_address = "0.0.0.0"; + uint16_t endpoint_port = 8080; + std::unique_ptr acceptor; + std::map cached_traces; + fc::optional onblock_trace; void get_log_entry(state_history_log& log, uint32_t block_num, fc::optional& result) { if (block_num < log.begin_block() || block_num >= log.end_block()) @@ -131,10 +138,10 @@ struct state_history_plugin_impl : std::enable_shared_from_thisresize(s); + bytes compressed(s); if (s) - stream.read(result->data(), s); + stream.read(compressed.data(), s); + result = zlib_decompress(compressed); } void get_block(uint32_t block_num, fc::optional& result) { @@ -144,7 +151,8 @@ struct state_history_plugin_impl : std::enable_shared_from_this get_block_id(uint32_t block_num) { @@ -180,10 +188,10 @@ struct state_history_plugin_impl : std::enable_shared_from_thisnext_layer().set_option(boost::asio::ip::tcp::no_delay(true)); socket_stream->next_layer().set_option(boost::asio::socket_base::send_buffer_size(1024 * 1024)); socket_stream->next_layer().set_option(boost::asio::socket_base::receive_buffer_size(1024 * 1024)); - socket_stream->async_accept([self = shared_from_this(), this](boost::system::error_code ec) { - callback(ec, "async_accept", [&] { - start_read(); - send(state_history_plugin_abi); + socket_stream->async_accept([self = shared_from_this()](boost::system::error_code ec) { + self->callback(ec, "async_accept", [self] { + self->start_read(); + self->send(state_history_plugin_abi); }); }); } @@ -191,15 +199,15 @@ struct state_history_plugin_impl : std::enable_shared_from_this(); socket_stream->async_read( - *in_buffer, [self = shared_from_this(), this, in_buffer](boost::system::error_code ec, size_t) { - callback(ec, "async_read", [&] { + *in_buffer, [self = shared_from_this(), in_buffer](boost::system::error_code ec, size_t) { + self->callback(ec, "async_read", [self, in_buffer] { auto d = boost::asio::buffer_cast(boost::beast::buffers_front(in_buffer->data())); auto s = boost::asio::buffer_size(in_buffer->data()); fc::datastream ds(d, s); state_request req; fc::raw::unpack(ds, req); - req.visit(*this); - start_read(); + req.visit(*self); + self->start_read(); }); }); } @@ -225,11 +233,11 @@ struct state_history_plugin_impl : std::enable_shared_from_thisasync_write( // boost::asio::buffer(send_queue[0]), - [self = shared_from_this(), this](boost::system::error_code ec, size_t) { - callback(ec, "async_write", [&] { - send_queue.erase(send_queue.begin()); - sending = false; - send(); + [self = shared_from_this()](boost::system::error_code ec, size_t) { + self->callback(ec, "async_write", [self] { + self->send_queue.erase(self->send_queue.begin()); + self->sending = false; + self->send(); }); }); } @@ -271,18 +279,14 @@ struct state_history_plugin_impl : std::enable_shared_from_thismax_messages_in_flight) + void send_update(get_blocks_result_v0 result) { + need_to_send_update = true; + if (!send_queue.empty() || !current_request || !current_request->max_messages_in_flight) return; - auto& chain = plugin->chain_plug->chain(); - get_blocks_result_v0 result; - result.head = {chain.head_block_num(), chain.head_block_id()}; + auto& chain = plugin->chain_plug->chain(); result.last_irreversible = {chain.last_irreversible_block_num(), chain.last_irreversible_block_id()}; uint32_t current = - current_request->irreversible_only ? result.last_irreversible.block_num : result.head.block_num; + current_request->irreversible_only ? result.last_irreversible.block_num : result.head.block_num; if (current_request->start_block_num <= current && current_request->start_block_num < current_request->end_block_num) { auto block_id = plugin->get_block_id(current_request->start_block_num); @@ -306,6 +310,27 @@ struct state_history_plugin_impl : std::enable_shared_from_thisstart_block_num < current_request->end_block_num; } + void send_update(const block_state_ptr& block_state) { + need_to_send_update = true; + if (!send_queue.empty() || !current_request || !current_request->max_messages_in_flight) + return; + get_blocks_result_v0 result; + result.head = {block_state->block_num, block_state->id}; + send_update(std::move(result)); + } + + void send_update(bool changed = false) { + if (changed) + need_to_send_update = true; + if (!send_queue.empty() || !need_to_send_update || !current_request || + !current_request->max_messages_in_flight) + return; + auto& chain = plugin->chain_plug->chain(); + get_blocks_result_v0 result; + result.head = {chain.head_block_num(), chain.head_block_id()}; + send_update(std::move(result)); + } + template void catch_and_close(F f) { try { @@ -373,7 +398,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this(app().get_io_service()); - acceptor->async_accept(*socket, [self = shared_from_this(), socket, this](auto ec) { + acceptor->async_accept(*socket, [self = shared_from_this(), socket, this](const boost::system::error_code& ec) { if (stopping) return; if (ec) { @@ -421,7 +446,7 @@ struct state_history_plugin_impl : std::enable_shared_from_thiscurrent_request && block_state->block_num < p->current_request->start_block_num) p->current_request->start_block_num = block_state->block_num; - p->send_update(true); + p->send_update(block_state); } } } @@ -429,9 +454,9 @@ struct state_history_plugin_impl : std::enable_shared_from_this traces; + std::vector traces; if (onblock_trace) - traces.push_back(onblock_trace); + traces.push_back(*onblock_trace); for (auto& r : block_state->block->transactions) { transaction_id_type id; if (r.trx.contains()) @@ -439,7 +464,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this().id(); auto it = cached_traces.find(id); - EOS_ASSERT(it != cached_traces.end() && it->second->receipt, plugin_exception, + EOS_ASSERT(it != cached_traces.end() && it->second.trace->receipt, plugin_exception, "missing trace for transaction ${id}", ("id", id)); traces.push_back(it->second); } @@ -447,10 +472,10 @@ struct state_history_plugin_impl : std::enable_shared_from_thischain().db(); - auto traces_bin = zlib_compress_bytes(fc::raw::pack(make_history_serial_wrapper(db, traces))); + auto traces_bin = zlib_compress_bytes(fc::raw::pack(make_history_context_wrapper(db, trace_debug_mode, traces))); EOS_ASSERT(traces_bin.size() == (uint32_t)traces_bin.size(), plugin_exception, "traces is too big"); - state_history_log_header header{.block_num = block_state->block->block_num(), + state_history_log_header header{.magic = ship_magic(ship_current_version), .block_id = block_state->block->id(), .payload_size = sizeof(uint32_t) + traces_bin.size()}; trace_log->write_entry(header, block_state->block->previous, [&](auto& stream) { @@ -511,7 +536,8 @@ struct state_history_plugin_impl : std::enable_shared_from_this(), pack_row); process_table("generated_transaction", db.get_index(), pack_row); + process_table("protocol_state", db.get_index(), pack_row); process_table("permission", db.get_index(), pack_row); process_table("permission_link", db.get_index(), pack_row); @@ -547,7 +574,7 @@ struct state_history_plugin_impl : std::enable_shared_from_thisblock->block_num(), + state_history_log_header header{.magic = ship_magic(ship_current_version), .block_id = block_state->block->id(), .payload_size = sizeof(uint32_t) + deltas_bin.size()}; chain_state_log->write_entry(header, block_state->block->previous, [&](auto& stream) { @@ -571,8 +598,11 @@ void state_history_plugin::set_program_options(options_description& cli, options cli.add_options()("delete-state-history", bpo::bool_switch()->default_value(false), "clear state history files"); options("trace-history", bpo::bool_switch()->default_value(false), "enable trace history"); options("chain-state-history", bpo::bool_switch()->default_value(false), "enable chain state history"); - options("state-history-endpoint", bpo::value()->default_value("0.0.0.0:8080"), - "the endpoint upon which to listen for incoming connections"); + options("state-history-endpoint", bpo::value()->default_value("127.0.0.1:8080"), + "the endpoint upon which to listen for incoming connections. Caution: only expose this port to " + "your internal network."); + options("trace-history-debug-mode", bpo::bool_switch()->default_value(false), + "enable debug mode for trace history"); } void state_history_plugin::plugin_initialize(const variables_map& options) { @@ -608,6 +638,10 @@ void state_history_plugin::plugin_initialize(const variables_map& options) { } boost::filesystem::create_directories(state_history_dir); + if (options.at("trace-history-debug-mode").as()) { + my->trace_debug_mode = true; + } + if (options.at("trace-history").as()) my->trace_log.emplace("trace_history", (state_history_dir / "trace_history.log").string(), (state_history_dir / "trace_history.index").string()); diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp index bdedcc81cd9..085486cdd5a 100644 --- a/plugins/state_history_plugin/state_history_plugin_abi.cpp +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -93,14 +93,30 @@ extern const char* const state_history_plugin_abi = R"({ }, { "name": "action_trace_v0", "fields": [ - { "name": "receipt", "type": "action_receipt" }, + { "name": "action_ordinal", "type": "varuint32" }, + { "name": "creator_action_ordinal", "type": "varuint32" }, + { "name": "receipt", "type": "action_receipt?" }, + { "name": "receiver", "type": "name" }, { "name": "act", "type": "action" }, { "name": "context_free", "type": "bool" }, { "name": "elapsed", "type": "int64" }, { "name": "console", "type": "string" }, { "name": "account_ram_deltas", "type": "account_delta[]" }, { "name": "except", "type": "string?" }, - { "name": "inline_traces", "type": "action_trace[]" } + { "name": "error_code", "type": "uint64?" } + ] + }, + { + "name": "partial_transaction_v0", "fields": [ + { "name": "expiration", "type": "time_point_sec" }, + { "name": "ref_block_num", "type": "uint16" }, + { "name": "ref_block_prefix", "type": "uint32" }, + { "name": "max_net_usage_words", "type": "varuint32" }, + { "name": "max_cpu_usage_ms", "type": "uint8" }, + { "name": "delay_sec", "type": "varuint32" }, + { "name": "transaction_extensions", "type": "extension[]" }, + { "name": "signatures", "type": "signature[]" }, + { "name": "context_free_data", "type": "bytes[]" } ] }, { @@ -113,8 +129,11 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "net_usage", "type": "uint64" }, { "name": "scheduled", "type": "bool" }, { "name": "action_traces", "type": "action_trace[]" }, + { "name": "account_ram_delta", "type": "account_delta?" }, { "name": "except", "type": "string?" }, - { "name": "failed_dtrx_trace", "type": "transaction_trace?" } + { "name": "error_code", "type": "uint64?" }, + { "name": "failed_dtrx_trace", "type": "transaction_trace?" }, + { "name": "partial", "type": "partial_transaction?" } ] }, { @@ -183,18 +202,35 @@ extern const char* const state_history_plugin_abi = R"({ ] }, { - "name": "account_v0", "fields": [ - { "type": "name", "name": "name" }, + "name": "code_id", "fields": [ { "type": "uint8", "name": "vm_type" }, { "type": "uint8", "name": "vm_version" }, - { "type": "bool", "name": "privileged" }, - { "type": "time_point", "name": "last_code_update" }, - { "type": "checksum256", "name": "code_version" }, + { "type": "checksum256", "name": "code_hash" } + ] + }, + { + "name": "account_v0", "fields": [ + { "type": "name", "name": "name" }, { "type": "block_timestamp_type", "name": "creation_date" }, - { "type": "bytes", "name": "code" }, { "type": "bytes", "name": "abi" } ] }, + { + "name": "account_metadata_v0", "fields": [ + { "type": "name", "name": "name" }, + { "type": "bool", "name": "privileged" }, + { "type": "time_point", "name": "last_code_update" }, + { "type": "code_id?", "name": "code" } + ] + }, + { + "name": "code_v0", "fields": [ + { "type": "uint8", "name": "vm_type" }, + { "type": "uint8", "name": "vm_version" }, + { "type": "checksum256", "name": "code_hash" }, + { "type": "bytes", "name": "code" } + ] + }, { "name": "contract_table_v0", "fields": [ { "type": "name", "name": "code" }, @@ -275,6 +311,24 @@ extern const char* const state_history_plugin_abi = R"({ { "type": "producer_key[]", "name": "producers" } ] }, + { + "name": "block_signing_authority_v0", "fields": [ + { "type": "uint32", "name": "threshold" }, + { "type": "key_weight[]", "name": "keys" } + ] + }, + { + "name": "producer_authority", "fields": [ + { "type": "name", "name": "producer_name" }, + { "type": "block_signing_authority", "name": "authority" } + ] + }, + { + "name": "producer_authority_schedule", "fields": [ + { "type": "uint32", "name": "version" }, + { "type": "producer_authority[]", "name": "producers" } + ] + }, { "name": "chain_config_v0", "fields": [ { "type": "uint64", "name": "max_block_net_usage" }, @@ -303,6 +357,14 @@ extern const char* const state_history_plugin_abi = R"({ { "type": "chain_config", "name": "configuration" } ] }, + { + "name": "global_property_v1", "fields": [ + { "type": "uint32?", "name": "proposed_schedule_block_num" }, + { "type": "producer_authority_schedule", "name": "proposed_schedule" }, + { "type": "chain_config", "name": "configuration" }, + { "type": "checksum256", "name": "chain_id" } + ] + }, { "name": "generated_transaction_v0", "fields": [ { "type": "name", "name": "sender" }, @@ -429,11 +491,14 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "action_receipt", "types": ["action_receipt_v0"] }, { "name": "action_trace", "types": ["action_trace_v0"] }, + { "name": "partial_transaction", "types": ["partial_transaction_v0"] }, { "name": "transaction_trace", "types": ["transaction_trace_v0"] }, { "name": "transaction_variant", "types": ["transaction_id", "packed_transaction"] }, { "name": "table_delta", "types": ["table_delta_v0"] }, { "name": "account", "types": ["account_v0"] }, + { "name": "account_metadata", "types": ["account_metadata_v0"] }, + { "name": "code", "types": ["code_v0"] }, { "name": "contract_table", "types": ["contract_table_v0"] }, { "name": "contract_row", "types": ["contract_row_v0"] }, { "name": "contract_index64", "types": ["contract_index64_v0"] }, @@ -442,7 +507,7 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "contract_index_double", "types": ["contract_index_double_v0"] }, { "name": "contract_index_long_double", "types": ["contract_index_long_double_v0"] }, { "name": "chain_config", "types": ["chain_config_v0"] }, - { "name": "global_property", "types": ["global_property_v0"] }, + { "name": "global_property", "types": ["global_property_v0", "global_property_v1"] }, { "name": "generated_transaction", "types": ["generated_transaction_v0"] }, { "name": "permission", "types": ["permission_v0"] }, { "name": "permission_link", "types": ["permission_link_v0"] }, @@ -452,10 +517,13 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "resource_limits_state", "types": ["resource_limits_state_v0"] }, { "name": "resource_limits_ratio", "types": ["resource_limits_ratio_v0"] }, { "name": "elastic_limit_parameters", "types": ["elastic_limit_parameters_v0"] }, - { "name": "resource_limits_config", "types": ["resource_limits_config_v0"] } + { "name": "resource_limits_config", "types": ["resource_limits_config_v0"] }, + { "name": "block_signing_authority", "types": ["block_signing_authority_v0"] } ], "tables": [ { "name": "account", "type": "account", "key_names": ["name"] }, + { "name": "account_metadata", "type": "account_metadata", "key_names": ["name"] }, + { "name": "code", "type": "code", "key_names": ["vm_type", "vm_version", "code_hash"] }, { "name": "contract_table", "type": "contract_table", "key_names": ["code", "scope", "table"] }, { "name": "contract_row", "type": "contract_row", "key_names": ["code", "scope", "table", "primary_key"] }, { "name": "contract_index64", "type": "contract_index64", "key_names": ["code", "scope", "table", "primary_key"] }, @@ -465,6 +533,7 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "contract_index_long_double", "type": "contract_index_long_double", "key_names": ["code", "scope", "table", "primary_key"] }, { "name": "global_property", "type": "global_property", "key_names": [] }, { "name": "generated_transaction", "type": "generated_transaction", "key_names": ["sender", "sender_id"] }, + { "name": "protocol_state", "type": "protocol_state", "key_names": [] }, { "name": "permission", "type": "permission", "key_names": ["owner", "name"] }, { "name": "permission_link", "type": "permission_link", "key_names": ["account", "code", "message_type"] }, { "name": "resource_limits", "type": "resource_limits", "key_names": ["owner"] }, diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index 30a1acb9b28..018867968ec 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -164,7 +164,7 @@ struct txn_test_gen_plugin_impl { auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountA, owner_auth, active_auth}); + trx.actions.emplace_back(vector{{creator,name("active")}}, newaccount{creator, newaccountA, owner_auth, active_auth}); //delegate cpu net and buyram auto act_delegatebw = create_action_delegatebw(creator, newaccountA,net,cpu,abi_serializer_max_time); @@ -179,7 +179,7 @@ struct txn_test_gen_plugin_impl { auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountB, owner_auth, active_auth}); + trx.actions.emplace_back(vector{{creator,name("active")}}, newaccount{creator, newaccountB, owner_auth, active_auth}); //delegate cpu net and buyram auto act_delegatebw = create_action_delegatebw(creator, newaccountB,net,cpu,abi_serializer_max_time); @@ -193,7 +193,7 @@ struct txn_test_gen_plugin_impl { auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountC, owner_auth, active_auth}); + trx.actions.emplace_back(vector{{creator,name("active")}}, newaccount{creator, newaccountC, owner_auth, active_auth}); //delegate cpu net and buyram auto act_delegatebw = create_action_delegatebw(creator, newaccountC,net,cpu,abi_serializer_max_time); @@ -220,13 +220,13 @@ struct txn_test_gen_plugin_impl { handler.account = newaccountC; handler.code.assign(wasm.begin(), wasm.end()); - trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); + trx.actions.emplace_back( vector{{newaccountC,name("active")}}, handler); { setabi handler; handler.account = newaccountC; handler.abi = fc::raw::pack(eosio_token_abi); - trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); + trx.actions.emplace_back( vector{{newaccountC,name("active")}}, handler); } { @@ -289,7 +289,7 @@ struct txn_test_gen_plugin_impl { abi_serializer eosio_system_serializer(eosio_abi, abi_serializer_max_time); auto payload_delegate = eosio_system_serializer.variant_to_binary( "delegatebw", variant_delegate, abi_serializer_max_time); - eosio::chain::action act_delegate{vector{{from,"active"}}, + eosio::chain::action act_delegate{vector{{from,name("active")}}, config::system_account_name, N(delegatebw), payload_delegate}; return act_delegate; @@ -306,7 +306,7 @@ struct txn_test_gen_plugin_impl { abi_serializer eosio_system_serializer(eosio_abi, abi_serializer_max_time); auto payload_buyram = eosio_system_serializer.variant_to_binary( "buyram", variant_buyram, abi_serializer_max_time); - eosio::chain::action act_buyram{vector{{from,"active"}}, + eosio::chain::action act_buyram{vector{{from,name("active")}}, config::system_account_name, N(buyram), payload_buyram}; return act_buyram; @@ -411,7 +411,7 @@ struct txn_test_gen_plugin_impl { { signed_transaction trx; trx.actions.push_back(act_a_to_b); - trx.context_free_actions.emplace_back(action({}, config::null_account_name, "nonce", fc::raw::pack(nonce++))); + trx.context_free_actions.emplace_back(action({}, config::null_account_name, name("nonce"), fc::raw::pack(nonce++))); trx.set_reference_block(reference_block_id); trx.expiration = cc.head_block_time() + fc::seconds(30); trx.max_net_usage_words = 100; @@ -422,7 +422,7 @@ struct txn_test_gen_plugin_impl { { signed_transaction trx; trx.actions.push_back(act_b_to_a); - trx.context_free_actions.emplace_back(action({}, config::null_account_name, "nonce", fc::raw::pack(nonce++))); + trx.context_free_actions.emplace_back(action({}, config::null_account_name, name("nonce"), fc::raw::pack(nonce++))); trx.set_reference_block(reference_block_id); trx.expiration = cc.head_block_time() + fc::seconds(30); trx.max_net_usage_words = 100; diff --git a/tests/Cluster.py b/tests/Cluster.py index b1c3baa3a66..91afc193d16 100644 --- a/tests/Cluster.py +++ b/tests/Cluster.py @@ -152,7 +152,7 @@ def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", p2pPlugin="ne if self.staging: cmdArr.append("--nogen") - nodeosArgs="--max-transaction-time -1 --abi-serializer-max-time-ms 990000 --filter-on * --p2p-max-nodes-per-host %d" % (totalNodes) + nodeosArgs="--max-transaction-time -1 --abi-serializer-max-time-us 990000 --filter-on * --p2p-max-nodes-per-host %d" % (totalNodes) if not self.walletd: nodeosArgs += " --plugin eosio::wallet_api_plugin" if self.enableMongo: From c8c27f40a77eb2598c1aae25a3e9c9468699118e Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Mon, 11 May 2020 20:11:52 +0800 Subject: [PATCH 04/25] FIX: unittests --- CMakeLists.txt | 4 +- libraries/CMakeLists.txt | 2 +- libraries/chain/apply_context.cpp | 3 +- .../testing/include/eosio/testing/tester.hpp | 8 +- libraries/testing/tester.cpp | 10 +- unittests/abi_tests.cpp | 96 +++---- unittests/api_tests.cpp | 267 +++++++++--------- unittests/auth_tests.cpp | 235 +++++++-------- unittests/bootseq_tests.cpp | 48 ++-- unittests/database_gmr_blklst_tests.cpp | 4 +- unittests/database_tests.cpp | 6 +- unittests/eosio_system_tester.hpp | 24 +- unittests/forked_tests.cpp | 35 +-- unittests/misc_tests.cpp | 167 +++++------ unittests/pbft_tests.cpp | 2 +- unittests/ram_tests.cpp | 2 +- unittests/special_accounts_tests.cpp | 18 +- unittests/wasm_tests.cpp | 36 +-- unittests/whitelist_blacklist_tests.cpp | 18 +- 19 files changed, 491 insertions(+), 494 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d5d4cb077c..fd82178bd72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -249,8 +249,8 @@ add_subdirectory( libraries ) add_subdirectory( plugins ) add_subdirectory( programs ) add_subdirectory( scripts ) -#add_subdirectory( unittests ) -#add_subdirectory( tests ) +add_subdirectory( unittests ) +add_subdirectory( tests ) add_subdirectory( tools ) add_subdirectory( debian ) diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 58583d1ed01..788e6194973 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -5,7 +5,7 @@ add_subdirectory( chainbase ) add_subdirectory( wasm-jit ) add_subdirectory( appbase ) add_subdirectory( chain ) -#add_subdirectory( testing ) +add_subdirectory( testing ) #turn tools&tests off; not needed for library build set(BUILD_TESTS OFF CACHE BOOL "Build GTest-based tests") diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 56ec3fbc375..3aa50c100e4 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -329,7 +329,8 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block() && !control.sender_avoids_whitelist_blacklist_enforcement( receiver ); trx_context.validate_referenced_accounts( trx, enforce_actor_whitelist_blacklist ); - + trx.expiration = control.pending_block_time() + fc::microseconds(999'999); // Rounds up to nearest second (makes expiration check unnecessary) + trx.set_reference_block(control.head_block_id()); // No TaPoS check necessary // Charge ahead of time for the additional net usage needed to retire the deferred transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. const auto& cfg = control.get_global_properties().configuration; diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 2df1be62360..e66e0b8c742 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -157,8 +157,8 @@ namespace eosio { namespace testing { vector get_producer_keys( const vector& producer_names )const; transaction_trace_ptr set_producers(const vector& producer_names); - void link_authority( account_name account, account_name code, permission_name req, action_name type = "" ); - void unlink_authority( account_name account, account_name code, action_name type = "" ); + void link_authority( account_name account, account_name code, permission_name req, action_name type = {} ); + void unlink_authority( account_name account, account_name code, action_name type = {} ); void set_authority( account_name account, permission_name perm, authority auth, permission_name parent, const vector& auths, const vector& keys ); void set_authority( account_name account, permission_name perm, authority auth, @@ -197,7 +197,7 @@ namespace eosio { namespace testing { template< typename KeyType = fc::ecc::private_key_shim > static private_key_type get_private_key( name keyname, string role = "owner" ) { - return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); + return private_key_type::regenerate(fc::sha256::hash(keyname.to_string()+role)); } template< typename KeyType = fc::ecc::private_key_shim > @@ -216,7 +216,7 @@ namespace eosio { namespace testing { const symbol& asset_symbol, const account_name& account ) const; - vector get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act ) const; + vector get_row_by_account( name code, name scope, name table, const account_name& act ) const; map get_last_produced_block_map()const { return last_produced_block; }; void set_last_produced_block_map( const map& lpb ) { last_produced_block = lpb; } diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 6cf772b6adb..a31275a7deb 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -382,12 +382,12 @@ namespace eosio { namespace testing { typename base_tester::action_result base_tester::push_action(action&& act, uint64_t authorizer) { signed_transaction trx; if (authorizer) { - act.authorization = vector{{authorizer, config::active_name}}; + act.authorization = vector{{account_name(authorizer), config::active_name}}; } trx.actions.emplace_back(std::move(act)); set_transaction_headers(trx); if (authorizer) { - trx.sign(get_private_key(authorizer, "active"), control->get_chain_id()); + trx.sign(get_private_key(account_name(authorizer), "active"), control->get_chain_id()); } try { push_transaction(trx); @@ -755,7 +755,7 @@ namespace eosio { namespace testing { } - vector base_tester::get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act ) const { + vector base_tester::get_row_by_account( name code, name scope, name table, const account_name& act ) const { vector data; const auto& db = control->db(); const auto* t_id = db.find( boost::make_tuple( code, scope, table ) ); @@ -766,8 +766,8 @@ namespace eosio { namespace testing { const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( t_id->id, act ) ); - if ( itr == idx.end() || itr->t_id != t_id->id || act.value != itr->primary_key ) { + auto itr = idx.lower_bound( boost::make_tuple( t_id->id, act.to_uint64_t() ) ); + if ( itr == idx.end() || itr->t_id != t_id->id || act.to_uint64_t() != itr->primary_key ) { return data; } diff --git a/unittests/abi_tests.cpp b/unittests/abi_tests.cpp index f41f664968e..316f7a1d2d6 100644 --- a/unittests/abi_tests.cpp +++ b/unittests/abi_tests.cpp @@ -818,10 +818,10 @@ BOOST_AUTO_TEST_CASE(linkauth_test) auto var = fc::json::from_string(test_data); auto lauth = var.as(); - BOOST_TEST("lnkauth.acct" == lauth.account); - BOOST_TEST("lnkauth.code" == lauth.code); - BOOST_TEST("lnkauth.type" == lauth.type); - BOOST_TEST("lnkauth.rqm" == lauth.requirement); + BOOST_TEST(name("lnkauth.acct") == lauth.account); + BOOST_TEST(name("lnkauth.code") == lauth.code); + BOOST_TEST(name("lnkauth.type") == lauth.type); + BOOST_TEST(name("lnkauth.rqm") == lauth.requirement); auto var2 = verify_byte_round_trip_conversion( abis, "linkauth", var ); auto linkauth2 = var2.as(); @@ -851,9 +851,9 @@ BOOST_AUTO_TEST_CASE(unlinkauth_test) auto var = fc::json::from_string(test_data); auto unlauth = var.as(); - BOOST_TEST("lnkauth.acct" == unlauth.account); - BOOST_TEST("lnkauth.code" == unlauth.code); - BOOST_TEST("lnkauth.type" == unlauth.type); + BOOST_TEST(name("lnkauth.acct") == unlauth.account); + BOOST_TEST(name("lnkauth.code") == unlauth.code); + BOOST_TEST(name("lnkauth.type") == unlauth.type); auto var2 = verify_byte_round_trip_conversion( abis, "unlinkauth", var ); auto unlinkauth2 = var2.as(); @@ -890,9 +890,9 @@ BOOST_AUTO_TEST_CASE(updateauth_test) auto var = fc::json::from_string(test_data); auto updauth = var.as(); - BOOST_TEST("updauth.acct" == updauth.account); - BOOST_TEST("updauth.prm" == updauth.permission); - BOOST_TEST("updauth.prnt" == updauth.parent); + BOOST_TEST(name("updauth.acct") == updauth.account); + BOOST_TEST(name("updauth.prm") == updauth.permission); + BOOST_TEST(name("updauth.prnt") == updauth.parent); BOOST_TEST(2147483145u == updauth.auth.threshold); BOOST_TEST_REQUIRE(2 == updauth.auth.keys.size()); @@ -901,12 +901,12 @@ BOOST_AUTO_TEST_CASE(updateauth_test) BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == (std::string)updauth.auth.keys[1].key); BOOST_TEST(57605u == updauth.auth.keys[1].weight); - BOOST_TEST_REQUIRE(2 == updauth.auth.accounts.size()); - BOOST_TEST("prm.acct1" == updauth.auth.accounts[0].permission.actor); - BOOST_TEST("prm.prm1" == updauth.auth.accounts[0].permission.permission); + BOOST_TEST_REQUIRE(2u == updauth.auth.accounts.size()); + BOOST_TEST(name("prm.acct1") == updauth.auth.accounts[0].permission.actor); + BOOST_TEST(name("prm.prm1") == updauth.auth.accounts[0].permission.permission); BOOST_TEST(53005u == updauth.auth.accounts[0].weight); - BOOST_TEST("prm.acct2" == updauth.auth.accounts[1].permission.actor); - BOOST_TEST("prm.prm2" == updauth.auth.accounts[1].permission.permission); + BOOST_TEST(name("prm.acct2") == updauth.auth.accounts[1].permission.actor); + BOOST_TEST(name("prm.prm2") == updauth.auth.accounts[1].permission.permission); BOOST_TEST(53405u == updauth.auth.accounts[1].weight); auto var2 = verify_byte_round_trip_conversion( abis, "updateauth", var ); @@ -951,8 +951,8 @@ BOOST_AUTO_TEST_CASE(deleteauth_test) auto var = fc::json::from_string(test_data); auto delauth = var.as(); - BOOST_TEST("delauth.acct" == delauth.account); - BOOST_TEST("delauth.prm" == delauth.permission); + BOOST_TEST(name("delauth.acct") == delauth.account); + BOOST_TEST(name("delauth.prm") == delauth.permission); auto var2 = verify_byte_round_trip_conversion( abis, "deleteauth", var ); auto deleteauth2 = var2.as(); @@ -994,39 +994,39 @@ BOOST_AUTO_TEST_CASE(newaccount_test) auto var = fc::json::from_string(test_data); auto newacct = var.as(); - BOOST_TEST("newacct.crtr" == newacct.creator); - BOOST_TEST("newacct.name" == newacct.name); + BOOST_TEST(name("newacct.crtr") == newacct.creator); + BOOST_TEST(name("newacct.name") == newacct.name); BOOST_TEST(2147483145u == newacct.owner.threshold); - BOOST_TEST_REQUIRE(2 == newacct.owner.keys.size()); + BOOST_TEST_REQUIRE(2u == newacct.owner.keys.size()); BOOST_TEST("EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im" == (std::string)newacct.owner.keys[0].key); BOOST_TEST(57005u == newacct.owner.keys[0].weight); BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == (std::string)newacct.owner.keys[1].key); BOOST_TEST(57605u == newacct.owner.keys[1].weight); - BOOST_TEST_REQUIRE(2 == newacct.owner.accounts.size()); - BOOST_TEST("prm.acct1" == newacct.owner.accounts[0].permission.actor); - BOOST_TEST("prm.prm1" == newacct.owner.accounts[0].permission.permission); + BOOST_TEST_REQUIRE(2u == newacct.owner.accounts.size()); + BOOST_TEST(name("prm.acct1") == newacct.owner.accounts[0].permission.actor); + BOOST_TEST(name("prm.prm1") == newacct.owner.accounts[0].permission.permission); BOOST_TEST(53005u == newacct.owner.accounts[0].weight); - BOOST_TEST("prm.acct2" == newacct.owner.accounts[1].permission.actor); - BOOST_TEST("prm.prm2" == newacct.owner.accounts[1].permission.permission); + BOOST_TEST(name("prm.acct2") == newacct.owner.accounts[1].permission.actor); + BOOST_TEST(name("prm.prm2") == newacct.owner.accounts[1].permission.permission); BOOST_TEST(53405u == newacct.owner.accounts[1].weight); BOOST_TEST(2146483145u == newacct.active.threshold); - BOOST_TEST_REQUIRE(2 == newacct.active.keys.size()); + BOOST_TEST_REQUIRE(2u == newacct.active.keys.size()); BOOST_TEST("EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im" == (std::string)newacct.active.keys[0].key); BOOST_TEST(57005u == newacct.active.keys[0].weight); BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == (std::string)newacct.active.keys[1].key); BOOST_TEST(57605u == newacct.active.keys[1].weight); - BOOST_TEST_REQUIRE(2 == newacct.active.accounts.size()); - BOOST_TEST("prm.acct1" == newacct.active.accounts[0].permission.actor); - BOOST_TEST("prm.prm1" == newacct.active.accounts[0].permission.permission); + BOOST_TEST_REQUIRE(2u == newacct.active.accounts.size()); + BOOST_TEST(name("prm.acct1") == newacct.active.accounts[0].permission.actor); + BOOST_TEST(name("prm.prm1") == newacct.active.accounts[0].permission.permission); BOOST_TEST(53005u == newacct.active.accounts[0].weight); - BOOST_TEST("prm.acct2" == newacct.active.accounts[1].permission.actor); - BOOST_TEST("prm.prm2" == newacct.active.accounts[1].permission.permission); + BOOST_TEST(name("prm.acct2") == newacct.active.accounts[1].permission.actor); + BOOST_TEST(name("prm.prm2") == newacct.active.accounts[1].permission.permission); BOOST_TEST(53405u == newacct.active.accounts[1].weight); @@ -1090,7 +1090,7 @@ BOOST_AUTO_TEST_CASE(setcode_test) auto var = fc::json::from_string(test_data); auto set_code = var.as(); - BOOST_TEST("setcode.acc" == set_code.account); + BOOST_TEST(name("setcode.acc") == set_code.account); BOOST_TEST(0 == set_code.vmtype); BOOST_TEST(0 == set_code.vmversion); BOOST_TEST("0061736d0100000001390a60037e7e7f017f60047e7e7f7f017f60017e0060057e7e7e7f7f" == fc::to_hex(set_code.code.data(), set_code.code.size())); @@ -1303,22 +1303,22 @@ BOOST_AUTO_TEST_CASE(setabi_test) auto var = fc::json::from_string(abi_string); auto abi = var.as(); - BOOST_TEST_REQUIRE(1 == abi.types.size()); + BOOST_TEST_REQUIRE(1u == abi.types.size()); BOOST_TEST("account_name" == abi.types[0].new_type_name); BOOST_TEST("name" == abi.types[0].type); - BOOST_TEST_REQUIRE(3 == abi.structs.size()); + BOOST_TEST_REQUIRE(3u == abi.structs.size()); BOOST_TEST("transfer_base" == abi.structs[0].name); BOOST_TEST("" == abi.structs[0].base); - BOOST_TEST_REQUIRE(1 == abi.structs[0].fields.size()); + BOOST_TEST_REQUIRE(1u == abi.structs[0].fields.size()); BOOST_TEST("memo" == abi.structs[0].fields[0].name); BOOST_TEST("string" == abi.structs[0].fields[0].type); BOOST_TEST("transfer" == abi.structs[1].name); BOOST_TEST("transfer_base" == abi.structs[1].base); - BOOST_TEST_REQUIRE(3 == abi.structs[1].fields.size()); + BOOST_TEST_REQUIRE(3u == abi.structs[1].fields.size()); BOOST_TEST("from" == abi.structs[1].fields[0].name); BOOST_TEST("account_name" == abi.structs[1].fields[0].type); BOOST_TEST("to" == abi.structs[1].fields[1].name); @@ -1328,23 +1328,23 @@ BOOST_AUTO_TEST_CASE(setabi_test) BOOST_TEST("account" == abi.structs[2].name); BOOST_TEST("" == abi.structs[2].base); - BOOST_TEST_REQUIRE(2 == abi.structs[2].fields.size()); + BOOST_TEST_REQUIRE(2u == abi.structs[2].fields.size()); BOOST_TEST("account" == abi.structs[2].fields[0].name); BOOST_TEST("name" == abi.structs[2].fields[0].type); BOOST_TEST("balance" == abi.structs[2].fields[1].name); BOOST_TEST("uint64" == abi.structs[2].fields[1].type); - BOOST_TEST_REQUIRE(1 == abi.actions.size()); - BOOST_TEST("transfer" == abi.actions[0].name); + BOOST_TEST_REQUIRE(1u == abi.actions.size()); + BOOST_TEST(name("transfer") == abi.actions[0].name); BOOST_TEST("transfer" == abi.actions[0].type); - BOOST_TEST_REQUIRE(1 == abi.tables.size()); - BOOST_TEST("account" == abi.tables[0].name); + BOOST_TEST_REQUIRE(1u == abi.tables.size()); + BOOST_TEST(name("account") == abi.tables[0].name); BOOST_TEST("account" == abi.tables[0].type); BOOST_TEST("i64" == abi.tables[0].index_type); - BOOST_TEST_REQUIRE(1 == abi.tables[0].key_names.size()); + BOOST_TEST_REQUIRE(1u == abi.tables[0].key_names.size()); BOOST_TEST("account" == abi.tables[0].key_names[0]); - BOOST_TEST_REQUIRE(1 == abi.tables[0].key_types.size()); + BOOST_TEST_REQUIRE(1u == abi.tables[0].key_types.size()); BOOST_TEST("name" == abi.tables[0].key_types[0]); auto var2 = verify_byte_round_trip_conversion( abis, "abi_def", var ); @@ -1446,20 +1446,20 @@ struct action2 { template void verify_action_equal(const chain::action& exp, const chain::action& act) { - BOOST_REQUIRE_EQUAL((std::string)exp.account, (std::string)act.account); - BOOST_REQUIRE_EQUAL((std::string)exp.name, (std::string)act.name); + BOOST_REQUIRE_EQUAL(exp.account.to_string(), act.account.to_string()); + BOOST_REQUIRE_EQUAL(exp.name.to_string(), act.name.to_string()); BOOST_REQUIRE_EQUAL(exp.authorization.size(), act.authorization.size()); for(unsigned int i = 0; i < exp.authorization.size(); ++i) { - BOOST_REQUIRE_EQUAL((std::string)exp.authorization[i].actor, (std::string)act.authorization[i].actor); - BOOST_REQUIRE_EQUAL((std::string)exp.authorization[i].permission, (std::string)act.authorization[i].permission); + BOOST_REQUIRE_EQUAL(exp.authorization[i].actor.to_string(), act.authorization[i].actor.to_string()); + BOOST_REQUIRE_EQUAL(exp.authorization[i].permission.to_string(), act.authorization[i].permission.to_string()); } BOOST_REQUIRE_EQUAL(exp.data.size(), act.data.size()); BOOST_REQUIRE(!memcmp(exp.data.data(), act.data.data(), exp.data.size())); } private_key_type get_private_key( name keyname, string role ) { - return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); + return private_key_type::regenerate(fc::sha256::hash(keyname.to_string()+role)); } public_key_type get_public_key( name keyname, string role ) { diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index bd0336b69f3..37d2301f5c6 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -93,13 +93,13 @@ struct dtt_action { return WASM_TEST_ACTION("test_transaction", "send_deferred_tx_with_dtt_action"); } static uint64_t get_account() { - return N(testapi); + return N(testapi).to_uint64_t(); } - uint64_t payer = N(testapi); - uint64_t deferred_account = N(testapi); + uint64_t payer = N(testapi).to_uint64_t(); + uint64_t deferred_account = N(testapi).to_uint64_t(); uint64_t deferred_action = WASM_TEST_ACTION("test_transaction", "deferred_print"); - uint64_t permission_name = N(active); + uint64_t permission_name = N(active).to_uint64_t(); uint32_t delay_sec = 2; }; @@ -246,6 +246,7 @@ transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, #define CALL_TEST_FUNCTION(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_api_action{}, DATA) #define CALL_TEST_FUNCTION_SYSTEM(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_chain_action{}, DATA, {config::system_account_name} ) #define CALL_TEST_FUNCTION_SCOPE(_TESTER, CLS, MTH, DATA, ACCOUNT) CallFunction(_TESTER, test_api_action{}, DATA, ACCOUNT) +#define CALL_TEST_FUNCTION_NO_THROW(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_api_action{}, DATA, {N(testapi)}, true) #define CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION(_TESTER, CLS, MTH, DATA, EXC, EXC_MESSAGE) \ BOOST_CHECK_EXCEPTION( \ CALL_TEST_FUNCTION( _TESTER, CLS, MTH, DATA), \ @@ -303,107 +304,107 @@ struct MySink : public bio::sink uint32_t last_fnc_err = 0; BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { - produce_blocks(2); - create_account( N(test) ); - set_code( N(test), contracts::payloadless_wasm() ); - produce_blocks(1); + produce_blocks(2); + create_account( N(test) ); + set_code( N(test), contracts::payloadless_wasm() ); + produce_blocks(1); + + auto call_doit_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { + signed_transaction trx; + trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(doit), bytes{} ); + this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); + trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); + auto res = this->push_transaction(trx); + checker( res ); + }; - auto call_doit_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { - signed_transaction trx; - trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(doit), bytes{} ); - this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); - trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); - auto res = this->push_transaction(trx); - checker( res ); - }; - - auto call_provereset_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { - signed_transaction trx; - trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(provereset), bytes{} ); - this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); - trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); - auto res = this->push_transaction(trx); - checker( res ); - }; - - auto result = push_reqauth( config::system_account_name, "active" ); - BOOST_REQUIRE_EQUAL( result->receipt->status, transaction_receipt::executed ); - BOOST_REQUIRE( result->action_traces[0].receipt.auth_sequence.find( config::system_account_name ) - != result->action_traces[0].receipt.auth_sequence.end() ); - auto base_global_sequence_num = result->action_traces[0].receipt.global_sequence; - auto base_system_recv_seq_num = result->action_traces[0].receipt.recv_sequence; - auto base_system_auth_seq_num = result->action_traces[0].receipt.auth_sequence[config::system_account_name]; - auto base_system_code_seq_num = result->action_traces[0].receipt.code_sequence.value; - auto base_system_abi_seq_num = result->action_traces[0].receipt.abi_sequence.value; - - uint64_t base_test_recv_seq_num = 0; - uint64_t base_test_auth_seq_num = 0; - call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { - BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 0 ); - base_test_recv_seq_num = res->action_traces[0].receipt.recv_sequence; - BOOST_CHECK( base_test_recv_seq_num > 0 ); - base_test_recv_seq_num--; - const auto& m = res->action_traces[0].receipt.auth_sequence; - BOOST_CHECK_EQUAL( m.size(), 1 ); - BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); - base_test_auth_seq_num = m.begin()->second; - BOOST_CHECK( base_test_auth_seq_num > 0 ); - --base_test_auth_seq_num; - } ); - - set_code( N(test), contracts::asserter_wasm() ); - set_code( config::system_account_name, contracts::payloadless_wasm() ); - - call_provereset_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { - BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_test_recv_seq_num + 2 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 2 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 0 ); - const auto& m = res->action_traces[0].receipt.auth_sequence; - BOOST_CHECK_EQUAL( m.size(), 1 ); - BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); - BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 3 ); - } ); - - produce_blocks(1); // Added to avoid the last doit transaction from being considered a duplicate. - // Adding a block also retires an onblock action which increments both the global sequence number - // and the recv and auth sequences numbers for the system account. - - call_doit_and_check( config::system_account_name, N(test), [&]( const transaction_trace_ptr& res ) { - BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 6 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_system_recv_seq_num + 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, base_system_code_seq_num + 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, base_system_abi_seq_num ); - const auto& m = res->action_traces[0].receipt.auth_sequence; - BOOST_CHECK_EQUAL( m.size(), 1 ); - BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); - BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 4 ); - } ); - - set_code( config::system_account_name, contracts::eosio_bios_wasm() ); - - set_code( N(test), contracts::eosio_bios_wasm() ); - set_abi( N(test), contracts::eosio_bios_abi().data() ); + auto call_provereset_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { + signed_transaction trx; + trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(provereset), bytes{} ); + this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); + trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); + auto res = this->push_transaction(trx); + checker( res ); + }; + + auto result = push_reqauth( config::system_account_name, "active" ); + BOOST_REQUIRE_EQUAL( result->receipt->status, transaction_receipt::executed ); + BOOST_REQUIRE( result->action_traces[0].receipt->auth_sequence.find( config::system_account_name ) + != result->action_traces[0].receipt->auth_sequence.end() ); + auto base_global_sequence_num = result->action_traces[0].receipt->global_sequence; + auto base_system_recv_seq_num = result->action_traces[0].receipt->recv_sequence; + auto base_system_auth_seq_num = result->action_traces[0].receipt->auth_sequence[config::system_account_name]; + auto base_system_code_seq_num = result->action_traces[0].receipt->code_sequence.value; + auto base_system_abi_seq_num = result->action_traces[0].receipt->abi_sequence.value; + + uint64_t base_test_recv_seq_num = 0; + uint64_t base_test_auth_seq_num = 0; + call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 0 ); + base_test_recv_seq_num = res->action_traces[0].receipt->recv_sequence; + BOOST_CHECK( base_test_recv_seq_num > 0 ); + base_test_recv_seq_num--; + const auto& m = res->action_traces[0].receipt->auth_sequence; + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); + base_test_auth_seq_num = m.begin()->second; + BOOST_CHECK( base_test_auth_seq_num > 0 ); + --base_test_auth_seq_num; + } ); + + set_code( N(test), contracts::asserter_wasm() ); + set_code( config::system_account_name, contracts::payloadless_wasm() ); + + call_provereset_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_test_recv_seq_num + 2 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 2 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 0 ); + const auto& m = res->action_traces[0].receipt->auth_sequence; + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); + BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 3 ); + } ); + + produce_blocks(1); // Added to avoid the last doit transaction from being considered a duplicate. + // Adding a block also retires an onblock action which increments both the global sequence number + // and the recv and auth sequences numbers for the system account. + + call_doit_and_check( config::system_account_name, N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 6 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_system_recv_seq_num + 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, base_system_code_seq_num + 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, base_system_abi_seq_num ); + const auto& m = res->action_traces[0].receipt->auth_sequence; + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); + BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 4 ); + } ); + + set_code( config::system_account_name, contracts::eosio_bios_wasm() ); + + set_code( N(test), contracts::eosio_bios_wasm() ); + set_abi( N(test), contracts::eosio_bios_abi().data() ); set_code( N(test), contracts::payloadless_wasm() ); - call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { - BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 11 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_test_recv_seq_num + 3 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 1 ); - const auto& m = res->action_traces[0].receipt.auth_sequence; - BOOST_CHECK_EQUAL( m.size(), 1 ); - BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); - BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 8 ); - } ); + call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 11 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_test_recv_seq_num + 3 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 1 ); + const auto& m = res->action_traces[0].receipt->auth_sequence; + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); + BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 8 ); + } ); - } FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() } /************************************************************************************* * action_tests test case @@ -592,13 +593,13 @@ BOOST_FIXTURE_TEST_CASE(ram_billing_in_notify_tests, TESTER) { try { set_code( N(testapi2), contracts::test_api_wasm() ); produce_blocks(1); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2) << 64) | N(testapi) ) ), + BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2).to_uint64_t() << 64) | N(testapi).to_uint64_t() ) ), subjective_block_production_exception, fc_exception_message_is("Cannot charge RAM to other accounts during notify.") ); - CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2) << 64) | 0 ) ); + CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2).to_uint64_t() << 64) | 0 ) ); - CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2) << 64) | N(testapi2) ) ); + CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2).to_uint64_t() << 64) | N(testapi2).to_uint64_t() ) ); BOOST_REQUIRE_EQUAL( validate(), true ); } FC_LOG_AND_RETHROW() } @@ -629,9 +630,6 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { trx.context_free_data.emplace_back(fc::raw::pack(200)); set_transaction_headers(trx); - // signing a transaction with only context_free_actions should not be allowed - // auto sigs = trx.sign(get_private_key(N(testapi), "active"), control->get_chain_id()); - BOOST_CHECK_EXCEPTION(push_transaction(trx), tx_no_auths, [](const fc::exception& e) { return expect_assert_message(e, "transaction must have at least one authorization"); @@ -700,12 +698,12 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { // test send context free action auto ttrace = CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action", {} ); - BOOST_CHECK_EQUAL(ttrace->action_traces.size(), 1); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces.size(), 1); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].receipt.receiver, account_name("dummy")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.account, account_name("dummy")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.name, account_name("event1")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.authorization.size(), 0); + BOOST_REQUIRE_EQUAL(ttrace->action_traces.size(), 2); + BOOST_CHECK_EQUAL((int)(ttrace->action_traces[1].creator_action_ordinal), 1); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].receiver, account_name("dummy")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.account, account_name("dummy")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.name, account_name("event1")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.authorization.size(), 0); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action_fail", {} ), eosio_assert_message_exception, @@ -729,7 +727,7 @@ BOOST_FIXTURE_TEST_CASE(cfa_tx_signature, TESTER) try { tx2.context_free_actions.push_back(cfa); set_transaction_headers(tx2); - const private_key_type& priv_key = get_private_key("dummy", "active"); + const private_key_type& priv_key = get_private_key(name("dummy"), "active"); BOOST_TEST((std::string)tx1.sign(priv_key, control->get_chain_id()) != (std::string)tx2.sign(priv_key, control->get_chain_id())); BOOST_REQUIRE_EQUAL( validate(), true ); @@ -981,42 +979,42 @@ BOOST_FIXTURE_TEST_CASE(checktime_hashing_fail, TESTER) { try { //hit deadline exception, but cache the contract BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); #warning TODO validate that the contract was successfully cached //the contract should be cached, now we should get deadline_exception because of calls to checktime() from hashing function BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_REQUIRE_EQUAL( validate(), true ); @@ -1039,7 +1037,7 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { action act({}, tm); trx.actions.push_back(act); - set_transaction_headers(trx); + set_transaction_headers(trx); BOOST_CHECK_EXCEPTION(push_transaction(trx), transaction_exception, [](const fc::exception& e) { return expect_assert_message(e, "transaction must have at least one authorization"); @@ -1231,27 +1229,27 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { // Trigger a tx which in turn sends a deferred tx with payer != receiver // Payer is alice in this case, this tx should fail since we don't have the authorization of alice dtt_action dtt_act1; - dtt_act1.payer = N(alice); + dtt_act1.payer = N(alice).to_uint64_t(); BOOST_CHECK_THROW(CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_tx_with_dtt_action", fc::raw::pack(dtt_act1)), missing_auth_exception); // Send a tx which in turn sends a deferred tx with the deferred tx's receiver != this tx receiver // This will include the authorization of the receiver, and impose any related delay associated with the authority // We set the authorization delay to be 10 sec here, and since the deferred tx delay is set to be 5 sec, so this tx should fail dtt_action dtt_act2; - dtt_act2.deferred_account = N(testapi2); - dtt_act2.permission_name = N(additional); + dtt_act2.deferred_account = N(testapi2).to_uint64_t(); + dtt_act2.permission_name = N(additional).to_uint64_t(); dtt_act2.delay_sec = 5; - auto auth = authority(get_public_key("testapi", name(dtt_act2.permission_name).to_string()), 10); + auto auth = authority(get_public_key(name("testapi"), name(dtt_act2.permission_name).to_string()), 10); auth.accounts.push_back( permission_level_weight{{N(testapi), config::eosio_code_name}, 1} ); - push_action(config::system_account_name, updateauth::get_name(), "testapi", fc::mutable_variant_object() + push_action(config::system_account_name, updateauth::get_name(), name("testapi"), fc::mutable_variant_object() ("account", "testapi") ("permission", name(dtt_act2.permission_name)) ("parent", "active") ("auth", auth) ); - push_action(config::system_account_name, linkauth::get_name(), "testapi", fc::mutable_variant_object() + push_action(config::system_account_name, linkauth::get_name(), name("testapi"), fc::mutable_variant_object() ("account", "testapi") ("code", name(dtt_act2.deferred_account)) ("type", name(dtt_act2.deferred_action)) @@ -1263,11 +1261,12 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_tx_with_dtt_action", fc::raw::pack(dtt_act2)); // If the deferred tx receiver == this tx receiver, the authorization checking would originally be bypassed. - // But not anymore. Now it should subjectively fail because testapi@additional permission is not unilaterally satisfied by testapi@eosio.code. + // But not anymore. With the RESTRICT_ACTION_TO_SELF protocol feature activated, it should now objectively + // fail because testapi@additional permission is not unilaterally satisfied by testapi@eosio.code. dtt_action dtt_act3; - dtt_act3.deferred_account = N(testapi); - dtt_act3.permission_name = N(additional); - push_action(config::system_account_name, linkauth::get_name(), "testapi", fc::mutable_variant_object() + dtt_act3.deferred_account = N(testapi).to_uint64_t(); + dtt_act3.permission_name = N(additional).to_uint64_t(); + push_action(config::system_account_name, linkauth::get_name(), name("testapi"), fc::mutable_variant_object() ("account", "testapi") ("code", name(dtt_act3.deferred_account)) ("type", name(dtt_act3.deferred_action)) diff --git a/unittests/auth_tests.cpp b/unittests/auth_tests.cpp index e54964b87b4..ea0ed49814d 100644 --- a/unittests/auth_tests.cpp +++ b/unittests/auth_tests.cpp @@ -96,272 +96,273 @@ BOOST_FIXTURE_TEST_CASE( delegate_auth, TESTER ) { try { BOOST_AUTO_TEST_CASE(update_auths) { try { TESTER chain; - chain.create_account("alice"); - chain.create_account("bob"); + chain.create_account(name("alice")); + chain.create_account(name("bob")); // Deleting active or owner should fail - BOOST_CHECK_THROW(chain.delete_authority("alice", "active"), action_validate_exception); - BOOST_CHECK_THROW(chain.delete_authority("alice", "owner"), action_validate_exception); + BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("active")), action_validate_exception); + BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("owner")), action_validate_exception); // Change owner permission - const auto new_owner_priv_key = chain.get_private_key("alice", "new_owner"); + const auto new_owner_priv_key = chain.get_private_key(name("alice"), "new_owner"); const auto new_owner_pub_key = new_owner_priv_key.get_public_key(); - chain.set_authority("alice", "owner", authority(new_owner_pub_key), ""); + chain.set_authority(name("alice"), name("owner"), authority(new_owner_pub_key), {}); chain.produce_blocks(); // Ensure the permission is updated permission_object::id_type owner_id; { - auto obj = chain.find(boost::make_tuple("alice", "owner")); + auto obj = chain.find(boost::make_tuple(name("alice"), name("owner"))); BOOST_TEST(obj != nullptr); - BOOST_TEST(obj->owner == "alice"); - BOOST_TEST(obj->name == "owner"); + BOOST_TEST(obj->owner == name("alice")); + BOOST_TEST(obj->name == name("owner")); BOOST_TEST(obj->parent == 0); owner_id = obj->id; auto auth = obj->auth.to_authority(); - BOOST_TEST(auth.threshold == 1); - BOOST_TEST(auth.keys.size() == 1); - BOOST_TEST(auth.accounts.size() == 0); + BOOST_TEST(auth.threshold == 1u); + BOOST_TEST(auth.keys.size() == 1u); + BOOST_TEST(auth.accounts.size() == 0u); BOOST_TEST(auth.keys[0].key == new_owner_pub_key); BOOST_TEST(auth.keys[0].weight == 1); } // Change active permission, remember that the owner key has been changed - const auto new_active_priv_key = chain.get_private_key("alice", "new_active"); + const auto new_active_priv_key = chain.get_private_key(name("alice"), "new_active"); const auto new_active_pub_key = new_active_priv_key.get_public_key(); - chain.set_authority("alice", "active", authority(new_active_pub_key), "owner", - { permission_level{"alice", "active"} }, { chain.get_private_key("alice", "active") }); + chain.set_authority(name("alice"), name("active"), authority(new_active_pub_key), name("owner"), + { permission_level{name("alice"), name("active")} }, { chain.get_private_key(name("alice"), "active") }); chain.produce_blocks(); { - auto obj = chain.find(boost::make_tuple("alice", "active")); + auto obj = chain.find(boost::make_tuple(name("alice"), name("active"))); BOOST_TEST(obj != nullptr); - BOOST_TEST(obj->owner == "alice"); - BOOST_TEST(obj->name == "active"); + BOOST_TEST(obj->owner == name("alice")); + BOOST_TEST(obj->name == name("active")); BOOST_TEST(obj->parent == owner_id); auto auth = obj->auth.to_authority(); - BOOST_TEST(auth.threshold == 1); - BOOST_TEST(auth.keys.size() == 1); - BOOST_TEST(auth.accounts.size() == 0); + BOOST_TEST(auth.threshold == 1u); + BOOST_TEST(auth.keys.size() == 1u); + BOOST_TEST(auth.accounts.size() == 0u); BOOST_TEST(auth.keys[0].key == new_active_pub_key); - BOOST_TEST(auth.keys[0].weight == 1); + BOOST_TEST(auth.keys[0].weight == 1u); } - auto spending_priv_key = chain.get_private_key("alice", "spending"); + auto spending_priv_key = chain.get_private_key(name("alice"), "spending"); auto spending_pub_key = spending_priv_key.get_public_key(); - auto trading_priv_key = chain.get_private_key("alice", "trading"); + auto trading_priv_key = chain.get_private_key(name("alice"), "trading"); auto trading_pub_key = trading_priv_key.get_public_key(); // Bob attempts to create new spending auth for Alice - BOOST_CHECK_THROW( chain.set_authority( "alice", "spending", authority(spending_pub_key), "active", - { permission_level{"bob", "active"} }, { chain.get_private_key("bob", "active") } ), + BOOST_CHECK_THROW( chain.set_authority( name("alice"), name("spending"), authority(spending_pub_key), name("active"), + { permission_level{name("bob"), name("active")} }, + { chain.get_private_key(name("bob"), "active") } ), irrelevant_auth_exception ); // Create new spending auth - chain.set_authority("alice", "spending", authority(spending_pub_key), "active", - { permission_level{"alice", "active"} }, { new_active_priv_key }); + chain.set_authority(name("alice"), name("spending"), authority(spending_pub_key), name("active"), + { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); chain.produce_blocks(); { - auto obj = chain.find(boost::make_tuple("alice", "spending")); + auto obj = chain.find(boost::make_tuple(name("alice"), name("spending"))); BOOST_TEST(obj != nullptr); - BOOST_TEST(obj->owner == "alice"); - BOOST_TEST(obj->name == "spending"); - BOOST_TEST(chain.get(obj->parent).owner == "alice"); - BOOST_TEST(chain.get(obj->parent).name == "active"); + BOOST_TEST(obj->owner == name("alice")); + BOOST_TEST(obj->name == name("spending")); + BOOST_TEST(chain.get(obj->parent).owner == name("alice")); + BOOST_TEST(chain.get(obj->parent).name == name("active")); } // Update spending auth parent to be its own, should fail - BOOST_CHECK_THROW(chain.set_authority("alice", "spending", spending_pub_key, "spending", - { permission_level{"alice", "spending"} }, { spending_priv_key }), action_validate_exception); + BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("spending"), + { permission_level{name("alice"), name("spending")} }, { spending_priv_key }), action_validate_exception); // Update spending auth parent to be owner, should fail - BOOST_CHECK_THROW(chain.set_authority("alice", "spending", spending_pub_key, "owner", - { permission_level{"alice", "spending"} }, { spending_priv_key }), action_validate_exception); + BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("owner"), + { permission_level{name("alice"), name("spending")} }, { spending_priv_key }), action_validate_exception); // Remove spending auth - chain.delete_authority("alice", "spending", { permission_level{"alice", "active"} }, { new_active_priv_key }); + chain.delete_authority(name("alice"), name("spending"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); { - auto obj = chain.find(boost::make_tuple("alice", "spending")); + auto obj = chain.find(boost::make_tuple(name("alice"), name("spending"))); BOOST_TEST(obj == nullptr); } chain.produce_blocks(); // Create new trading auth - chain.set_authority("alice", "trading", trading_pub_key, "active", - { permission_level{"alice", "active"} }, { new_active_priv_key }); + chain.set_authority(name("alice"), name("trading"), trading_pub_key, name("active"), + { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); // Recreate spending auth again, however this time, it's under trading instead of owner - chain.set_authority("alice", "spending", spending_pub_key, "trading", - { permission_level{"alice", "trading"} }, { trading_priv_key }); + chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("trading"), + { permission_level{name("alice"), name("trading")} }, { trading_priv_key }); chain.produce_blocks(); // Verify correctness of trading and spending { - const auto* trading = chain.find(boost::make_tuple("alice", "trading")); - const auto* spending = chain.find(boost::make_tuple("alice", "spending")); + const auto* trading = chain.find(boost::make_tuple(name("alice"), name("trading"))); + const auto* spending = chain.find(boost::make_tuple(name("alice"), name("spending"))); BOOST_TEST(trading != nullptr); BOOST_TEST(spending != nullptr); - BOOST_TEST(trading->owner == "alice"); - BOOST_TEST(spending->owner == "alice"); - BOOST_TEST(trading->name == "trading"); - BOOST_TEST(spending->name == "spending"); + BOOST_TEST(trading->owner == name("alice")); + BOOST_TEST(spending->owner == name("alice")); + BOOST_TEST(trading->name == name("trading")); + BOOST_TEST(spending->name == name("spending")); BOOST_TEST(spending->parent == trading->id); - BOOST_TEST(chain.get(trading->parent).owner == "alice"); - BOOST_TEST(chain.get(trading->parent).name == "active"); + BOOST_TEST(chain.get(trading->parent).owner == name("alice")); + BOOST_TEST(chain.get(trading->parent).name == name("active")); } // Delete trading, should fail since it has children (spending) - BOOST_CHECK_THROW(chain.delete_authority("alice", "trading", - { permission_level{"alice", "active"} }, { new_active_priv_key }), action_validate_exception); + BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("trading"), + { permission_level{name("alice"), name("active")} }, { new_active_priv_key }), action_validate_exception); // Update trading parent to be spending, should fail since changing parent authority is not supported - BOOST_CHECK_THROW(chain.set_authority("alice", "trading", trading_pub_key, "spending", - { permission_level{"alice", "trading"} }, { trading_priv_key }), action_validate_exception); + BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("trading"), trading_pub_key, name("spending"), + { permission_level{name("alice"), name("trading")} }, { trading_priv_key }), action_validate_exception); // Delete spending auth - chain.delete_authority("alice", "spending", { permission_level{"alice", "active"} }, { new_active_priv_key }); - BOOST_TEST((chain.find(boost::make_tuple("alice", "spending"))) == nullptr); + chain.delete_authority(name("alice"), name("spending"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); + BOOST_TEST((chain.find(boost::make_tuple(name("alice"), name("spending")))) == nullptr); // Delete trading auth, now it should succeed since it doesn't have any children anymore - chain.delete_authority("alice", "trading", { permission_level{"alice", "active"} }, { new_active_priv_key }); - BOOST_TEST((chain.find(boost::make_tuple("alice", "trading"))) == nullptr); + chain.delete_authority(name("alice"), name("trading"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); + BOOST_TEST((chain.find(boost::make_tuple(name("alice"), name("trading")))) == nullptr); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(link_auths) { try { TESTER chain; - chain.create_accounts({"alice","bob"}); + chain.create_accounts({name("alice"),name("bob")}); - const auto spending_priv_key = chain.get_private_key("alice", "spending"); + const auto spending_priv_key = chain.get_private_key(name("alice"), "spending"); const auto spending_pub_key = spending_priv_key.get_public_key(); - const auto scud_priv_key = chain.get_private_key("alice", "scud"); + const auto scud_priv_key = chain.get_private_key(name("alice"), "scud"); const auto scud_pub_key = scud_priv_key.get_public_key(); - chain.set_authority("alice", "spending", spending_pub_key, "active"); - chain.set_authority("alice", "scud", scud_pub_key, "spending"); + chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("active")); + chain.set_authority(name("alice"), name("scud"), scud_pub_key, name("spending")); // Send req auth action with alice's spending key, it should fail - BOOST_CHECK_THROW(chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }), irrelevant_auth_exception); + BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }), irrelevant_auth_exception); // Link authority for eosio reqauth action with alice's spending key - chain.link_authority("alice", "eosio", "spending", "reqauth"); + chain.link_authority(name("alice"), name("eosio"), name("spending"), name("reqauth")); // Now, req auth action with alice's spending key should succeed - chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }); chain.produce_block(); // Relink the same auth should fail - BOOST_CHECK_THROW( chain.link_authority("alice", "eosio", "spending", "reqauth"), action_validate_exception); + BOOST_CHECK_THROW( chain.link_authority(name("alice"), name("eosio"), name("spending"), name("reqauth")), action_validate_exception); // Unlink alice with eosio reqauth - chain.unlink_authority("alice", "eosio", "reqauth"); + chain.unlink_authority(name("alice"), name("eosio"), name("reqauth")); // Now, req auth action with alice's spending key should fail - BOOST_CHECK_THROW(chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }), irrelevant_auth_exception); + BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }), irrelevant_auth_exception); chain.produce_block(); // Send req auth action with scud key, it should fail - BOOST_CHECK_THROW(chain.push_reqauth("alice", { permission_level{N(alice), "scud"} }, { scud_priv_key }), irrelevant_auth_exception); + BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{N(alice), name("scud")} }, { scud_priv_key }), irrelevant_auth_exception); // Link authority for any eosio action with alice's scud key - chain.link_authority("alice", "eosio", "scud"); + chain.link_authority(name("alice"), name("eosio"), name("scud")); // Now, req auth action with alice's scud key should succeed - chain.push_reqauth("alice", { permission_level{N(alice), "scud"} }, { scud_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("scud")} }, { scud_priv_key }); // req auth action with alice's spending key should also be fine, since it is the parent of alice's scud key - chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(link_then_update_auth) { try { TESTER chain; - chain.create_account("alice"); + chain.create_account(name("alice")); - const auto first_priv_key = chain.get_private_key("alice", "first"); + const auto first_priv_key = chain.get_private_key(name("alice"), "first"); const auto first_pub_key = first_priv_key.get_public_key(); - const auto second_priv_key = chain.get_private_key("alice", "second"); + const auto second_priv_key = chain.get_private_key(name("alice"), "second"); const auto second_pub_key = second_priv_key.get_public_key(); - chain.set_authority("alice", "first", first_pub_key, "active"); + chain.set_authority(name("alice"), name("first"), first_pub_key, name("active")); - chain.link_authority("alice", "eosio", "first", "reqauth"); - chain.push_reqauth("alice", { permission_level{N(alice), "first"} }, { first_priv_key }); + chain.link_authority(name("alice"), name("eosio"), name("first"), name("reqauth")); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("first")} }, { first_priv_key }); chain.produce_blocks(13); // Wait at least 6 seconds for first push_reqauth transaction to expire. // Update "first" auth public key - chain.set_authority("alice", "first", second_pub_key, "active"); + chain.set_authority(name("alice"), name("first"), second_pub_key, name("active")); // Authority updated, using previous "first" auth should fail on linked auth - BOOST_CHECK_THROW(chain.push_reqauth("alice", { permission_level{N(alice), "first"} }, { first_priv_key }), unsatisfied_authorization); + BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{N(alice), name("first")} }, { first_priv_key }), unsatisfied_authorization); // Using updated authority, should succeed - chain.push_reqauth("alice", { permission_level{N(alice), "first"} }, { second_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("first")} }, { second_priv_key }); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(create_account) { try { TESTER chain; - chain.create_account("joe"); + chain.create_account(name("joe")); chain.produce_block(); // Verify account created properly - const auto& joe_owner_authority = chain.get(boost::make_tuple("joe", "owner")); - BOOST_TEST(joe_owner_authority.auth.threshold == 1); - BOOST_TEST(joe_owner_authority.auth.accounts.size() == 1); - BOOST_TEST(joe_owner_authority.auth.keys.size() == 1); - BOOST_TEST(string(joe_owner_authority.auth.keys[0].key) == string(chain.get_public_key("joe", "owner"))); - BOOST_TEST(joe_owner_authority.auth.keys[0].weight == 1); - - const auto& joe_active_authority = chain.get(boost::make_tuple("joe", "active")); - BOOST_TEST(joe_active_authority.auth.threshold == 1); - BOOST_TEST(joe_active_authority.auth.accounts.size() == 1); - BOOST_TEST(joe_active_authority.auth.keys.size() == 1); - BOOST_TEST(string(joe_active_authority.auth.keys[0].key) == string(chain.get_public_key("joe", "active"))); - BOOST_TEST(joe_active_authority.auth.keys[0].weight == 1); + const auto& joe_owner_authority = chain.get(boost::make_tuple(name("joe"), name("owner"))); + BOOST_TEST(joe_owner_authority.auth.threshold == 1u); + BOOST_TEST(joe_owner_authority.auth.accounts.size() == 1u); + BOOST_TEST(joe_owner_authority.auth.keys.size() == 1u); + BOOST_TEST(string(joe_owner_authority.auth.keys[0].key) == string(chain.get_public_key(name("joe"), "owner"))); + BOOST_TEST(joe_owner_authority.auth.keys[0].weight == 1u); + + const auto& joe_active_authority = chain.get(boost::make_tuple(name("joe"), name("active"))); + BOOST_TEST(joe_active_authority.auth.threshold == 1u); + BOOST_TEST(joe_active_authority.auth.accounts.size() == 1u); + BOOST_TEST(joe_active_authority.auth.keys.size() == 1u); + BOOST_TEST(string(joe_active_authority.auth.keys[0].key) == string(chain.get_public_key(name("joe"), "active"))); + BOOST_TEST(joe_active_authority.auth.keys[0].weight == 1u); // Create duplicate name - BOOST_CHECK_EXCEPTION(chain.create_account("joe"), action_validate_exception, + BOOST_CHECK_EXCEPTION(chain.create_account(name("joe")), action_validate_exception, fc_exception_message_is("Cannot create account named joe, as that name is already taken")); // Creating account with name more than 12 chars - BOOST_CHECK_EXCEPTION(chain.create_account("aaaaaaaaaaaaa"), action_validate_exception, + BOOST_CHECK_EXCEPTION(chain.create_account(name("aaaaaaaaaaaaa")), action_validate_exception, fc_exception_message_is("account names can only be 12 chars long")); // Creating account with eosio. prefix with privileged account - chain.create_account("eosio.test1"); + chain.create_account(name("eosio.test1")); // Creating account with eosio. prefix with non-privileged account, should fail - BOOST_CHECK_EXCEPTION(chain.create_account("eosio.test2", "joe"), action_validate_exception, + BOOST_CHECK_EXCEPTION(chain.create_account(name("eosio.test2"), name("joe")), action_validate_exception, fc_exception_message_is("only privileged accounts can have names that start with 'eosio.'")); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE( any_auth ) { try { TESTER chain; - chain.create_accounts( {"alice","bob"} ); + chain.create_accounts( {name("alice"), name("bob")} ); chain.produce_block(); - const auto spending_priv_key = chain.get_private_key("alice", "spending"); + const auto spending_priv_key = chain.get_private_key(name("alice"), "spending"); const auto spending_pub_key = spending_priv_key.get_public_key(); - const auto bob_spending_priv_key = chain.get_private_key("bob", "spending"); + const auto bob_spending_priv_key = chain.get_private_key(name("bob"), "spending"); const auto bob_spending_pub_key = spending_priv_key.get_public_key(); - chain.set_authority("alice", "spending", spending_pub_key, "active"); - chain.set_authority("bob", "spending", bob_spending_pub_key, "active"); + chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("active")); + chain.set_authority(name("bob"), name("spending"), bob_spending_pub_key, name("active")); /// this should fail because spending is not active which is default for reqauth - BOOST_REQUIRE_THROW( chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }), + BOOST_REQUIRE_THROW( chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }), irrelevant_auth_exception ); chain.produce_block(); //test.push_reqauth( N(alice), { permission_level{N(alice),"spending"} }, { spending_priv_key }); - chain.link_authority( "alice", "eosio", "eosio.any", "reqauth" ); - chain.link_authority( "bob", "eosio", "eosio.any", "reqauth" ); + chain.link_authority( name("alice"), name("eosio"), name("eosio.any"), name("reqauth") ); + chain.link_authority( name("bob"), name("eosio"), name("eosio.any"), name("reqauth") ); /// this should succeed because eosio::reqauth is linked to any permission - chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }); /// this should fail because bob cannot authorize for alice, the permission given must be one-of alices - BOOST_REQUIRE_THROW( chain.push_reqauth("alice", { permission_level{N(bob), "spending"} }, { spending_priv_key }), + BOOST_REQUIRE_THROW( chain.push_reqauth(name("alice"), { permission_level{N(bob), name("spending")} }, { spending_priv_key }), missing_auth_exception ); @@ -395,9 +396,9 @@ try { authority owner_auth = authority( chain.get_public_key( a, "owner" ) ); - vector pls = {{acc1, "active"}}; - pls.push_back({acc1, "owner"}); // same account but different permission names - pls.push_back({acc1a, "owner"}); + vector pls = {{acc1, name("active")}}; + pls.push_back({acc1, name("owner")}); // same account but different permission names + pls.push_back({acc1a, name("owner")}); trx.actions.emplace_back( pls, newaccount{ .creator = acc1, @@ -419,8 +420,8 @@ try { const auto &usage2 = db.get(acc1a); - BOOST_TEST(usage.cpu_usage.average() > 0); - BOOST_TEST(usage.net_usage.average() > 0); + BOOST_TEST(usage.cpu_usage.average() > 0U); + BOOST_TEST(usage.net_usage.average() > 0U); BOOST_REQUIRE_EQUAL(usage.cpu_usage.average(), usage2.cpu_usage.average()); BOOST_REQUIRE_EQUAL(usage.net_usage.average(), usage2.net_usage.average()); chain.produce_block(); @@ -449,7 +450,7 @@ try { authority invalid_auth = authority(threshold, {key_weight{chain.get_public_key( a, "owner" ), 1}}, {permission_level_weight{{creator, config::active_name}, 1}}); vector pls; - pls.push_back({creator, "active"}); + pls.push_back({creator, name("active")}); trx.actions.emplace_back( pls, newaccount{ .creator = creator, diff --git a/unittests/bootseq_tests.cpp b/unittests/bootseq_tests.cpp index ca325f86585..f5fabe1e26b 100644 --- a/unittests/bootseq_tests.cpp +++ b/unittests/bootseq_tests.cpp @@ -276,13 +276,15 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) { votepro( N(whale3), {N(proda), N(prodb), N(prodc), N(prodd), N(prode)} ); // Total Stakes = b1 + whale2 + whale3 stake = (100,000,000 - 1,000) + (20,000,000 - 1,000) + (30,000,000 - 1,000) + vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global), N(global) ); + BOOST_TEST(get_global_state()["total_activated_stake"].as() == 1499999997000); // No producers will be set, since the total activated stake is less than 150,000,000 produce_blocks_for_n_rounds(2); // 2 rounds since new producer schedule is set when the first block of next round is irreversible auto active_schedule = control->head_block_state()->active_schedule; - BOOST_TEST(active_schedule.producers.size() == 1); - BOOST_TEST(active_schedule.producers.front().producer_name == "eosio"); + BOOST_TEST(active_schedule.producers.size() == 1u); + BOOST_TEST(active_schedule.producers.front().producer_name == name("eosio")); // Spend some time so the producer pay pool is filled by the inflation rate produce_min_num_of_blocks_to_spend_time_wo_inactive_prod(fc::seconds(30 * 24 * 3600)); // 30 days @@ -297,27 +299,27 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) { produce_blocks_for_n_rounds(2); // 2 rounds since new producer schedule is set when the first block of next round is irreversible active_schedule = control->head_block_state()->active_schedule; BOOST_REQUIRE(active_schedule.producers.size() == 21); - BOOST_TEST(active_schedule.producers.at(0).producer_name == "proda"); - BOOST_TEST(active_schedule.producers.at(1).producer_name == "prodb"); - BOOST_TEST(active_schedule.producers.at(2).producer_name == "prodc"); - BOOST_TEST(active_schedule.producers.at(3).producer_name == "prodd"); - BOOST_TEST(active_schedule.producers.at(4).producer_name == "prode"); - BOOST_TEST(active_schedule.producers.at(5).producer_name == "prodf"); - BOOST_TEST(active_schedule.producers.at(6).producer_name == "prodg"); - BOOST_TEST(active_schedule.producers.at(7).producer_name == "prodh"); - BOOST_TEST(active_schedule.producers.at(8).producer_name == "prodi"); - BOOST_TEST(active_schedule.producers.at(9).producer_name == "prodj"); - BOOST_TEST(active_schedule.producers.at(10).producer_name == "prodk"); - BOOST_TEST(active_schedule.producers.at(11).producer_name == "prodl"); - BOOST_TEST(active_schedule.producers.at(12).producer_name == "prodm"); - BOOST_TEST(active_schedule.producers.at(13).producer_name == "prodn"); - BOOST_TEST(active_schedule.producers.at(14).producer_name == "prodo"); - BOOST_TEST(active_schedule.producers.at(15).producer_name == "prodp"); - BOOST_TEST(active_schedule.producers.at(16).producer_name == "prodq"); - BOOST_TEST(active_schedule.producers.at(17).producer_name == "prodr"); - BOOST_TEST(active_schedule.producers.at(18).producer_name == "prods"); - BOOST_TEST(active_schedule.producers.at(19).producer_name == "prodt"); - BOOST_TEST(active_schedule.producers.at(20).producer_name == "produ"); + BOOST_TEST(active_schedule.producers.at( 0).producer_name == name("proda")); + BOOST_TEST(active_schedule.producers.at( 1).producer_name == name("prodb")); + BOOST_TEST(active_schedule.producers.at( 2).producer_name == name("prodc")); + BOOST_TEST(active_schedule.producers.at( 3).producer_name == name("prodd")); + BOOST_TEST(active_schedule.producers.at( 4).producer_name == name("prode")); + BOOST_TEST(active_schedule.producers.at( 5).producer_name == name("prodf")); + BOOST_TEST(active_schedule.producers.at( 6).producer_name == name("prodg")); + BOOST_TEST(active_schedule.producers.at( 7).producer_name == name("prodh")); + BOOST_TEST(active_schedule.producers.at( 8).producer_name == name("prodi")); + BOOST_TEST(active_schedule.producers.at( 9).producer_name == name("prodj")); + BOOST_TEST(active_schedule.producers.at(10).producer_name == name("prodk")); + BOOST_TEST(active_schedule.producers.at(11).producer_name == name("prodl")); + BOOST_TEST(active_schedule.producers.at(12).producer_name == name("prodm")); + BOOST_TEST(active_schedule.producers.at(13).producer_name == name("prodn")); + BOOST_TEST(active_schedule.producers.at(14).producer_name == name("prodo")); + BOOST_TEST(active_schedule.producers.at(15).producer_name == name("prodp")); + BOOST_TEST(active_schedule.producers.at(16).producer_name == name("prodq")); + BOOST_TEST(active_schedule.producers.at(17).producer_name == name("prodr")); + BOOST_TEST(active_schedule.producers.at(18).producer_name == name("prods")); + BOOST_TEST(active_schedule.producers.at(19).producer_name == name("prodt")); + BOOST_TEST(active_schedule.producers.at(20).producer_name == name("produ")); // Spend some time so the producer pay pool is filled by the inflation rate produce_min_num_of_blocks_to_spend_time_wo_inactive_prod(fc::seconds(30 * 24 * 3600)); // 30 days diff --git a/unittests/database_gmr_blklst_tests.cpp b/unittests/database_gmr_blklst_tests.cpp index e856de77ea8..9b5e01ef2b5 100644 --- a/unittests/database_gmr_blklst_tests.cpp +++ b/unittests/database_gmr_blklst_tests.cpp @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(set_name_list_test) flat_set nameset(list.begin(), list.end()); // Create an account db.create([](account_object2 &a) { - a.name = "alice"; + a.name = name("alice"); }); @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(set_name_list_test) auto convert_names = [&](const shared_vector& namevec, flat_set& nameset) -> void { for(const auto& a :namevec) { - nameset.insert(uint64_t(a)); + nameset.insert(a); } }; diff --git a/unittests/database_tests.cpp b/unittests/database_tests.cpp index 316ef7a5b24..079330f49c0 100644 --- a/unittests/database_tests.cpp +++ b/unittests/database_tests.cpp @@ -34,18 +34,18 @@ BOOST_AUTO_TEST_SUITE(database_tests) // Create an account db.create([](account_object2 &a) { - a.name = "billy"; + a.name = name("billy"); }); // Make sure we can retrieve that account by name - auto ptr = db.find("billy"); + auto ptr = db.find(name("billy")); BOOST_TEST(ptr != nullptr); // Undo creation of the account ses.undo(); // Make sure we can no longer find the account - ptr = db.find("billy"); + ptr = db.find(name("billy")); BOOST_TEST(ptr == nullptr); } FC_LOG_AND_RETHROW() } diff --git a/unittests/eosio_system_tester.hpp b/unittests/eosio_system_tester.hpp index 9b3fb642c3b..74c64822f41 100644 --- a/unittests/eosio_system_tester.hpp +++ b/unittests/eosio_system_tester.hpp @@ -56,7 +56,7 @@ class eosio_system_tester : public TESTER { create_currency( N(eosio.token), config::system_account_name, core_from_string("10000000000.0000") ); issue(config::system_account_name, core_from_string("1000000000.0000")); - BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance( "eosio" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance( name("eosio") ) ); set_code( config::system_account_name, contracts::eosio_system_wasm() ); set_abi( config::system_account_name, contracts::eosio_system_abi().data() ); @@ -79,7 +79,8 @@ class eosio_system_tester : public TESTER { create_account_with_resources( N(bob111111111), config::system_account_name, core_from_string("0.4500"), false ); create_account_with_resources( N(carol1111111), config::system_account_name, core_from_string("1.0000"), false ); - BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance("eosio") + get_balance("eosio.ramfee") + get_balance("eosio.stake") + get_balance("eosio.ram") ); + BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), + get_balance(name("eosio")) + get_balance(name("eosio.ramfee")) + get_balance(name("eosio.stake")) + get_balance(name("eosio.ram")) ); } @@ -228,7 +229,8 @@ class eosio_system_tester : public TESTER { act.name = name; act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer_max_time ); - return base_tester::push_action( std::move(act), auth ? uint64_t(signer) : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111) ); + return base_tester::push_action( std::move(act), auth ? signer.to_uint64_t() : + signer == N(bob111111111) ? N(alice1111111).to_uint64_t() : N(bob111111111).to_uint64_t() ); } action_result stake( const account_name& from, const account_name& to, const asset& net, const asset& cpu ) { @@ -326,7 +328,7 @@ class eosio_system_tester : public TESTER { } asset get_balance( const account_name& act ) { - vector data = get_row_by_account( N(eosio.token), act, N(accounts), symbol(CORE_SYMBOL).to_symbol_code().value ); + vector data = get_row_by_account( N(eosio.token), act, N(accounts), name(symbol(CORE_SYMBOL).to_symbol_code().value) ); return data.empty() ? asset(0, symbol(CORE_SYMBOL)) : token_abi_ser.binary_to_variant("account", data, abi_serializer_max_time)["balance"].as(); } @@ -381,7 +383,7 @@ class eosio_system_tester : public TESTER { fc::variant get_stats( const string& symbolname ) { auto symb = eosio::chain::symbol::from_string(symbolname); auto symbol_code = symb.to_symbol_code().value; - vector data = get_row_by_account( N(eosio.token), symbol_code, N(stat), symbol_code ); + vector data = get_row_by_account( N(eosio.token), name(symbol_code), N(stat), name(symbol_code) ); return data.empty() ? fc::variant() : token_abi_ser.binary_to_variant( "currency_stats", data, abi_serializer_max_time ); } @@ -405,7 +407,7 @@ class eosio_system_tester : public TESTER { abi_serializer msig_abi_ser; { create_account_with_resources( N(eosio.msig), config::system_account_name ); - BOOST_REQUIRE_EQUAL( success(), buyram( "eosio", "eosio.msig", core_from_string("5000.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), buyram( name("eosio"), name("eosio.msig"), core_from_string("5000.0000") ) ); produce_block(); auto trace = base_tester::push_action(config::system_account_name, N(setpriv), @@ -428,8 +430,8 @@ class eosio_system_tester : public TESTER { vector active_and_vote_producers() { //stake more than 15% of total EOS supply to activate chain - transfer( "eosio", "alice1111111", core_from_string("650000000.0000"), "eosio" ); - BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("300000000.0000"), core_from_string("300000000.0000") ) ); + transfer( name("eosio"), name("alice1111111"), core_from_string("650000000.0000"), name("eosio") ); + BOOST_REQUIRE_EQUAL( success(), stake( name("alice1111111"), name("alice1111111"), core_from_string("300000000.0000"), core_from_string("300000000.0000") ) ); // create accounts {defproducera, defproducerb, ..., defproducerz} and register as producers std::vector producer_names; @@ -461,9 +463,9 @@ class eosio_system_tester : public TESTER { //vote for producers { - transfer( config::system_account_name, "alice1111111", core_from_string("100000000.0000"), config::system_account_name ); - BOOST_REQUIRE_EQUAL(success(), stake( "alice1111111", core_from_string("30000000.0000"), core_from_string("30000000.0000") ) ); - BOOST_REQUIRE_EQUAL(success(), buyram( "alice1111111", "alice1111111", core_from_string("30000000.0000") ) ); + transfer( config::system_account_name, name("alice1111111"), core_from_string("100000000.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL(success(), stake( name("alice1111111"), core_from_string("30000000.0000"), core_from_string("30000000.0000") ) ); + BOOST_REQUIRE_EQUAL(success(), buyram( name("alice1111111"), name("alice1111111"), core_from_string("30000000.0000") ) ); BOOST_REQUIRE_EQUAL(success(), push_action(N(alice1111111), N(voteproducer), mvo() ("voter", "alice1111111") ("proxy", name(0).to_string()) diff --git a/unittests/forked_tests.cpp b/unittests/forked_tests.cpp index b1e5a6c9c6a..ea16c41a1d4 100644 --- a/unittests/forked_tests.cpp +++ b/unittests/forked_tests.cpp @@ -15,14 +15,6 @@ using namespace eosio::chain; using namespace eosio::testing; -private_key_type get_private_key( name keyname, string role ) { - return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); -} - -public_key_type get_public_key( name keyname, string role ){ - return get_private_key( keyname, role ).get_public_key(); -} - void push_blocks( tester& from, tester& to ) { while( to.control->fork_db_head_block_num() < from.control->fork_db_head_block_num() ) { auto fb = from.control->fetch_block_by_number( to.control->fork_db_head_block_num()+1 ); @@ -37,15 +29,11 @@ BOOST_AUTO_TEST_CASE( irrblock ) try { c.produce_blocks(10); auto r = c.create_accounts( {N(dan),N(sam),N(pam),N(scott)} ); auto res = c.set_producers( {N(dan),N(sam),N(pam),N(scott)} ); - vector sch = { {N(dan),get_public_key(N(dan), "active")}, - {N(sam),get_public_key(N(sam), "active")}, - {N(scott),get_public_key(N(scott), "active")}, - {N(pam),get_public_key(N(pam), "active")} - }; + wlog("set producer schedule to [dan,sam,pam]"); c.produce_blocks(50); -} FC_LOG_AND_RETHROW() +} FC_LOG_AND_RETHROW() struct fork_tracker { vector blocks; @@ -145,15 +133,14 @@ BOOST_AUTO_TEST_CASE( fork_with_bad_block ) try { BOOST_AUTO_TEST_CASE( forking ) try { tester c; - c.produce_block(); - c.produce_block(); + while (c.control->head_block_num() < 3) { + c.produce_block(); + } auto r = c.create_accounts( {N(dan),N(sam),N(pam)} ); wdump((fc::json::to_pretty_string(r))); c.produce_block(); auto res = c.set_producers( {N(dan),N(sam),N(pam)} ); - vector sch = { {N(dan),get_public_key(N(dan), "active")}, - {N(sam),get_public_key(N(sam), "active")}, - {N(pam),get_public_key(N(pam), "active")}}; + wdump((fc::json::to_pretty_string(res))); wlog("set producer schedule to [dan,sam,pam]"); c.produce_blocks(30); @@ -170,15 +157,19 @@ BOOST_AUTO_TEST_CASE( forking ) try { ("maximum_supply", core_from_string("10000000.0000")) ); - wdump((fc::json::to_pretty_string(cr))); - cr = c.push_action( N(eosio.token), N(issue), config::system_account_name, mutable_variant_object() + ("to", "eosio" ) + ("quantity", core_from_string("100.0000")) + ("memo", "") + ); + + cr = c.push_action( N(eosio.token), N(transfer), config::system_account_name, mutable_variant_object() + ("from", "eosio") ("to", "dan" ) ("quantity", core_from_string("100.0000")) ("memo", "") ); - wdump((fc::json::to_pretty_string(cr))); tester c2; diff --git a/unittests/misc_tests.cpp b/unittests/misc_tests.cpp index 563c1922e9e..d7b8fe5fd16 100644 --- a/unittests/misc_tests.cpp +++ b/unittests/misc_tests.cpp @@ -30,7 +30,8 @@ namespace eosio using namespace chain; using namespace std; -static constexpr uint64_t name_suffix( uint64_t n ) { +static constexpr uint64_t name_suffix( name nv ) { + uint64_t n = nv.to_uint64_t(); uint32_t remaining_bits_after_last_actual_dot = 0; uint32_t tmp = 0; for( int32_t remaining_bits = 59; remaining_bits >= 4; remaining_bits -= 5 ) { // Note: remaining_bits must remain signed integer @@ -64,7 +65,7 @@ BOOST_AUTO_TEST_SUITE(misc_tests) BOOST_AUTO_TEST_CASE(name_suffix_tests) { - BOOST_CHECK_EQUAL( name{name_suffix(0)}, name{0} ); + BOOST_CHECK_EQUAL( name{name_suffix(name(0))}, name{0} ); BOOST_CHECK_EQUAL( name{name_suffix(N(abcdehijklmn))}, name{N(abcdehijklmn)} ); BOOST_CHECK_EQUAL( name{name_suffix(N(abcdehijklmn1))}, name{N(abcdehijklmn1)} ); BOOST_CHECK_EQUAL( name{name_suffix(N(abc.def))}, name{N(def)} ); @@ -233,9 +234,9 @@ struct permission_visitor { BOOST_AUTO_TEST_CASE(authority_checker) { try { testing::TESTER test; - auto a = test.get_public_key("a", "active"); - auto b = test.get_public_key("b", "active"); - auto c = test.get_public_key("c", "active"); + auto a = test.get_public_key(name("a"), "active"); + auto b = test.get_public_key(name("b"), "active"); + auto c = test.get_public_key(name("c"), "active"); auto GetNullAuthority = [](auto){abort(); return authority();}; @@ -244,31 +245,31 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetNullAuthority, 2, {a, b}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.unused_keys().size() == 0); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().size() == 0u); } { auto checker = make_auth_checker(GetNullAuthority, 2, {a, c}); BOOST_TEST(!checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 0); - BOOST_TEST(checker.unused_keys().size() == 2); + BOOST_TEST(checker.used_keys().size() == 0u); + BOOST_TEST(checker.unused_keys().size() == 2u); } { auto checker = make_auth_checker(GetNullAuthority, 2, {a, b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.used_keys().count(a) == 1); - BOOST_TEST(checker.used_keys().count(b) == 1); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.used_keys().count(a) == 1u); + BOOST_TEST(checker.used_keys().count(b) == 1u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } { auto checker = make_auth_checker(GetNullAuthority, 2, {b, c}); BOOST_TEST(!checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 0); + BOOST_TEST(checker.used_keys().size() == 0u); } A = authority(3, {key_weight{a, 1}, key_weight{b, 1}, key_weight{c, 1}}); @@ -291,7 +292,7 @@ BOOST_AUTO_TEST_CASE(authority_checker) return authority(1, {key_weight{c, 1}}); }; - A = authority(2, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 1}}); + A = authority(2, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{name("hello"), name("world")}, 1}}); { auto checker = make_auth_checker(GetCAuthority, 2, {a}); BOOST_TEST(checker.satisfied(A)); @@ -300,38 +301,38 @@ BOOST_AUTO_TEST_CASE(authority_checker) { auto checker = make_auth_checker(GetCAuthority, 2, {b}); BOOST_TEST(!checker.satisfied(A)); - BOOST_TEST(checker.used_keys().size() == 0); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.unused_keys().count(b) == 1); + BOOST_TEST(checker.used_keys().size() == 0u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().count(b) == 1u); } { auto checker = make_auth_checker(GetCAuthority, 2, {c}); BOOST_TEST(!checker.satisfied(A)); - BOOST_TEST(checker.used_keys().size() == 0); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 0u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } { auto checker = make_auth_checker(GetCAuthority, 2, {b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.unused_keys().size() == 0); - BOOST_TEST(checker.used_keys().count(b) == 1); - BOOST_TEST(checker.used_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().size() == 0u); + BOOST_TEST(checker.used_keys().count(b) == 1u); + BOOST_TEST(checker.used_keys().count(c) == 1u); } { auto checker = make_auth_checker(GetCAuthority, 2, {b, c, a}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 1); - BOOST_TEST(checker.used_keys().count(a) == 1); - BOOST_TEST(checker.unused_keys().size() == 2); - BOOST_TEST(checker.unused_keys().count(b) == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 1u); + BOOST_TEST(checker.used_keys().count(a) == 1u); + BOOST_TEST(checker.unused_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().count(b) == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } - A = authority(3, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 3}}); + A = authority(3, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{name("hello"), name("world")}, 3}}); { auto checker = make_auth_checker(GetCAuthority, 2, {a, b}); BOOST_TEST(checker.satisfied(A)); @@ -341,14 +342,14 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetCAuthority, 2, {a, b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 1); - BOOST_TEST(checker.used_keys().count(c) == 1); - BOOST_TEST(checker.unused_keys().size() == 2); - BOOST_TEST(checker.unused_keys().count(a) == 1); - BOOST_TEST(checker.unused_keys().count(b) == 1); + BOOST_TEST(checker.used_keys().size() == 1u); + BOOST_TEST(checker.used_keys().count(c) == 1u); + BOOST_TEST(checker.unused_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().count(a) == 1u); + BOOST_TEST(checker.unused_keys().count(b) == 1u); } - A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 1}}); + A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{name("hello"), name("world")}, 1}}); BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {a}).satisfied(A)); BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {b}).satisfied(A)); BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {c}).satisfied(A)); @@ -359,12 +360,12 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetCAuthority, 2, {a, b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } - A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 2}}); + A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{name("hello"), name("world")}, 2}}); BOOST_TEST(make_auth_checker(GetCAuthority, 2, {a, b}).satisfied(A)); BOOST_TEST(make_auth_checker(GetCAuthority, 2, {c}).satisfied(A)); BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {a}).satisfied(A)); @@ -373,21 +374,21 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetCAuthority, 2, {a, b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 1); - BOOST_TEST(checker.unused_keys().size() == 2); - BOOST_TEST(checker.used_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().size() == 2u); + BOOST_TEST(checker.used_keys().count(c) == 1u); } - auto d = test.get_public_key("d", "active"); - auto e = test.get_public_key("e", "active"); + auto d = test.get_public_key(name("d"), "active"); + auto e = test.get_public_key(name("e"), "active"); auto GetAuthority = [d, e] (const permission_level& perm) { - if (perm.actor == "top") - return authority(2, {key_weight{d, 1}}, {permission_level_weight{{"bottom", "bottom"}, 1}}); + if (perm.actor == name("top")) + return authority(2, {key_weight{d, 1}}, {permission_level_weight{{name("bottom"), name("bottom")}, 1}}); return authority{1, {{e, 1}}, {}}; }; - A = authority(5, {key_weight{a, 2}, key_weight{b, 2}, key_weight{c, 2}}, {permission_level_weight{{"top", "top"}, 5}}); + A = authority(5, {key_weight{a, 2}, key_weight{b, 2}, key_weight{c, 2}}, {permission_level_weight{{name("top"), name("top")}, 5}}); { auto checker = make_auth_checker(GetAuthority, 2, {d, e}); BOOST_TEST(checker.satisfied(A)); @@ -397,20 +398,20 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetAuthority, 2, {a, b, c, d, e}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.unused_keys().size() == 3); - BOOST_TEST(checker.used_keys().count(d) == 1); - BOOST_TEST(checker.used_keys().count(e) == 1); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().size() == 3u); + BOOST_TEST(checker.used_keys().count(d) == 1u); + BOOST_TEST(checker.used_keys().count(e) == 1u); } { auto checker = make_auth_checker(GetAuthority, 2, {a, b, c, e}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 3); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.used_keys().count(a) == 1); - BOOST_TEST(checker.used_keys().count(b) == 1); - BOOST_TEST(checker.used_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 3u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.used_keys().count(a) == 1u); + BOOST_TEST(checker.used_keys().count(b) == 1u); + BOOST_TEST(checker.used_keys().count(c) == 1u); } BOOST_TEST(make_auth_checker(GetAuthority, 1, {a, b, c}).satisfied(A)); // Fails due to short recursion depth limit @@ -442,50 +443,50 @@ BOOST_AUTO_TEST_CASE(authority_checker) BOOST_TEST(!validate(F)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.unused_keys().count(b) == 1); - BOOST_TEST(checker.unused_keys().count(a) == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.unused_keys().count(b) == 1u); + BOOST_TEST(checker.unused_keys().count(a) == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(checker.satisfied(B)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.unused_keys().count(b) == 0); - BOOST_TEST(checker.unused_keys().count(a) == 0); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.unused_keys().count(b) == 0u); + BOOST_TEST(checker.unused_keys().count(a) == 0u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } { auto A2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"a", "world"}, 1}, - permission_level_weight{{"hello", "world"}, 1}, - permission_level_weight{{"hi", "world"}, 1} + { permission_level_weight{{name("a"), name("world")}, 1}, + permission_level_weight{{name("hello"), name("world")}, 1}, + permission_level_weight{{name("hi"), name("world")}, 1} }); auto B2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - {permission_level_weight{{"hello", "world"}, 1} + {permission_level_weight{{name("hello"), name("world")}, 1} }); auto C2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"hello", "there"}, 1}, - permission_level_weight{{"hello", "world"}, 1} + { permission_level_weight{{name("hello"), name("there")}, 1}, + permission_level_weight{{name("hello"), name("world")}, 1} }); // invalid: duplicate auto D2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"hello", "world"}, 1}, - permission_level_weight{{"hello", "world"}, 2} + { permission_level_weight{{name("hello"), name("world")}, 1}, + permission_level_weight{{name("hello"), name("world")}, 2} }); // invalid: wrong order auto E2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"hello", "world"}, 2}, - permission_level_weight{{"hello", "there"}, 1} + { permission_level_weight{{name("hello"), name("world")}, 2}, + permission_level_weight{{name("hello"), name("there")}, 1} }); // invalid: wrong order auto F2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"hi", "world"}, 2}, - permission_level_weight{{"hello", "world"}, 1} + { permission_level_weight{{name("hi"), name("world")}, 2}, + permission_level_weight{{name("hello"), name("world")}, 1} }); // invalid: insufficient weight auto G2 = authority(7, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"a", "world"}, 1}, - permission_level_weight{{"hello", "world"}, 1}, - permission_level_weight{{"hi", "world"}, 1} + { permission_level_weight{{name("a"), name("world")}, 1}, + permission_level_weight{{name("hello"), name("world")}, 1}, + permission_level_weight{{name("hi"), name("world")}, 1} }); BOOST_TEST(validate(A2)); @@ -530,7 +531,7 @@ BOOST_AUTO_TEST_CASE(alphabetic_sort) vector uwords; for(const auto w: words) { auto n = name(w.c_str()); - uwords.push_back(n.value); + uwords.push_back(n.to_uint64_t()); } std::sort(uwords.begin(), uwords.end(), std::less()); @@ -541,7 +542,7 @@ BOOST_AUTO_TEST_CASE(alphabetic_sort) tmp.push_back(str); } - for(int i = 0; i < words.size(); ++i ) { + for(size_t i = 0; i < words.size(); ++i ) { BOOST_TEST(tmp[i] == words[i]); } @@ -583,7 +584,7 @@ BOOST_AUTO_TEST_CASE(transaction_test) { try { trx.expiration = fc::time_point::now(); trx.validate(); - BOOST_CHECK_EQUAL(0, trx.signatures.size()); + BOOST_CHECK_EQUAL(0u, trx.signatures.size()); ((const signed_transaction &)trx).sign( test.get_private_key( config::system_account_name, "active" ), test.control->get_chain_id()); BOOST_CHECK_EQUAL(0, trx.signatures.size()); trx.sign( test.get_private_key( config::system_account_name, "active" ), test.control->get_chain_id() ); diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index c87708d2685..34b7da32e7f 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -444,7 +444,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo private_key_type get_private_key( name keyname, string role ) { - return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); + return private_key_type::regenerate(fc::sha256::hash(keyname.to_string()+role)); } public_key_type get_public_key( name keyname, string role ){ diff --git a/unittests/ram_tests.cpp b/unittests/ram_tests.cpp index f85d3a41ea4..288422e5229 100644 --- a/unittests/ram_tests.cpp +++ b/unittests/ram_tests.cpp @@ -36,7 +36,7 @@ BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try { create_account_with_resources(N(testram11111),config::system_account_name, init_request_bytes + 40); create_account_with_resources(N(testram22222),config::system_account_name, init_request_bytes + 1190); produce_blocks(10); - BOOST_REQUIRE_EQUAL( success(), stake( "eosio.stake", "testram11111", core_from_string("10.0000"), core_from_string("5.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), stake( name("eosio.stake"), name("testram11111"), core_from_string("10.0000"), core_from_string("5.0000") ) ); produce_blocks(10); for (auto i = 0; i < 10; ++i) { diff --git a/unittests/special_accounts_tests.cpp b/unittests/special_accounts_tests.cpp index 2c4b6d8bc27..ec66c40430c 100644 --- a/unittests/special_accounts_tests.cpp +++ b/unittests/special_accounts_tests.cpp @@ -38,14 +38,14 @@ BOOST_FIXTURE_TEST_CASE(accounts_exists, tester) auto nobody = chain1_db.find(config::null_account_name); BOOST_CHECK(nobody != nullptr); const auto& nobody_active_authority = chain1_db.get(boost::make_tuple(config::null_account_name, config::active_name)); - BOOST_CHECK_EQUAL(nobody_active_authority.auth.threshold, 1); - BOOST_CHECK_EQUAL(nobody_active_authority.auth.accounts.size(), 0); - BOOST_CHECK_EQUAL(nobody_active_authority.auth.keys.size(), 0); + BOOST_CHECK_EQUAL(nobody_active_authority.auth.threshold, 1u); + BOOST_CHECK_EQUAL(nobody_active_authority.auth.accounts.size(), 0u); + BOOST_CHECK_EQUAL(nobody_active_authority.auth.keys.size(), 0u); const auto& nobody_owner_authority = chain1_db.get(boost::make_tuple(config::null_account_name, config::owner_name)); - BOOST_CHECK_EQUAL(nobody_owner_authority.auth.threshold, 1); - BOOST_CHECK_EQUAL(nobody_owner_authority.auth.accounts.size(), 0); - BOOST_CHECK_EQUAL(nobody_owner_authority.auth.keys.size(), 0); + BOOST_CHECK_EQUAL(nobody_owner_authority.auth.threshold, 1u); + BOOST_CHECK_EQUAL(nobody_owner_authority.auth.accounts.size(), 0u); + BOOST_CHECK_EQUAL(nobody_owner_authority.auth.keys.size(), 0u); auto producers = chain1_db.find(config::producers_account_name); BOOST_CHECK(producers != nullptr); @@ -56,7 +56,7 @@ BOOST_FIXTURE_TEST_CASE(accounts_exists, tester) auto expected_threshold = (active_producers.producers.size() * 2)/3 + 1; BOOST_CHECK_EQUAL(producers_active_authority.auth.threshold, expected_threshold); BOOST_CHECK_EQUAL(producers_active_authority.auth.accounts.size(), active_producers.producers.size()); - BOOST_CHECK_EQUAL(producers_active_authority.auth.keys.size(), 0); + BOOST_CHECK_EQUAL(producers_active_authority.auth.keys.size(), 0u); std::vector active_auth; for(auto& apw : producers_active_authority.auth.accounts) { @@ -64,10 +64,10 @@ BOOST_FIXTURE_TEST_CASE(accounts_exists, tester) } std::vector diff; - for (int i = 0; i < std::max(active_auth.size(), active_producers.producers.size()); ++i) { + for (size_t i = 0; i < std::max(active_auth.size(), active_producers.producers.size()); ++i) { account_name n1 = i < active_auth.size() ? active_auth[i] : (account_name)0; account_name n2 = i < active_producers.producers.size() ? active_producers.producers[i].producer_name : (account_name)0; - if (n1 != n2) diff.push_back((uint64_t)n2 - (uint64_t)n1); + if (n1 != n2) diff.push_back(name(n2.to_uint64_t() - n1.to_uint64_t())); } BOOST_CHECK_EQUAL(diff.size(), 0); diff --git a/unittests/wasm_tests.cpp b/unittests/wasm_tests.cpp index 1e3d31b24c9..ff0cb91b674 100644 --- a/unittests/wasm_tests.cpp +++ b/unittests/wasm_tests.cpp @@ -90,11 +90,11 @@ BOOST_FIXTURE_TEST_CASE( basic_test, TESTER ) try { trx.sign( get_private_key( N(asserter), "active" ), control->get_chain_id() ); auto result = push_transaction( trx ); BOOST_CHECK_EQUAL(result->receipt->status, transaction_receipt::executed); - BOOST_CHECK_EQUAL(result->action_traces.size(), 1); - BOOST_CHECK_EQUAL(result->action_traces.at(0).receipt.receiver.to_string(), name(N(asserter)).to_string() ); + BOOST_CHECK_EQUAL(result->action_traces.size(), 1u); + BOOST_CHECK_EQUAL(result->action_traces.at(0).receiver.to_string(), name(N(asserter)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.account.to_string(), name(N(asserter)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.name.to_string(), name(N(procassert)).to_string() ); - BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.size(), 1 ); + BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.size(), 1u ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.at(0).actor.to_string(), name(N(asserter)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.at(0).permission.to_string(), name(config::active_name).to_string() ); no_assert_id = trx.id(); @@ -382,23 +382,23 @@ BOOST_FIXTURE_TEST_CASE( f32_f64_overflow_tests, tester ) try { int count = 0; auto check = [&](const char *wast_template, const char *op, const char *param) -> bool { count+=16; - create_accounts( {N(f_tests)+count} ); + create_accounts( {name(N(f_tests).to_uint64_t()+count)} ); produce_blocks(1); std::vector wast; wast.resize(strlen(wast_template) + 128); sprintf(&(wast[0]), wast_template, op, param); - set_code(N(f_tests)+count, &(wast[0])); + set_code(name(N(f_tests).to_uint64_t()+count), &(wast[0])); produce_blocks(10); signed_transaction trx; action act; - act.account = N(f_tests)+count; + act.account = name(N(f_tests).to_uint64_t()+count); act.name = N(); - act.authorization = vector{{N(f_tests)+count,config::active_name}}; + act.authorization = vector{{name(N(f_tests).to_uint64_t()+count),config::active_name}}; trx.actions.push_back(act); set_transaction_headers(trx); - trx.sign(get_private_key( N(f_tests)+count, "active" ), control->get_chain_id()); + trx.sign(get_private_key( name(N(f_tests).to_uint64_t()+count), "active" ), control->get_chain_id()); try { push_transaction(trx); @@ -624,7 +624,7 @@ BOOST_FIXTURE_TEST_CASE( check_global_reset, TESTER ) try { { action act; act.account = N(globalreset); - act.name = 1ULL; + act.name = name(1ULL); act.authorization = vector{{N(globalreset),config::active_name}}; trx.actions.push_back(act); } @@ -1103,7 +1103,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 555ULL<<32 | 0ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(555ULL<<32 | 0ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1117,7 +1117,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 555ULL<<32 | 1022ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(555ULL<<32 | 1022ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1131,7 +1131,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 7777ULL<<32 | 1023ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(7777ULL<<32 | 1023ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1145,7 +1145,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 7778ULL<<32 | 1023ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(7778ULL<<32 | 1023ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1161,7 +1161,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 133ULL<<32 | 5ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(133ULL<<32 | 5ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1177,7 +1177,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = eosio::chain::wasm_constraints::maximum_table_elements+54334; + act.name = name(eosio::chain::wasm_constraints::maximum_table_elements+54334); act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1197,7 +1197,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 555ULL<<32 | 1022ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(555ULL<<32 | 1022ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1210,7 +1210,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 7777ULL<<32 | 1023ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(7777ULL<<32 | 1023ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1224,7 +1224,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 888ULL; + act.name = name(888ULL); act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); diff --git a/unittests/whitelist_blacklist_tests.cpp b/unittests/whitelist_blacklist_tests.cpp index d2734681f60..efd2bf50b1d 100644 --- a/unittests/whitelist_blacklist_tests.cpp +++ b/unittests/whitelist_blacklist_tests.cpp @@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { tester1.chain->set_abi( N(charlie), contracts::deferred_test_abi().data() ); tester1.chain->produce_blocks(); - auto auth = authority(eosio::testing::base_tester::get_public_key("alice", "active")); + auto auth = authority(eosio::testing::base_tester::get_public_key(name("alice"), "active")); auth.accounts.push_back( permission_level_weight{{N(alice), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(alice), mvo() @@ -463,7 +463,7 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { ( "auth", auth ) ); - auth = authority(eosio::testing::base_tester::get_public_key("bob", "active")); + auth = authority(eosio::testing::base_tester::get_public_key(name("bob"), "active")); auth.accounts.push_back( permission_level_weight{{N(alice), config::eosio_code_name}, 1} ); auth.accounts.push_back( permission_level_weight{{N(bob), config::eosio_code_name}, 1} ); @@ -474,7 +474,7 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { ( "auth", auth ) ); - auth = authority(eosio::testing::base_tester::get_public_key("charlie", "active")); + auth = authority(eosio::testing::base_tester::get_public_key(name("charlie"), "active")); auth.accounts.push_back( permission_level_weight{{N(charlie), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(charlie), mvo() @@ -527,7 +527,7 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { auto num_deferred = tester1.chain->control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0, num_deferred); + BOOST_REQUIRE_EQUAL(0u, num_deferred); // Schedule a deferred transaction authorized by charlie@active tester1.chain->push_action( N(charlie), N(defercall), N(alice), mvo() @@ -538,14 +538,14 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { ); num_deferred = tester1.chain->control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1, num_deferred); + BOOST_REQUIRE_EQUAL(1u, num_deferred); // Do not allow that deferred transaction to retire yet tester1.chain->finish_block(); tester1.chain->produce_blocks(2, true); // Produce 2 empty blocks (other than onblock of course). num_deferred = tester1.chain->control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1, num_deferred); + BOOST_REQUIRE_EQUAL(1u, num_deferred); c1.disconnect(); @@ -596,7 +596,7 @@ BOOST_AUTO_TEST_CASE( blacklist_sender_bypass ) { try { tester1.chain->set_abi( N(charlie), contracts::deferred_test_abi().data() ); tester1.chain->produce_blocks(); - auto auth = authority(eosio::testing::base_tester::get_public_key("alice", "active")); + auto auth = authority(eosio::testing::base_tester::get_public_key(name("alice"), "active")); auth.accounts.push_back( permission_level_weight{{N(alice), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(alice), mvo() @@ -606,7 +606,7 @@ BOOST_AUTO_TEST_CASE( blacklist_sender_bypass ) { try { ( "auth", auth ) ); - auth = authority(eosio::testing::base_tester::get_public_key("bob", "active")); + auth = authority(eosio::testing::base_tester::get_public_key(name("bob"), "active")); auth.accounts.push_back( permission_level_weight{{N(bob), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(bob), mvo() @@ -616,7 +616,7 @@ BOOST_AUTO_TEST_CASE( blacklist_sender_bypass ) { try { ( "auth", auth ) ); - auth = authority(eosio::testing::base_tester::get_public_key("charlie", "active")); + auth = authority(eosio::testing::base_tester::get_public_key(name("charlie"), "active")); auth.accounts.push_back( permission_level_weight{{N(charlie), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(charlie), mvo() From 07e60de2e9982e6c6dc2a092b6c622984eadced0 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 13 May 2020 16:00:01 +0800 Subject: [PATCH 05/25] fix a potential crash in fetching lib. --- libraries/chain/controller.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index dfe210a5f90..d003a3557a8 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1758,20 +1758,15 @@ struct controller_impl { if (!pbft_enabled) return; if ( pending_pbft_lib ) { - //this is a temp solution for getting current lib, should not use anywhere else; - auto current_lib = fork_db.get_block_in_current_chain_by_num(head->bft_irreversible_blocknum)->id; + auto current_lib_num = std::max(std::max(head->bft_irreversible_blocknum, head->dpos_irreversible_blocknum), snapshot_head_block); fork_db.set_bft_irreversible(*pending_pbft_lib); if (!replaying) { - auto libs_to_be_emitted = vector{}; + // emit lib signal to a separate channel, plugins should connect to this channel in order to process libs asap. auto b = fork_db.get_block(*pending_pbft_lib); - while (b->id != current_lib) { - libs_to_be_emitted.emplace_back(b); + while (b && b->block_num > current_lib_num) { + emit( self.new_irreversible_block, b ); b = fork_db.get_block(b->prev()); } - while (!libs_to_be_emitted.empty()) { - emit( self.new_irreversible_block, libs_to_be_emitted.back() ); - libs_to_be_emitted.pop_back(); - } } pending_pbft_lib.reset(); From e7056d2d8913a1013007fc1dc6644ce1067958bd Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 13 May 2020 16:17:15 +0800 Subject: [PATCH 06/25] emit lib in ascending order. --- libraries/chain/controller.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index d003a3557a8..a2a86f16bfb 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1761,12 +1761,18 @@ struct controller_impl { auto current_lib_num = std::max(std::max(head->bft_irreversible_blocknum, head->dpos_irreversible_blocknum), snapshot_head_block); fork_db.set_bft_irreversible(*pending_pbft_lib); if (!replaying) { - // emit lib signal to a separate channel, plugins should connect to this channel in order to process libs asap. + // emit lib signals to a separate channel, plugins should connect to this channel in order to process libs asap. + auto libs_to_be_emitted = vector{}; auto b = fork_db.get_block(*pending_pbft_lib); while (b && b->block_num > current_lib_num) { - emit( self.new_irreversible_block, b ); + libs_to_be_emitted.emplace_back(b); b = fork_db.get_block(b->prev()); } + while (!libs_to_be_emitted.empty()) { + // emit all libs in ascending order. + emit( self.new_irreversible_block, libs_to_be_emitted.back() ); + libs_to_be_emitted.pop_back(); + } } pending_pbft_lib.reset(); From 9e01179c389fc39d3c0ff7d55a0329ea98c4aa68 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 13 May 2020 16:00:01 +0800 Subject: [PATCH 07/25] fix a potential crash in fetching lib. --- libraries/chain/controller.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index e6d8a636952..5e53d4b49b7 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1758,20 +1758,15 @@ struct controller_impl { if (!pbft_enabled) return; if ( pending_pbft_lib ) { - //this is a temp solution for getting current lib, should not use anywhere else; - auto current_lib = fork_db.get_block_in_current_chain_by_num(head->bft_irreversible_blocknum)->id; + auto current_lib_num = std::max(std::max(head->bft_irreversible_blocknum, head->dpos_irreversible_blocknum), snapshot_head_block); fork_db.set_bft_irreversible(*pending_pbft_lib); if (!replaying) { - auto libs_to_be_emitted = vector{}; + // emit lib signal to a separate channel, plugins should connect to this channel in order to process libs asap. auto b = fork_db.get_block(*pending_pbft_lib); - while (b->id != current_lib) { - libs_to_be_emitted.emplace_back(b); + while (b && b->block_num > current_lib_num) { + emit( self.new_irreversible_block, b ); b = fork_db.get_block(b->prev()); } - while (!libs_to_be_emitted.empty()) { - emit( self.new_irreversible_block, libs_to_be_emitted.back() ); - libs_to_be_emitted.pop_back(); - } } pending_pbft_lib.reset(); From 483b9eafe2d84c5f57c12a571196802112e263f8 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 13 May 2020 16:17:15 +0800 Subject: [PATCH 08/25] emit lib in ascending order. --- libraries/chain/controller.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 5e53d4b49b7..414a8487ab3 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1761,12 +1761,18 @@ struct controller_impl { auto current_lib_num = std::max(std::max(head->bft_irreversible_blocknum, head->dpos_irreversible_blocknum), snapshot_head_block); fork_db.set_bft_irreversible(*pending_pbft_lib); if (!replaying) { - // emit lib signal to a separate channel, plugins should connect to this channel in order to process libs asap. + // emit lib signals to a separate channel, plugins should connect to this channel in order to process libs asap. + auto libs_to_be_emitted = vector{}; auto b = fork_db.get_block(*pending_pbft_lib); while (b && b->block_num > current_lib_num) { - emit( self.new_irreversible_block, b ); + libs_to_be_emitted.emplace_back(b); b = fork_db.get_block(b->prev()); } + while (!libs_to_be_emitted.empty()) { + // emit all libs in ascending order. + emit( self.new_irreversible_block, libs_to_be_emitted.back() ); + libs_to_be_emitted.pop_back(); + } } pending_pbft_lib.reset(); From 6f51cc165df02a7d30fa123ac75edf7f458a2e94 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Tue, 19 May 2020 17:04:19 +0800 Subject: [PATCH 09/25] Change abi-serializer-max-time-us to abi-serializer-max-time-ms --- plugins/chain_plugin/chain_plugin.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 78228a960c6..20478af10e9 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -263,7 +263,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip EOS_ASSERT(false, plugin_exception, ""); } #endif - }), "Override default WASM runtime") ("abi-serializer-max-time-us", bpo::value()->default_value(config::default_abi_serializer_max_time_us), + }), "Override default WASM runtime") + ("abi-serializer-max-time-ms", bpo::value()->default_value(config::default_abi_serializer_max_time_us / 1000), "Override default maximum ABI serialization time allowed in ms") ("chain-state-db-size-mb", bpo::value()->default_value(config::default_state_size / (1024 * 1024)), "Maximum size (in MiB) of the chain state database") ("chain-state-db-guard-size-mb", bpo::value()->default_value(config::default_state_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the chain state database drops below this size (in MiB).") @@ -520,8 +521,8 @@ void chain_plugin::plugin_initialize(const variables_map& options) { if( options.count( "wasm-runtime" )) my->wasm_runtime = options.at( "wasm-runtime" ).as(); - if(options.count("abi-serializer-max-time-us")) - my->abi_serializer_max_time_us = fc::microseconds(options.at("abi-serializer-max-time-us").as() * 1000); + if(options.count("abi-serializer-max-time-ms")) + my->abi_serializer_max_time_us = fc::microseconds(options.at("abi-serializer-max-time-ms").as() * 1000); my->chain_config->blocks_dir = my->blocks_dir; my->chain_config->state_dir = app().data_dir() / config::default_state_dir_name; From 931235f2bf9faf18d0106fdcaa1f07a0aaa1b461 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Wed, 20 May 2020 11:25:42 +0800 Subject: [PATCH 10/25] Fix: TODO --- libraries/chain/apply_context.cpp | 4 +- libraries/chain/controller.cpp | 10 ++ .../include/eosio/chain/apply_context.hpp | 1 + .../chain/include/eosio/chain/controller.hpp | 1 + .../chain/include/eosio/chain/exceptions.hpp | 50 ++++++- libraries/chain/wasm_interface.cpp | 123 +++++++++--------- plugins/chain_plugin/chain_plugin.cpp | 28 ++-- plugins/notify_plugin/notify_plugin.cpp | 5 - .../state_history_serialization.hpp | 26 ++-- 9 files changed, 151 insertions(+), 97 deletions(-) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 3aa50c100e4..679e4149032 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -56,6 +56,8 @@ void apply_context::exec_one() action_receipt r; r.receiver = receiver; r.act_digest = digest_type::hash(*act); + const auto& p = control.get_dynamic_global_properties(); + global_action_sequence = p.global_action_sequence + 1; const auto& cfg = control.get_global_properties().configuration; const account_metadata_object* receiver_account = nullptr; @@ -91,7 +93,7 @@ void apply_context::exec_one() } catch( fc::exception& e ) { action_trace& trace = trx_context.get_action_trace( action_ordinal ); /// TODO -// trace.error_code = controller::convert_exception_to_error_code( e ); + trace.error_code = controller::convert_exception_to_error_code( e ); trace.except = e; finalize_trace( trace, start ); throw; diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 414a8487ab3..7bf3cd91697 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2866,4 +2866,14 @@ vm::wasm_allocator& controller::get_wasm_allocator() { } #endif +fc::optional controller::convert_exception_to_error_code( const fc::exception& e ) { + const chain_exception* e_ptr = dynamic_cast( &e ); + + if( e_ptr == nullptr ) return {}; + + if( !e_ptr->error_code ) return static_cast(system_error_code::generic_system_error); + + return e_ptr->error_code; +} + } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index c9cdb527bae..3366727be9e 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -563,6 +563,7 @@ class apply_context { controller& control; chainbase::database& db; ///< database where state is stored transaction_context& trx_context; ///< transaction context in which the action is running + uint64_t global_action_sequence = 0; private: const action* act = nullptr; ///< action being applied diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index bcc416fb242..241d1ddca2d 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -303,6 +303,7 @@ namespace eosio { namespace chain { #if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED) vm::wasm_allocator& get_wasm_allocator(); #endif + static fc::optional convert_exception_to_error_code( const fc::exception& e ); signal pre_accepted_block; signal accepted_block_header; diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 68d3d93b156..46fae198034 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -68,14 +68,52 @@ { throw( effect_type( e.what(), e.get_log() ) ); } +#define FC_DECLARE_DERIVED_EXCEPTION_WITH_ERROR_CODE( TYPE, BASE, CODE, WHAT ) \ + class TYPE : public BASE \ + { \ + public: \ + enum code_enum { \ + code_value = CODE, \ + }; \ + explicit TYPE( int64_t code, const std::string& name_value, const std::string& what_value ) \ + :BASE( code, name_value, what_value ){} \ + explicit TYPE( fc::log_message&& m, int64_t code, const std::string& name_value, const std::string& what_value ) \ + :BASE( std::move(m), code, name_value, what_value ){} \ + explicit TYPE( fc::log_messages&& m, int64_t code, const std::string& name_value, const std::string& what_value )\ + :BASE( std::move(m), code, name_value, what_value ){}\ + explicit TYPE( const fc::log_messages& m, int64_t code, const std::string& name_value, const std::string& what_value )\ + :BASE( m, code, name_value, what_value ){}\ + TYPE( const std::string& what_value, const fc::log_messages& m ) \ + :BASE( m, CODE, BOOST_PP_STRINGIZE(TYPE), what_value ){} \ + TYPE( fc::log_message&& m ) \ + :BASE( fc::move(m), CODE, BOOST_PP_STRINGIZE(TYPE), WHAT ){}\ + TYPE( fc::log_messages msgs ) \ + :BASE( fc::move( msgs ), CODE, BOOST_PP_STRINGIZE(TYPE), WHAT ) {} \ + TYPE( const TYPE& c ) \ + :BASE(c),error_code(c.error_code) {} \ + TYPE( const BASE& c ) \ + :BASE(c){} \ + TYPE():BASE(CODE, BOOST_PP_STRINGIZE(TYPE), WHAT){}\ + \ + virtual std::shared_ptr dynamic_copy_exception()const\ + { return std::make_shared( *this ); } \ + virtual NO_RETURN void dynamic_rethrow_exception()const \ + { if( code() == CODE ) throw *this;\ + else fc::exception::dynamic_rethrow_exception(); \ + } \ + fc::optional error_code; \ + }; + namespace eosio { namespace chain { - enum class system_error_code : uint64_t { - generic_system_error = 10000000000000000000ULL, - contract_restricted_error_code, //< contract used an error code reserved for system usage - }; - FC_DECLARE_EXCEPTION( chain_exception, - 3000000, "blockchain exception" ) + enum class system_error_code : uint64_t { + generic_system_error = 10000000000000000000ULL, + contract_restricted_error_code, //< contract used an error code reserved for system usage + }; + + + FC_DECLARE_DERIVED_EXCEPTION_WITH_ERROR_CODE( chain_exception, fc::exception, + 3000000, "blockchain exception" ) /** * chain_exception * |- chain_type_exception diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 2ebd2abc503..2f36c66741a 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -1466,7 +1466,7 @@ class context_free_transaction_api : public context_aware_api { /// TODO void get_action_sequence(uint64_t& seq){ -// seq = context.global_action_sequence; + seq = context.global_action_sequence; } bool has_contract(account_name name){ @@ -1779,70 +1779,69 @@ class action_seed_api : public context_aware_api { : context_aware_api(ctx) {} int bpsig_action_time_seed(array_ptr sig, uint32_t siglen) { -// auto data = action_timestamp(); -// fc::sha256::encoder encoder; -// encoder.write(reinterpret_cast(data.data()), data.size()* sizeof(uint32_t)); -// auto digest = encoder.result(); -// optional signature; -// auto block_state = context.control.pending_block_state(); -// for (auto& extension: block_state->block->block_extensions) { -// if (extension.first != static_cast(block_extension_type::bpsig_action_time_seed)) continue; -// EOS_ASSERT(extension.second.size() > 8, transaction_exception, "invalid producer signature in block extensions"); -// uint64_t* act_parts = reinterpret_cast(extension.second.data()); -// /// TODO -//// if ( act_parts[0] != context.global_action_sequence) continue; -// -// auto sig_data = extension.second.data() + 8; -// auto sig_size = extension.second.size() - 8; -// signature.emplace(); -// datastream ds(sig_data, sig_size); -// fc::raw::unpack(ds, *signature); -// auto check = fc::crypto::public_key(*signature, digest, false); -// EOS_ASSERT( check == block_state->block_signing_key, transaction_exception, "wrong expected key different than recovered key" ); -// break; -// } -// bool sign = false; -// if (context.control.is_producing_block() && !signature) { -// auto signer = context.control.pending_producer_signer(); -// if (signer) { -// // Producer is producing this block -// signature = signer(digest); -// sign = true; -// } else { -// // Non-producer is speculating this block, so skips the signing -// // TODO: speculating result will be different from producing result -// signature.emplace(); -// } -// } -// EOS_ASSERT(!!signature, transaction_exception, "empty sig action seed"); -// auto& s = *signature; -// auto sig_size = fc::raw::pack_size(s); -// if (siglen == 0) return sig_size; -// if (sig_size <= siglen) { -// datastream ds(sig, sig_size); -// fc::raw::pack(ds, s); -// if (sign) { -// block_state->block->block_extensions.emplace_back(); -//// char* act_parts = reinterpret_cast(&context.global_action_sequence); -// auto &extension = block_state->block->block_extensions.back(); -// extension.first = static_cast(block_extension_type::bpsig_action_time_seed); -// extension.second.resize(8 + sig_size); -//// std::copy(act_parts, act_parts + 8, extension.second.data()); -//// std::copy((char*)sig, (char*)sig + sig_size, extension.second.data() + 8); -// } -// return sig_size; -// } + auto data = action_timestamp(); + fc::sha256::encoder encoder; + encoder.write(reinterpret_cast(data.data()), data.size()* sizeof(uint32_t)); + auto digest = encoder.result(); + optional signature; + auto block_state = context.control.pending_block_state(); + for (auto& extension: block_state->block->block_extensions) { + if (extension.first != static_cast(block_extension_type::bpsig_action_time_seed)) continue; + EOS_ASSERT(extension.second.size() > 8, transaction_exception, "invalid producer signature in block extensions"); + uint64_t* act_parts = reinterpret_cast(extension.second.data()); + if ( act_parts[0] != context.global_action_sequence) continue; + + auto sig_data = extension.second.data() + 8; + auto sig_size = extension.second.size() - 8; + signature.emplace(); + datastream ds(sig_data, sig_size); + fc::raw::unpack(ds, *signature); + auto check = fc::crypto::public_key(*signature, digest, false); + EOS_ASSERT( check == block_state->block_signing_key, transaction_exception, "wrong expected key different than recovered key" ); + break; + } + bool sign = false; + if (context.control.is_producing_block() && !signature) { + auto signer = context.control.pending_producer_signer(); + if (signer) { + // Producer is producing this block + signature = signer(digest); + sign = true; + } else { + // Non-producer is speculating this block, so skips the signing + // TODO: speculating result will be different from producing result + signature.emplace(); + } + } + EOS_ASSERT(!!signature, transaction_exception, "empty sig action seed"); + auto& s = *signature; + auto sig_size = fc::raw::pack_size(s); + if (siglen == 0) return sig_size; + if (sig_size <= siglen) { + datastream ds(sig, sig_size); + fc::raw::pack(ds, s); + if (sign) { + block_state->block->block_extensions.emplace_back(); + char* act_parts = reinterpret_cast(&context.global_action_sequence); + auto &extension = block_state->block->block_extensions.back(); + extension.first = static_cast(block_extension_type::bpsig_action_time_seed); + extension.second.resize(8 + sig_size); + std::copy(act_parts, act_parts + 8, extension.second.data()); + std::copy((char*)sig, (char*)sig + sig_size, extension.second.data() + 8); + } + return sig_size; + } return 0; } private: -// vector action_timestamp() { -// auto current = context.control.pending_block_time().time_since_epoch().count(); -// current -= current % (config::block_interval_us); -// -// uint32_t* current_halves = reinterpret_cast(¤t); -// uint32_t* act_parts = reinterpret_cast(&context.global_action_sequence); -// return vector{act_parts[0],act_parts[1], current_halves[0], current_halves[1]}; -// } + vector action_timestamp() { + auto current = context.control.pending_block_time().time_since_epoch().count(); + current -= current % (config::block_interval_us); + + uint32_t* current_halves = reinterpret_cast(¤t); + uint32_t* act_parts = reinterpret_cast(&context.global_action_sequence); + return vector{act_parts[0],act_parts[1], current_halves[0], current_halves[1]}; + } }; REGISTER_INTRINSICS(action_seed_api, diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 20478af10e9..a97f21e0cca 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2042,21 +2042,19 @@ read_only::get_account_results read_only::get_account( const get_account_params& abi_def abi_personal; if( abi_serializer::to_abi(personal_account.abi, abi_personal) ) { abi_serializer abis_personal( abi_personal, abi_serializer_max_time ); - /// TODO -// const auto* t_id = d.find(boost::make_tuple( N(personal.bos), params.account_name.to_uint64_t(), N(personaldata) )); -// const auto *t_id = nullptr_t; -// if (t_id != nullptr) { -// const auto &idx = d.get_index(); -// -// name key_name{"homepage"}; -// auto it = idx.find(boost::make_tuple( t_id->id, key_name.to_uint64_t())); -// if ( it != idx.end() ) { -// vector data; -// copy_inline_row(*it, data); -// variant raw_data= abis_personal.binary_to_variant( "personal", data, abi_serializer_max_time, shorten_abi_errors ); -// result.homepage=raw_data["value"].as_string(); -// } -// } + const auto* t_id = d.find(boost::make_tuple( N(personal.bos), params.account_name, N(personaldata) )); + if (t_id != nullptr) { + const auto &idx = d.get_index(); + + name key_name{"homepage"}; + auto it = idx.find(boost::make_tuple( t_id->id, key_name.to_uint64_t())); + if ( it != idx.end() ) { + vector data; + copy_inline_row(*it, data); + variant raw_data= abis_personal.binary_to_variant( "personal", data, abi_serializer_max_time, shorten_abi_errors ); + result.homepage=raw_data["value"].as_string(); + } + } } } return result; diff --git a/plugins/notify_plugin/notify_plugin.cpp b/plugins/notify_plugin/notify_plugin.cpp index 0684f39a009..8fec2a0f133 100644 --- a/plugins/notify_plugin/notify_plugin.cpp +++ b/plugins/notify_plugin/notify_plugin.cpp @@ -168,11 +168,6 @@ action_seq_type notify_plugin_impl::on_action_trace(const action_trace &act, con } act_s++; - /// TODO -// for (const auto &iline : act.inline_traces) -// { -// act_s = on_action_trace(iline, tx_id, act_s); -// } return act_s; } diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp index 386b520780d..a599a4eef10 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -288,13 +288,29 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.producer_name.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.block_signing_key)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.version)); + history_serialize_container(ds, obj.db, + as_type>(obj.obj.producers)); + return ds; +} + template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(1)); fc::raw::pack(ds, as_type>(obj.obj.proposed_schedule_block_num)); -// fc::raw::pack(ds, make_history_serial_wrapper( -// obj.db, as_type(obj.obj.proposed_schedule))); + fc::raw::pack(ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.proposed_schedule))); fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.configuration))); return ds; @@ -327,12 +343,6 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper -//datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { -// fc::raw::pack(ds, as_type(obj.obj.key)); -// fc::raw::pack(ds, as_type(obj.obj.weight)); -// return ds; -//} template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { From e757b8a8e7b2ee8aaa8a55252ec59727ad284f57 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Wed, 20 May 2020 12:44:17 +0800 Subject: [PATCH 11/25] Fix: mongodb plugin --- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 32 ++++++++------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index bf5be74dc4d..3e0d50b8077 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -60,9 +60,9 @@ struct filter_entry { // receiver action actor bool match( const name& rr, const name& an, const name& ar ) const { - return (receiver.value == 0 || receiver == rr) && - (action.value == 0 || action == an) && - (actor.value == 0 || actor == ar); + return (receiver.to_uint64_t() == 0 || receiver == rr) && + (action.to_uint64_t() == 0 || action == an) && + (actor.to_uint64_t() == 0 || actor == ar); } }; @@ -229,7 +229,7 @@ bool mongo_db_plugin_impl::filter_include( const account_name& receiver, const a include = true; } else { auto itr = std::find_if( filter_on.cbegin(), filter_on.cend(), [&receiver, &act_name]( const auto& filter ) { - return filter.match( receiver, act_name, 0 ); + return filter.match( receiver, act_name, {} ); } ); if( itr != filter_on.cend() ) { include = true; @@ -250,7 +250,7 @@ bool mongo_db_plugin_impl::filter_include( const account_name& receiver, const a if( filter_out.empty() ) { return true; } auto itr = std::find_if( filter_out.cbegin(), filter_out.cend(), [&receiver, &act_name]( const auto& filter ) { - return filter.match( receiver, act_name, 0 ); + return filter.match( receiver, act_name, {} ); } ); if( itr != filter_out.cend() ) { return false; } @@ -816,22 +816,20 @@ mongo_db_plugin_impl::add_action_trace( mongocxx::bulk_write& bulk_action_traces using namespace bsoncxx::types; using bsoncxx::builder::basic::kvp; - if( executed && atrace.receipt.receiver == chain::config::system_account_name ) { + if( executed && atrace.receiver == chain::config::system_account_name ) { update_account( atrace.act ); } bool added = false; const bool in_filter = (store_action_traces || store_transaction_traces) && start_block_reached && - filter_include( atrace.receipt.receiver, atrace.act.name, atrace.act.authorization ); + filter_include( atrace.receiver, atrace.act.name, atrace.act.authorization ); write_ttrace |= in_filter; if( start_block_reached && store_action_traces && in_filter ) { auto action_traces_doc = bsoncxx::builder::basic::document{}; - const chain::base_action_trace& base = atrace; // without inline action traces - // improve data distributivity when using mongodb sharding action_traces_doc.append( kvp( "_id", make_custom_oid() ) ); - auto v = to_variant_with_abi( base ); + auto v = to_variant_with_abi( atrace ); string json = fc::json::to_string( v ); try { const auto& value = bsoncxx::from_json( json ); @@ -857,10 +855,6 @@ mongo_db_plugin_impl::add_action_trace( mongocxx::bulk_write& bulk_action_traces added = true; } - for( const auto& iline_atrace : atrace.inline_traces ) { - added |= add_action_trace( bulk_action_traces, iline_atrace, t, executed, now, write_ttrace ); - } - return added; } @@ -1063,7 +1057,6 @@ void mongo_db_plugin_impl::_process_irreversible_block(const chain::block_state_ } auto update_doc = make_document( kvp( "$set", make_document( kvp( "irreversible", b_bool{true} ), - kvp( "validated", b_bool{bs->validated} ), kvp( "updatedAt", b_date{now} ) ) ) ); _blocks.update_one( make_document( kvp( "_id", ir_block->view()["_id"].get_oid() ) ), update_doc.view() ); @@ -1078,7 +1071,6 @@ void mongo_db_plugin_impl::_process_irreversible_block(const chain::block_state_ } auto update_doc = make_document( kvp( "$set", make_document( kvp( "irreversible", b_bool{true} ), - kvp( "validated", b_bool{bs->validated} ), kvp( "updatedAt", b_date{now} ) ) ) ); _block_states.update_one( make_document( kvp( "_id", ir_block->view()["_id"].get_oid() ) ), update_doc.view() ); @@ -1529,8 +1521,8 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) } } - if( options.count( "abi-serializer-max-time-us") == 0 ) { - EOS_ASSERT(false, chain::plugin_config_exception, "--abi-serializer-max-time-us required as default value not appropriate for parsing full blocks"); + if( options.count( "abi-serializer-max-time-ms") == 0 ) { + EOS_ASSERT(false, chain::plugin_config_exception, "--abi-serializer-max-time-ms required as default value not appropriate for parsing full blocks"); } my->abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); @@ -1573,7 +1565,7 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) std::vector v; boost::split( v, s, boost::is_any_of( ":" )); EOS_ASSERT( v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --mongodb-filter-on", ("s", s)); - filter_entry fe{v[0], v[1], v[2]}; + filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1]), eosio::chain::name(v[2])}; my->filter_on.insert( fe ); } } else { @@ -1585,7 +1577,7 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) std::vector v; boost::split( v, s, boost::is_any_of( ":" )); EOS_ASSERT( v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --mongodb-filter-out", ("s", s)); - filter_entry fe{v[0], v[1], v[2]}; + filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1]), eosio::chain::name(v[2])}; my->filter_out.insert( fe ); } } From 5366d8a9f820aaccc4720aed693b2d27a65b2e58 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Wed, 20 May 2020 13:22:18 +0800 Subject: [PATCH 12/25] Fix: cleos name issue --- programs/cleos/main.cpp | 257 ++++++++++++++++++++-------------------- 1 file changed, 131 insertions(+), 126 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 28f05c77e5b..92279ec651f 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -225,7 +225,7 @@ vector get_account_permissions(const vector& pe vector pieces; split(pieces, p, boost::algorithm::is_any_of("@")); if( pieces.size() == 1 ) pieces.push_back( "active" ); - return chain::permission_level{ .actor = pieces[0], .permission = pieces[1] }; + return chain::permission_level{ .actor = name(pieces[0]), .permission = name(pieces[1]) }; }); vector accountPermissions; boost::range::copy(fixedPermissions, back_inserter(accountPermissions)); @@ -273,7 +273,7 @@ string generate_nonce_string() { } chain::action generate_nonce_action() { - return chain::action( {}, config::null_account_name, "nonce", fc::raw::pack(fc::time_point::now().time_since_epoch().count())); + return chain::action( {}, config::null_account_name, name("nonce"), fc::raw::pack(fc::time_point::now().time_since_epoch().count())); } void prompt_for_wallet_password(string& pw, const string& name) { @@ -577,8 +577,8 @@ chain::action create_open(const string& contract, const name& owner, symbol sym, ("symbol", sym) ("ram_payer", ram_payer); return action { - get_account_permissions(tx_permission, {ram_payer,config::active_name}), - contract, "open", variant_to_bin( contract, N(open), open_ ) + get_account_permissions(tx_permission, {ram_payer, config::active_name}), + name(contract), N(open), variant_to_bin( name(contract), N(open), open_ ) }; } @@ -592,7 +592,7 @@ chain::action create_transfer(const string& contract, const name& sender, const return action { get_account_permissions(tx_permission, {sender,config::active_name}), - contract, "transfer", variant_to_bin( contract, N(transfer), transfer ) + name(contract), N(transfer), variant_to_bin( name(contract), N(transfer), transfer ) }; } @@ -693,10 +693,10 @@ inline asset to_asset( const string& s ) { } struct set_account_permission_subcommand { - name account; - name permission; + string account; + string permission; string authority_json_or_file; - name parent; + string parent; bool add_code; bool remove_code; @@ -717,34 +717,34 @@ struct set_account_permission_subcommand { authority auth; - bool need_parent = parent.empty() && (permission != name("owner")); + bool need_parent = parent.empty() && (name(permission) != name("owner")); bool need_auth = add_code || remove_code; if ( !need_auth && boost::iequals(authority_json_or_file, "null") ) { - send_actions( { create_deleteauth(account, permission) } ); + send_actions( { create_deleteauth(name(account), name(permission)) } ); return; } if ( need_parent || need_auth ) { - fc::variant json = call(get_account_func, fc::mutable_variant_object("account_name", account.to_string())); + fc::variant json = call(get_account_func, fc::mutable_variant_object("account_name", account)); auto res = json.as(); auto itr = std::find_if(res.permissions.begin(), res.permissions.end(), [&](const auto& perm) { - return perm.perm_name == permission; + return perm.perm_name == name(permission); }); if ( need_parent ) { // see if we can auto-determine the proper parent if ( itr != res.permissions.end() ) { - parent = (*itr).parent; + parent = (*itr).parent.to_string(); } else { // if this is a new permission and there is no parent we default to "active" - parent = name(config::active_name); + parent = config::active_name.to_string(); } } if ( need_auth ) { - auto actor = (authority_json_or_file.empty()) ? account : name(authority_json_or_file); - auto code_name = name(config::eosio_code_name); + auto actor = (authority_json_or_file.empty()) ? name(account) : name(authority_json_or_file); + auto code_name = config::eosio_code_name; if ( itr != res.permissions.end() ) { // fetch existing authority @@ -787,7 +787,7 @@ struct set_account_permission_subcommand { // remove code permission, if authority becomes empty by the removal of code permission, delete permission auth.accounts.erase( itr2 ); if ( auth.keys.empty() && auth.accounts.empty() && auth.waits.empty() ) { - send_actions( { create_deleteauth(account, permission) } ); + send_actions( { create_deleteauth(name(account), name(permission)) } ); return; } } else { @@ -818,7 +818,7 @@ struct set_account_permission_subcommand { auth = parse_json_authority_or_key(authority_json_or_file); } - send_actions( { create_updateauth(account, permission, parent, auth) } ); + send_actions( { create_updateauth(name(account), name(permission), name(parent), auth) } ); }); } }; @@ -994,8 +994,8 @@ struct register_producer_subcommand { producer_key = public_key_type(producer_key_str); } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid producer public key: ${public_key}", ("public_key", producer_key_str)) - auto regprod_var = regproducer_variant(producer_str, producer_key, url, loc ); - auto accountPermissions = get_account_permissions(tx_permission, {producer_str,config::active_name}); + auto regprod_var = regproducer_variant(name(producer_str), producer_key, url, loc ); + auto accountPermissions = get_account_permissions(tx_permission, {name(producer_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(regproducer), regprod_var)}); }); } @@ -1052,16 +1052,16 @@ struct create_account_subcommand { try { active_key = public_key_type(active_key_str); } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid active public key: ${public_key}", ("public_key", active_key_str)); - auto create = create_newaccount(creator, account_name, owner_key, active_key); + auto create = create_newaccount(name(creator), name(account_name), owner_key, active_key); if (!simple) { EOSC_ASSERT( buy_ram_eos.size() || buy_ram_bytes_in_kbytes || buy_ram_bytes, "ERROR: One of --buy-ram, --buy-ram-kbytes or --buy-ram-bytes should have non-zero value" ); EOSC_ASSERT( !buy_ram_bytes_in_kbytes || !buy_ram_bytes, "ERROR: --buy-ram-kbytes and --buy-ram-bytes cannot be set at the same time" ); - action buyram = !buy_ram_eos.empty() ? create_buyram(creator, account_name, to_asset(buy_ram_eos)) - : create_buyrambytes(creator, account_name, (buy_ram_bytes_in_kbytes) ? (buy_ram_bytes_in_kbytes * 1024) : buy_ram_bytes); + action buyram = !buy_ram_eos.empty() ? create_buyram(name(creator), name(account_name), to_asset(buy_ram_eos)) + : create_buyrambytes(name(creator), name(account_name), (buy_ram_bytes_in_kbytes) ? (buy_ram_bytes_in_kbytes * 1024) : buy_ram_bytes); auto net = to_asset(stake_net); auto cpu = to_asset(stake_cpu); if ( net.get_amount() != 0 || cpu.get_amount() != 0 ) { - action delegate = create_delegate( creator, account_name, net, cpu, transfer); + action delegate = create_delegate( name(creator), name(account_name), net, cpu, transfer); send_actions( { create, buyram, delegate } ); } else { send_actions( { create, buyram } ); @@ -1085,7 +1085,7 @@ struct unregister_producer_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("producer", producer_str); - auto accountPermissions = get_account_permissions(tx_permission, {producer_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(producer_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(unregprod), act_payload)}); }); } @@ -1106,7 +1106,7 @@ struct vote_producer_proxy_subcommand { ("voter", voter_str) ("proxy", proxy_str) ("producers", std::vector{}); - auto accountPermissions = get_account_permissions(tx_permission, {voter_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(voter_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } @@ -1114,7 +1114,7 @@ struct vote_producer_proxy_subcommand { struct vote_producers_subcommand { string voter_str; - vector producer_names; + vector producer_names; vote_producers_subcommand(CLI::App* actionRoot) { auto vote_producers = actionRoot->add_subcommand("prods", localized("Vote for one or more producers")); @@ -1130,15 +1130,15 @@ struct vote_producers_subcommand { ("voter", voter_str) ("proxy", "") ("producers", producer_names); - auto accountPermissions = get_account_permissions(tx_permission, {voter_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(voter_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; struct approve_producer_subcommand { - eosio::name voter; - eosio::name producer_name; + string voter; + string producer_name; approve_producer_subcommand(CLI::App* actionRoot) { auto approve_producer = actionRoot->add_subcommand("approve", localized("Add one producer to list of voted producers")); @@ -1152,8 +1152,8 @@ struct approve_producer_subcommand { ("scope", name(config::system_account_name).to_string()) ("table", "voters") ("table_key", "owner") - ("lower_bound", voter.value) - ("upper_bound", voter.value + 1) + ("lower_bound", name(voter).to_uint64_t()) + ("upper_bound", name(voter).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to voter.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -1172,7 +1172,7 @@ struct approve_producer_subcommand { for ( auto& x : prod_vars ) { prods.push_back( name(x.as_string()) ); } - prods.push_back( producer_name ); + prods.push_back( name(producer_name) ); std::sort( prods.begin(), prods.end() ); auto it = std::unique( prods.begin(), prods.end() ); if (it != prods.end() ) { @@ -1183,15 +1183,15 @@ struct approve_producer_subcommand { ("voter", voter) ("proxy", "") ("producers", prods); - auto accountPermissions = get_account_permissions(tx_permission, {voter,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(voter), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; struct unapprove_producer_subcommand { - eosio::name voter; - eosio::name producer_name; + string voter; + string producer_name; unapprove_producer_subcommand(CLI::App* actionRoot) { auto approve_producer = actionRoot->add_subcommand("unapprove", localized("Remove one producer from list of voted producers")); @@ -1205,8 +1205,8 @@ struct unapprove_producer_subcommand { ("scope", name(config::system_account_name).to_string()) ("table", "voters") ("table_key", "owner") - ("lower_bound", voter.value) - ("upper_bound", voter.value + 1) + ("lower_bound", name(voter).to_uint64_t()) + ("upper_bound", name(voter).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to voter.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -1225,7 +1225,7 @@ struct unapprove_producer_subcommand { for ( auto& x : prod_vars ) { prods.push_back( name(x.as_string()) ); } - auto it = std::remove( prods.begin(), prods.end(), producer_name ); + auto it = std::remove( prods.begin(), prods.end(), name(producer_name) ); if (it == prods.end() ) { std::cerr << "Cannot remove: producer \"" << producer_name << "\" is not on the list." << std::endl; return; @@ -1235,7 +1235,7 @@ struct unapprove_producer_subcommand { ("voter", voter) ("proxy", "") ("producers", prods); - auto accountPermissions = get_account_permissions(tx_permission, {voter,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(voter), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } @@ -1397,13 +1397,13 @@ struct delegate_bandwidth_subcommand { ("stake_net_quantity", to_asset(stake_net_amount)) ("stake_cpu_quantity", to_asset(stake_cpu_amount)) ("transfer", transfer); - auto accountPermissions = get_account_permissions(tx_permission, {from_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); std::vector acts{create_action(accountPermissions, config::system_account_name, N(delegatebw), act_payload)}; EOSC_ASSERT( !(buy_ram_amount.size()) || !buy_ram_bytes, "ERROR: --buyram and --buy-ram-bytes cannot be set at the same time" ); if (buy_ram_amount.size()) { - acts.push_back( create_buyram(from_str, receiver_str, to_asset(buy_ram_amount)) ); + acts.push_back( create_buyram(name(from_str), name(receiver_str), to_asset(buy_ram_amount)) ); } else if (buy_ram_bytes) { - acts.push_back( create_buyrambytes(from_str, receiver_str, buy_ram_bytes) ); + acts.push_back( create_buyrambytes(name(from_str), name(receiver_str), buy_ram_bytes) ); } send_actions(std::move(acts)); }); @@ -1431,7 +1431,7 @@ struct undelegate_bandwidth_subcommand { ("receiver", receiver_str) ("unstake_net_quantity", to_asset(unstake_net_amount)) ("unstake_cpu_quantity", to_asset(unstake_cpu_amount)); - auto accountPermissions = get_account_permissions(tx_permission, {from_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(undelegatebw), act_payload)}); }); } @@ -1452,7 +1452,7 @@ struct bidname_subcommand { ("bidder", bidder_str) ("newname", newname_str) ("bid", to_asset(bid_amount)); - auto accountPermissions = get_account_permissions(tx_permission, {bidder_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(bidder_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(bidname), act_payload)}); }); } @@ -1460,7 +1460,7 @@ struct bidname_subcommand { struct bidname_info_subcommand { bool print_json = false; - name newname; + string newname; bidname_info_subcommand(CLI::App* actionRoot) { auto list_producers = actionRoot->add_subcommand("bidnameinfo", localized("Get bidname info")); list_producers->add_flag("--json,-j", print_json, localized("Output in JSON format")); @@ -1468,19 +1468,18 @@ struct bidname_info_subcommand { list_producers->set_callback([this] { auto rawResult = call(get_table_func, fc::mutable_variant_object("json", true) ("code", "eosio")("scope", "eosio")("table", "namebids") - ("lower_bound", newname.value) - ("upper_bound", newname.value + 1) + ("lower_bound", name(newname).to_uint64_t()) + ("upper_bound", name(newname).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to newname.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1)); - if ( print_json ) { std::cout << fc::json::to_pretty_string(rawResult) << std::endl; return; } auto result = rawResult.as(); // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 - if( result.rows.empty() || result.rows[0].get_object()["newname"].as_string() != newname.to_string() ) { + if( result.rows.empty() || result.rows[0].get_object()["newname"].as_string() != name(newname).to_string() ) { std::cout << "No bidname record found" << std::endl; return; } @@ -1501,7 +1500,7 @@ struct bidname_info_subcommand { }; struct list_bw_subcommand { - eosio::name account; + string account; bool print_json = false; list_bw_subcommand(CLI::App* actionRoot) { @@ -1513,7 +1512,7 @@ struct list_bw_subcommand { //get entire table in scope of user account auto result = call(get_table_func, fc::mutable_variant_object("json", true) ("code", name(config::system_account_name).to_string()) - ("scope", account.to_string()) + ("scope", name(account).to_string()) ("table", "delband") ); if (!print_json) { @@ -1555,9 +1554,9 @@ struct buyram_subcommand { buyram->set_callback([this] { EOSC_ASSERT( !kbytes || !bytes, "ERROR: --kbytes and --bytes cannot be set at the same time" ); if (kbytes || bytes) { - send_actions( { create_buyrambytes(from_str, receiver_str, fc::to_uint64(amount) * ((kbytes) ? 1024ull : 1ull)) } ); + send_actions( { create_buyrambytes(name(from_str), name(receiver_str), fc::to_uint64(amount) * ((kbytes) ? 1024ull : 1ull)) } ); } else { - send_actions( { create_buyram(from_str, receiver_str, to_asset(amount)) } ); + send_actions( { create_buyram(name(from_str), name(receiver_str), to_asset(amount)) } ); } }); } @@ -1578,7 +1577,7 @@ struct sellram_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("account", receiver_str) ("bytes", amount); - auto accountPermissions = get_account_permissions(tx_permission, {receiver_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(receiver_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(sellram), act_payload)}); }); } @@ -1595,7 +1594,7 @@ struct claimrewards_subcommand { claim_rewards->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner); - auto accountPermissions = get_account_permissions(tx_permission, {owner,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(claimrewards), act_payload)}); }); } @@ -1613,7 +1612,7 @@ struct regproxy_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("proxy", proxy) ("isproxy", true); - auto accountPermissions = get_account_permissions(tx_permission, {proxy,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(proxy), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(regproxy), act_payload)}); }); } @@ -1631,7 +1630,7 @@ struct unregproxy_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("proxy", proxy) ("isproxy", false); - auto accountPermissions = get_account_permissions(tx_permission, {proxy,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(proxy), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(regproxy), act_payload)}); }); } @@ -1650,7 +1649,7 @@ struct canceldelay_subcommand { add_standard_transaction_options(cancel_delay, "canceling_account@canceling_permission"); cancel_delay->set_callback([this] { - auto canceling_auth = permission_level{canceling_account, canceling_permission}; + auto canceling_auth = permission_level{name(canceling_account), name(canceling_permission)}; fc::variant act_payload = fc::mutable_variant_object() ("canceling_auth", canceling_auth) ("trx_id", trx_id); @@ -1674,7 +1673,7 @@ struct deposit_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1694,7 +1693,7 @@ struct withdraw_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1714,7 +1713,7 @@ struct buyrex_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("from", from_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1738,7 +1737,7 @@ struct lendrex_subcommand { fc::variant act_payload2 = fc::mutable_variant_object() ("from", from_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name1, act_payload1), create_action(accountPermissions, config::system_account_name, act_name2, act_payload2)}); }); @@ -1756,8 +1755,8 @@ struct unstaketorex_subcommand { auto unstaketorex = actionRoot->add_subcommand("unstaketorex", localized("Buy REX using staked tokens")); unstaketorex->add_option("owner", owner_str, localized("Account buying REX tokens"))->required(); unstaketorex->add_option("receiver", receiver_str, localized("Account that tokens have been staked to"))->required(); - unstaketorex->add_option("from_net", from_net_str, localized("Amount to be unstaked from CPU resources and used in REX purchase"))->required(); - unstaketorex->add_option("from_cpu", from_cpu_str, localized("Amount to be unstaked from Net resources and used in REX purchase"))->required(); + unstaketorex->add_option("from_net", from_net_str, localized("Amount to be unstaked from Net resources and used in REX purchase"))->required(); + unstaketorex->add_option("from_cpu", from_cpu_str, localized("Amount to be unstaked from CPU resources and used in REX purchase"))->required(); add_standard_transaction_options(unstaketorex, "owner@active"); unstaketorex->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() @@ -1765,7 +1764,7 @@ struct unstaketorex_subcommand { ("receiver", receiver_str) ("from_net", from_net_str) ("from_cpu", from_cpu_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1785,7 +1784,7 @@ struct sellrex_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("from", from_str) ("rex", rex_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1801,7 +1800,7 @@ struct cancelrexorder_subcommand { add_standard_transaction_options(cancelrexorder, "owner@active"); cancelrexorder->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1827,7 +1826,7 @@ struct rentcpu_subcommand { ("receiver", receiver_str) ("loan_payment", loan_payment_str) ("loan_fund", loan_fund_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1853,7 +1852,7 @@ struct rentnet_subcommand { ("receiver", receiver_str) ("loan_payment", loan_payment_str) ("loan_fund", loan_fund_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1876,7 +1875,7 @@ struct fundcpuloan_subcommand { ("from", from_str) ("loan_num", loan_num_str) ("payment", payment_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1899,7 +1898,7 @@ struct fundnetloan_subcommand { ("from", from_str) ("loan_num", loan_num_str) ("payment", payment_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1922,7 +1921,7 @@ struct defcpuloan_subcommand { ("from", from_str) ("loan_num", loan_num_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1945,7 +1944,7 @@ struct defnetloan_subcommand { ("from", from_str) ("loan_num", loan_num_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1965,7 +1964,7 @@ struct mvtosavings_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner_str) ("rex", rex_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1985,7 +1984,7 @@ struct mvfrsavings_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner_str) ("rex", rex_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2001,7 +2000,7 @@ struct updaterex_subcommand { add_standard_transaction_options(updaterex, "owner@active"); updaterex->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2017,7 +2016,7 @@ struct consolidate_subcommand { add_standard_transaction_options(consolidate, "owner@active"); consolidate->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2037,7 +2036,7 @@ struct rexexec_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("user", user_str) ("max", max_str); - auto accountPermissions = get_account_permissions(tx_permission, {user_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(user_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2053,7 +2052,7 @@ struct closerex_subcommand { add_standard_transaction_options(closerex, "owner@active"); closerex->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2108,7 +2107,7 @@ void get_account( const string& accountName, const string& coresym, bool json_fo sep = ", "; } for ( auto& acc : p.required_auth.accounts ) { - std::cout << sep << acc.weight << ' ' << string(acc.permission.actor) << '@' << string(acc.permission.permission); + std::cout << sep << acc.weight << ' ' << acc.permission.actor.to_string() << '@' << acc.permission.permission.to_string(); sep = ", "; } std::cout << std::endl; @@ -2304,7 +2303,7 @@ void get_account( const string& accountName, const string& coresym, bool json_fo auto& prods = obj["producers"].get_array(); std::cout << "producers:"; if ( !prods.empty() ) { - for ( int i = 0; i < prods.size(); ++i ) { + for ( size_t i = 0; i < prods.size(); ++i ) { if ( i%3 == 0 ) { std::cout << std::endl << indent; } @@ -2467,11 +2466,11 @@ int main( int argc, char** argv ) { pack_action_data->add_option("name", unpacked_action_data_name_string, localized("The name of the function that's called by this action"))->required(); pack_action_data->add_option("unpacked_action_data", unpacked_action_data_string, localized("The action data expressed as json"))->required(); pack_action_data->set_callback([&] { - fc::variant unpacked_action_data_json; + fc::variant unpacked_action_data_json = json_from_file_or_string(unpacked_action_data_string); + bytes packed_action_data_string; try { - unpacked_action_data_json = json_from_file_or_string(unpacked_action_data_string); + packed_action_data_string = variant_to_bin(name(unpacked_action_data_account_string), name(unpacked_action_data_name_string), unpacked_action_data_json); } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse unpacked action data JSON") - bytes packed_action_data_string = variant_to_bin(unpacked_action_data_account_string, unpacked_action_data_name_string, unpacked_action_data_json); std::cout << fc::to_hex(packed_action_data_string.data(), packed_action_data_string.size()) << std::endl; }); @@ -2487,7 +2486,7 @@ int main( int argc, char** argv ) { EOS_ASSERT( packed_action_data_string.size() >= 2, transaction_type_exception, "No packed_action_data found" ); vector packed_action_data_blob(packed_action_data_string.size()/2); fc::from_hex(packed_action_data_string, packed_action_data_blob.data(), packed_action_data_blob.size()); - fc::variant unpacked_action_data_json = bin_to_variant(packed_action_data_account_string, packed_action_data_name_string, packed_action_data_blob); + fc::variant unpacked_action_data_json = bin_to_variant(name(packed_action_data_account_string), name(packed_action_data_name_string), packed_action_data_blob); std::cout << fc::json::to_pretty_string(unpacked_action_data_json) << std::endl; }); @@ -2621,7 +2620,6 @@ int main( int argc, char** argv ) { getTable->add_option( "account", code, localized("The account who owns the table") )->required(); getTable->add_option( "scope", scope, localized("The scope within the contract in which the table is found") )->required(); getTable->add_option( "table", table, localized("The name of the table as specified by the contract abi") )->required(); - getTable->add_option( "-b,--binary", binary, localized("Return the value as BINARY rather than using abi to interpret as JSON") ); getTable->add_option( "-l,--limit", limit, localized("The maximum number of rows to return") ); getTable->add_option( "-k,--key", table_key, localized("Deprecated") ); getTable->add_option( "-L,--lower", lower, localized("JSON representation of lower bound value of key, defaults to first") ); @@ -2635,6 +2633,7 @@ int main( int argc, char** argv ) { getTable->add_option( "--encode-type", encode_type, localized("The encoding type of key_type (i64 , i128 , float64, float128) only support decimal encoding e.g. 'dec'" "i256 - supports both 'dec' and 'hex', ripemd160 and sha256 is 'hex' only")); + getTable->add_flag("-b,--binary", binary, localized("Return the value as BINARY rather than using abi to interpret as JSON")); getTable->add_flag("-r,--reverse", reverse, localized("Iterate in reverse order")); getTable->add_flag("--show-payer", show_payer, localized("show RAM payer")); @@ -2681,23 +2680,28 @@ int main( int argc, char** argv ) { // currency accessors // get currency balance string symbol; + bool currency_balance_print_json = false; auto get_currency = get->add_subcommand( "currency", localized("Retrieve information related to standard currencies"), true); get_currency->require_subcommand(); auto get_balance = get_currency->add_subcommand( "balance", localized("Retrieve the balance of an account for a given currency"), false); get_balance->add_option( "contract", code, localized("The contract that operates the currency") )->required(); get_balance->add_option( "account", accountName, localized("The account to query balances for") )->required(); get_balance->add_option( "symbol", symbol, localized("The symbol for the currency if the contract operates multiple currencies") ); + get_balance->add_flag("--json,-j", currency_balance_print_json, localized("Output in JSON format") ); get_balance->set_callback([&] { auto result = call(get_currency_balance_func, fc::mutable_variant_object ("account", accountName) ("code", code) ("symbol", symbol.empty() ? fc::variant() : symbol) ); - - const auto& rows = result.get_array(); - for( const auto& r : rows ) { - std::cout << r.as_string() - << std::endl; + if (!currency_balance_print_json) { + const auto& rows = result.get_array(); + for( const auto& r : rows ) { + std::cout << r.as_string() + << std::endl; + } + } else { + std::cout << fc::json::to_pretty_string(result) << std::endl; } }); @@ -2994,7 +2998,7 @@ int main( int argc, char** argv ) { } if (!duplicate) { - actions.emplace_back( create_setcode(account, code_bytes ) ); + actions.emplace_back( create_setcode(name(account), code_bytes ) ); if ( shouldSend ) { std::cerr << localized("Setting Code...") << std::endl; send_actions(std::move(actions), 10000, packed_transaction::zlib); @@ -3041,7 +3045,7 @@ int main( int argc, char** argv ) { if (!duplicate) { try { - actions.emplace_back( create_setabi(account, abi_bytes) ); + actions.emplace_back( create_setabi(name(account), abi_bytes) ); } EOS_RETHROW_EXCEPTIONS(abi_type_exception, "Fail to parse ABI JSON") if ( shouldSend ) { std::cerr << localized("Setting ABI...") << std::endl; @@ -3108,12 +3112,12 @@ int main( int argc, char** argv ) { tx_force_unique = false; } - auto transfer_amount = to_asset(con, amount); - auto transfer = create_transfer(con, sender, recipient, transfer_amount, memo); + auto transfer_amount = to_asset(name(con), amount); + auto transfer = create_transfer(con, name(sender), name(recipient), transfer_amount, memo); if (!pay_ram) { send_actions( { transfer }); } else { - auto open_ = create_open(con, recipient, transfer_amount.get_symbol(), sender); + auto open_ = create_open(con, name(recipient), transfer_amount.get_symbol(), name(sender)); send_actions( { open_, transfer } ); } }); @@ -3380,7 +3384,8 @@ int main( int argc, char** argv ) { } auto accountPermissions = get_account_permissions(tx_permission); - send_actions({chain::action{accountPermissions, contract_account, action, variant_to_bin( contract_account, action, action_args_var ) }}); + send_actions({chain::action{accountPermissions, name(contract_account), name(action), + variant_to_bin( name(contract_account), name(action), action_args_var ) }}); }); // push transaction @@ -3467,7 +3472,7 @@ int main( int argc, char** argv ) { trx_var = json_from_file_or_string(proposed_transaction); } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse transaction JSON '${data}'", ("data",proposed_transaction)) transaction proposed_trx = trx_var.as(); - bytes proposed_trx_serialized = variant_to_bin( proposed_contract, proposed_action, trx_var ); + bytes proposed_trx_serialized = variant_to_bin( name(proposed_contract), name(proposed_action), trx_var ); vector reqperm; try { @@ -3482,7 +3487,7 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if (accountPermissions.empty()) { if (!proposer.empty()) { - accountPermissions = vector{{proposer, config::active_name}}; + accountPermissions = vector{{name(proposer), config::active_name}}; } else { EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); } @@ -3509,7 +3514,7 @@ int main( int argc, char** argv ) { ("requested", requested_perm_var) ("trx", trx_var); - send_actions({chain::action{accountPermissions, "eosio.msig", "propose", variant_to_bin( N(eosio.msig), N(propose), args ) }}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(propose), variant_to_bin( N(eosio.msig), N(propose), args ) }}); }); //multisig propose transaction @@ -3534,7 +3539,7 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if (accountPermissions.empty()) { if (!proposer.empty()) { - accountPermissions = vector{{proposer, config::active_name}}; + accountPermissions = vector{{name(proposer), config::active_name}}; } else { EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); } @@ -3549,7 +3554,7 @@ int main( int argc, char** argv ) { ("requested", requested_perm_var) ("trx", trx_var); - send_actions({chain::action{accountPermissions, "eosio.msig", "propose", variant_to_bin( N(eosio.msig), N(propose), args ) }}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(propose), variant_to_bin( N(eosio.msig), N(propose), args ) }}); }); @@ -3566,8 +3571,8 @@ int main( int argc, char** argv ) { ("scope", proposer) ("table", "proposal") ("table_key", "") - ("lower_bound", name(proposal_name).value) - ("upper_bound", name(proposal_name).value + 1) + ("lower_bound", name(proposal_name).to_uint64_t()) + ("upper_bound", name(proposal_name).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3604,8 +3609,8 @@ int main( int argc, char** argv ) { ("scope", proposer) ("table", "approvals2") ("table_key", "") - ("lower_bound", name(proposal_name).value) - ("upper_bound", name(proposal_name).value + 1) + ("lower_bound", name(proposal_name).to_uint64_t()) + ("upper_bound", name(proposal_name).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3621,7 +3626,7 @@ int main( int argc, char** argv ) { for( const auto& ra : approvals_object["requested_approvals"].get_array() ) { const auto& ra_obj = ra.get_object(); auto pl = ra["level"].as(); - auto res = all_approvals.emplace( pl, std::make_pair(ra["time"].as(), approval_status::unapproved) ); + all_approvals.emplace( pl, std::make_pair(ra["time"].as(), approval_status::unapproved) ); } for( const auto& pa : approvals_object["provided_approvals"].get_array() ) { @@ -3636,8 +3641,8 @@ int main( int argc, char** argv ) { ("scope", proposer) ("table", "approvals") ("table_key", "") - ("lower_bound", name(proposal_name).value) - ("upper_bound", name(proposal_name).value + 1) + ("lower_bound", name(proposal_name).to_uint64_t()) + ("upper_bound", name(proposal_name).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3652,7 +3657,7 @@ int main( int argc, char** argv ) { for( const auto& ra : approvals_object["requested_approvals"].get_array() ) { auto pl = ra.as(); - auto res = all_approvals.emplace( pl, std::make_pair(fc::time_point{}, approval_status::unapproved) ); + all_approvals.emplace( pl, std::make_pair(fc::time_point{}, approval_status::unapproved) ); } for( const auto& pa : approvals_object["provided_approvals"].get_array() ) { @@ -3669,8 +3674,8 @@ int main( int argc, char** argv ) { ("scope", "eosio.msig") ("table", "invals") ("table_key", "") - ("lower_bound", a.first.value) - ("upper_bound", a.first.value + 1) + ("lower_bound", a.first.to_uint64_t()) + ("upper_bound", a.first.to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3699,8 +3704,8 @@ int main( int argc, char** argv ) { ("scope", proposer) ("table", "opposes") ("table_key", "") - ("lower_bound", name(proposal_name).value) - ("upper_bound", name(proposal_name).value + 1) + ("lower_bound", name(proposal_name).to_uint64_t()) + ("upper_bound", name(proposal_name).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3820,8 +3825,8 @@ int main( int argc, char** argv ) { args("proposal_hash", proposal_hash); } - auto accountPermissions = get_account_permissions(tx_permission, {proposer,config::active_name}); - send_actions({chain::action{accountPermissions, "eosio.msig", action, variant_to_bin( N(eosio.msig), action, args ) }}); + auto accountPermissions = get_account_permissions(tx_permission, {name(proposer), config::active_name}); + send_actions({chain::action{accountPermissions, N(eosio.msig), name(action), variant_to_bin( N(eosio.msig), name(action), args ) }}); }; // multisig approve @@ -3884,8 +3889,8 @@ int main( int argc, char** argv ) { auto args = fc::mutable_variant_object() ("account", invalidator); - auto accountPermissions = get_account_permissions(tx_permission, {invalidator,config::active_name}); - send_actions({chain::action{accountPermissions, "eosio.msig", "invalidate", variant_to_bin( N(eosio.msig), "invalidate", args ) }}); + auto accountPermissions = get_account_permissions(tx_permission, {name(invalidator), config::active_name}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(invalidate), variant_to_bin( N(eosio.msig), N(invalidate), args ) }}); }); // multisig cancel @@ -3899,7 +3904,7 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if (accountPermissions.empty()) { if (!canceler.empty()) { - accountPermissions = vector{{canceler, config::active_name}}; + accountPermissions = vector{{name(canceler), config::active_name}}; } else { EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); } @@ -3912,7 +3917,7 @@ int main( int argc, char** argv ) { ("proposal_name", proposal_name) ("canceler", canceler); - send_actions({chain::action{accountPermissions, "eosio.msig", "cancel", variant_to_bin( N(eosio.msig), N(cancel), args ) }}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(cancel), variant_to_bin( N(eosio.msig), N(cancel), args ) }}); } ); @@ -3927,7 +3932,7 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if (accountPermissions.empty()) { if (!executer.empty()) { - accountPermissions = vector{{executer, config::active_name}}; + accountPermissions = vector{{name(executer), config::active_name}}; } else { EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); } @@ -3941,7 +3946,7 @@ int main( int argc, char** argv ) { ("proposal_name", proposal_name) ("executer", executer); - send_actions({chain::action{accountPermissions, "eosio.msig", "exec", variant_to_bin( N(eosio.msig), N(exec), args ) }}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(exec), variant_to_bin( N(eosio.msig), N(exec), args ) }}); } ); @@ -3967,14 +3972,14 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if( accountPermissions.empty() ) { - accountPermissions = vector{{executer, config::active_name}, {wrap_con, config::active_name}}; + accountPermissions = vector{{name(executer), config::active_name}, {name(wrap_con), config::active_name}}; } auto args = fc::mutable_variant_object() ("executer", executer ) ("trx", trx_var); - send_actions({chain::action{accountPermissions, wrap_con, "exec", variant_to_bin( wrap_con, N(exec), args ) }}); + send_actions({chain::action{accountPermissions, name(wrap_con), N(exec), variant_to_bin( name(wrap_con), N(exec), args ) }}); }); // system subcommand @@ -4000,7 +4005,7 @@ int main( int argc, char** argv ) { auto bidname = bidname_subcommand(system); auto bidnameinfo = bidname_info_subcommand(system); - auto biyram = buyram_subcommand(system); + auto buyram = buyram_subcommand(system); auto sellram = sellram_subcommand(system); auto claimRewards = claimrewards_subcommand(system); From 982cf821ad50e0d0def23fab5ba9126e2f32787b Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Wed, 20 May 2020 13:50:39 +0800 Subject: [PATCH 13/25] Fix: tests --- tests/get_table_tests.cpp | 66 +++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/tests/get_table_tests.cpp b/tests/get_table_tests.cpp index f806edc76ae..1a202e5113e 100644 --- a/tests/get_table_tests.cpp +++ b/tests/get_table_tests.cpp @@ -34,6 +34,34 @@ using namespace fc; BOOST_AUTO_TEST_SUITE(get_table_tests) +transaction_trace_ptr +issue_tokens( TESTER& t, account_name issuer, account_name to, const asset& amount, + std::string memo = "", account_name token_contract = N(eosio.token) ) +{ + signed_transaction trx; + + trx.actions.emplace_back( t.get_action( token_contract, N(issue), + vector{{issuer, config::active_name}}, + mutable_variant_object() + ("to", issuer.to_string()) + ("quantity", amount) + ("memo", memo) + ) ); + + trx.actions.emplace_back( t.get_action( token_contract, N(transfer), + vector{{issuer, config::active_name}}, + mutable_variant_object() + ("from", issuer.to_string()) + ("to", to.to_string()) + ("quantity", amount) + ("memo", memo) + ) ); + + t.set_transaction_headers(trx); + trx.sign( t.get_private_key( issuer, "active" ), t.control->get_chain_id() ); + return t.push_transaction( trx ); +} + BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { produce_blocks(2); @@ -56,11 +84,7 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("999.0000 SYS") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("999.0000 SYS") ); } produce_blocks(1); @@ -132,11 +156,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("10000.0000 SYS") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("10000.0000 SYS") ); } produce_blocks(1); @@ -147,11 +167,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { push_action(N(eosio.token), N(create), N(eosio.token), act ); // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("9999.0000 AAA") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("9999.0000 AAA") ); } produce_blocks(1); @@ -162,11 +178,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { push_action(N(eosio.token), N(create), N(eosio.token), act ); // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("7777.0000 CCC") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("7777.0000 CCC") ); } produce_blocks(1); @@ -177,11 +189,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { push_action(N(eosio.token), N(create), N(eosio.token), act ); // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("8888.0000 BBB") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("8888.0000 BBB") ); } produce_blocks(1); @@ -327,11 +335,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("10000.0000 SYS") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("10000.0000 SYS") ); } produce_blocks(1); @@ -341,7 +345,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { base_tester::push_action(config::system_account_name, N(init), config::system_account_name, mutable_variant_object() ("version", 0) - ("core", CORE_SYM_STR)); + ("core", "4,SYS")); // bidname auto bidname = [this]( const account_name& bidder, const account_name& newname, const asset& bid ) { From 20c3c17fd4787f91072bd0df2aa4748cf8f771c4 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Wed, 20 May 2020 18:42:15 +0800 Subject: [PATCH 14/25] Add back get block detail in history plugin --- plugins/history_plugin/history_plugin.cpp | 88 +++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index 5223c147f61..feb100d806a 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -559,6 +559,94 @@ namespace eosio { return result; } + fc::variant read_only::get_block_detail(const read_only::get_block_detail_params& params) const { + static char const TRANSACTIONS[] = "transactions"; + static char const TRX[] = "trx"; + static char const ID[] = "id"; + static char const TRACES[] = "traces"; + + auto & plugin = history->chain_plug; + auto & chain = plugin->chain(); + + auto get_object_value = [](fc::variant const& src, char const * key) -> fc::variant const & { + static auto const null_variant = fc::variant(); + + if ( !src.is_object() ) + return null_variant; + + auto & obj = src.get_object(); + auto const & itr = obj.find(key); + if ( itr == obj.end() ) + return null_variant; + + return itr->value(); + }; + + auto get_tx_array = [&get_object_value](fc::variant const& block) -> fc::variants const & { + static auto const null_variants = fc::variants(); + + auto & value = get_object_value(block, TRANSACTIONS); + if ( !value.is_array() ) + return null_variants; + + return value.get_array(); + }; + + auto get_tx_id = [&get_object_value](fc::variant const& tx) -> optional { + auto & id = get_object_value(get_object_value(tx, TRX), ID); + if ( !id.is_string() ) + return fc::optional(); + + return fc::optional(id.get_string()); + }; + + auto const & src = plugin->get_read_only_api().get_block( + chain_apis::read_only::get_block_params { + /*block_num_or_id = */ params.block_num_or_id + } + ); + + auto & rhs = get_tx_array(src); + if ( rhs.empty() ) + return src; + + auto lhs = fc::variants(); + lhs.reserve(rhs.size()); + + auto & database = chain.db(); + auto & index = database.get_index(); + auto const abi_serializer_max_time = plugin->get_abi_serializer_max_time(); + for ( auto const & tx : rhs ) { + auto maybe_id = get_tx_id(tx); + if ( maybe_id ) { + auto id = *maybe_id; + auto itr = index.lower_bound(boost::make_tuple(id)); + auto traces = fc::variants(); + + while ( itr != index.end() && itr->trx_id == id ) { + + fc::datastream ds( itr->packed_action_trace.data(), itr->packed_action_trace.size() ); + action_trace t; + fc::raw::unpack( ds, t ); + traces.emplace_back( chain.to_variant_with_abi(t, abi_serializer_max_time) ); + + ++itr; + } + + if ( !traces.empty() ) { + auto new_trx = fc::mutable_variant_object(tx[TRX])(TRACES, traces); + auto new_tx = fc::mutable_variant_object(tx).set(TRX, move(new_trx)); + lhs.emplace_back(move(new_tx)); + continue; + } + } + + lhs.emplace_back(tx); + } + + return fc::mutable_variant_object(src).set(TRANSACTIONS, move(lhs)); + } + read_only::get_key_accounts_results read_only::get_key_accounts(const get_key_accounts_params& params) const { std::set accounts; const auto& db = history->chain_plug->chain().db(); From d33bb6cdee719f227768539c522d53a2356e0c68 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 28 May 2020 00:28:53 +0800 Subject: [PATCH 15/25] update connected lib channels of plugins --- plugins/kafka_plugin/kafka_plugin.cpp | 2 +- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 2 +- plugins/notify_plugin/notify_plugin.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/kafka_plugin/kafka_plugin.cpp b/plugins/kafka_plugin/kafka_plugin.cpp index 901fd57a29e..074b119eff0 100644 --- a/plugins/kafka_plugin/kafka_plugin.cpp +++ b/plugins/kafka_plugin/kafka_plugin.cpp @@ -126,7 +126,7 @@ void kafka_plugin::plugin_initialize(const variables_map& options) { } handle([=] { kafka_->push_block(b, false); }, "push block"); }); - irreversible_block_conn_ = chain.irreversible_block.connect([=](const chain::block_state_ptr& b) { + irreversible_block_conn_ = chain.new_irreversible_block.connect([=](const chain::block_state_ptr& b) { if (not start_sync_) { if (b->block_num >= start_block_num) start_sync_ = true; else return; diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 3e0d50b8077..7720ad1dd4a 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -1608,7 +1608,7 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) my->accepted_block( bs ); } )); my->irreversible_block_connection.emplace( - chain.irreversible_block.connect( [&]( const chain::block_state_ptr& bs ) { + chain.new_irreversible_block.connect( [&]( const chain::block_state_ptr& bs ) { my->applied_irreversible_block( bs ); } )); my->accepted_transaction_connection.emplace( diff --git a/plugins/notify_plugin/notify_plugin.cpp b/plugins/notify_plugin/notify_plugin.cpp index 8fec2a0f133..676147b0891 100644 --- a/plugins/notify_plugin/notify_plugin.cpp +++ b/plugins/notify_plugin/notify_plugin.cpp @@ -323,7 +323,7 @@ void notify_plugin::plugin_initialize(const variables_map &options) my->on_accepted_block(b_state); })); - my->irreversible_block_conn.emplace(chain.irreversible_block.connect( + my->irreversible_block_conn.emplace(chain.new_irreversible_block.connect( [&](const block_state_ptr &bs) { my->on_irreversible_block(bs); })); From 1e7fb89f1d7e02c5adcabc52068a7ef1e382685c Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Wed, 3 Jun 2020 13:35:46 +0800 Subject: [PATCH 16/25] Fix: state history plugin issues --- plugins/chain_plugin/chain_plugin.cpp | 2 +- .../state_history_serialization.hpp | 4 ++- .../state_history_plugin.cpp | 2 +- .../state_history_plugin_abi.cpp | 32 ++----------------- tests/chain_plugin_tests.cpp | 2 +- 5 files changed, 8 insertions(+), 34 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index a97f21e0cca..04e7c897d8a 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2087,7 +2087,7 @@ read_only::get_act_token_result read_only::get_act_token( const name& account_na } // REX const auto& d = db.db(); - const auto& code_account = db.db().get( config::system_account_name ); + const auto& code_account = db.db().get( config::system_account_name ); abi_def abi; if( abi_serializer::to_abi(code_account.abi, abi) ) { abi_serializer abis( abi, abi_serializer_max_time ); diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp index a599a4eef10..6149c381f06 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -127,7 +127,7 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); fc::raw::pack(ds, as_type(obj.obj.name.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.creation_date)); @@ -576,6 +576,8 @@ datastream& operator<<(datastream& ds, const history_context_wrapper>(e)); + fc::raw::pack(ds, as_type>(debug_mode ? obj.obj.error_code + : cap_error_code(obj.obj.error_code))); return ds; } diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp index 411383d2f49..2304a7da1e0 100644 --- a/plugins/state_history_plugin/state_history_plugin.cpp +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -548,7 +548,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this(), pack_row); + process_table("account", db.get_index(), pack_row); process_table("account_metadata", db.get_index(), pack_row); process_table("code", db.get_index(), pack_row); diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp index 085486cdd5a..a5ff928f52c 100644 --- a/plugins/state_history_plugin/state_history_plugin_abi.cpp +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -311,24 +311,6 @@ extern const char* const state_history_plugin_abi = R"({ { "type": "producer_key[]", "name": "producers" } ] }, - { - "name": "block_signing_authority_v0", "fields": [ - { "type": "uint32", "name": "threshold" }, - { "type": "key_weight[]", "name": "keys" } - ] - }, - { - "name": "producer_authority", "fields": [ - { "type": "name", "name": "producer_name" }, - { "type": "block_signing_authority", "name": "authority" } - ] - }, - { - "name": "producer_authority_schedule", "fields": [ - { "type": "uint32", "name": "version" }, - { "type": "producer_authority[]", "name": "producers" } - ] - }, { "name": "chain_config_v0", "fields": [ { "type": "uint64", "name": "max_block_net_usage" }, @@ -357,14 +339,6 @@ extern const char* const state_history_plugin_abi = R"({ { "type": "chain_config", "name": "configuration" } ] }, - { - "name": "global_property_v1", "fields": [ - { "type": "uint32?", "name": "proposed_schedule_block_num" }, - { "type": "producer_authority_schedule", "name": "proposed_schedule" }, - { "type": "chain_config", "name": "configuration" }, - { "type": "checksum256", "name": "chain_id" } - ] - }, { "name": "generated_transaction_v0", "fields": [ { "type": "name", "name": "sender" }, @@ -507,7 +481,7 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "contract_index_double", "types": ["contract_index_double_v0"] }, { "name": "contract_index_long_double", "types": ["contract_index_long_double_v0"] }, { "name": "chain_config", "types": ["chain_config_v0"] }, - { "name": "global_property", "types": ["global_property_v0", "global_property_v1"] }, + { "name": "global_property", "types": ["global_property_v0"] }, { "name": "generated_transaction", "types": ["generated_transaction_v0"] }, { "name": "permission", "types": ["permission_v0"] }, { "name": "permission_link", "types": ["permission_link_v0"] }, @@ -517,8 +491,7 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "resource_limits_state", "types": ["resource_limits_state_v0"] }, { "name": "resource_limits_ratio", "types": ["resource_limits_ratio_v0"] }, { "name": "elastic_limit_parameters", "types": ["elastic_limit_parameters_v0"] }, - { "name": "resource_limits_config", "types": ["resource_limits_config_v0"] }, - { "name": "block_signing_authority", "types": ["block_signing_authority_v0"] } + { "name": "resource_limits_config", "types": ["resource_limits_config_v0"] } ], "tables": [ { "name": "account", "type": "account", "key_names": ["name"] }, @@ -533,7 +506,6 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "contract_index_long_double", "type": "contract_index_long_double", "key_names": ["code", "scope", "table", "primary_key"] }, { "name": "global_property", "type": "global_property", "key_names": [] }, { "name": "generated_transaction", "type": "generated_transaction", "key_names": ["sender", "sender_id"] }, - { "name": "protocol_state", "type": "protocol_state", "key_names": [] }, { "name": "permission", "type": "permission", "key_names": ["owner", "name"] }, { "name": "permission_link", "type": "permission_link", "key_names": ["account", "code", "message_type"] }, { "name": "resource_limits", "type": "resource_limits", "key_names": ["owner"] }, diff --git a/tests/chain_plugin_tests.cpp b/tests/chain_plugin_tests.cpp index af44e2a2950..038ac905211 100644 --- a/tests/chain_plugin_tests.cpp +++ b/tests/chain_plugin_tests.cpp @@ -47,7 +47,7 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, TESTER ) try { auto resolver = [&,this]( const account_name& name ) -> fc::optional { try { - const auto& accnt = this->control->db().get( name ); + const auto& accnt = this->control->db().get( name ); abi_def abi; if (abi_serializer::to_abi(accnt.abi, abi)) { return abi_serializer(abi, abi_serializer_max_time); From 58ff806c6bb6d6e136531d7c10a1df5e29ae780c Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Fri, 5 Jun 2020 10:36:08 +0800 Subject: [PATCH 17/25] Change: applied transaction channel for statehistory plugin --- Docker/Dockerfile | 12 +- libraries/chain/controller.cpp | 14 +- .../chain/include/eosio/chain/controller.hpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 4 +- plugins/history_plugin/history_plugin.cpp | 4 +- plugins/kafka_plugin/kafka_plugin.cpp | 4 +- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 4 +- plugins/notify_plugin/notify_plugin.cpp | 4 +- .../state_history_log.hpp | 448 +++++++++--------- .../state_history_plugin.cpp | 12 +- unittests/api_tests.cpp | 29 +- unittests/whitelist_blacklist_tests.cpp | 3 +- 12 files changed, 279 insertions(+), 261 deletions(-) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 32c238e30f2..7f91e91b12c 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -1,11 +1,11 @@ FROM boscore/builder:v2.0.6 as builder -ARG branch=master +ARG branch=statehistoryplugin ARG symbol=EOS ENV OPENSSL_ROOT_DIR /usr/include/openssl -RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ - && cd bos && echo "$branch:$(git rev-parse HEAD)" > /etc/boscore-version \ +RUN git clone -b $branch https://github.com/eosiosg/eos.git --recursive \ + && cd eos && echo "$branch:$(git rev-parse HEAD)" > /etc/eoscore-version \ && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" -DENABLE_TOOLS=OFF \ @@ -16,9 +16,9 @@ FROM ubuntu:18.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl ca-certificates iproute2 && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/lib/* /usr/local/lib/ COPY --from=builder /tmp/build/bin /opt/eosio/bin -COPY --from=builder /bos/Docker/config.ini / -COPY --from=builder /etc/boscore-version /etc -COPY --from=builder /bos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh +COPY --from=builder /eos/Docker/config.ini / +COPY --from=builder /etc/eoscore-version /etc +COPY --from=builder /eos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh ENV EOSIO_ROOT=/opt/eosio RUN chmod +x /opt/eosio/bin/nodeosd.sh ENV LD_LIBRARY_PATH /usr/local/lib diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 7bf3cd91697..1f265a0cb9d 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1201,7 +1201,7 @@ struct controller_impl { trace->scheduled = true; trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); undo_session.squash(); return trace; } @@ -1241,7 +1241,7 @@ struct controller_impl { fc::move_append( pending->_actions, move(trx_context.executed) ); emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); trx_context.squash(); undo_session.squash(); @@ -1269,7 +1269,7 @@ struct controller_impl { trace = error_trace; if( !trace->except_ptr ) { emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); undo_session.squash(); return trace; } @@ -1306,12 +1306,12 @@ struct controller_impl { trace->receipt = push_receipt(gtrx.trx_id, transaction_receipt::hard_fail, cpu_time_to_bill_us, 0); emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); undo_session.squash(); } else { emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); } return trace; @@ -1421,7 +1421,7 @@ struct controller_impl { emit( self.accepted_transaction, trx); } - emit(self.applied_transaction, trace); + emit(self.applied_transaction, std::tie(trace, trn)); if ( read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete ) { @@ -1446,7 +1446,7 @@ struct controller_impl { } emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, trn) ); return trace; } FC_CAPTURE_AND_RETHROW((trace)) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 241d1ddca2d..c22f3457e1b 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -311,7 +311,7 @@ namespace eosio { namespace chain { signal irreversible_block; signal new_irreversible_block; signal accepted_transaction; - signal applied_transaction; + signal)> applied_transaction; signal accepted_confirmation; signal bad_alloc; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 04e7c897d8a..35b6af33083 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -829,8 +829,8 @@ void chain_plugin::plugin_initialize(const variables_map& options) { } ); my->applied_transaction_connection = my->chain->applied_transaction.connect( - [this]( const transaction_trace_ptr& trace ) { - my->applied_transaction_channel.publish( trace ); + [this]( std::tuple t ) { + my->applied_transaction_channel.publish( std::get<0>(t) ); } ); my->accepted_confirmation_connection = my->chain->accepted_confirmation.connect( diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index feb100d806a..5e834db19c2 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -351,8 +351,8 @@ namespace eosio { db.add_index(); my->applied_transaction_connection.emplace( - chain.applied_transaction.connect( [&]( const transaction_trace_ptr& p ) { - my->on_applied_transaction( p ); + chain.applied_transaction.connect( [&]( std::tuple t ) { + my->on_applied_transaction( std::get<0>(t) ); } )); } FC_LOG_AND_RETHROW() } diff --git a/plugins/kafka_plugin/kafka_plugin.cpp b/plugins/kafka_plugin/kafka_plugin.cpp index 901fd57a29e..cd36554b2da 100644 --- a/plugins/kafka_plugin/kafka_plugin.cpp +++ b/plugins/kafka_plugin/kafka_plugin.cpp @@ -133,9 +133,9 @@ void kafka_plugin::plugin_initialize(const variables_map& options) { } handle([=] { kafka_->push_block(b, true); }, "push irreversible block"); }); - transaction_conn_ = chain.applied_transaction.connect([=](const chain::transaction_trace_ptr& t) { + transaction_conn_ = chain.applied_transaction.connect([=]( std::tuple t) { if (not start_sync_) return; - handle([=] { kafka_->push_transaction_trace(t); }, "push transaction"); + handle([=] { kafka_->push_transaction_trace(std::get<0>(t)); }, "push transaction"); }); } diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 3e0d50b8077..513ae586d79 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -1616,8 +1616,8 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) my->accepted_transaction( t ); } )); my->applied_transaction_connection.emplace( - chain.applied_transaction.connect( [&]( const chain::transaction_trace_ptr& t ) { - my->applied_transaction( t ); + chain.applied_transaction.connect( [&]( std::tuple t ) { + my->applied_transaction( std::get<0>(t) ); } )); if( my->wipe_database_on_startup ) { diff --git a/plugins/notify_plugin/notify_plugin.cpp b/plugins/notify_plugin/notify_plugin.cpp index 8fec2a0f133..f15c979199d 100644 --- a/plugins/notify_plugin/notify_plugin.cpp +++ b/plugins/notify_plugin/notify_plugin.cpp @@ -329,8 +329,8 @@ void notify_plugin::plugin_initialize(const variables_map &options) })); my->applied_tx_conn.emplace(chain.applied_transaction.connect( - [&](const transaction_trace_ptr &tx) { - my->on_applied_tx(tx); + [&](std::tuple t) { + my->on_applied_tx(std::get<0>(t)); })); } FC_LOG_AND_RETHROW() diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp index 5749694ce3a..065a59638bc 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp @@ -34,94 +34,94 @@ inline bool is_ship_supported_version(uint64_t magic) { return get_shi static const uint32_t ship_current_version = 0; struct state_history_log_header { - uint64_t magic = ship_magic(ship_current_version); - chain::block_id_type block_id = {}; - uint64_t payload_size = 0; + uint64_t magic = ship_magic(ship_current_version); + chain::block_id_type block_id = {}; + uint64_t payload_size = 0; }; static const int state_history_log_header_serial_size = sizeof(state_history_log_header::magic) + - sizeof(state_history_log_header::block_id) + - sizeof(state_history_log_header::payload_size); + sizeof(state_history_log_header::block_id) + + sizeof(state_history_log_header::payload_size); class state_history_log { -private: - const char* const name = ""; - std::string log_filename; - std::string index_filename; - std::fstream log; - std::fstream index; - uint32_t _begin_block = 0; - uint32_t _end_block = 0; - chain::block_id_type last_block_id; + private: + const char* const name = ""; + std::string log_filename; + std::string index_filename; + std::fstream log; + std::fstream index; + uint32_t _begin_block = 0; + uint32_t _end_block = 0; + chain::block_id_type last_block_id; -public: - state_history_log(const char* const name, std::string log_filename, std::string index_filename) - : name(name) - , log_filename(std::move(log_filename)) - , index_filename(std::move(index_filename)) { - open_log(); - open_index(); - } + public: + state_history_log(const char* const name, std::string log_filename, std::string index_filename) + : name(name) + , log_filename(std::move(log_filename)) + , index_filename(std::move(index_filename)) { + open_log(); + open_index(); + } - uint32_t begin_block() const { return _begin_block; } - uint32_t end_block() const { return _end_block; } + uint32_t begin_block() const { return _begin_block; } + uint32_t end_block() const { return _end_block; } - void read_header(state_history_log_header& header, bool assert_version = true) { - char bytes[state_history_log_header_serial_size]; - log.read(bytes, sizeof(bytes)); - fc::datastream ds(bytes, sizeof(bytes)); - fc::raw::unpack(ds, header); - EOS_ASSERT(!ds.remaining(), chain::plugin_exception, "state_history_log_header_serial_size mismatch"); - if (assert_version) - EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic), chain::plugin_exception, - "corrupt ${name}.log (0)", ("name", name)); - } + void read_header(state_history_log_header& header, bool assert_version = true) { + char bytes[state_history_log_header_serial_size]; + log.read(bytes, sizeof(bytes)); + fc::datastream ds(bytes, sizeof(bytes)); + fc::raw::unpack(ds, header); + EOS_ASSERT(!ds.remaining(), chain::plugin_exception, "state_history_log_header_serial_size mismatch"); + if (assert_version) + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic), chain::plugin_exception, + "corrupt ${name}.log (0)", ("name", name)); + } - void write_header(const state_history_log_header& header) { - char bytes[state_history_log_header_serial_size]; - fc::datastream ds(bytes, sizeof(bytes)); - fc::raw::pack(ds, header); - EOS_ASSERT(!ds.remaining(), chain::plugin_exception, "state_history_log_header_serial_size mismatch"); - log.write(bytes, sizeof(bytes)); - } + void write_header(const state_history_log_header& header) { + char bytes[state_history_log_header_serial_size]; + fc::datastream ds(bytes, sizeof(bytes)); + fc::raw::pack(ds, header); + EOS_ASSERT(!ds.remaining(), chain::plugin_exception, "state_history_log_header_serial_size mismatch"); + log.write(bytes, sizeof(bytes)); + } - template - void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) { - auto block_num = chain::block_header::num_from_id(header.block_id); - EOS_ASSERT(_begin_block == _end_block || block_num <= _end_block, chain::plugin_exception, - "missed a block in ${name}.log", ("name", name)); + template + void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) { + auto block_num = chain::block_header::num_from_id(header.block_id); + EOS_ASSERT(_begin_block == _end_block || block_num <= _end_block, chain::plugin_exception, + "missed a block in ${name}.log", ("name", name)); - if (_begin_block != _end_block && block_num > _begin_block) { - if (block_num == _end_block) { - EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log", - ("name", name)); - } else { - state_history_log_header prev; - get_entry(block_num - 1, prev); - EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log", - ("name", name)); - } - } + if (_begin_block != _end_block && block_num > _begin_block) { + if (block_num == _end_block) { + EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log", + ("name", name)); + } else { + state_history_log_header prev; + get_entry(block_num - 1, prev); + EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log", + ("name", name)); + } + } - if (block_num < _end_block) - truncate(block_num); - log.seekg(0, std::ios_base::end); - uint64_t pos = log.tellp(); - write_header(header); - write_payload(log); - uint64_t end = log.tellp(); - EOS_ASSERT(end == pos + state_history_log_header_serial_size + header.payload_size, chain::plugin_exception, - "wrote payload with incorrect size to ${name}.log", ("name", name)); - log.write((char*)&pos, sizeof(pos)); + if (block_num < _end_block) + truncate(block_num); + log.seekg(0, std::ios_base::end); + uint64_t pos = log.tellp(); + write_header(header); + write_payload(log); + uint64_t end = log.tellp(); + EOS_ASSERT(end == pos + state_history_log_header_serial_size + header.payload_size, chain::plugin_exception, + "wrote payload with incorrect size to ${name}.log", ("name", name)); + log.write((char*)&pos, sizeof(pos)); - index.seekg(0, std::ios_base::end); - index.write((char*)&pos, sizeof(pos)); - if (_begin_block == _end_block) - _begin_block = block_num; - _end_block = block_num + 1; - last_block_id = header.block_id; - } + index.seekg(0, std::ios_base::end); + index.write((char*)&pos, sizeof(pos)); + if (_begin_block == _end_block) + _begin_block = block_num; + _end_block = block_num + 1; + last_block_id = header.block_id; + } - // returns stream positioned at payload + // returns cfile positioned at payload std::fstream& get_entry(uint32_t block_num, state_history_log_header& header) { EOS_ASSERT(block_num >= _begin_block && block_num < _end_block, chain::plugin_exception, "read non-existing block in ${name}.log", ("name", name)); @@ -130,163 +130,163 @@ class state_history_log { return log; } - chain::block_id_type get_block_id(uint32_t block_num) { - state_history_log_header header; - get_entry(block_num, header); - return header.block_id; - } + chain::block_id_type get_block_id(uint32_t block_num) { + state_history_log_header header; + get_entry(block_num, header); + return header.block_id; + } -private: - bool get_last_block(uint64_t size) { - state_history_log_header header; - uint64_t suffix; - log.seekg(size - sizeof(suffix)); - log.read((char*)&suffix, sizeof(suffix)); - if (suffix > size || suffix + state_history_log_header_serial_size > size) { - elog("corrupt ${name}.log (2)", ("name", name)); - return false; - } - log.seekg(suffix); - read_header(header, false); - if (!is_ship(header.magic) || !is_ship_supported_version(header.magic) || - suffix + state_history_log_header_serial_size + header.payload_size + sizeof(suffix) != size) { - elog("corrupt ${name}.log (3)", ("name", name)); - return false; - } - _end_block = chain::block_header::num_from_id(header.block_id) + 1; - last_block_id = header.block_id; - if (_begin_block >= _end_block) { - elog("corrupt ${name}.log (4)", ("name", name)); - return false; - } - return true; - } + private: + bool get_last_block(uint64_t size) { + state_history_log_header header; + uint64_t suffix; + log.seekg(size - sizeof(suffix)); + log.read((char*)&suffix, sizeof(suffix)); + if (suffix > size || suffix + state_history_log_header_serial_size > size) { + elog("corrupt ${name}.log (2)", ("name", name)); + return false; + } + log.seekg(suffix); + read_header(header, false); + if (!is_ship(header.magic) || !is_ship_supported_version(header.magic) || + suffix + state_history_log_header_serial_size + header.payload_size + sizeof(suffix) != size) { + elog("corrupt ${name}.log (3)", ("name", name)); + return false; + } + _end_block = chain::block_header::num_from_id(header.block_id) + 1; + last_block_id = header.block_id; + if (_begin_block >= _end_block) { + elog("corrupt ${name}.log (4)", ("name", name)); + return false; + } + return true; + } - void recover_blocks(uint64_t size) { - ilog("recover ${name}.log", ("name", name)); - uint64_t pos = 0; - uint32_t num_found = 0; - while (true) { - state_history_log_header header; - if (pos + state_history_log_header_serial_size > size) - break; - log.seekg(pos); - read_header(header, false); - uint64_t suffix; - if (!is_ship(header.magic) || !is_ship_supported_version(header.magic) || header.payload_size > size || - pos + state_history_log_header_serial_size + header.payload_size + sizeof(suffix) > size) { - EOS_ASSERT(!is_ship(header.magic) || is_ship_supported_version(header.magic), chain::plugin_exception, - "${name}.log has an unsupported version", ("name", name)); - break; - } - log.seekg(pos + sizeof(header) + header.payload_size); - log.read((char*)&suffix, sizeof(suffix)); - if (suffix != pos) - break; - pos = pos + state_history_log_header_serial_size + header.payload_size + sizeof(suffix); - if (!(++num_found % 10000)) { - printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); - fflush(stdout); - } - } - log.flush(); - boost::filesystem::resize_file(log_filename, pos); - log.flush(); - EOS_ASSERT(get_last_block(pos), chain::plugin_exception, "recover ${name}.log failed", ("name", name)); - } + void recover_blocks(uint64_t size) { + ilog("recover ${name}.log", ("name", name)); + uint64_t pos = 0; + uint32_t num_found = 0; + while (true) { + state_history_log_header header; + if (pos + state_history_log_header_serial_size > size) + break; + log.seekg(pos); + read_header(header, false); + uint64_t suffix; + if (!is_ship(header.magic) || !is_ship_supported_version(header.magic) || header.payload_size > size || + pos + state_history_log_header_serial_size + header.payload_size + sizeof(suffix) > size) { + EOS_ASSERT(!is_ship(header.magic) || is_ship_supported_version(header.magic), chain::plugin_exception, + "${name}.log has an unsupported version", ("name", name)); + break; + } + log.seekg(pos + state_history_log_header_serial_size + header.payload_size); + log.read((char*)&suffix, sizeof(suffix)); + if (suffix != pos) + break; + pos = pos + state_history_log_header_serial_size + header.payload_size + sizeof(suffix); + if (!(++num_found % 10000)) { + printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); + fflush(stdout); + } + } + log.flush(); + boost::filesystem::resize_file(log_filename, pos); + log.flush(); + EOS_ASSERT(get_last_block(pos), chain::plugin_exception, "recover ${name}.log failed", ("name", name)); + } - void open_log() { - log.open(log_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); - log.seekg(0, std::ios_base::end); - uint64_t size = log.tellp(); - if (size >= state_history_log_header_serial_size) { - state_history_log_header header; - log.seekg(0); - read_header(header, false); - EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic) && - state_history_log_header_serial_size + header.payload_size + sizeof(uint64_t) <= size, - chain::plugin_exception, "corrupt ${name}.log (1)", ("name", name)); - _begin_block = chain::block_header::num_from_id(header.block_id); - last_block_id = header.block_id; - if (!get_last_block(size)) - recover_blocks(size); - ilog("${name}.log has blocks ${b}-${e}", ("name", name)("b", _begin_block)("e", _end_block - 1)); - } else { - EOS_ASSERT(!size, chain::plugin_exception, "corrupt ${name}.log (5)", ("name", name)); - ilog("${name}.log is empty", ("name", name)); - } - } + void open_log() { + log.open(log_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); + log.seekg(0, std::ios_base::end); + uint64_t size = log.tellp(); + if (size >= state_history_log_header_serial_size) { + state_history_log_header header; + log.seekg(0); + read_header(header, false); + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic) && + state_history_log_header_serial_size + header.payload_size + sizeof(uint64_t) <= size, + chain::plugin_exception, "corrupt ${name}.log (1)", ("name", name)); + _begin_block = chain::block_header::num_from_id(header.block_id); + last_block_id = header.block_id; + if (!get_last_block(size)) + recover_blocks(size); + ilog("${name}.log has blocks ${b}-${e}", ("name", name)("b", _begin_block)("e", _end_block - 1)); + } else { + EOS_ASSERT(!size, chain::plugin_exception, "corrupt ${name}.log (5)", ("name", name)); + ilog("${name}.log is empty", ("name", name)); + } + } - void open_index() { - index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); - index.seekg(0, std::ios_base::end); - if (index.tellp() == (static_cast(_end_block) - _begin_block) * sizeof(uint64_t)) - return; - ilog("Regenerate ${name}.index", ("name", name)); - index.close(); - index.open( "w+b" ); // std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc + void open_index() { + index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); + index.seekg(0, std::ios_base::end); + if (index.tellp() == (static_cast(_end_block) - _begin_block) * sizeof(uint64_t)) + return; + ilog("Regenerate ${name}.index", ("name", name)); + index.close(); + index.open( "w+b" ); // std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc - log.seekg(0, std::ios_base::end); - uint64_t size = log.tellp(); - uint64_t pos = 0; - uint32_t num_found = 0; - while (pos < size) { - state_history_log_header header; - EOS_ASSERT(pos + state_history_log_header_serial_size <= size, chain::plugin_exception, - "corrupt ${name}.log (6)", ("name", name)); - log.seekg(pos); - read_header(header, false); - uint64_t suffix_pos = pos + state_history_log_header_serial_size + header.payload_size; - uint64_t suffix; - EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic) && - suffix_pos + sizeof(suffix) <= size, - chain::plugin_exception, "corrupt ${name}.log (7)", ("name", name)); - log.seekg(suffix_pos); - log.read((char*)&suffix, sizeof(suffix)); - // ilog("block ${b} at ${pos}-${end} suffix=${suffix} file_size=${fs}", - // ("b", header.block_num)("pos", pos)("end", suffix_pos + sizeof(suffix))("suffix", suffix)("fs", size)); - EOS_ASSERT(suffix == pos, chain::plugin_exception, "corrupt ${name}.log (8)", ("name", name)); + log.seekg(0, std::ios_base::end); + uint64_t size = log.tellp(); + uint64_t pos = 0; + uint32_t num_found = 0; + while (pos < size) { + state_history_log_header header; + EOS_ASSERT(pos + state_history_log_header_serial_size <= size, chain::plugin_exception, + "corrupt ${name}.log (6)", ("name", name)); + log.seekg(pos); + read_header(header, false); + uint64_t suffix_pos = pos + state_history_log_header_serial_size + header.payload_size; + uint64_t suffix; + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic) && + suffix_pos + sizeof(suffix) <= size, + chain::plugin_exception, "corrupt ${name}.log (7)", ("name", name)); + log.seekg(suffix_pos); + log.read((char*)&suffix, sizeof(suffix)); + // ilog("block ${b} at ${pos}-${end} suffix=${suffix} file_size=${fs}", + // ("b", header.block_num)("pos", pos)("end", suffix_pos + sizeof(suffix))("suffix", suffix)("fs", size)); + EOS_ASSERT(suffix == pos, chain::plugin_exception, "corrupt ${name}.log (8)", ("name", name)); - index.write((char*)&pos, sizeof(pos)); - pos = suffix_pos + sizeof(suffix); - if (!(++num_found % 10000)) { - printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); - fflush(stdout); - } - } - } + index.write((char*)&pos, sizeof(pos)); + pos = suffix_pos + sizeof(suffix); + if (!(++num_found % 10000)) { + printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); + fflush(stdout); + } + } + } - uint64_t get_pos(uint32_t block_num) { - uint64_t pos; - index.seekg((block_num - _begin_block) * sizeof(pos)); - index.read((char*)&pos, sizeof(pos)); - return pos; - } + uint64_t get_pos(uint32_t block_num) { + uint64_t pos; + index.seekg((block_num - _begin_block) * sizeof(pos)); + index.read((char*)&pos, sizeof(pos)); + return pos; + } - void truncate(uint32_t block_num) { - log.flush(); - index.flush(); - uint64_t num_removed = 0; - if (block_num <= _begin_block) { - num_removed = _end_block - _begin_block; - log.seekg(0); - index.seekg(0); - boost::filesystem::resize_file(log_filename, 0); - boost::filesystem::resize_file(index_filename, 0); - _begin_block = _end_block = 0; - } else { - num_removed = _end_block - block_num; - uint64_t pos = get_pos(block_num); - log.seekg(0); - index.seekg(0); - boost::filesystem::resize_file(log_filename, pos); - boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(uint64_t)); - _end_block = block_num; - } - log.flush(); - index.flush(); - ilog("fork or replay: removed ${n} blocks from ${name}.log", ("n", num_removed)("name", name)); - } + void truncate(uint32_t block_num) { + log.flush(); + index.flush(); + uint64_t num_removed = 0; + if (block_num <= _begin_block) { + num_removed = _end_block - _begin_block; + log.seekg(0); + index.seekg(0); + boost::filesystem::resize_file(log_filename, 0); + boost::filesystem::resize_file(index_filename, 0); + _begin_block = _end_block = 0; + } else { + num_removed = _end_block - block_num; + uint64_t pos = get_pos(block_num); + log.seekg(0); + index.seekg(0); + boost::filesystem::resize_file(log_filename, pos); + boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(uint64_t)); + _end_block = block_num; + } + log.flush(); + index.flush(); + ilog("fork or replay: removed ${n} blocks from ${name}.log", ("n", num_removed)("name", name)); + } }; // state_history_log } // namespace eosio diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp index 2304a7da1e0..b91d0afc5ca 100644 --- a/plugins/state_history_plugin/state_history_plugin.cpp +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -427,14 +427,14 @@ struct state_history_plugin_impl : std::enable_shared_from_thisreceipt && trace_log) { if (is_onblock(p)) - onblock_trace = p; + onblock_trace.emplace(p, t); else if (p->failed_dtrx_trace) - cached_traces[p->failed_dtrx_trace->id] = p; + cached_traces[p->failed_dtrx_trace->id] = augmented_transaction_trace{p, t}; else - cached_traces[p->id] = p; + cached_traces[p->id] = augmented_transaction_trace{p, t}; } } @@ -614,7 +614,9 @@ void state_history_plugin::plugin_initialize(const variables_map& options) { EOS_ASSERT(my->chain_plug, chain::missing_chain_plugin_exception, ""); auto& chain = my->chain_plug->chain(); my->applied_transaction_connection.emplace( - chain.applied_transaction.connect([&](const transaction_trace_ptr& p) { my->on_applied_transaction(p); })); + chain.applied_transaction.connect([&](std::tuple t) { + my->on_applied_transaction(std::get<0>(t), std::get<1>(t)); + })); my->accepted_block_connection.emplace( chain.accepted_block.connect([&](const block_state_ptr& p) { my->on_accepted_block(p); })); diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 37d2301f5c6..c42457a8c26 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -1076,8 +1076,10 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { { produce_blocks(10); transaction_trace_ptr trace; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->receipt && t->receipt->status != transaction_receipt::executed) { trace = t; } } ); - + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->receipt && t->receipt->status != transaction_receipt::executed) { trace = t; } + } ); // test error handling on deferred transaction failure CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction_trigger_error_handler", {}); @@ -1120,7 +1122,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { //schedule { transaction_trace_ptr trace; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } ); + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t->scheduled) { trace = t; } + } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {} ); BOOST_CHECK(!trace); produce_block( fc::seconds(2) ); @@ -1140,7 +1145,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { { transaction_trace_ptr trace; uint32_t count = 0; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->scheduled) { trace = t; ++count; } } ); + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->scheduled) { trace = t; ++count; } + } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {}); BOOST_CHECK_THROW(CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {}), deferred_tx_duplicate); produce_blocks( 3 ); @@ -1165,7 +1173,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { { transaction_trace_ptr trace; uint32_t count = 0; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->scheduled) { trace = t; ++count; } } ); + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->scheduled) { trace = t; ++count; } + } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction_replace", {}); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction_replace", {}); produce_blocks( 3 ); @@ -1188,7 +1199,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { //schedule and cancel { transaction_trace_ptr trace; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->scheduled) { trace = t; } } ); + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->scheduled) { trace = t; } + } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {}); CALL_TEST_FUNCTION(*this, "test_transaction", "cancel_deferred_transaction_success", {}); produce_block( fc::seconds(2) ); @@ -1208,7 +1222,8 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { //repeated deferred transactions { vector traces; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); if (t && t->scheduled) { traces.push_back( t ); } diff --git a/unittests/whitelist_blacklist_tests.cpp b/unittests/whitelist_blacklist_tests.cpp index efd2bf50b1d..db6a433b7bf 100644 --- a/unittests/whitelist_blacklist_tests.cpp +++ b/unittests/whitelist_blacklist_tests.cpp @@ -499,7 +499,8 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { tester2.chain->push_block( b ); } - auto log_trxs = [&]( const transaction_trace_ptr& t) { + auto log_trxs = [&](std::tuple x) { + auto& t = std::get<0>(x); if( !t || t->action_traces.size() == 0 ) return; const auto& act = t->action_traces[0].act; From 6f91e2cf29f2a0071e481e79837d67dabac7efc6 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 5 Jun 2020 17:41:01 +0800 Subject: [PATCH 18/25] fix: exclude invalid cert; shuffle view changes before generation; add debug functions in pbft api plugin --- .../include/eosio/chain/pbft_database.hpp | 2 +- libraries/chain/pbft_database.cpp | 25 +++-- plugins/pbft_api_plugin/README.md | 21 ++++ plugins/pbft_api_plugin/pbft_api_plugin.cpp | 3 + .../include/eosio/pbft_plugin/pbft_plugin.hpp | 6 +- plugins/pbft_plugin/pbft_plugin.cpp | 99 +++++++++++++++++-- 6 files changed, 137 insertions(+), 19 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index fd38f9e9330..3e200b4da38 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -519,6 +519,7 @@ namespace eosio { vector get_pbft_watermarks() const; flat_map get_pbft_fork_schedules() const; + producer_schedule_type lscb_active_producers() const; private: controller& ctrl; pbft_state_multi_index_type pbft_state_index; @@ -537,7 +538,6 @@ namespace eosio { bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false, bool at_the_top = false); bool is_valid_longest_fork(const vector& producers, const block_info_type& cert_info, bool at_the_top = false); - producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); flat_map& get_updated_fork_schedules(); block_num_type get_current_pbft_watermark(); diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index c8ebab42447..891c160bd36 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace eosio { namespace chain { @@ -597,19 +598,29 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); - for (const auto& vc: vcc.view_changes) { - if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num()) { - highest_ppc = vc.prepared_cert; + // shuffle view changes to avoid fixed orders. + std::vector idx_v(vcc.view_changes.size()) ; + std::iota (std::begin(idx_v), std::end(idx_v), 0); + auto seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::shuffle( idx_v.begin(), idx_v.end(), std::default_random_engine(seed)); + for (const auto i: idx_v) { + auto& prepared_cert = vcc.view_changes[i].prepared_cert; + auto& committed_certs = vcc.view_changes[i].committed_certs; + auto& stable_ckpts = vcc.view_changes[i].stable_checkpoint; + if (prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() + && is_valid_prepared_certificate(prepared_cert)) { + highest_ppc = prepared_cert; } - for (const auto& cc: vc.committed_certs) { + for (const auto& cc:committed_certs ) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); - if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); + if (p_itr == highest_pcc.end() && is_valid_committed_certificate(cc)) highest_pcc.emplace_back(cc); } - if (vc.stable_checkpoint.block_info.block_num() > highest_sc.block_info.block_num()) { - highest_sc = vc.stable_checkpoint; + if (stable_ckpts.block_info.block_num() > highest_sc.block_info.block_num() + && is_valid_stable_checkpoint(stable_ckpts)) { + highest_sc = stable_ckpts; } } diff --git a/plugins/pbft_api_plugin/README.md b/plugins/pbft_api_plugin/README.md index 54d3552089a..e94bcea1e9d 100644 --- a/plugins/pbft_api_plugin/README.md +++ b/plugins/pbft_api_plugin/README.md @@ -84,4 +84,25 @@ ``` curl --request POST --data uint32_t --url http://localhost:8888/v1/pbft/set_pbft_current_view + ``` +* **get_view_change_missing_bps** + + -- To get missing bp names of a given pbft view on my node, empty will be returned if all have been collected or not in view change state + + ``` + curl --request POST --data uint32_t --url http://localhost:8888/v1/pbft/get_view_change_missing_bps + ``` +* **get_prepare_missing_bps** + + -- To get missing bp names of prepare messages of a given block id at the highest view on my node, empty will be returned if all have been collected or the block id is unreachable + + ``` + curl --request POST --data string --url http://localhost:8888/v1/pbft/get_prepare_missing_bps + ``` +* **get_commit_missing_bps** + + -- To get missing bp names of commit messages of a given block id at the highest view on my node, empty will be returned if all have been collected or the block id is unreachable + + ``` + curl --request POST --data string --url http://localhost:8888/v1/pbft/get_commit_missing_bps ``` \ No newline at end of file diff --git a/plugins/pbft_api_plugin/pbft_api_plugin.cpp b/plugins/pbft_api_plugin/pbft_api_plugin.cpp index 33fcd7b8654..321761165f6 100644 --- a/plugins/pbft_api_plugin/pbft_api_plugin.cpp +++ b/plugins/pbft_api_plugin/pbft_api_plugin.cpp @@ -59,6 +59,9 @@ void pbft_api_plugin::plugin_startup() { CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), CALL(pbft, pbft, get_pbft_prepared_id, INVOKE_R(pbft, get_pbft_prepared_id), 200), CALL(pbft, pbft, get_pbft_my_prepare_id, INVOKE_R(pbft, get_pbft_my_prepare_id), 200), + CALL(pbft, pbft, get_view_change_missing_bps, INVOKE_R_P(pbft, get_view_change_missing_bps, pbft_view_type), 200), + CALL(pbft, pbft, get_prepare_missing_bps, INVOKE_R_P(pbft, get_prepare_missing_bps, block_id_type), 200), + CALL(pbft, pbft, get_commit_missing_bps, INVOKE_R_P(pbft, get_commit_missing_bps, block_id_type), 200), CALL(pbft, pbft, set_pbft_current_view, INVOKE_W_P(pbft, set_pbft_current_view, pbft_view_type), 201), }); } diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index 726e4d43591..bb449bf0d85 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace eosio { @@ -33,12 +34,15 @@ class pbft_plugin : public appbase::plugin { const char* get_pbft_status()const; block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; - + vector get_view_change_missing_bps(pbft_view_type view)const; + vector get_prepare_missing_bps(const block_id_type& bid)const; + vector get_commit_missing_bps(const block_id_type& bid)const; void set_pbft_current_view(pbft_view_type view); private: std::unique_ptr my; + chain_plugin* chain_plug = nullptr; }; } diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 7d27f1607bd..4790dd2b3a4 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -51,6 +51,7 @@ namespace eosio { bool is_replaying(); bool is_syncing(); bool pbft_ready(); + bool is_production_paused(); }; void pbft_plugin_impl::on_committed_transition() { @@ -142,6 +143,10 @@ namespace eosio { return app().get_plugin().is_syncing(); } + bool pbft_plugin_impl::is_production_paused() { + return app().get_plugin().paused(); + } + bool pbft_plugin_impl::pbft_ready() { // only trigger pbft related logic if I am in sync and replayed. @@ -162,7 +167,7 @@ namespace eosio { upgraded = true; } - return enabled && !is_syncing() && !is_replaying(); + return enabled && !is_syncing() && !is_replaying() && !is_production_paused(); } pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} @@ -178,6 +183,7 @@ namespace eosio { my->commit_timer = std::make_unique(app().get_io_service()); my->view_change_timer = std::make_unique(app().get_io_service()); my->checkpoint_timer = std::make_unique(app().get_io_service()); + chain_plug = app().find_plugin(); } void pbft_plugin::plugin_startup() { @@ -198,53 +204,126 @@ namespace eosio { void pbft_plugin::plugin_shutdown() {} pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); if (record) return *record; return pbft_state(); } vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); if (!records.empty()) return records; return vector(); } pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); if (record) return *record; return pbft_view_change_state(); } vector pbft_plugin::get_watermarks() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); return pbft_ctrl.pbft_db.get_pbft_watermarks(); } flat_map pbft_plugin::get_fork_schedules() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); } const char* pbft_plugin::get_pbft_status() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); return pbft_ctrl.state_machine.get_current()->get_name(); } block_id_type pbft_plugin::get_pbft_prepared_id() const { - auto& ctrl = app().get_plugin().chain(); + auto& ctrl = chain_plug->chain(); return ctrl.get_pbft_prepared(); } block_id_type pbft_plugin::get_pbft_my_prepare_id() const { - auto& ctrl = app().get_plugin().chain(); + auto& ctrl = chain_plug->chain(); return ctrl.get_pbft_my_prepare(); } + vector pbft_plugin::get_view_change_missing_bps(pbft_view_type view) const { + auto& pbft_ctrl = chain_plug->pbft_ctrl(); + auto missing_bps = vector{}; + auto records = get_view_change_record(view); + if (!records.view_changes.empty() && !records.is_view_changed) { + auto lscb_bps = pbft_ctrl.pbft_db.lscb_active_producers().producers; + missing_bps.reserve(lscb_bps.size()); + for (const auto& bp: lscb_bps) { + auto found = false; + for (const auto& v: records.view_changes) { + if (bp.block_signing_key == v.first) found = true; + } + if (!found) missing_bps.emplace_back(bp); + } + } + return missing_bps; + } + + vector pbft_plugin::get_prepare_missing_bps(const block_id_type& bid) const { + auto& ctrl = chain_plug->chain(); + auto missing_bps = vector{}; + auto blk = ctrl.fetch_block_state_by_id(bid); + if (blk) { + auto records = get_pbft_record(bid); + if (!records.prepares.empty() && !records.is_prepared) { + pbft_view_type highest_view; + for (const auto &p: records.prepares) { + if (p.first.first > highest_view) highest_view = p.first.first; + } + auto active_bps = blk->active_schedule.producers;; + missing_bps.reserve(active_bps.size()); + for (const auto &bp: active_bps) { + auto found = false; + for (const auto &p: records.prepares) { + if (p.first.first == highest_view && bp.block_signing_key == p.first.second) { + found = true; + } + } + if (!found) missing_bps.emplace_back(bp); + } + } + + } + return missing_bps; + } + + vector pbft_plugin::get_commit_missing_bps(const block_id_type& bid) const { + auto& ctrl = chain_plug->chain(); + auto missing_bps = vector{}; + auto blk = ctrl.fetch_block_state_by_id(bid); + if (blk) { + auto records = get_pbft_record(bid); + if (!records.commits.empty() && !records.is_committed) { + pbft_view_type highest_view; + for (const auto &p: records.commits) { + if (p.first.first > highest_view) highest_view = p.first.first; + } + auto active_bps = blk->active_schedule.producers;; + missing_bps.reserve(active_bps.size()); + for (const auto &bp: active_bps) { + auto found = false; + for (const auto &c: records.commits) { + if (c.first.first == highest_view && bp.block_signing_key == c.first.second) { + found = true; + } + } + if (!found) missing_bps.emplace_back(bp); + } + } + } + return missing_bps; + } + void pbft_plugin::set_pbft_current_view(pbft_view_type view) { + auto& pbft_ctrl = chain_plug->pbft_ctrl(); //this is used to boost the recovery from a disaster, do not set this unless you have to do so. - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.state_machine.manually_set_current_view(view); } } From 7d5a128839bb1ea2579177a369faa328dab2eb36 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Sat, 6 Jun 2020 15:02:19 +0800 Subject: [PATCH 19/25] Fix: state history get block from forkdb null --- libraries/chain/controller.cpp | 24 +++++++++++++++++++ libraries/chain/fork_database.cpp | 9 +++++++ .../chain/include/eosio/chain/controller.hpp | 2 ++ .../include/eosio/chain/fork_database.hpp | 1 + .../eosio/chain/reversible_block_object.hpp | 9 +++++++ .../state_history_plugin.cpp | 4 ++-- 6 files changed, 47 insertions(+), 2 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 1f265a0cb9d..107b83a725f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2482,6 +2482,15 @@ signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const { return my->blog.read_block_by_num(block_num); } FC_CAPTURE_AND_RETHROW( (block_num) ) } +signed_block_ptr controller::fetch_block_by_number_state_history( uint32_t block_num )const { try { + auto blk_state = fetch_block_state_by_number_state_history( block_num ); + if( blk_state ) { + return blk_state->block; + } + + return my->blog.read_block_by_num(block_num); +} FC_CAPTURE_AND_RETHROW( (block_num) ) } + block_state_ptr controller::fetch_block_state_by_id( block_id_type id )const { auto state = my->fork_db.get_block(id); return state; @@ -2492,6 +2501,21 @@ block_state_ptr controller::fetch_block_state_by_number( uint32_t block_num )con return blk_state; } FC_CAPTURE_AND_RETHROW( (block_num) ) } +block_state_ptr controller::fetch_block_state_by_number_state_history( uint32_t block_num )const { try { + const auto& rev_blocks = my->reversible_blocks.get_index(); + auto objitr = rev_blocks.find(block_num); + + if( objitr == rev_blocks.end() ) { + if( my->read_mode == db_read_mode::IRREVERSIBLE ) { + return my->fork_db.search_on_branch( my->pending->_pending_block_state->id, block_num ); + } else { + return block_state_ptr(); + } + } + + return my->fork_db.get_block( objitr->get_block_id() ); +} FC_CAPTURE_AND_RETHROW( (block_num) ) } + block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try { auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num ); if( blk_state ) { diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index be36a908895..6343caf2829 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -293,6 +293,15 @@ namespace eosio { namespace chain { return result; } /// fetch_branch_from + block_state_ptr fork_database::search_on_branch( const block_id_type& h, uint32_t block_num )const { + for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) { + if( s->block_num == block_num ) + return s; + } + + return {}; + } + /// remove all of the invalid forks built of this id including this id void fork_database::remove( const block_id_type& id ) { vector remove_queue{id}; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index c22f3457e1b..590a019877c 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -233,9 +233,11 @@ namespace eosio { namespace chain { block_id_type last_irreversible_block_id() const; signed_block_ptr fetch_block_by_number( uint32_t block_num )const; + signed_block_ptr fetch_block_by_number_state_history( uint32_t block_num )const; signed_block_ptr fetch_block_by_id( block_id_type id )const; block_state_ptr fetch_block_state_by_number( uint32_t block_num )const; + block_state_ptr fetch_block_state_by_number_state_history( uint32_t block_num )const; block_state_ptr fetch_block_state_by_id( block_id_type id )const; block_id_type get_block_id_for_num( uint32_t block_num )const; diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 9dfb3f0cc9c..a10c4542588 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -55,6 +55,7 @@ namespace eosio { namespace chain { pair< branch_type, branch_type > fetch_branch_from( const block_id_type& first, const block_id_type& second )const; + block_state_ptr search_on_branch( const block_id_type& h, uint32_t block_num )const; /** * If the block is invalid, it will be removed. If it is valid, then blocks older diff --git a/libraries/chain/include/eosio/chain/reversible_block_object.hpp b/libraries/chain/include/eosio/chain/reversible_block_object.hpp index ea9a4c9e122..daaac00a71b 100644 --- a/libraries/chain/include/eosio/chain/reversible_block_object.hpp +++ b/libraries/chain/include/eosio/chain/reversible_block_object.hpp @@ -32,6 +32,15 @@ namespace eosio { namespace chain { fc::raw::unpack( ds, *result ); return result; } + + block_id_type get_block_id()const { + fc::datastream ds( packedblock.data(), packedblock.size() ); + block_header h; + fc::raw::unpack( ds, h ); + // Only need the block id to then look up the block state in fork database, so just unpack the block_header from the stored packed data. + // Avoid calling get_block() since that constructs a new signed_block in heap memory and unpacks the full signed_block from the stored packed data. + return h.id(); + } }; struct by_num; diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp index b91d0afc5ca..61794edfac7 100644 --- a/plugins/state_history_plugin/state_history_plugin.cpp +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -147,7 +147,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this& result) { chain::signed_block_ptr p; try { - p = chain_plug->chain().fetch_block_by_number(block_num); + p = chain_plug->chain().fetch_block_by_number_state_history(block_num); } catch (...) { return; } @@ -161,7 +161,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this= chain_state_log->begin_block() && block_num < chain_state_log->end_block()) return chain_state_log->get_block_id(block_num); try { - auto block = chain_plug->chain().fetch_block_by_number(block_num); + auto block = chain_plug->chain().fetch_block_by_number_state_history(block_num); if (block) return block->id(); } catch (...) { From 064a9891dbef75366d9df32bc3444645f42aea5c Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Sat, 6 Jun 2020 15:46:39 +0800 Subject: [PATCH 20/25] reset docker file --- Docker/Dockerfile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 7f91e91b12c..32c238e30f2 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -1,11 +1,11 @@ FROM boscore/builder:v2.0.6 as builder -ARG branch=statehistoryplugin +ARG branch=master ARG symbol=EOS ENV OPENSSL_ROOT_DIR /usr/include/openssl -RUN git clone -b $branch https://github.com/eosiosg/eos.git --recursive \ - && cd eos && echo "$branch:$(git rev-parse HEAD)" > /etc/eoscore-version \ +RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ + && cd bos && echo "$branch:$(git rev-parse HEAD)" > /etc/boscore-version \ && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" -DENABLE_TOOLS=OFF \ @@ -16,9 +16,9 @@ FROM ubuntu:18.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl ca-certificates iproute2 && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/lib/* /usr/local/lib/ COPY --from=builder /tmp/build/bin /opt/eosio/bin -COPY --from=builder /eos/Docker/config.ini / -COPY --from=builder /etc/eoscore-version /etc -COPY --from=builder /eos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh +COPY --from=builder /bos/Docker/config.ini / +COPY --from=builder /etc/boscore-version /etc +COPY --from=builder /bos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh ENV EOSIO_ROOT=/opt/eosio RUN chmod +x /opt/eosio/bin/nodeosd.sh ENV LD_LIBRARY_PATH /usr/local/lib From 353d3116d4f931580cc86f4ce6f8184eec4fed09 Mon Sep 17 00:00:00 2001 From: Thaipanda Date: Sat, 6 Jun 2020 20:03:40 +0800 Subject: [PATCH 21/25] prepare v3.0.8 --- CMakeLists.txt | 2 +- Docker/README.md | 4 ++-- README.md | 4 ++-- README_CN.md | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fd82178bd72..c20d9d03540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 3) set(VERSION_MINOR 0) -set(VERSION_PATCH 7) +set(VERSION_PATCH 8) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/Docker/README.md b/Docker/README.md index a775ee257ec..be937e39857 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.7 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.8 tag, you could do the following: ```bash -docker build -t boscore/bos:v3.0.7 --build-arg branch=v3.0.7 . +docker build -t boscore/bos:v3.0.8 --build-arg branch=v3.0.8 . ``` diff --git a/README.md b/README.md index d669170b8b5..90fa46654ef 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # BOSCore - Blockchain financial center building a trusted business ecosystem. -## BOSCore Version: v3.0.7 -### Basic EOSIO Version: v1.6.6 (support REX & EOSVM, part 2.0.x) +## BOSCore Version: v3.0.8 +### Basic EOSIO Version: v2.0 (support REX & EOSVM, llvm v90) # Background The emergence of EOS has brought new imagination to the blockchain. In just a few months since the main network was launched, the version has undergone dozens of upgrades, not only the stability has been greatly improved, but also the new functions have been gradually realized. The node team is also actively involved in building the EOSIO ecosystem. What is even more exciting is that EOS has attracted more and more development teams. There are already hundreds of DApp running on the EOS main network. The transaction volume and circulation market value far exceed Ethereum, and the space for development is growing broader. diff --git a/README_CN.md b/README_CN.md index d5541436351..acad87eeda2 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,7 +1,7 @@ # BOSCore - 区块链自由港,构建可信商业生态。 -## BOSCore Version: v3.0.7 -### Basic EOSIO Version: v1.6.6 (support REX & EOSVM, part 2.0.x) +## BOSCore Version: v3.0.8 +### Basic EOSIO Version: v2.0 (support REX & EOSVM, llvm v90) # 背景 EOS的出现给区块链带来了新的想象力,主网启动短短几个月以来,版本经历了几十次升级,不仅稳定性得到了很大提高,并且新功能也逐步实现,各个节点团队也积极参与建设EOSIO生态。让人更加兴奋的是,EOS已经吸引了越来越多的开发团队,当前已经有数百个DApp在EOS主网上面运行,其交易量和流通市值远超以太坊,可发展的空间愈来愈广阔。 From fba85800931a80f61312d5e1a2179abff4e720f3 Mon Sep 17 00:00:00 2001 From: thaipanda <45444502+Thaipanda@users.noreply.github.com> Date: Sat, 6 Jun 2020 21:01:07 +0800 Subject: [PATCH 22/25] merge v3.0.8 into develop branch (#169) * check llvm version >= 7 and install automatically * Remove bytes in flight * Upgrade: name apply context transaction context and plugins * FIX: unittests * fix a potential crash in fetching lib. * emit lib in ascending order. * fix a potential crash in fetching lib. * emit lib in ascending order. * Change abi-serializer-max-time-us to abi-serializer-max-time-ms * Fix: TODO * Fix: mongodb plugin * Fix: cleos name issue * Fix: tests * Add back get block detail in history plugin * update connected lib channels of plugins * Fix: state history plugin issues * Change: applied transaction channel for statehistory plugin * fix: exclude invalid cert; shuffle view changes before generation; add debug functions in pbft api plugin * Fix: state history get block from forkdb null * reset docker file * prepare v3.0.8 Co-authored-by: Frank-AFN Co-authored-by: oldcold --- CMakeLists.txt | 6 +- Docker/README.md | 4 +- README.md | 4 +- README_CN.md | 4 +- eosio_build.sh | 16 +- libraries/chain/CMakeLists.txt | 1 + libraries/chain/apply_context.cpp | 212 ++++--- libraries/chain/authorization_manager.cpp | 2 +- libraries/chain/controller.cpp | 61 +- libraries/chain/eosio_contract.cpp | 25 +- libraries/chain/fork_database.cpp | 9 + .../include/eosio/chain/abi_serializer.hpp | 1 - .../include/eosio/chain/apply_context.hpp | 103 ++- .../chain/include/eosio/chain/config.hpp | 31 +- .../eosio/chain/contract_table_objects.hpp | 20 +- .../chain/include/eosio/chain/controller.hpp | 5 +- .../chain/include/eosio/chain/exceptions.hpp | 46 +- .../include/eosio/chain/fork_database.hpp | 1 + libraries/chain/include/eosio/chain/name.hpp | 122 ++-- .../include/eosio/chain/pbft_database.hpp | 2 +- .../eosio/chain/reversible_block_object.hpp | 9 + libraries/chain/include/eosio/chain/trace.hpp | 65 +- .../eosio/chain/transaction_context.hpp | 79 +-- .../include/eosio/chain/webassembly/wabt.hpp | 2 +- .../include/eosio/chain/webassembly/wavm.hpp | 596 ------------------ libraries/chain/name.cpp | 24 +- libraries/chain/pbft_database.cpp | 25 +- libraries/chain/trace.cpp | 37 ++ libraries/chain/transaction_context.cpp | 377 ++++++----- libraries/chain/wasm_interface.cpp | 3 +- .../testing/include/eosio/testing/tester.hpp | 8 +- libraries/testing/tester.cpp | 10 +- plugins/chain_plugin/chain_plugin.cpp | 71 ++- .../eosio/chain_plugin/chain_plugin.hpp | 13 +- .../history_api_plugin/history_api_plugin.cpp | 1 - plugins/history_plugin/history_plugin.cpp | 79 ++- plugins/http_plugin/http_plugin.cpp | 7 +- plugins/kafka_plugin/kafka.cpp | 20 +- plugins/kafka_plugin/kafka_plugin.cpp | 6 +- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 34 +- plugins/notify_plugin/notify_plugin.cpp | 22 +- plugins/pbft_api_plugin/README.md | 21 + plugins/pbft_api_plugin/pbft_api_plugin.cpp | 3 + .../include/eosio/pbft_plugin/pbft_plugin.hpp | 6 +- plugins/pbft_plugin/pbft_plugin.cpp | 99 ++- plugins/producer_plugin/producer_plugin.cpp | 12 +- .../state_history_log.hpp | 179 +++--- .../state_history_plugin.hpp | 47 ++ .../state_history_serialization.hpp | 284 ++++++--- .../state_history_plugin.cpp | 148 +++-- .../state_history_plugin_abi.cpp | 59 +- .../txn_test_gen_plugin.cpp | 18 +- programs/cleos/main.cpp | 257 ++++---- scripts/eosio_build_amazon.sh | 20 +- scripts/eosio_build_centos.sh | 22 +- scripts/eosio_build_fedora.sh | 20 +- scripts/eosio_build_ubuntu.sh | 23 +- tests/Cluster.py | 2 +- tests/chain_plugin_tests.cpp | 2 +- tests/get_table_tests.cpp | 66 +- unittests/abi_tests.cpp | 96 +-- unittests/api_tests.cpp | 296 ++++----- unittests/auth_tests.cpp | 235 +++---- unittests/bootseq_tests.cpp | 48 +- unittests/database_gmr_blklst_tests.cpp | 4 +- unittests/database_tests.cpp | 6 +- unittests/eosio_system_tester.hpp | 24 +- unittests/forked_tests.cpp | 35 +- unittests/misc_tests.cpp | 167 ++--- unittests/pbft_tests.cpp | 2 +- unittests/ram_tests.cpp | 2 +- unittests/special_accounts_tests.cpp | 18 +- unittests/wasm_tests.cpp | 36 +- unittests/whitelist_blacklist_tests.cpp | 21 +- 74 files changed, 2200 insertions(+), 2241 deletions(-) create mode 100644 libraries/chain/trace.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c6b16e4958c..c20d9d03540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 3) set(VERSION_MINOR 0) -set(VERSION_PATCH 7) +set(VERSION_PATCH 8) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") @@ -55,8 +55,8 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") add_compile_options(-fdiagnostics-color=always) endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) - message(FATAL_ERROR "Clang version must be at least 6.0!") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) + message(FATAL_ERROR "Clang version must be at least 7.0!") endif() endif() diff --git a/Docker/README.md b/Docker/README.md index a775ee257ec..be937e39857 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.7 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.8 tag, you could do the following: ```bash -docker build -t boscore/bos:v3.0.7 --build-arg branch=v3.0.7 . +docker build -t boscore/bos:v3.0.8 --build-arg branch=v3.0.8 . ``` diff --git a/README.md b/README.md index d669170b8b5..90fa46654ef 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # BOSCore - Blockchain financial center building a trusted business ecosystem. -## BOSCore Version: v3.0.7 -### Basic EOSIO Version: v1.6.6 (support REX & EOSVM, part 2.0.x) +## BOSCore Version: v3.0.8 +### Basic EOSIO Version: v2.0 (support REX & EOSVM, llvm v90) # Background The emergence of EOS has brought new imagination to the blockchain. In just a few months since the main network was launched, the version has undergone dozens of upgrades, not only the stability has been greatly improved, but also the new functions have been gradually realized. The node team is also actively involved in building the EOSIO ecosystem. What is even more exciting is that EOS has attracted more and more development teams. There are already hundreds of DApp running on the EOS main network. The transaction volume and circulation market value far exceed Ethereum, and the space for development is growing broader. diff --git a/README_CN.md b/README_CN.md index d5541436351..acad87eeda2 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,7 +1,7 @@ # BOSCore - 区块链自由港,构建可信商业生态。 -## BOSCore Version: v3.0.7 -### Basic EOSIO Version: v1.6.6 (support REX & EOSVM, part 2.0.x) +## BOSCore Version: v3.0.8 +### Basic EOSIO Version: v2.0 (support REX & EOSVM, llvm v90) # 背景 EOS的出现给区块链带来了新的想象力,主网启动短短几个月以来,版本经历了几十次升级,不仅稳定性得到了很大提高,并且新功能也逐步实现,各个节点团队也积极参与建设EOSIO生态。让人更加兴奋的是,EOS已经吸引了越来越多的开发团队,当前已经有数百个DApp在EOS主网上面运行,其交易量和流通市值远超以太坊,可发展的空间愈来愈广阔。 diff --git a/eosio_build.sh b/eosio_build.sh index 3db66b5e66b..7969c261cac 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -63,7 +63,7 @@ fi START_MAKE=true TIME_BEGIN=$( date -u +%s ) - VERSION=1.2 + VERSION=3.0.7 txtbld=$(tput bold) bldred=${txtbld}$(tput setaf 1) @@ -174,7 +174,7 @@ MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm export CMAKE=${HOME}/opt/cmake/bin/cmake - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "CentOS Linux") FILE="${SOURCE_DIR}/scripts/eosio_build_centos.sh" @@ -183,14 +183,14 @@ MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm export CMAKE=${HOME}/opt/cmake/bin/cmake - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "elementary OS") FILE="${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh" CXX_COMPILER=clang++ C_COMPILER=clang MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "Fedora") FILE="${SOURCE_DIR}/scripts/eosio_build_fedora.sh" @@ -204,21 +204,21 @@ CXX_COMPILER=clang++ C_COMPILER=clang MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "Ubuntu") FILE="${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh" CXX_COMPILER=clang++ C_COMPILER=clang MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; "Debian GNU/Linux") FILE=${SOURCE_DIR}/scripts/eosio_build_ubuntu.sh CXX_COMPILER=clang++ C_COMPILER=clang MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf - export PATH=${HOME}/opt/mongodb/bin:$PATH + export PATH=${HOME}/opt/mongodb/bin:${HOME}/opt/wasm/bin:$PATH ;; *) printf "\\n\\tUnsupported Linux Distribution. Exiting now.\\n\\n" @@ -274,7 +274,7 @@ -DENABLE_COVERAGE_TESTING="${ENABLE_COVERAGE_TESTING}" -DBUILD_DOXYGEN="${DOXYGEN}" \ -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ -DCMAKE_INSTALL_PREFIX="/usr/local/eosio" ${LOCAL_CMAKE_FLAGS} "${SOURCE_DIR}" \ - -DENABLE_TOOLS=OFF + -DENABLE_TOOLS=OFF then printf "\\n\\t>>>>>>>>>>>>>>>>>>>> CMAKE building BOSCore has exited with the above error.\\n\\n" exit -1 diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 4ab7dceebee..dbd7de4985b 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -95,6 +95,7 @@ add_library( eosio_chain # global_property_object.cpp # # contracts/chain_initializer.cpp + trace.cpp protocol_state_object.cpp genesis_intrinsics.cpp whitelisted_intrinsics.cpp diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 5a35eafd29a..679e4149032 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -30,21 +30,32 @@ static inline void print_debug(account_name receiver, const action_trace& ar) { } } -void apply_context::exec_one( action_trace& trace ) +apply_context::apply_context(controller& con, transaction_context& trx_ctx, uint32_t action_ordinal, uint32_t depth) +:control(con) +,db(con.mutable_db()) +,trx_context(trx_ctx) +,recurse_depth(depth) +,first_receiver_action_ordinal(action_ordinal) +,action_ordinal(action_ordinal) +,idx64(*this) +,idx128(*this) +,idx256(*this) +,idx_double(*this) +,idx_long_double(*this) +{ + action_trace& trace = trx_ctx.get_action_trace(action_ordinal); + act = &trace.act; + receiver = trace.receiver; + context_free = trace.context_free; +} + +void apply_context::exec_one() { auto start = fc::time_point::now(); action_receipt r; r.receiver = receiver; - r.act_digest = digest_type::hash(act); - - trace.trx_id = trx_context.id; - trace.block_num = control.pending_block_state()->block_num; - trace.block_time = control.pending_block_time(); - trace.producer_block_id = control.pending_producer_block_id(); - trace.act = act; - trace.context_free = context_free; - + r.act_digest = digest_type::hash(*act); const auto& p = control.get_dynamic_global_properties(); global_action_sequence = p.global_action_sequence + 1; @@ -53,56 +64,67 @@ void apply_context::exec_one( action_trace& trace ) try { try { receiver_account = &db.get( receiver ); - privileged = receiver_account->is_privileged(); - auto native = control.find_apply_handler( receiver, act.account, act.name ); + privileged = receiver_account->is_privileged(); + auto native = control.find_apply_handler( receiver, act->account, act->name ); if( native ) { if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); - control.check_action_list( act.account, act.name ); + control.check_action_list( act->account, act->name ); } (*native)( *this ); } - if( receiver_account->code_hash != digest_type() && - !(act.account == config::system_account_name && act.name == N( setcode ) && - receiver == config::system_account_name) ) { + if( ( receiver_account->code_hash != digest_type() ) && + ( !( act->account == config::system_account_name + && act->name == N( setcode ) + && receiver == config::system_account_name ) +// || control.is_builtin_activated( builtin_protocol_feature_t::forward_setcode ) + ) + ) { if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); - control.check_action_list( act.account, act.name ); + control.check_action_list( act->account, act->name ); } try { control.get_wasm_interface().apply( receiver_account->code_hash, receiver_account->vm_type, receiver_account->vm_version, *this ); } catch( const wasm_exit& ) {} } - } FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output.str()) ) + } FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output) ) } catch( fc::exception& e ) { - trace.receipt = r; // fill with known data - trace.except = e; - finalize_trace( trace, start ); - throw; + action_trace& trace = trx_context.get_action_trace( action_ordinal ); + /// TODO + trace.error_code = controller::convert_exception_to_error_code( e ); + trace.except = e; + finalize_trace( trace, start ); + throw; } + // Note: It should not be possible for receiver_account to be invalidated because: + // * a pointer to an object in a chainbase index is not invalidated if other objects in that index are modified, removed, or added; + // * a pointer to an object in a chainbase index is not invalidated if the fields of that object are modified; + // * and, the *receiver_account object itself cannot be removed because accounts cannot be deleted in EOSIO. + r.global_sequence = next_global_sequence(); - r.recv_sequence = next_recv_sequence( receiver ); + r.recv_sequence = next_recv_sequence( *receiver_account ); const account_metadata_object* first_receiver_account = nullptr; - if( act.account == receiver ) { + if( act->account == receiver ) { first_receiver_account = receiver_account; } else { - first_receiver_account = &db.get(act.account); + first_receiver_account = &db.get(act->account); } r.code_sequence = first_receiver_account->code_sequence; // could be modified by action execution above r.abi_sequence = first_receiver_account->abi_sequence; // could be modified by action execution above - - for( const auto& auth : act.authorization ) { + for( const auto& auth : act->authorization ) { r.auth_sequence[auth.actor] = next_auth_sequence( auth.actor ); } + action_trace& trace = trx_context.get_action_trace( action_ordinal ); trace.receipt = r; - trx_context.executed.emplace_back( move(r) ); + trx_context.executed.emplace_back( std::move(r) ); finalize_trace( trace, start ); @@ -116,20 +138,19 @@ void apply_context::finalize_trace( action_trace& trace, const fc::time_point& s trace.account_ram_deltas = std::move( _account_ram_deltas ); _account_ram_deltas.clear(); - trace.console = _pending_console_output.str(); - reset_console(); + trace.console = std::move( _pending_console_output ); + _pending_console_output.clear(); trace.elapsed = fc::time_point::now() - start; } -void apply_context::exec( action_trace& trace ) +void apply_context::exec() { - _notified.push_back(receiver); - exec_one( trace ); + _notified.emplace_back( receiver, action_ordinal ); + exec_one(); for( uint32_t i = 1; i < _notified.size(); ++i ) { - receiver = _notified[i]; - trace.inline_traces.emplace_back( ); - exec_one( trace.inline_traces.back() ); + std::tie( receiver, action_ordinal ) = _notified[i]; + exec_one(); } if( _cfa_inline_actions.size() > 0 || _inline_actions.size() > 0 ) { @@ -137,14 +158,12 @@ void apply_context::exec( action_trace& trace ) transaction_exception, "max inline action depth per transaction reached" ); } - for( const auto& inline_action : _cfa_inline_actions ) { - trace.inline_traces.emplace_back(); - trx_context.dispatch_action( trace.inline_traces.back(), inline_action, inline_action.account, true, recurse_depth + 1 ); + for( uint32_t ordinal : _cfa_inline_actions ) { + trx_context.execute_action( ordinal, recurse_depth + 1 ); } - for( const auto& inline_action : _inline_actions ) { - trace.inline_traces.emplace_back(); - trx_context.dispatch_action( trace.inline_traces.back(), inline_action, inline_action.account, false, recurse_depth + 1 ); + for( uint32_t ordinal : _inline_actions ) { + trx_context.execute_action( ordinal, recurse_depth + 1 ); } } /// exec() @@ -154,9 +173,8 @@ bool apply_context::is_account( const account_name& account )const { } void apply_context::require_authorization( const account_name& account ) { - for( uint32_t i=0; i < act.authorization.size(); i++ ) { - if( act.authorization[i].actor == account ) { - used_authorizations[i] = true; + for( uint32_t i=0; i < act->authorization.size(); i++ ) { + if( act->authorization[i].actor == account ) { return; } } @@ -164,7 +182,7 @@ void apply_context::require_authorization( const account_name& account ) { } bool apply_context::has_authorization( const account_name& account )const { - for( const auto& auth : act.authorization ) + for( const auto& auth : act->authorization ) if( auth.actor == account ) return true; return false; @@ -172,10 +190,9 @@ bool apply_context::has_authorization( const account_name& account )const { void apply_context::require_authorization(const account_name& account, const permission_name& permission) { - for( uint32_t i=0; i < act.authorization.size(); i++ ) - if( act.authorization[i].actor == account ) { - if( act.authorization[i].permission == permission ) { - used_authorizations[i] = true; + for( uint32_t i=0; i < act->authorization.size(); i++ ) + if( act->authorization[i].actor == account ) { + if( act->authorization[i].permission == permission ) { return; } } @@ -184,15 +201,18 @@ void apply_context::require_authorization(const account_name& account, } bool apply_context::has_recipient( account_name code )const { - for( auto a : _notified ) - if( a == code ) + for( const auto& p : _notified ) + if( p.first == code ) return true; return false; } void apply_context::require_recipient( account_name recipient ) { if( !has_recipient(recipient) ) { - _notified.push_back(recipient); + _notified.emplace_back( + recipient, + schedule_action( action_ordinal, recipient, false ) + ); } } @@ -222,7 +242,7 @@ void apply_context::execute_inline( action&& a ) { bool disallow_send_to_self_bypass = false; // eventually set to whether the appropriate protocol feature has been activated bool send_to_self = (a.account == receiver); - bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act.account) && control.is_producing_block()); + bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act->account) && control.is_producing_block()); flat_set inherited_authorizations; if( inherit_parent_authorizations ) { @@ -239,7 +259,7 @@ void apply_context::execute_inline( action&& a ) { if( enforce_actor_whitelist_blacklist ) actors.insert( auth.actor ); - if( inherit_parent_authorizations && std::find(act.authorization.begin(), act.authorization.end(), auth) != act.authorization.end() ) { + if( inherit_parent_authorizations && std::find(act->authorization.begin(), act->authorization.end(), auth) != act->authorization.end() ) { inherited_authorizations.insert( auth ); } } @@ -283,7 +303,10 @@ void apply_context::execute_inline( action&& a ) { } } - _inline_actions.emplace_back( move(a) ); + auto inline_receiver = a.account; + _inline_actions.emplace_back( + schedule_action( std::move(a), inline_receiver, false ) + ); } void apply_context::execute_context_free_inline( action&& a ) { @@ -294,19 +317,22 @@ void apply_context::execute_context_free_inline( action&& a ) { EOS_ASSERT( a.authorization.size() == 0, action_validate_exception, "context-free actions cannot have authorizations" ); - _cfa_inline_actions.emplace_back( move(a) ); + + auto inline_receiver = a.account; + _cfa_inline_actions.emplace_back( + schedule_action( std::move(a), inline_receiver, true ) + ); } void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ) { EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" ); - trx.expiration = control.pending_block_time() + fc::microseconds(999'999); // Rounds up to nearest second (makes expiration check unnecessary) - trx.set_reference_block(control.head_block_id()); // No TaPoS check necessary bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block() && !control.sender_avoids_whitelist_blacklist_enforcement( receiver ); trx_context.validate_referenced_accounts( trx, enforce_actor_whitelist_blacklist ); - + trx.expiration = control.pending_block_time() + fc::microseconds(999'999); // Rounds up to nearest second (makes expiration check unnecessary) + trx.set_reference_block(control.head_block_id()); // No TaPoS check necessary // Charge ahead of time for the additional net usage needed to retire the deferred transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. const auto& cfg = control.get_global_properties().configuration; @@ -406,7 +432,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a }); } - EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act.account) || (receiver == payer) || privileged, + EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act->account) || (receiver == payer) || privileged, subjective_block_production_exception, "Cannot charge RAM to other accounts during notify." ); add_ram_usage( payer, (config::billable_size_v + trx_size) ); } @@ -421,6 +447,26 @@ bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, acc return gto; } +uint32_t apply_context::schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free ) +{ + uint32_t scheduled_action_ordinal = trx_context.schedule_action( ordinal_of_action_to_schedule, + receiver, context_free, + action_ordinal, first_receiver_action_ordinal ); + + act = &trx_context.get_action_trace( action_ordinal ).act; + return scheduled_action_ordinal; +} + +uint32_t apply_context::schedule_action( action&& act_to_schedule, account_name receiver, bool context_free ) +{ + uint32_t scheduled_action_ordinal = trx_context.schedule_action( std::move(act_to_schedule), + receiver, context_free, + action_ordinal, first_receiver_action_ordinal ); + + act = &trx_context.get_action_trace( action_ordinal ).act; + return scheduled_action_ordinal; +} + const table_id_object* apply_context::find_table( name code, name scope, name table ) { return db.find(boost::make_tuple(code, scope, table)); } @@ -456,11 +502,6 @@ vector apply_context::get_active_producers() const { return accounts; } -void apply_context::reset_console() { - _pending_console_output = std::ostringstream(); - _pending_console_output.setf( std::ios::scientific, std::ios::floatfield ); -} - bytes apply_context::get_packed_transaction() { auto r = fc::raw::pack( static_cast(trx_context.trx) ); return r; @@ -469,7 +510,7 @@ bytes apply_context::get_packed_transaction() { void apply_context::update_db_usage( const account_name& payer, int64_t delta ) { if( delta > 0 ) { if( !(privileged || payer == account_name(receiver)) ) { - EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act.account), + EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act->account), subjective_block_production_exception, "Cannot charge RAM to other accounts during notify." ); require_authorization( payer ); } @@ -519,11 +560,11 @@ int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t b return copy_size; } -int apply_context::db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { +int apply_context::db_store_i64( name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { return db_store_i64( receiver, scope, table, payer, id, buffer, buffer_size); } -int apply_context::db_store_i64( uint64_t code, uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { +int apply_context::db_store_i64( name code, name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) { // require_write_lock( scope ); const auto& tab = find_or_create_table( code, scope, table, payer ); auto tableid = tab.id; @@ -659,7 +700,7 @@ int apply_context::db_previous_i64( int iterator, uint64_t& primary ) { return keyval_cache.add(*itr); } -int apply_context::db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { +int apply_context::db_find_i64( name code, name scope, name table, uint64_t id ) { //require_read_lock( code, scope ); // redundant? const auto* tab = find_table( code, scope, table ); @@ -673,7 +714,7 @@ int apply_context::db_find_i64( uint64_t code, uint64_t scope, uint64_t table, u return keyval_cache.add( *obj ); } -int apply_context::db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { +int apply_context::db_lowerbound_i64( name code, name scope, name table, uint64_t id ) { //require_read_lock( code, scope ); // redundant? const auto* tab = find_table( code, scope, table ); @@ -689,7 +730,7 @@ int apply_context::db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t ta return keyval_cache.add( *itr ); } -int apply_context::db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ) { +int apply_context::db_upperbound_i64( name code, name scope, name table, uint64_t id ) { //require_read_lock( code, scope ); // redundant? const auto* tab = find_table( code, scope, table ); @@ -705,7 +746,7 @@ int apply_context::db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t ta return keyval_cache.add( *itr ); } -int apply_context::db_end_i64( uint64_t code, uint64_t scope, uint64_t table ) { +int apply_context::db_end_i64( name code, name scope, name table ) { //require_read_lock( code, scope ); // redundant? const auto* tab = find_table( code, scope, table ); @@ -722,19 +763,18 @@ uint64_t apply_context::next_global_sequence() { return p.global_action_sequence; } -uint64_t apply_context::next_recv_sequence( account_name receiver ) { - const auto& rs = db.get( receiver ); - db.modify( rs, [&]( auto& mrs ) { - ++mrs.recv_sequence; +uint64_t apply_context::next_recv_sequence( const account_metadata_object& receiver_account ) { + db.modify( receiver_account, [&]( auto& ra ) { + ++ra.recv_sequence; }); - return rs.recv_sequence; + return receiver_account.recv_sequence; } uint64_t apply_context::next_auth_sequence( account_name actor ) { - const auto& rs = db.get( actor ); - db.modify( rs, [&](auto& mrs ){ - ++mrs.auth_sequence; + const auto& amo = db.get( actor ); + db.modify( amo, [&](auto& am ){ + ++am.auth_sequence; }); - return rs.auth_sequence; + return amo.auth_sequence; } void apply_context::add_ram_usage( account_name account, int64_t ram_delta ) { @@ -746,5 +786,13 @@ void apply_context::add_ram_usage( account_name account, int64_t ram_delta ) { } } +action_name apply_context::get_sender() const { + const action_trace& trace = trx_context.get_action_trace( action_ordinal ); + if (trace.creator_action_ordinal > 0) { + const action_trace& creator_trace = trx_context.get_action_trace( trace.creator_action_ordinal ); + return creator_trace.receiver; + } + return action_name(); +} } } /// eosio::chain diff --git a/libraries/chain/authorization_manager.cpp b/libraries/chain/authorization_manager.cpp index e69f7129121..fd60e8baa99 100644 --- a/libraries/chain/authorization_manager.cpp +++ b/libraries/chain/authorization_manager.cpp @@ -238,7 +238,7 @@ namespace eosio { namespace chain { auto link = _db.find(key); // If no specific link found, check for a contract-wide default if (link == nullptr) { - boost::get<2>(key) = ""; + boost::get<2>(key) = {}; link = _db.find(key); } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index dfe210a5f90..107b83a725f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -213,7 +213,8 @@ struct controller_impl { { #define SET_APP_HANDLER( receiver, contract, action) \ - set_apply_handler( #receiver, #contract, #action, &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) ) + set_apply_handler( account_name(#receiver), account_name(#contract), action_name(#action), \ + &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) ) SET_APP_HANDLER( eosio, eosio, newaccount ); SET_APP_HANDLER( eosio, eosio, setcode ); @@ -1104,8 +1105,7 @@ struct controller_impl { try { trx_context.init_for_implicit_trx(); trx_context.published = gtrx.published; - trx_context.trace->action_traces.emplace_back(); - trx_context.dispatch_action( trx_context.trace->action_traces.back(), etrx.actions.back(), gtrx.sender ); + trx_context.execute_action( trx_context.schedule_action( etrx.actions.back(), gtrx.sender, false, 0, 0 ), 0 ); trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful auto restore = make_block_restore_point(); @@ -1201,7 +1201,7 @@ struct controller_impl { trace->scheduled = true; trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); undo_session.squash(); return trace; } @@ -1241,7 +1241,7 @@ struct controller_impl { fc::move_append( pending->_actions, move(trx_context.executed) ); emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); trx_context.squash(); undo_session.squash(); @@ -1269,7 +1269,7 @@ struct controller_impl { trace = error_trace; if( !trace->except_ptr ) { emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); undo_session.squash(); return trace; } @@ -1306,12 +1306,12 @@ struct controller_impl { trace->receipt = push_receipt(gtrx.trx_id, transaction_receipt::hard_fail, cpu_time_to_bill_us, 0); emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); undo_session.squash(); } else { emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, dtrx) ); } return trace; @@ -1421,7 +1421,7 @@ struct controller_impl { emit( self.accepted_transaction, trx); } - emit(self.applied_transaction, trace); + emit(self.applied_transaction, std::tie(trace, trn)); if ( read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete ) { @@ -1446,7 +1446,7 @@ struct controller_impl { } emit( self.accepted_transaction, trx ); - emit( self.applied_transaction, trace ); + emit( self.applied_transaction, std::tie(trace, trn) ); return trace; } FC_CAPTURE_AND_RETHROW((trace)) @@ -1758,17 +1758,18 @@ struct controller_impl { if (!pbft_enabled) return; if ( pending_pbft_lib ) { - //this is a temp solution for getting current lib, should not use anywhere else; - auto current_lib = fork_db.get_block_in_current_chain_by_num(head->bft_irreversible_blocknum)->id; + auto current_lib_num = std::max(std::max(head->bft_irreversible_blocknum, head->dpos_irreversible_blocknum), snapshot_head_block); fork_db.set_bft_irreversible(*pending_pbft_lib); if (!replaying) { + // emit lib signals to a separate channel, plugins should connect to this channel in order to process libs asap. auto libs_to_be_emitted = vector{}; auto b = fork_db.get_block(*pending_pbft_lib); - while (b->id != current_lib) { + while (b && b->block_num > current_lib_num) { libs_to_be_emitted.emplace_back(b); b = fork_db.get_block(b->prev()); } while (!libs_to_be_emitted.empty()) { + // emit all libs in ascending order. emit( self.new_irreversible_block, libs_to_be_emitted.back() ); libs_to_be_emitted.pop_back(); } @@ -2481,6 +2482,15 @@ signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const { return my->blog.read_block_by_num(block_num); } FC_CAPTURE_AND_RETHROW( (block_num) ) } +signed_block_ptr controller::fetch_block_by_number_state_history( uint32_t block_num )const { try { + auto blk_state = fetch_block_state_by_number_state_history( block_num ); + if( blk_state ) { + return blk_state->block; + } + + return my->blog.read_block_by_num(block_num); +} FC_CAPTURE_AND_RETHROW( (block_num) ) } + block_state_ptr controller::fetch_block_state_by_id( block_id_type id )const { auto state = my->fork_db.get_block(id); return state; @@ -2491,6 +2501,21 @@ block_state_ptr controller::fetch_block_state_by_number( uint32_t block_num )con return blk_state; } FC_CAPTURE_AND_RETHROW( (block_num) ) } +block_state_ptr controller::fetch_block_state_by_number_state_history( uint32_t block_num )const { try { + const auto& rev_blocks = my->reversible_blocks.get_index(); + auto objitr = rev_blocks.find(block_num); + + if( objitr == rev_blocks.end() ) { + if( my->read_mode == db_read_mode::IRREVERSIBLE ) { + return my->fork_db.search_on_branch( my->pending->_pending_block_state->id, block_num ); + } else { + return block_state_ptr(); + } + } + + return my->fork_db.get_block( objitr->get_block_id() ); +} FC_CAPTURE_AND_RETHROW( (block_num) ) } + block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try { auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num ); if( blk_state ) { @@ -2865,4 +2890,14 @@ vm::wasm_allocator& controller::get_wasm_allocator() { } #endif +fc::optional controller::convert_exception_to_error_code( const fc::exception& e ) { + const chain_exception* e_ptr = dynamic_cast( &e ); + + if( e_ptr == nullptr ) return {}; + + if( !e_ptr->error_code ) return static_cast(system_error_code::generic_system_error); + + return e_ptr->error_code; +} + } } /// eosio::chain diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index 3e925d175da..fa16ea56dfb 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -68,7 +69,7 @@ void validate_authority_precondition( const apply_context& context, const author * This method is called assuming precondition_system_newaccount succeeds a */ void apply_eosio_newaccount(apply_context& context) { - auto create = context.act.data_as(); + auto create = context.get_action().data_as(); try { context.require_authorization(create.creator); // context.require_write_lock( config::eosio_auth_scope ); @@ -129,7 +130,7 @@ void apply_eosio_setcode(apply_context& context) { const auto& cfg = context.control.get_global_properties().configuration; auto& db = context.db; - auto act = context.act.data_as(); + auto act = context.get_action().data_as(); context.require_authorization(act.account); EOS_ASSERT( act.vmtype == 0, invalid_contract_vm_type, "code should be 0" ); @@ -201,7 +202,7 @@ void apply_eosio_setcode(apply_context& context) { void apply_eosio_setabi(apply_context& context) { auto& db = context.db; - auto act = context.act.data_as(); + auto act = context.get_action().data_as(); context.require_authorization(act.account); @@ -220,9 +221,9 @@ void apply_eosio_setabi(apply_context& context) { } }); - const auto& account_sequence = db.get(act.account); - db.modify( account_sequence, [&]( auto& aso ) { - aso.abi_sequence += 1; + const auto& account_metadata = db.get(act.account); + db.modify( account_metadata, [&]( auto& a ) { + a.abi_sequence += 1; }); if (new_size != old_size) { @@ -232,7 +233,7 @@ void apply_eosio_setabi(apply_context& context) { void apply_eosio_updateauth(apply_context& context) { - auto update = context.act.data_as(); + auto update = context.get_action().data_as(); context.require_authorization(update.account); // only here to mark the single authority on this action as used auto& authorization = context.control.get_mutable_authorization_manager(); @@ -297,7 +298,7 @@ void apply_eosio_updateauth(apply_context& context) { void apply_eosio_deleteauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); - auto remove = context.act.data_as(); + auto remove = context.get_action().data_as(); context.require_authorization(remove.account); // only here to mark the single authority on this action as used EOS_ASSERT(remove.permission != config::active_name, action_validate_exception, "Cannot delete active authority"); @@ -313,7 +314,7 @@ void apply_eosio_deleteauth(apply_context& context) { auto range = index.equal_range(boost::make_tuple(remove.account, remove.permission)); EOS_ASSERT(range.first == range.second, action_validate_exception, "Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.", - ("code", string(range.first->code))("type", string(range.first->message_type))); + ("code", range.first->code)("type", range.first->message_type)); } const auto& permission = authorization.get_permission({remove.account, remove.permission}); @@ -328,7 +329,7 @@ void apply_eosio_deleteauth(apply_context& context) { void apply_eosio_linkauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); - auto requirement = context.act.data_as(); + auto requirement = context.get_action().data_as(); try { EOS_ASSERT(!requirement.requirement.empty(), action_validate_exception, "Required permission cannot be empty"); @@ -377,7 +378,7 @@ void apply_eosio_unlinkauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); auto& db = context.db; - auto unlink = context.act.data_as(); + auto unlink = context.get_action().data_as(); context.require_authorization(unlink.account); // only here to mark the single authority on this action as used @@ -393,7 +394,7 @@ void apply_eosio_unlinkauth(apply_context& context) { } void apply_eosio_canceldelay(apply_context& context) { - auto cancel = context.act.data_as(); + auto cancel = context.get_action().data_as(); context.require_authorization(cancel.canceling_auth.actor); // only here to mark the single authority on this action as used const auto& trx_id = cancel.trx_id; diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index be36a908895..6343caf2829 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -293,6 +293,15 @@ namespace eosio { namespace chain { return result; } /// fetch_branch_from + block_state_ptr fork_database::search_on_branch( const block_id_type& h, uint32_t block_num )const { + for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) { + if( s->block_num == block_num ) + return s; + } + + return {}; + } + /// remove all of the invalid forks built of this id including this id void fork_database::remove( const block_id_type& id ) { vector remove_queue{id}; diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 06b9d2bb761..769e685bb4d 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -240,7 +240,6 @@ namespace impl { std::is_same::value || std::is_same::value || std::is_same::value || - std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 6272636deab..3366727be9e 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -71,7 +71,8 @@ class apply_context { void remove( int iterator ) { EOS_ASSERT( iterator != -1, invalid_table_iterator, "invalid iterator" ); EOS_ASSERT( iterator >= 0, table_operation_not_permitted, "cannot call remove on end iterators" ); - EOS_ASSERT( iterator < _iterator_to_object.size(), invalid_table_iterator, "iterator out of range" ); + EOS_ASSERT( (size_t)iterator < _iterator_to_object.size(), invalid_table_iterator, "iterator out of range" ); + auto obj_ptr = _iterator_to_object[iterator]; if( !obj_ptr ) return; _iterator_to_object[iterator] = nullptr; @@ -183,7 +184,7 @@ class apply_context { // context.require_write_lock( scope ); - const auto& tab = context.find_or_create_table( context.receiver, scope, table, payer ); + const auto& tab = context.find_or_create_table( context.receiver, name(scope), name(table), payer ); const auto& obj = context.db.create( [&]( auto& o ){ o.t_id = tab.id; @@ -247,7 +248,7 @@ class apply_context { } int find_secondary( uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_const_type secondary, uint64_t& primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -261,7 +262,7 @@ class apply_context { } int lowerbound_secondary( uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t& primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -278,7 +279,7 @@ class apply_context { } int upperbound_secondary( uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t& primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -295,7 +296,7 @@ class apply_context { } int end_secondary( uint64_t code, uint64_t scope, uint64_t table ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; return itr_cache.cache_table( *tab ); @@ -349,7 +350,7 @@ class apply_context { } int find_primary( uint64_t code, uint64_t scope, uint64_t table, secondary_key_proxy_type secondary, uint64_t primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -362,7 +363,7 @@ class apply_context { } int lowerbound_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if (!tab) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -376,7 +377,7 @@ class apply_context { } int upperbound_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary ) { - auto tab = context.find_table( code, scope, table ); + auto tab = context.find_table( name(code), name(scope), name(table) ); if ( !tab ) return -1; auto table_end_itr = itr_cache.cache_table( *tab ); @@ -451,35 +452,23 @@ class apply_context { /// Constructor public: - apply_context(controller& con, transaction_context& trx_ctx, const action& a, uint32_t depth=0) - :control(con) - ,db(con.mutable_db()) - ,trx_context(trx_ctx) - ,act(a) - ,receiver(act.account) - ,used_authorizations(act.authorization.size(), false) - ,recurse_depth(depth) - ,idx64(*this) - ,idx128(*this) - ,idx256(*this) - ,idx_double(*this) - ,idx_long_double(*this) - { - reset_console(); - } - + apply_context(controller& con, transaction_context& trx_ctx, uint32_t action_ordinal, uint32_t depth=0); /// Execution methods: public: - void exec_one( action_trace& trace ); - void exec( action_trace& trace ); + void exec_one(); + void exec(); void execute_inline( action&& a ); void execute_context_free_inline( action&& a ); void schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ); bool cancel_deferred_transaction( const uint128_t& sender_id, account_name sender ); bool cancel_deferred_transaction( const uint128_t& sender_id ) { return cancel_deferred_transaction(sender_id, receiver); } + protected: + uint32_t schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free ); + uint32_t schedule_action( action&& act_to_schedule, account_name receiver, bool context_free ); + /// Authorization methods: public: @@ -516,23 +505,8 @@ class apply_context { /// Console methods: public: - void reset_console(); - std::ostringstream& get_console_stream() { return _pending_console_output; } - const std::ostringstream& get_console_stream()const { return _pending_console_output; } - - template - void console_append(T val) { - _pending_console_output << val; - } - - template - void console_append(T val, Ts ...rest) { - console_append(val); - console_append(rest...); - }; - - inline void console_append_formatted(const string& fmt, const variant_object& vo) { - console_append(fc::format_string(fmt, vo)); + void console_append( const string& val ) { + _pending_console_output += val; } /// Database methods: @@ -540,16 +514,16 @@ class apply_context { void update_db_usage( const account_name& payer, int64_t delta ); - int db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); + int db_store_i64( name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); void db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size ); void db_remove_i64( int iterator ); int db_get_i64( int iterator, char* buffer, size_t buffer_size ); int db_next_i64( int iterator, uint64_t& primary ); int db_previous_i64( int iterator, uint64_t& primary ); - int db_find_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ); - int db_lowerbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ); - int db_upperbound_i64( uint64_t code, uint64_t scope, uint64_t table, uint64_t id ); - int db_end_i64( uint64_t code, uint64_t scope, uint64_t table ); + int db_find_i64( name code, name scope, name table, uint64_t id ); + int db_lowerbound_i64( name code, name scope, name table, uint64_t id ); + int db_upperbound_i64( name code, name scope, name table, uint64_t id ); + int db_end_i64( name code, name scope, name table ); private: @@ -557,19 +531,20 @@ class apply_context { const table_id_object& find_or_create_table( name code, name scope, name table, const account_name &payer ); void remove_table( const table_id_object& tid ); - int db_store_i64( uint64_t code, uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); + int db_store_i64( name code, name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ); /// Misc methods: public: + int get_action( uint32_t type, uint32_t index, char* buffer, size_t buffer_size )const; int get_context_free_data( uint32_t index, char* buffer, size_t buffer_size )const; vector get_active_producers() const; bytes get_packed_transaction(); uint64_t next_global_sequence(); - uint64_t next_recv_sequence( account_name receiver ); + uint64_t next_recv_sequence( const account_metadata_object& receiver_account ); uint64_t next_auth_sequence( account_name actor ); void add_ram_usage( account_name account, int64_t ram_delta ); @@ -578,7 +553,9 @@ class apply_context { bool is_context_free()const { return context_free; } bool is_privileged()const { return privileged; } action_name get_receiver()const { return receiver; } - const action& get_action()const { return act; } + const action& get_action()const { return *act; } + + action_name get_sender() const; /// Fields: public: @@ -586,15 +563,19 @@ class apply_context { controller& control; chainbase::database& db; ///< database where state is stored transaction_context& trx_context; ///< transaction context in which the action is running - const action& act; ///< message being applied + uint64_t global_action_sequence = 0; + + private: + const action* act = nullptr; ///< action being applied + // act pointer may be invalidated on call to trx_context.schedule_action account_name receiver; ///< the code that is currently running - vector used_authorizations; ///< Parallel to act.authorization; tracks which permissions have been used while processing the message uint32_t recurse_depth; ///< how deep inline actions can recurse + uint32_t first_receiver_action_ordinal = 0; + uint32_t action_ordinal = 0; bool privileged = false; bool context_free = false; - bool used_context_free_api = false; - uint64_t global_action_sequence = 0; + public: generic_index idx64; generic_index idx128; generic_index idx256; @@ -604,10 +585,10 @@ class apply_context { private: iterator_cache keyval_cache; - vector _notified; ///< keeps track of new accounts to be notifed of current message - vector _inline_actions; ///< queued inline messages - vector _cfa_inline_actions; ///< queued inline messages - std::ostringstream _pending_console_output; + vector< std::pair > _notified; ///< keeps track of new accounts to be notifed of current message + vector _inline_actions; ///< action_ordinals of queued inline actions + vector _cfa_inline_actions; ///< action_ordinals of queued inline context-free actions + std::string _pending_console_output; flat_set _account_ram_deltas; ///< flat_set of account_delta so json is an array of objects //bytes _cached_trx; diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 3f44522498b..8c7a854a3df 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -26,26 +26,26 @@ const static auto default_state_guard_size = 128*1024*1024ll; const static auto checkpoints_filename = "checkpoints.dat"; - -const static uint64_t system_account_name = N(eosio); -const static uint64_t null_account_name = N(eosio.null); -const static uint64_t producers_account_name = N(eosio.prods); +const static name system_account_name { N(eosio) }; +const static name null_account_name { N(eosio.null) }; +const static name producers_account_name { N(eosio.prods) }; // Active permission of producers account requires greater than 2/3 of the producers to authorize -const static uint64_t majority_producers_permission_name = N(prod.major); // greater than 1/2 of producers needed to authorize -const static uint64_t minority_producers_permission_name = N(prod.minor); // greater than 1/3 of producers needed to authorize0 +const static name majority_producers_permission_name { N(prod.major) }; // greater than 1/2 of producers needed to authorize +const static name minority_producers_permission_name { N(prod.minor) }; // greater than 1/3 of producers needed to authorize0 -const static uint64_t eosio_auth_scope = N(eosio.auth); -const static uint64_t eosio_all_scope = N(eosio.all); +const static name eosio_auth_scope { N(eosio.auth) }; +const static name eosio_all_scope { N(eosio.all) }; -const static uint64_t active_name = N(active); -const static uint64_t owner_name = N(owner); -const static uint64_t eosio_any_name = N(eosio.any); -const static uint64_t eosio_code_name = N(eosio.code); +const static name active_name { N(active) }; +const static name owner_name { N(owner) }; +const static name eosio_any_name { N(eosio.any) }; +const static name eosio_code_name { N(eosio.code) }; const static int block_interval_ms = 500; const static int block_interval_us = block_interval_ms*1000; const static uint64_t block_timestamp_epoch = 946684800000ll; // epoch is year 2000. +const static uint32_t genesis_num_supported_key_types = 2; /** Percentages are fixed point with a denominator of 10,000 */ const static int percent_100 = 10000; @@ -55,7 +55,7 @@ static const uint32_t account_cpu_usage_average_window_ms = 24*60*60*1000l; static const uint32_t account_net_usage_average_window_ms = 24*60*60*1000l; static const uint32_t block_cpu_usage_average_window_ms = 60*1000l; static const uint32_t block_size_average_window_ms = 60*1000l; -const static uint32_t genesis_num_supported_key_types = 2; +static const uint32_t maximum_elastic_resource_multiplier = 1000; //const static uint64_t default_max_storage_size = 10 * 1024; //const static uint32_t default_max_trx_runtime = 10*1000; @@ -77,6 +77,7 @@ const static uint32_t default_max_block_cpu_usage = 200'000; / const static uint32_t default_target_block_cpu_usage_pct = 10 * percent_1; const static uint32_t default_max_transaction_cpu_usage = 3*default_max_block_cpu_usage/4; /// max trx cpu usage in microseconds const static uint32_t default_min_transaction_cpu_usage = 100; /// min trx cpu usage in microseconds (10000 TPS equiv) +const static uint32_t default_subjective_cpu_leeway_us = 31000; /// default subjective cpu leeway in microseconds const static uint32_t default_max_trx_lifetime = 60*60; // 1 hour const static uint32_t default_deferred_trx_expiration_window = 10*60; // 10 minutes @@ -85,7 +86,9 @@ const static uint32_t default_max_inline_action_size = 4 * 1024; // const static uint16_t default_max_inline_action_depth = 4; const static uint16_t default_max_auth_depth = 6; const static uint32_t default_sig_cpu_bill_pct = 50 * percent_1; // billable percentage of signature recovery +const static uint32_t default_block_cpu_effort_pct = 80 * percent_1; // percentage of block time used for producing block const static uint16_t default_controller_thread_pool_size = 2; +const static uint32_t default_max_variable_signature_length = 16384u; const static uint32_t min_net_usage_delta_between_base_and_max_for_trx = 10*1024; // Should be large enough to allow recovery from badly set blockchain parameters without a hard fork @@ -101,7 +104,7 @@ const static uint32_t setcode_ram_bytes_multiplier = 10; ///< multip const static uint32_t hashing_checktime_block_size = 10*1024; /// call checktime from hashing intrinsic once per this number of bytes const static eosio::chain::wasm_interface::vm_type default_wasm_runtime = eosio::chain::wasm_interface::vm_type::wabt; -const static uint32_t default_abi_serializer_max_time_ms = 15*1000; ///< default deadline for abi serialization methods +const static uint32_t default_abi_serializer_max_time_us = 15*1000; ///< default deadline for abi serialization methods /** * The number of sequential blocks produced by a single producer diff --git a/libraries/chain/include/eosio/chain/contract_table_objects.hpp b/libraries/chain/include/eosio/chain/contract_table_objects.hpp index dc6b25b0501..fb02fb5e1e0 100644 --- a/libraries/chain/include/eosio/chain/contract_table_objects.hpp +++ b/libraries/chain/include/eosio/chain/contract_table_objects.hpp @@ -20,9 +20,9 @@ namespace eosio { namespace chain { OBJECT_CTOR(table_id_object) id_type id; - account_name code; - scope_name scope; - table_name table; + account_name code; //< code should not be changed within a chainbase modifier lambda + scope_name scope; //< scope should not be changed within a chainbase modifier lambda + table_name table; //< table should not be changed within a chainbase modifier lambda account_name payer; uint32_t count = 0; /// the number of elements in the table }; @@ -59,9 +59,9 @@ namespace eosio { namespace chain { static const int number_of_keys = 1; id_type id; - table_id t_id; - uint64_t primary_key; - account_name payer = 0; + table_id t_id; //< t_id should not be changed within a chainbase modifier lambda + uint64_t primary_key; //< primary_key should not be changed within a chainbase modifier lambda + account_name payer; shared_blob value; }; @@ -90,10 +90,10 @@ namespace eosio { namespace chain { typedef SecondaryKey secondary_key_type; typename chainbase::object::id_type id; - table_id t_id; - uint64_t primary_key; - account_name payer = 0; - SecondaryKey secondary_key; + table_id t_id; //< t_id should not be changed within a chainbase modifier lambda + uint64_t primary_key; //< primary_key should not be changed within a chainbase modifier lambda + account_name payer; + SecondaryKey secondary_key; //< secondary_key should not be changed within a chainbase modifier lambda }; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index bcc416fb242..590a019877c 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -233,9 +233,11 @@ namespace eosio { namespace chain { block_id_type last_irreversible_block_id() const; signed_block_ptr fetch_block_by_number( uint32_t block_num )const; + signed_block_ptr fetch_block_by_number_state_history( uint32_t block_num )const; signed_block_ptr fetch_block_by_id( block_id_type id )const; block_state_ptr fetch_block_state_by_number( uint32_t block_num )const; + block_state_ptr fetch_block_state_by_number_state_history( uint32_t block_num )const; block_state_ptr fetch_block_state_by_id( block_id_type id )const; block_id_type get_block_id_for_num( uint32_t block_num )const; @@ -303,6 +305,7 @@ namespace eosio { namespace chain { #if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED) vm::wasm_allocator& get_wasm_allocator(); #endif + static fc::optional convert_exception_to_error_code( const fc::exception& e ); signal pre_accepted_block; signal accepted_block_header; @@ -310,7 +313,7 @@ namespace eosio { namespace chain { signal irreversible_block; signal new_irreversible_block; signal accepted_transaction; - signal applied_transaction; + signal)> applied_transaction; signal accepted_confirmation; signal bad_alloc; diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 5c295192a1d..46fae198034 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -68,10 +68,52 @@ { throw( effect_type( e.what(), e.get_log() ) ); } +#define FC_DECLARE_DERIVED_EXCEPTION_WITH_ERROR_CODE( TYPE, BASE, CODE, WHAT ) \ + class TYPE : public BASE \ + { \ + public: \ + enum code_enum { \ + code_value = CODE, \ + }; \ + explicit TYPE( int64_t code, const std::string& name_value, const std::string& what_value ) \ + :BASE( code, name_value, what_value ){} \ + explicit TYPE( fc::log_message&& m, int64_t code, const std::string& name_value, const std::string& what_value ) \ + :BASE( std::move(m), code, name_value, what_value ){} \ + explicit TYPE( fc::log_messages&& m, int64_t code, const std::string& name_value, const std::string& what_value )\ + :BASE( std::move(m), code, name_value, what_value ){}\ + explicit TYPE( const fc::log_messages& m, int64_t code, const std::string& name_value, const std::string& what_value )\ + :BASE( m, code, name_value, what_value ){}\ + TYPE( const std::string& what_value, const fc::log_messages& m ) \ + :BASE( m, CODE, BOOST_PP_STRINGIZE(TYPE), what_value ){} \ + TYPE( fc::log_message&& m ) \ + :BASE( fc::move(m), CODE, BOOST_PP_STRINGIZE(TYPE), WHAT ){}\ + TYPE( fc::log_messages msgs ) \ + :BASE( fc::move( msgs ), CODE, BOOST_PP_STRINGIZE(TYPE), WHAT ) {} \ + TYPE( const TYPE& c ) \ + :BASE(c),error_code(c.error_code) {} \ + TYPE( const BASE& c ) \ + :BASE(c){} \ + TYPE():BASE(CODE, BOOST_PP_STRINGIZE(TYPE), WHAT){}\ + \ + virtual std::shared_ptr dynamic_copy_exception()const\ + { return std::make_shared( *this ); } \ + virtual NO_RETURN void dynamic_rethrow_exception()const \ + { if( code() == CODE ) throw *this;\ + else fc::exception::dynamic_rethrow_exception(); \ + } \ + fc::optional error_code; \ + }; + namespace eosio { namespace chain { - FC_DECLARE_EXCEPTION( chain_exception, - 3000000, "blockchain exception" ) + enum class system_error_code : uint64_t { + generic_system_error = 10000000000000000000ULL, + contract_restricted_error_code, //< contract used an error code reserved for system usage + }; + + + FC_DECLARE_DERIVED_EXCEPTION_WITH_ERROR_CODE( chain_exception, fc::exception, + 3000000, "blockchain exception" ) /** * chain_exception * |- chain_type_exception diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 9dfb3f0cc9c..a10c4542588 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -55,6 +55,7 @@ namespace eosio { namespace chain { pair< branch_type, branch_type > fetch_branch_from( const block_id_type& first, const block_id_type& second )const; + block_state_ptr search_on_branch( const block_id_type& h, uint32_t block_num )const; /** * If the block is invalid, it will be removed. If it is valid, then blocks older diff --git a/libraries/chain/include/eosio/chain/name.hpp b/libraries/chain/include/eosio/chain/name.hpp index 52a100b5c00..eef06b81ece 100644 --- a/libraries/chain/include/eosio/chain/name.hpp +++ b/libraries/chain/include/eosio/chain/name.hpp @@ -3,9 +3,16 @@ #include #include -namespace eosio { namespace chain { - using std::string; +namespace eosio::chain { + struct name; +} +namespace fc { + class variant; + void to_variant(const eosio::chain::name& c, fc::variant& v); + void from_variant(const fc::variant& v, eosio::chain::name& check); +} // fc +namespace eosio::chain { static constexpr uint64_t char_to_symbol( char c ) { if( c >= 'a' && c <= 'z' ) return (c - 'a') + 6; @@ -14,102 +21,83 @@ namespace eosio { namespace chain { return 0; } - // Each char of the string is encoded into 5-bit chunk and left-shifted - // to its 5-bit slot starting with the highest slot for the first char. - // The 13th char, if str is long enough, is encoded into 4-bit chunk - // and placed in the lowest 4 bits. 64 = 12 * 5 + 4 - static constexpr uint64_t string_to_name( const char* str ) - { - uint64_t name = 0; + static constexpr uint64_t string_to_uint64_t( std::string_view str ) { + uint64_t n = 0; int i = 0; for ( ; str[i] && i < 12; ++i) { - // NOTE: char_to_symbol() returns char type, and without this explicit - // expansion to uint64 type, the compilation fails at the point of usage - // of string_to_name(), where the usage requires constant (compile time) expression. - name |= (char_to_symbol(str[i]) & 0x1f) << (64 - 5 * (i + 1)); - } + // NOTE: char_to_symbol() returns char type, and without this explicit + // expansion to uint64 type, the compilation fails at the point of usage + // of string_to_name(), where the usage requires constant (compile time) expression. + n |= (char_to_symbol(str[i]) & 0x1f) << (64 - 5 * (i + 1)); + } // The for-loop encoded up to 60 high bits into uint64 'name' variable, // if (strlen(str) > 12) then encode str[12] into the low (remaining) // 4 bits of 'name' if (i == 12) - name |= char_to_symbol(str[12]) & 0x0F; - return name; + n |= char_to_symbol(str[12]) & 0x0F; + return n; } -#define N(X) eosio::chain::string_to_name(#X) - + /// Immutable except for fc::from_variant. struct name { + private: uint64_t value = 0; - bool empty()const { return 0 == value; } - bool good()const { return !empty(); } - - name( const char* str ) { set(str); } - name( const string& str ) { set( str.c_str() ); } - void set( const char* str ); + friend struct fc::reflector; + friend void fc::from_variant(const fc::variant& v, eosio::chain::name& check); - template - name( T v ):value(v){} - name(){} + void set( std::string_view str ); - explicit operator string()const; + public: + constexpr bool empty()const { return 0 == value; } + constexpr bool good()const { return !empty(); } - string to_string() const { return string(*this); } - constexpr uint64_t to_uint64_t()const { return value; } + explicit name( std::string_view str ) { set( str ); } + constexpr explicit name( uint64_t v ) : value(v) {} + constexpr name() = default; - name& operator=( uint64_t v ) { - value = v; - return *this; - } - - name& operator=( const string& n ) { - value = name(n).value; - return *this; - } - name& operator=( const char* n ) { - value = name(n).value; - return *this; - } + std::string to_string()const; + constexpr uint64_t to_uint64_t()const { return value; } friend std::ostream& operator << ( std::ostream& out, const name& n ) { - return out << string(n); + return out << n.to_string(); } - friend bool operator < ( const name& a, const name& b ) { return a.value < b.value; } - friend bool operator <= ( const name& a, const name& b ) { return a.value <= b.value; } - friend bool operator > ( const name& a, const name& b ) { return a.value > b.value; } - friend bool operator >=( const name& a, const name& b ) { return a.value >= b.value; } - friend bool operator == ( const name& a, const name& b ) { return a.value == b.value; } + friend constexpr bool operator < ( const name& a, const name& b ) { return a.value < b.value; } + friend constexpr bool operator > ( const name& a, const name& b ) { return a.value > b.value; } + friend constexpr bool operator <= ( const name& a, const name& b ) { return a.value <= b.value; } + friend constexpr bool operator >= ( const name& a, const name& b ) { return a.value >= b.value; } + friend constexpr bool operator == ( const name& a, const name& b ) { return a.value == b.value; } + friend constexpr bool operator != ( const name& a, const name& b ) { return a.value != b.value; } - friend bool operator == ( const name& a, uint64_t b ) { return a.value == b; } - friend bool operator != ( const name& a, uint64_t b ) { return a.value != b; } + friend constexpr bool operator == ( const name& a, uint64_t b ) { return a.value == b; } + friend constexpr bool operator != ( const name& a, uint64_t b ) { return a.value != b; } - friend bool operator != ( const name& a, const name& b ) { return a.value != b.value; } - - operator bool()const { return value; } - operator uint64_t()const { return value; } - operator unsigned __int128()const { return value; } + constexpr explicit operator bool()const { return value != 0; } }; -} } // eosio::chain + // Each char of the string is encoded into 5-bit chunk and left-shifted + // to its 5-bit slot starting with the highest slot for the first char. + // The 13th char, if str is long enough, is encoded into 4-bit chunk + // and placed in the lowest 4 bits. 64 = 12 * 5 + 4 + static constexpr name string_to_name( std::string_view str ) + { + return name( string_to_uint64_t( str ) ); + } + +#define N(X) eosio::chain::string_to_name(#X) + +} // eosio::chain namespace std { template<> struct hash : private hash { typedef eosio::chain::name argument_type; - typedef typename hash::result_type result_type; - result_type operator()(const argument_type& name) const noexcept + size_t operator()(const argument_type& name) const noexcept { - return hash::operator()(name.value); + return hash::operator()(name.to_uint64_t()); } }; }; -namespace fc { - class variant; - void to_variant(const eosio::chain::name& c, fc::variant& v); - void from_variant(const fc::variant& v, eosio::chain::name& check); -} // fc - - FC_REFLECT( eosio::chain::name, (value) ) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index fd38f9e9330..3e200b4da38 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -519,6 +519,7 @@ namespace eosio { vector get_pbft_watermarks() const; flat_map get_pbft_fork_schedules() const; + producer_schedule_type lscb_active_producers() const; private: controller& ctrl; pbft_state_multi_index_type pbft_state_index; @@ -537,7 +538,6 @@ namespace eosio { bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false, bool at_the_top = false); bool is_valid_longest_fork(const vector& producers, const block_info_type& cert_info, bool at_the_top = false); - producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); flat_map& get_updated_fork_schedules(); block_num_type get_current_pbft_watermark(); diff --git a/libraries/chain/include/eosio/chain/reversible_block_object.hpp b/libraries/chain/include/eosio/chain/reversible_block_object.hpp index ea9a4c9e122..daaac00a71b 100644 --- a/libraries/chain/include/eosio/chain/reversible_block_object.hpp +++ b/libraries/chain/include/eosio/chain/reversible_block_object.hpp @@ -32,6 +32,15 @@ namespace eosio { namespace chain { fc::raw::unpack( ds, *result ); return result; } + + block_id_type get_block_id()const { + fc::datastream ds( packedblock.data(), packedblock.size() ); + block_header h; + fc::raw::unpack( ds, h ); + // Only need the block id to then look up the block state in fork database, so just unpack the block_header from the stored packed data. + // Avoid calling get_block() since that constructs a new signed_block in heap memory and unpacks the full signed_block from the stored packed data. + return h.id(); + } }; struct by_num; diff --git a/libraries/chain/include/eosio/chain/trace.hpp b/libraries/chain/include/eosio/chain/trace.hpp index 58de120bdd8..a7a069bde38 100644 --- a/libraries/chain/include/eosio/chain/trace.hpp +++ b/libraries/chain/include/eosio/chain/trace.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ #pragma once #include @@ -20,33 +16,36 @@ namespace eosio { namespace chain { friend bool operator<( const account_delta& lhs, const account_delta& rhs ) { return lhs.account < rhs.account; } }; - struct base_action_trace { - base_action_trace( const action_receipt& r ):receipt(r){} - base_action_trace(){} - - action_receipt receipt; - action act; - bool context_free = false; - fc::microseconds elapsed; - string console; + struct transaction_trace; + using transaction_trace_ptr = std::shared_ptr; - transaction_id_type trx_id; ///< the transaction that generated this action - uint32_t block_num = 0; - block_timestamp_type block_time; + struct action_trace { + action_trace( const transaction_trace& trace, const action& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ); + action_trace( const transaction_trace& trace, action&& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ); + action_trace(){} + + fc::unsigned_int action_ordinal; + fc::unsigned_int creator_action_ordinal; + fc::unsigned_int closest_unnotified_ancestor_action_ordinal; + fc::optional receipt; + action_name receiver; + action act; + bool context_free = false; + fc::microseconds elapsed; + string console; + transaction_id_type trx_id; ///< the transaction that generated this action + uint32_t block_num = 0; + block_timestamp_type block_time; fc::optional producer_block_id; flat_set account_ram_deltas; fc::optional except; + fc::optional error_code; }; - struct action_trace : public base_action_trace { - using base_action_trace::base_action_trace; - - vector inline_traces; - }; - - struct transaction_trace; - using transaction_trace_ptr = std::shared_ptr; - struct transaction_trace { transaction_id_type id; uint32_t block_num = 0; @@ -56,10 +55,12 @@ namespace eosio { namespace chain { fc::microseconds elapsed; uint64_t net_usage = 0; bool scheduled = false; - vector action_traces; ///< disposable + vector action_traces; + fc::optional account_ram_delta; transaction_trace_ptr failed_dtrx_trace; fc::optional except; + fc::optional error_code; std::exception_ptr except_ptr; }; @@ -68,13 +69,11 @@ namespace eosio { namespace chain { FC_REFLECT( eosio::chain::account_delta, (account)(delta) ) -FC_REFLECT( eosio::chain::base_action_trace, - (receipt)(act)(context_free)(elapsed)(console)(trx_id) - (block_num)(block_time)(producer_block_id)(account_ram_deltas)(except) ) - -FC_REFLECT_DERIVED( eosio::chain::action_trace, - (eosio::chain::base_action_trace), (inline_traces) ) +FC_REFLECT( eosio::chain::action_trace, + (action_ordinal)(creator_action_ordinal)(closest_unnotified_ancestor_action_ordinal)(receipt) + (receiver)(act)(context_free)(elapsed)(console)(trx_id)(block_num)(block_time) + (producer_block_id)(account_ram_deltas)(except)(error_code) ) FC_REFLECT( eosio::chain::transaction_trace, (id)(block_num)(block_time)(producer_block_id) (receipt)(elapsed)(net_usage)(scheduled) - (action_traces)(failed_dtrx_trace)(except) ) + (action_traces)(account_ram_delta)(failed_dtrx_trace)(except)(error_code) ) diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index 0d627c6613b..cbbca9b5b1e 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -6,40 +6,27 @@ namespace eosio { namespace chain { - struct transaction_checktime_timer { - public: - transaction_checktime_timer() = delete; - transaction_checktime_timer(const transaction_checktime_timer&) = delete; - transaction_checktime_timer(transaction_checktime_timer&&) = default; - ~transaction_checktime_timer(); - - void start(fc::time_point tp); - void stop(); - - /* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or - on any particular thread. Only a single callback can be registered at once; trying to register more will - result in an exception. Use nullptr to disable a previously set callback. */ - void set_expiration_callback(void(*func)(void*), void* user); - - std::atomic_bool& expired; - private: - platform_timer& _timer; - - transaction_checktime_timer(platform_timer& timer); - friend controller_impl; - }; - - struct deadline_timer { - deadline_timer(); - ~deadline_timer(); + struct transaction_checktime_timer { + public: + transaction_checktime_timer() = delete; + transaction_checktime_timer(const transaction_checktime_timer&) = delete; + transaction_checktime_timer(transaction_checktime_timer&&) = default; + ~transaction_checktime_timer(); void start(fc::time_point tp); void stop(); - static volatile sig_atomic_t expired; + /* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or + on any particular thread. Only a single callback can be registered at once; trying to register more will + result in an exception. Use nullptr to disable a previously set callback. */ + void set_expiration_callback(void(*func)(void*), void* user); + + std::atomic_bool& expired; private: - static void timer_expired(int); - static bool initialized; + platform_timer& _timer; + + transaction_checktime_timer(platform_timer& timer); + friend controller_impl; }; class transaction_context { @@ -51,8 +38,8 @@ namespace eosio { namespace chain { transaction_context( controller& c, const signed_transaction& t, const transaction_id_type& trx_id, - transaction_checktime_timer&& timer, - fc::time_point start = fc::time_point::now() ); + transaction_checktime_timer&& timer, + fc::time_point start = fc::time_point::now() ); void init_for_implicit_trx( uint64_t initial_net_usage = 0 ); @@ -89,14 +76,30 @@ namespace eosio { namespace chain { void add_ram_usage( account_name account, int64_t ram_delta ); - void dispatch_action( action_trace& trace, const action& a, account_name receiver, bool context_free = false, uint32_t recurse_depth = 0 ); - inline void dispatch_action( action_trace& trace, const action& a, bool context_free = false ) { - dispatch_action(trace, a, a.account, context_free); - }; + action_trace& get_action_trace( uint32_t action_ordinal ); + const action_trace& get_action_trace( uint32_t action_ordinal )const; + + /** invalidates any action_trace references returned by get_action_trace */ + uint32_t schedule_action( const action& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal ); + + /** invalidates any action_trace references returned by get_action_trace */ + uint32_t schedule_action( action&& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal ); + + /** invalidates any action_trace references returned by get_action_trace */ + uint32_t schedule_action( uint32_t action_ordinal, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal ); + + void execute_action( uint32_t action_ordinal, uint32_t recurse_depth ); + void schedule_transaction(); void record_transaction( const transaction_id_type& id, fc::time_point_sec expire ); - void validate_cpu_usage_to_bill( int64_t u, bool check_minimum = true )const; + void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const; + void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, bool estimate )const; + + void disallow_transaction_extensions( const char* error_msg )const; /// Fields: public: @@ -130,7 +133,7 @@ namespace eosio { namespace chain { transaction_checktime_timer transaction_timer; - private: + private: bool is_initialized = false; @@ -150,8 +153,6 @@ namespace eosio { namespace chain { fc::time_point pseudo_start; fc::microseconds billed_time; fc::microseconds billing_timer_duration_limit; - - deadline_timer _deadline_timer; }; } } diff --git a/libraries/chain/include/eosio/chain/webassembly/wabt.hpp b/libraries/chain/include/eosio/chain/webassembly/wabt.hpp index 49cbfef05c1..ae403ce3ed3 100644 --- a/libraries/chain/include/eosio/chain/webassembly/wabt.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/wabt.hpp @@ -190,7 +190,7 @@ inline auto convert_native_to_literal(const wabt_apply_instance_vars&, const dou inline auto convert_native_to_literal(const wabt_apply_instance_vars&, const name &val) { TypedValue tv(Type::I64); - tv.set_i64(val.value); + tv.set_i64(val.to_uint64_t()); return tv; } diff --git a/libraries/chain/include/eosio/chain/webassembly/wavm.hpp b/libraries/chain/include/eosio/chain/webassembly/wavm.hpp index 16ff8dd96cd..7dde4a443bd 100644 --- a/libraries/chain/include/eosio/chain/webassembly/wavm.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/wavm.hpp @@ -145,600 +145,6 @@ struct wasm_function_type_provider { #define __INTRINSIC_NAME(LABEL, SUFFIX) LABEL##SUFFIX #define _INTRINSIC_NAME(LABEL, SUFFIX) __INTRINSIC_NAME(LABEL,SUFFIX) -#ifdef EOSIO_WAVM_RUNTIME_ENABLED - -/** - * class to represent an in-wasm-memory array - * it is a hint to the transcriber that the next parameter will - * be a size (in Ts) and that the pair are validated together - * This triggers the template specialization of intrinsic_invoker_impl - * @tparam T - */ -template -inline array_ptr array_ptr_impl (running_instance_context& ctx, U32 ptr, size_t length) -{ - MemoryInstance* mem = ctx.memory; - if (!mem) - Runtime::causeException(Exception::Cause::accessViolation); - - size_t mem_total = IR::numBytesPerPage * Runtime::getMemoryNumPages(mem); - if (ptr >= mem_total || length > (mem_total - ptr) / sizeof(T)) - Runtime::causeException(Exception::Cause::accessViolation); - - T* ret_ptr = (T*)(getMemoryBaseAddress(mem) + ptr); - - return array_ptr((T*)(getMemoryBaseAddress(mem) + ptr)); -} - -/** - * class to represent an in-wasm-memory char array that must be null terminated - */ -inline null_terminated_ptr null_terminated_ptr_impl(running_instance_context& ctx, U32 ptr) -{ - MemoryInstance* mem = ctx.memory; - if(!mem) - Runtime::causeException(Exception::Cause::accessViolation); - - char *value = (char*)(getMemoryBaseAddress(mem) + ptr); - const char* p = value; - const char* const top_of_memory = (char*)(getMemoryBaseAddress(mem) + IR::numBytesPerPage*Runtime::getMemoryNumPages(mem)); - while(p < top_of_memory) - if(*p++ == '\0') - return null_terminated_ptr(value); - - Runtime::causeException(Exception::Cause::accessViolation); -} - - -/** - * template that maps native types to WASM VM types - * @tparam T the native type - */ -template -struct native_to_wasm { - using type = void; -}; - -/** - * specialization for mapping pointers to int32's - */ -template -struct native_to_wasm { - using type = I32; -}; - -/** - * Mappings for native types - */ -template<> -struct native_to_wasm { - using type = F32; -}; -template<> -struct native_to_wasm { - using type = F64; -}; -template<> -struct native_to_wasm { - using type = I32; -}; -template<> -struct native_to_wasm { - using type = I32; -}; -template<> -struct native_to_wasm { - using type = I64; -}; -template<> -struct native_to_wasm { - using type = I64; -}; -template<> -struct native_to_wasm { - using type = I32; -}; -template<> -struct native_to_wasm { - using type = I64; -}; -template<> -struct native_to_wasm { - using type = I64; -}; -template<> -struct native_to_wasm { - using type = I32; -}; - -template<> -struct native_to_wasm { - using type = I32; -}; - -// convenience alias -template -using native_to_wasm_t = typename native_to_wasm::type; - -template -inline auto convert_native_to_wasm(const running_instance_context& ctx, T val) { - return native_to_wasm_t(val); -} - -inline auto convert_native_to_wasm(const running_instance_context& ctx, const name &val) { - return native_to_wasm_t(val.value); -} - -inline auto convert_native_to_wasm(const running_instance_context& ctx, const fc::time_point_sec& val) { - return native_to_wasm_t(val.sec_since_epoch()); -} - -inline auto convert_native_to_wasm(running_instance_context& ctx, char* ptr) { - MemoryInstance* mem = ctx.memory; - if(!mem) - Runtime::causeException(Exception::Cause::accessViolation); - char* base = (char*)getMemoryBaseAddress(mem); - char* top_of_memory = base + IR::numBytesPerPage*Runtime::getMemoryNumPages(mem); - if(ptr < base || ptr >= top_of_memory) - Runtime::causeException(Exception::Cause::accessViolation); - return (U32)(ptr - base); -} - -template -inline auto convert_wasm_to_native(native_to_wasm_t val) { - return T(val); -} - -/** - * Forward declaration of the invoker type which transcribes arguments to/from a native method - * and injects the appropriate checks - * - * @tparam Ret - the return type of the native function - * @tparam NativeParameters - a std::tuple of the remaining native parameters to transcribe - * @tparam WasmParameters - a std::tuple of the transribed parameters - */ -template -struct intrinsic_invoker_impl; - -/** - * Specialization for the fully transcribed signature - * @tparam Ret - the return type of the native function - * @tparam Translated - the arguments to the wasm function - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_method_type = Ret (*)(running_instance_context &, Translated...); - - template - static native_to_wasm_t invoke(Translated... translated) { - try { - return convert_native_to_wasm(the_running_instance_context, Method(the_running_instance_context, translated...)); - } - catch(...) { - Platform::immediately_exit(std::current_exception()); - } - } - - template - static const auto fn() { - return invoke; - } -}; - -/** - * specialization of the fully transcribed signature for void return values - * @tparam Translated - the arguments to the wasm function - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_method_type = void_type (*)(running_instance_context &, Translated...); - - template - static void invoke(Translated... translated) { - try { - Method(the_running_instance_context, translated...); - } - catch(...) { - Platform::immediately_exit(std::current_exception()); - } - } - - template - static const auto fn() { - return invoke; - } -}; - -/** - * Sepcialization for transcribing a simple type in the native method signature - * @tparam Ret - the return type of the native method - * @tparam Input - the type of the native parameter to transcribe - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using translated_type = native_to_wasm_t; - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret (*)(running_instance_context &, Input, Inputs..., Translated...); - - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, translated_type last) { - auto native = convert_wasm_to_native(last); - return Then(ctx, native, rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a array_ptr type in the native method signature - * This type transcribes into 2 wasm parameters: a pointer and byte length and checks the validity of that memory - * range before dispatching to the native method - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, uint32_t, Inputs...>, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret(*)(running_instance_context&, array_ptr, uint32_t, Inputs..., Translated...); - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr, I32 size) -> std::enable_if_t::value, Ret> { - static_assert(!std::is_pointer::value, "Currently don't support array of pointers"); - const auto length = size_t(size); - T* base = array_ptr_impl(ctx, (U32)ptr, length); - if ( reinterpret_cast(base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned array of const values" ); - std::vector > copy(length > 0 ? length : 1); - T* copy_ptr = ©[0]; - memcpy( (void*)copy_ptr, (void*)base, length * sizeof(T) ); - return Then(ctx, static_cast>(copy_ptr), length, rest..., translated...); - } - return Then(ctx, static_cast>(base), length, rest..., translated...); - }; - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr, I32 size) -> std::enable_if_t::value, Ret> { - static_assert(!std::is_pointer::value, "Currently don't support array of pointers"); - const auto length = size_t(size); - T* base = array_ptr_impl(ctx, (U32)ptr, length); - if ( reinterpret_cast(base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned array of values" ); - std::vector > copy(length > 0 ? length : 1); - T* copy_ptr = ©[0]; - memcpy( (void*)copy_ptr, (void*)base, length * sizeof(T) ); - Ret ret = Then(ctx, static_cast>(copy_ptr), length, rest..., translated...); - memcpy( (void*)base, (void*)copy_ptr, length * sizeof(T) ); - return ret; - } - return Then(ctx, static_cast>(base), length, rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a null_terminated_ptr type in the native method signature - * This type transcribes 1 wasm parameters: a char pointer which is validated to contain - * a null value before the end of the allocated memory. - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret(*)(running_instance_context&, null_terminated_ptr, Inputs..., Translated...); - - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) { - return Then(ctx, null_terminated_ptr_impl(ctx, (U32)ptr), rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a pair of array_ptr types in the native method signature that share size - * This type transcribes into 3 wasm parameters: 2 pointers and byte length and checks the validity of those memory - * ranges before dispatching to the native method - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, array_ptr, uint32_t, Inputs...>, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret(*)(running_instance_context&, array_ptr, array_ptr, uint32_t, Inputs..., Translated...); - - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr_t, I32 ptr_u, I32 size) { - static_assert(std::is_same, char>::value && std::is_same, char>::value, "Currently only support array of (const)chars"); - const auto length = size_t(size); - return Then(ctx, array_ptr_impl(ctx, (U32)ptr_t, length), array_ptr_impl(ctx, (U32)ptr_u, length), length, rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing memset parameters - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, int, uint32_t>, std::tuple<>> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret(*)(running_instance_context&, array_ptr, int, uint32_t); - - template - static Ret translate_one(running_instance_context& ctx, I32 ptr, I32 value, I32 size) { - const auto length = size_t(size); - return Then(ctx, array_ptr_impl(ctx, (U32)ptr, length), value, length); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a pointer type in the native method signature - * This type transcribes into an int32 pointer checks the validity of that memory - * range before dispatching to the native method - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret (*)(running_instance_context&, T *, Inputs..., Translated...); - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t::value, Ret> { - T* base = array_ptr_impl(ctx, (U32)ptr, 1); - if ( reinterpret_cast(base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned const pointer" ); - std::remove_const_t copy; - T* copy_ptr = © - memcpy( (void*)copy_ptr, (void*)base, sizeof(T) ); - return Then(ctx, copy_ptr, rest..., translated...); - } - return Then(ctx, base, rest..., translated...); - }; - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t::value, Ret> { - T* base = array_ptr_impl(ctx, (U32)ptr, 1); - if ( reinterpret_cast(base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned pointer" ); - std::remove_const_t copy; - T* copy_ptr = © - memcpy( (void*)copy_ptr, (void*)base, sizeof(T) ); - Ret ret = Then(ctx, copy_ptr, rest..., translated...); - memcpy( (void*)base, (void*)copy_ptr, sizeof(T) ); - return ret; - } - return Then(ctx, base, rest..., translated...); - }; - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a reference to a name which can be passed as a native value - * This type transcribes into a native type which is loaded by value into a - * variable on the stack and then passed by reference to the intrinsic. - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple >>; - using then_type = Ret (*)(running_instance_context&, const name&, Inputs..., Translated...); - - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, native_to_wasm_t wasm_value) { - auto value = name(wasm_value); - return Then(ctx, value, rest..., translated...); - } - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * Specialization for transcribing a reference type in the native method signature - * This type transcribes into an int32 pointer checks the validity of that memory - * range before dispatching to the native method - * - * @tparam Ret - the return type of the native method - * @tparam Inputs - the remaining native parameters to transcribe - * @tparam Translated - the list of transcribed wasm parameters - */ -template -struct intrinsic_invoker_impl, std::tuple> { - using next_step = intrinsic_invoker_impl, std::tuple>; - using then_type = Ret (*)(running_instance_context &, T &, Inputs..., Translated...); - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t::value, Ret> { - // references cannot be created for null pointers - EOS_ASSERT((U32)ptr != 0, wasm_exception, "references cannot be created for null pointers"); - MemoryInstance* mem = ctx.memory; - if(!mem || (U32)ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem)) - Runtime::causeException(Exception::Cause::accessViolation); - T &base = *(T*)(getMemoryBaseAddress(mem)+(U32)ptr); - if ( reinterpret_cast(&base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned const reference" ); - std::remove_const_t copy; - T* copy_ptr = © - memcpy( (void*)copy_ptr, (void*)&base, sizeof(T) ); - return Then(ctx, *copy_ptr, rest..., translated...); - } - return Then(ctx, base, rest..., translated...); - } - - template - static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t::value, Ret> { - // references cannot be created for null pointers - EOS_ASSERT((U32)ptr != 0, wasm_exception, "reference cannot be created for null pointers"); - MemoryInstance* mem = ctx.memory; - if(!mem || (U32)ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem)) - Runtime::causeException(Exception::Cause::accessViolation); - T &base = *(T*)(getMemoryBaseAddress(mem)+(U32)ptr); - if ( reinterpret_cast(&base) % alignof(T) != 0 ) { - if(ctx.apply_ctx->control.contracts_console()) - wlog( "misaligned reference" ); - std::remove_const_t copy; - T* copy_ptr = © - memcpy( (void*)copy_ptr, (void*)&base, sizeof(T) ); - Ret ret = Then(ctx, *copy_ptr, rest..., translated...); - memcpy( (void*)&base, (void*)copy_ptr, sizeof(T) ); - return ret; - } - return Then(ctx, base, rest..., translated...); - } - - template - static const auto fn() { - return next_step::template fn>(); - } -}; - -/** - * forward declaration of a wrapper class to call methods of the class - */ -template -struct intrinsic_function_invoker { - using impl = intrinsic_invoker_impl, std::tuple<>>; - - template - static Ret wrapper(running_instance_context& ctx, Params... params) { - class_from_wasm::value(*ctx.apply_ctx).checktime(); - return (class_from_wasm::value(*ctx.apply_ctx).*Method)(params...); - } - - template - static const WasmSig *fn() { - auto fn = impl::template fn>(); - static_assert(std::is_same::value, - "Intrinsic function signature does not match the ABI"); - return fn; - } -}; - -template -struct intrinsic_function_invoker { - using impl = intrinsic_invoker_impl, std::tuple<>>; - - template - static void_type wrapper(running_instance_context& ctx, Params... params) { - class_from_wasm::value(*ctx.apply_ctx).checktime(); - (class_from_wasm::value(*ctx.apply_ctx).*Method)(params...); - return void_type(); - } - - template - static const WasmSig *fn() { - auto fn = impl::template fn>(); - static_assert(std::is_same::value, - "Intrinsic function signature does not match the ABI"); - return fn; - } -}; - -template -struct void_ret_wrapper { - using type = T; -}; - -template<> -struct void_ret_wrapper { - using type = char; -}; - -template -using void_ret_wrapper_t = typename void_ret_wrapper::type; - -template -struct intrinsic_function_invoker_wrapper; - -template -struct intrinsic_function_invoker_wrapper { - static_assert( !(std::is_pointer_v && alignof(std::remove_pointer_t>) != 1) && - !(std::is_lvalue_reference_v && alignof(std::remove_reference_t>) != 1), - "intrinsics should only return a reference or pointer with single byte alignment"); - using type = intrinsic_function_invoker; -}; - -template -struct intrinsic_function_invoker_wrapper { - static_assert( !(std::is_pointer_v && alignof(std::remove_pointer_t>) != 1) && - !(std::is_lvalue_reference_v && alignof(std::remove_reference_t>) != 1), - "intrinsics should only return a reference or pointer with single byte alignment"); - using type = intrinsic_function_invoker; -}; - -template -struct intrinsic_function_invoker_wrapper { - static_assert( !(std::is_pointer_v && alignof(std::remove_pointer_t>) != 1) && - !(std::is_lvalue_reference_v && alignof(std::remove_reference_t>) != 1), - "intrinsics should only return a reference or pointer with single byte alignment"); - using type = intrinsic_function_invoker; -}; - -template -struct intrinsic_function_invoker_wrapper { - static_assert( !(std::is_pointer_v && alignof(std::remove_pointer_t>) != 1) && - !(std::is_lvalue_reference_v && alignof(std::remove_reference_t>) != 1), - "intrinsics should only return a reference or pointer with single byte alignment"); - using type = intrinsic_function_invoker; -}; - -#define _REGISTER_WAVM_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\ - static Intrinsics::Function _INTRINSIC_NAME(__intrinsic_fn, __COUNTER__) (\ - MOD "." NAME,\ - eosio::chain::webassembly::wavm::wasm_function_type_provider::type(),\ - (void *)eosio::chain::webassembly::wavm::intrinsic_function_invoker_wrapper::type::fn<&CLS::METHOD>()\ - ); - -#else - #define _REGISTER_WAVM_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\ static Intrinsics::Function _INTRINSIC_NAME(__intrinsic_fn, __COUNTER__) (\ MOD "." NAME,\ @@ -746,6 +152,4 @@ struct intrinsic_function_invoker_wrapper #include -namespace eosio { namespace chain { +namespace eosio::chain { - void name::set( const char* str ) { - const auto len = strnlen(str, 14); - EOS_ASSERT(len <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name", string(str))); - value = string_to_name(str); - EOS_ASSERT(to_string() == string(str), name_type_exception, + void name::set( std::string_view str ) { + const auto len = str.size(); + EOS_ASSERT(len <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name", std::string(str))); + value = string_to_uint64_t(str); + EOS_ASSERT(to_string() == str, name_type_exception, "Name not properly normalized (name: ${name}, normalized: ${normalized}) ", - ("name", string(str))("normalized", to_string())); + ("name", std::string(str))("normalized", to_string())); } // keep in sync with name::to_string() in contract definition for name - name::operator string()const { + std::string name::to_string()const { static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz"; - string str(13,'.'); + std::string str(13,'.'); uint64_t tmp = value; for( uint32_t i = 0; i <= 12; ++i ) { @@ -32,9 +32,9 @@ namespace eosio { namespace chain { return str; } -} } /// eosio::chain +} // eosio::chain namespace fc { - void to_variant(const eosio::chain::name& c, fc::variant& v) { v = std::string(c); } - void from_variant(const fc::variant& v, eosio::chain::name& check) { check = v.get_string(); } + void to_variant(const eosio::chain::name& c, fc::variant& v) { v = c.to_string(); } + void from_variant(const fc::variant& v, eosio::chain::name& check) { check.set( v.get_string() ); } } // fc diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index c8ebab42447..891c160bd36 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace eosio { namespace chain { @@ -597,19 +598,29 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); - for (const auto& vc: vcc.view_changes) { - if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num()) { - highest_ppc = vc.prepared_cert; + // shuffle view changes to avoid fixed orders. + std::vector idx_v(vcc.view_changes.size()) ; + std::iota (std::begin(idx_v), std::end(idx_v), 0); + auto seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::shuffle( idx_v.begin(), idx_v.end(), std::default_random_engine(seed)); + for (const auto i: idx_v) { + auto& prepared_cert = vcc.view_changes[i].prepared_cert; + auto& committed_certs = vcc.view_changes[i].committed_certs; + auto& stable_ckpts = vcc.view_changes[i].stable_checkpoint; + if (prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() + && is_valid_prepared_certificate(prepared_cert)) { + highest_ppc = prepared_cert; } - for (const auto& cc: vc.committed_certs) { + for (const auto& cc:committed_certs ) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); - if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); + if (p_itr == highest_pcc.end() && is_valid_committed_certificate(cc)) highest_pcc.emplace_back(cc); } - if (vc.stable_checkpoint.block_info.block_num() > highest_sc.block_info.block_num()) { - highest_sc = vc.stable_checkpoint; + if (stable_ckpts.block_info.block_num() > highest_sc.block_info.block_num() + && is_valid_stable_checkpoint(stable_ckpts)) { + highest_sc = stable_ckpts; } } diff --git a/libraries/chain/trace.cpp b/libraries/chain/trace.cpp new file mode 100644 index 00000000000..7ce555d8a11 --- /dev/null +++ b/libraries/chain/trace.cpp @@ -0,0 +1,37 @@ +#include + +namespace eosio { namespace chain { + +action_trace::action_trace( + const transaction_trace& trace, const action& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal +) +:action_ordinal( action_ordinal ) +,creator_action_ordinal( creator_action_ordinal ) +,closest_unnotified_ancestor_action_ordinal( closest_unnotified_ancestor_action_ordinal ) +,receiver( receiver ) +,act( act ) +,context_free( context_free ) +,trx_id( trace.id ) +,block_num( trace.block_num ) +,block_time( trace.block_time ) +,producer_block_id( trace.producer_block_id ) +{} + +action_trace::action_trace( + const transaction_trace& trace, action&& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t closest_unnotified_ancestor_action_ordinal +) +:action_ordinal( action_ordinal ) +,creator_action_ordinal( creator_action_ordinal ) +,closest_unnotified_ancestor_action_ordinal( closest_unnotified_ancestor_action_ordinal ) +,receiver( receiver ) +,act( std::move(act) ) +,context_free( context_free ) +,trx_id( trace.id ) +,block_num( trace.block_num ) +,block_time( trace.block_time ) +,producer_block_id( trace.producer_block_id ) +{} + +} } // eosio::chain diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 619afb2ce19..8018440bda6 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -21,158 +21,33 @@ namespace eosio { namespace chain { -namespace bacc = boost::accumulators; - - struct deadline_timer_verify { - deadline_timer_verify() { - //keep longest first in list. You're effectively going to take test_intervals[0]*sizeof(test_intervals[0]) - //time to do the the "calibration" - int test_intervals[] = {50000, 10000, 5000, 1000, 500, 100, 50, 10}; - - struct sigaction act; - sigemptyset(&act.sa_mask); - act.sa_handler = timer_hit; - act.sa_flags = 0; - if(sigaction(SIGALRM, &act, NULL)) - return; - - sigset_t alrm; - sigemptyset(&alrm); - sigaddset(&alrm, SIGALRM); - int dummy; - - for(int& interval : test_intervals) { - unsigned int loops = test_intervals[0]/interval; - - for(unsigned int i = 0; i < loops; ++i) { - struct itimerval enable = {{0, 0}, {0, interval}}; - hit = 0; - auto start = std::chrono::high_resolution_clock::now(); - if(setitimer(ITIMER_REAL, &enable, NULL)) - return; - while(!hit) {} - auto end = std::chrono::high_resolution_clock::now(); - int timer_slop = std::chrono::duration_cast(end-start).count() - interval; - - //since more samples are run for the shorter expirations, weigh the longer expirations accordingly. This - //helps to make a few results more fair. Two such examples: AWS c4&i5 xen instances being rather stable - //down to 100us but then struggling with 50us and 10us. MacOS having performance that seems to correlate - //with expiry length; that is, long expirations have high error, short expirations have low error. - //That said, for these platforms, a tighter tolerance may possibly be achieved by taking performance - //metrics in mulitple bins and appliying the slop based on which bin a deadline resides in. Not clear - //if that's worth the extra complexity at this point. - samples(timer_slop, bacc::weight = interval/(float)test_intervals[0]); - } - } - timer_overhead = bacc::mean(samples) + sqrt(bacc::variance(samples))*2; //target 95% of expirations before deadline - use_deadline_timer = timer_overhead < 1000; - - act.sa_handler = SIG_DFL; - sigaction(SIGALRM, &act, NULL); - } - - static void timer_hit(int) { - hit = 1; - } - static volatile sig_atomic_t hit; - - bacc::accumulator_set, float> samples; - bool use_deadline_timer = false; - int timer_overhead; - }; - volatile sig_atomic_t deadline_timer_verify::hit; - static deadline_timer_verify deadline_timer_verification; - - deadline_timer::deadline_timer() { - if(initialized) - return; - initialized = true; - - #define TIMER_STATS_FORMAT "min:${min}us max:${max}us mean:${mean}us stddev:${stddev}us" - #define TIMER_STATS \ - ("min", bacc::min(deadline_timer_verification.samples))("max", bacc::max(deadline_timer_verification.samples)) \ - ("mean", (int)bacc::mean(deadline_timer_verification.samples))("stddev", (int)sqrt(bacc::variance(deadline_timer_verification.samples))) \ - ("t", deadline_timer_verification.timer_overhead) - - if(deadline_timer_verification.use_deadline_timer) { - struct sigaction act; - act.sa_handler = timer_expired; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - if(sigaction(SIGALRM, &act, NULL) == 0) { - ilog("Using ${t}us deadline timer for checktime: " TIMER_STATS_FORMAT, TIMER_STATS); - return; - } - } - - wlog("Using polled checktime; deadline timer too inaccurate: " TIMER_STATS_FORMAT, TIMER_STATS); - deadline_timer_verification.use_deadline_timer = false; //set in case sigaction() fails above + transaction_checktime_timer::transaction_checktime_timer(platform_timer& timer) + : expired(timer.expired), _timer(timer) { + expired = 0; } - void deadline_timer::start(fc::time_point tp) { - if(tp == fc::time_point::maximum()) { - expired = 0; - return; - } - if(!deadline_timer_verification.use_deadline_timer) { - expired = 1; - return; - } - microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch(); - if(x.count() <= deadline_timer_verification.timer_overhead) - expired = 1; - else { - struct itimerval enable = {{0, 0}, {0, (int)x.count()-deadline_timer_verification.timer_overhead}}; - expired = 0; - if(setitimer(ITIMER_REAL, &enable, NULL)) - expired = 1; - } + void transaction_checktime_timer::start(fc::time_point tp) { + _timer.start(tp); } - void deadline_timer::stop() { - if(expired) - return; - struct itimerval disable = {{0, 0}, {0, 0}}; - setitimer(ITIMER_REAL, &disable, NULL); + void transaction_checktime_timer::stop() { + _timer.stop(); } - deadline_timer::~deadline_timer() { - stop(); + void transaction_checktime_timer::set_expiration_callback(void(*func)(void*), void* user) { + _timer.set_expiration_callback(func, user); } - void deadline_timer::timer_expired(int) { - expired = 1; + transaction_checktime_timer::~transaction_checktime_timer() { + stop(); + _timer.set_expiration_callback(nullptr, nullptr); } - volatile sig_atomic_t deadline_timer::expired = 0; - bool deadline_timer::initialized = false; - - transaction_checktime_timer::transaction_checktime_timer(platform_timer& timer) - : expired(timer.expired), _timer(timer) { - expired = 0; - } - - void transaction_checktime_timer::start(fc::time_point tp) { - _timer.start(tp); - } - - void transaction_checktime_timer::stop() { - _timer.stop(); - } - - void transaction_checktime_timer::set_expiration_callback(void(*func)(void*), void* user) { - _timer.set_expiration_callback(func, user); - } - - transaction_checktime_timer::~transaction_checktime_timer() { - stop(); - _timer.set_expiration_callback(nullptr, nullptr); - } transaction_context::transaction_context( controller& c, const signed_transaction& t, const transaction_id_type& trx_id, - transaction_checktime_timer&& tmr, - fc::time_point s ) + transaction_checktime_timer&& tmr, + fc::time_point s ) :control(c) ,trx(t) ,id(trx_id) @@ -187,11 +62,18 @@ namespace bacc = boost::accumulators; undo_session = c.mutable_db().start_undo_session(true); } trace->id = id; - trace->block_num = c.pending_block_state()->block_num; + trace->block_num = c.head_block_num() + 1; trace->block_time = c.pending_block_time(); trace->producer_block_id = c.pending_producer_block_id(); executed.reserve( trx.total_actions() ); - EOS_ASSERT( trx.transaction_extensions.size() == 0, unsupported_feature, "we don't support any extensions yet" ); + } + + void transaction_context::disallow_transaction_extensions( const char* error_msg )const { + if( control.is_producing_block() ) { + EOS_THROW( subjective_block_production_exception, error_msg ); + } else { +// EOS_THROW( disallowed_transaction_extensions_bad_block_exception, error_msg ); + } } void transaction_context::init(uint64_t initial_net_usage) @@ -239,8 +121,8 @@ namespace bacc = boost::accumulators; initial_objective_duration_limit = objective_duration_limit; - if( billed_cpu_time_us > 0 ) // could also call on explicit_billed_cpu_time but it would be redundant - validate_cpu_usage_to_bill( billed_cpu_time_us, false ); // Fail early if the amount to be billed is too high + if( explicit_billed_cpu_time ) + validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits::max(), false ); // Fail early if the amount to be billed is too high // Record accounts to be billed for network and CPU usage for( const auto& act : trx.actions ) { @@ -286,6 +168,11 @@ namespace bacc = boost::accumulators; deadline_exception_code = billing_timer_exception_code; } + if( !explicit_billed_cpu_time ) { + // if account no longer has enough cpu to exec trx, don't try + validate_account_cpu_usage( billed_cpu_time_us, account_cpu_limit, true ); + } + eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes) so check_net_usage can be efficient if( initial_net_usage > 0 ) @@ -294,15 +181,19 @@ namespace bacc = boost::accumulators; checktime(); // Fail early if deadline has already been exceeded if(control.skip_trx_checks()) - _deadline_timer.expired = 0; + transaction_timer.start(fc::time_point::maximum()); else - _deadline_timer.start(_deadline); + transaction_timer.start(_deadline); is_initialized = true; } void transaction_context::init_for_implicit_trx( uint64_t initial_net_usage ) { + if( trx.transaction_extensions.size() > 0 ) { + disallow_transaction_extensions( "no transaction extensions supported yet for implicit transactions" ); + } + published = control.pending_block_time(); init( initial_net_usage); } @@ -311,6 +202,10 @@ namespace bacc = boost::accumulators; uint64_t packed_trx_prunable_size, bool skip_recording ) { + if( trx.transaction_extensions.size() > 0 ) { + disallow_transaction_extensions( "no transaction extensions supported yet for input transactions" ); + } + const auto& cfg = control.get_global_properties().configuration; uint64_t discounted_size_for_pruned_data = packed_trx_prunable_size; @@ -347,6 +242,14 @@ namespace bacc = boost::accumulators; void transaction_context::init_for_deferred_trx( fc::time_point p ) { + if( (trx.expiration.sec_since_epoch() != 0) && (trx.transaction_extensions.size() > 0) ) { + disallow_transaction_extensions( "no transaction extensions supported yet for deferred transactions" ); + } + // If (trx.expiration.sec_since_epoch() == 0) then it was created after NO_DUPLICATE_DEFERRED_ID activation, + // and so validation of its extensions was done either in: + // * apply_context::schedule_deferred_transaction for contract-generated transactions; + // * or transaction_context::init_for_input_trx for delayed input transactions. + published = p; trace->scheduled = true; apply_context_free = false; @@ -358,17 +261,23 @@ namespace bacc = boost::accumulators; if( apply_context_free ) { for( const auto& act : trx.context_free_actions ) { - trace->action_traces.emplace_back(); - dispatch_action( trace->action_traces.back(), act, true ); + schedule_action( act, act.account, true, 0, 0 ); } } if( delay == fc::microseconds() ) { for( const auto& act : trx.actions ) { - trace->action_traces.emplace_back(); - dispatch_action( trace->action_traces.back(), act ); + schedule_action( act, act.account, false, 0, 0 ); } - } else { + } + + auto& action_traces = trace->action_traces; + uint32_t num_original_actions_to_execute = action_traces.size(); + for( uint32_t i = 1; i <= num_original_actions_to_execute; ++i ) { + execute_action( i, 0 ); + } + + if( delay != fc::microseconds() ) { schedule_transaction(); } } @@ -422,7 +331,7 @@ namespace bacc = boost::accumulators; update_billed_cpu_time( now ); - validate_cpu_usage_to_bill( billed_cpu_time_us ); + validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true ); rl.add_transaction_usage( bill_to_accounts, static_cast(billed_cpu_time_us), net_usage, block_timestamp_type(control.pending_block_time()).slot ); // Should never fail @@ -457,35 +366,34 @@ namespace bacc = boost::accumulators; } void transaction_context::checktime()const { - if(BOOST_LIKELY(_deadline_timer.expired == false)) + if(BOOST_LIKELY(transaction_timer.expired == false)) return; + auto now = fc::time_point::now(); - if( BOOST_UNLIKELY( now > _deadline ) ) { - // edump((now-start)(now-pseudo_start)); - if( explicit_billed_cpu_time || deadline_exception_code == deadline_exception::code_value ) { - EOS_THROW( deadline_exception, "deadline exceeded", ("now", now)("deadline", _deadline)("start", start) ); - } else if( deadline_exception_code == block_cpu_usage_exceeded::code_value ) { - EOS_THROW( block_cpu_usage_exceeded, - "not enough time left in block to complete executing transaction", - ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); - } else if( deadline_exception_code == tx_cpu_usage_exceeded::code_value ) { - if (cpu_limit_due_to_greylist) { - EOS_THROW( greylist_cpu_usage_exceeded, - "greylisted transaction was executing for too long", - ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); - } else { - EOS_THROW( tx_cpu_usage_exceeded, - "transaction was executing for too long", - ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); - } - } else if( deadline_exception_code == leeway_deadline_exception::code_value ) { - EOS_THROW( leeway_deadline_exception, - "the transaction was unable to complete by deadline, " - "but it is possible it could have succeeded if it were allowed to run to completion", - ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); + if( explicit_billed_cpu_time || deadline_exception_code == deadline_exception::code_value ) { + EOS_THROW( deadline_exception, "deadline exceeded ${billing_timer}us", + ("billing_timer", now - pseudo_start)("now", now)("deadline", _deadline)("start", start) ); + } else if( deadline_exception_code == block_cpu_usage_exceeded::code_value ) { + EOS_THROW( block_cpu_usage_exceeded, + "not enough time left in block to complete executing transaction ${billing_timer}us", + ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); + } else if( deadline_exception_code == tx_cpu_usage_exceeded::code_value ) { + if (cpu_limit_due_to_greylist) { + EOS_THROW( greylist_cpu_usage_exceeded, + "greylisted transaction was executing for too long ${billing_timer}us", + ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); + } else { + EOS_THROW( tx_cpu_usage_exceeded, + "transaction was executing for too long ${billing_timer}us", + ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); } - EOS_ASSERT( false, transaction_exception, "unexpected deadline exception code" ); + } else if( deadline_exception_code == leeway_deadline_exception::code_value ) { + EOS_THROW( leeway_deadline_exception, + "the transaction was unable to complete by deadline, " + "but it is possible it could have succeeded if it were allowed to run to completion ${billing_timer}", + ("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) ); } + EOS_ASSERT( false, transaction_exception, "unexpected deadline exception code ${code}", ("code", deadline_exception_code) ); } void transaction_context::pause_billing_timer() { @@ -495,7 +403,7 @@ namespace bacc = boost::accumulators; billed_time = now - pseudo_start; deadline_exception_code = deadline_exception::code_value; // Other timeout exceptions cannot be thrown while billable timer is paused. pseudo_start = fc::time_point(); - _deadline_timer.stop(); + transaction_timer.stop(); } void transaction_context::resume_billing_timer() { @@ -510,10 +418,10 @@ namespace bacc = boost::accumulators; _deadline = deadline; deadline_exception_code = deadline_exception::code_value; } - _deadline_timer.start(_deadline); + transaction_timer.start(_deadline); } - void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, bool check_minimum )const { + void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const { if (!control.skip_trx_checks()) { if( check_minimum ) { const auto& cfg = control.get_global_properties().configuration; @@ -523,25 +431,35 @@ namespace bacc = boost::accumulators; ); } - if( billing_timer_exception_code == block_cpu_usage_exceeded::code_value ) { + validate_account_cpu_usage( billed_us, account_cpu_limit, false ); + } + } + + void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, bool estimate )const { + if( (billed_us > 0) && !control.skip_trx_checks() ) { + const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count()); + + if( !cpu_limited_by_account && (billing_timer_exception_code == block_cpu_usage_exceeded::code_value) ) { EOS_ASSERT( billed_us <= objective_duration_limit.count(), block_cpu_usage_exceeded, - "billed CPU time (${billed} us) is greater than the billable CPU time left in the block (${billable} us)", - ("billed", billed_us)("billable", objective_duration_limit.count()) - ); + "${desc} CPU time (${billed} us) is greater than the billable CPU time left in the block (${billable} us)", + ("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", objective_duration_limit.count() ) + ); } else { - if (cpu_limit_due_to_greylist) { - EOS_ASSERT( billed_us <= objective_duration_limit.count(), + if( cpu_limit_due_to_greylist && cpu_limited_by_account ) { + EOS_ASSERT( billed_us <= account_cpu_limit, greylist_cpu_usage_exceeded, - "billed CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)", - ("billed", billed_us)("billable", objective_duration_limit.count()) + "${desc} CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)", + ("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", account_cpu_limit ) ); } else { - EOS_ASSERT( billed_us <= objective_duration_limit.count(), + // exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater + const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count()); + EOS_ASSERT( billed_us <= cpu_limit, tx_cpu_usage_exceeded, - "billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)", - ("billed", billed_us)("billable", objective_duration_limit.count()) - ); + "${desc} CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)", + ("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", cpu_limit ) + ); } } } @@ -591,14 +509,75 @@ namespace bacc = boost::accumulators; return std::make_tuple(account_net_limit, account_cpu_limit, greylisted_net, greylisted_cpu); } - void transaction_context::dispatch_action( action_trace& trace, const action& a, account_name receiver, bool context_free, uint32_t recurse_depth ) { - apply_context acontext( control, *this, a, recurse_depth ); - acontext.context_free = context_free; - acontext.receiver = receiver; + action_trace& transaction_context::get_action_trace( uint32_t action_ordinal ) { + EOS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() , + transaction_exception, + "action_ordinal ${ordinal} is outside allowed range [1,${max}]", + ("ordinal", action_ordinal)("max", trace->action_traces.size()) + ); + return trace->action_traces[action_ordinal-1]; + } - acontext.exec( trace ); + const action_trace& transaction_context::get_action_trace( uint32_t action_ordinal )const { + EOS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() , + transaction_exception, + "action_ordinal ${ordinal} is outside allowed range [1,${max}]", + ("ordinal", action_ordinal)("max", trace->action_traces.size()) + ); + return trace->action_traces[action_ordinal-1]; } + uint32_t transaction_context::schedule_action( const action& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ) + { + uint32_t new_action_ordinal = trace->action_traces.size() + 1; + + trace->action_traces.emplace_back( *trace, act, receiver, context_free, + new_action_ordinal, creator_action_ordinal, + closest_unnotified_ancestor_action_ordinal ); + + return new_action_ordinal; + } + + uint32_t transaction_context::schedule_action( action&& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ) + { + uint32_t new_action_ordinal = trace->action_traces.size() + 1; + + trace->action_traces.emplace_back( *trace, std::move(act), receiver, context_free, + new_action_ordinal, creator_action_ordinal, + closest_unnotified_ancestor_action_ordinal ); + + return new_action_ordinal; + } + + uint32_t transaction_context::schedule_action( uint32_t action_ordinal, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, + uint32_t closest_unnotified_ancestor_action_ordinal ) + { + uint32_t new_action_ordinal = trace->action_traces.size() + 1; + + trace->action_traces.reserve( new_action_ordinal ); + + const action& provided_action = get_action_trace( action_ordinal ).act; + + // The reserve above is required so that the emplace_back below does not invalidate the provided_action reference. + + trace->action_traces.emplace_back( *trace, provided_action, receiver, context_free, + new_action_ordinal, creator_action_ordinal, + closest_unnotified_ancestor_action_ordinal ); + + return new_action_ordinal; + } + + void transaction_context::execute_action( uint32_t action_ordinal, uint32_t recurse_depth ) { + apply_context acontext( control, *this, action_ordinal, recurse_depth ); + acontext.exec(); + } + + void transaction_context::schedule_transaction() { // Charge ahead of time for the additional net usage needed to retire the delayed transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. @@ -622,7 +601,9 @@ namespace bacc = boost::accumulators; trx_size = gto.set( trx ); }); - add_ram_usage( cgto.payer, (config::billable_size_v + trx_size) ); + int64_t ram_delta = (config::billable_size_v + trx_size); + add_ram_usage( cgto.payer, ram_delta ); + trace->account_ram_delta = account_delta( cgto.payer, ram_delta ); } void transaction_context::record_transaction( const transaction_id_type& id, fc::time_point_sec expire ) { @@ -664,7 +645,7 @@ namespace bacc = boost::accumulators; EOS_ASSERT( actor != nullptr, transaction_exception, "action's authorizing actor '${account}' does not exist", ("account", auth.actor) ); EOS_ASSERT( auth_manager.find_permission(auth) != nullptr, transaction_exception, - "action's authorizations include a non-existent permission: {permission}", + "action's authorizations include a non-existent permission: ${permission}", ("permission", auth) ); if( enforce_actor_whitelist_blacklist ) actors.insert( auth.actor ); diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index a89251f293c..2f36c66741a 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -144,7 +144,7 @@ class privileged_api : public context_aware_api { privileged_api( apply_context& ctx ) :context_aware_api(ctx) { - EOS_ASSERT( context.privileged, unaccessible_api, "${code} does not have permission to call this API", ("code",context.receiver) ); + EOS_ASSERT( context.is_privileged(), unaccessible_api, "${code} does not have permission to call this API", ("code",context.get_receiver()) ); } /** @@ -1464,6 +1464,7 @@ class context_free_transaction_api : public context_aware_api { id = context.trx_context.id; } + /// TODO void get_action_sequence(uint64_t& seq){ seq = context.global_action_sequence; } diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 2df1be62360..e66e0b8c742 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -157,8 +157,8 @@ namespace eosio { namespace testing { vector get_producer_keys( const vector& producer_names )const; transaction_trace_ptr set_producers(const vector& producer_names); - void link_authority( account_name account, account_name code, permission_name req, action_name type = "" ); - void unlink_authority( account_name account, account_name code, action_name type = "" ); + void link_authority( account_name account, account_name code, permission_name req, action_name type = {} ); + void unlink_authority( account_name account, account_name code, action_name type = {} ); void set_authority( account_name account, permission_name perm, authority auth, permission_name parent, const vector& auths, const vector& keys ); void set_authority( account_name account, permission_name perm, authority auth, @@ -197,7 +197,7 @@ namespace eosio { namespace testing { template< typename KeyType = fc::ecc::private_key_shim > static private_key_type get_private_key( name keyname, string role = "owner" ) { - return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); + return private_key_type::regenerate(fc::sha256::hash(keyname.to_string()+role)); } template< typename KeyType = fc::ecc::private_key_shim > @@ -216,7 +216,7 @@ namespace eosio { namespace testing { const symbol& asset_symbol, const account_name& account ) const; - vector get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act ) const; + vector get_row_by_account( name code, name scope, name table, const account_name& act ) const; map get_last_produced_block_map()const { return last_produced_block; }; void set_last_produced_block_map( const map& lpb ) { last_produced_block = lpb; } diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 6cf772b6adb..a31275a7deb 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -382,12 +382,12 @@ namespace eosio { namespace testing { typename base_tester::action_result base_tester::push_action(action&& act, uint64_t authorizer) { signed_transaction trx; if (authorizer) { - act.authorization = vector{{authorizer, config::active_name}}; + act.authorization = vector{{account_name(authorizer), config::active_name}}; } trx.actions.emplace_back(std::move(act)); set_transaction_headers(trx); if (authorizer) { - trx.sign(get_private_key(authorizer, "active"), control->get_chain_id()); + trx.sign(get_private_key(account_name(authorizer), "active"), control->get_chain_id()); } try { push_transaction(trx); @@ -755,7 +755,7 @@ namespace eosio { namespace testing { } - vector base_tester::get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act ) const { + vector base_tester::get_row_by_account( name code, name scope, name table, const account_name& act ) const { vector data; const auto& db = control->db(); const auto* t_id = db.find( boost::make_tuple( code, scope, table ) ); @@ -766,8 +766,8 @@ namespace eosio { namespace testing { const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( t_id->id, act ) ); - if ( itr == idx.end() || itr->t_id != t_id->id || act.value != itr->primary_key ) { + auto itr = idx.lower_bound( boost::make_tuple( t_id->id, act.to_uint64_t() ) ); + if ( itr == idx.end() || itr->t_id != t_id->id || act.to_uint64_t() != itr->primary_key ) { return data; } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ff20e506064..35b6af33083 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -176,7 +176,7 @@ class chain_plugin_impl { fc::optional pbft_ctrl; //txn_msg_rate_limits rate_limits; fc::optional wasm_runtime; - fc::microseconds abi_serializer_max_time_ms; + fc::microseconds abi_serializer_max_time_us; fc::optional snapshot_path; void on_pbft_incoming_prepare(const pbft_metadata_ptr& p); @@ -263,7 +263,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip EOS_ASSERT(false, plugin_exception, ""); } #endif - }), "Override default WASM runtime") ("abi-serializer-max-time-ms", bpo::value()->default_value(config::default_abi_serializer_max_time_ms), + }), "Override default WASM runtime") + ("abi-serializer-max-time-ms", bpo::value()->default_value(config::default_abi_serializer_max_time_us / 1000), "Override default maximum ABI serialization time allowed in ms") ("chain-state-db-size-mb", bpo::value()->default_value(config::default_state_size / (1024 * 1024)), "Maximum size (in MiB) of the chain state database") ("chain-state-db-guard-size-mb", bpo::value()->default_value(config::default_state_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the chain state database drops below this size (in MiB).") @@ -360,10 +361,12 @@ T dejsonify(const string& s) { return fc::json::from_string(s).as(); } -#define LOAD_VALUE_SET(options, name, container) \ -if( options.count(name) ) { \ - const std::vector& ops = options[name].as>(); \ - std::copy(ops.begin(), ops.end(), std::inserter(container, container.end())); \ +#define LOAD_VALUE_SET(options, op_name, container) \ +if( options.count(op_name) ) { \ + const std::vector& ops = options[op_name].as>(); \ + for( const auto& v : ops ) { \ + container.emplace( eosio::chain::name( v ) ); \ + } \ } static signature_provider_type @@ -477,7 +480,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { EOS_ASSERT( pos != std::string::npos, plugin_config_exception, "Invalid entry in action-blacklist: '${a}'", ("a", a)); account_name code( a.substr( 0, pos )); action_name act( a.substr( pos + 2 )); - list.emplace( code.value, act.value ); + list.emplace( code, act ); } } @@ -519,7 +522,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->wasm_runtime = options.at( "wasm-runtime" ).as(); if(options.count("abi-serializer-max-time-ms")) - my->abi_serializer_max_time_ms = fc::microseconds(options.at("abi-serializer-max-time-ms").as() * 1000); + my->abi_serializer_max_time_us = fc::microseconds(options.at("abi-serializer-max-time-ms").as() * 1000); my->chain_config->blocks_dir = my->blocks_dir; my->chain_config->state_dir = app().data_dir() / config::default_state_dir_name; @@ -826,8 +829,8 @@ void chain_plugin::plugin_initialize(const variables_map& options) { } ); my->applied_transaction_connection = my->chain->applied_transaction.connect( - [this]( const transaction_trace_ptr& trace ) { - my->applied_transaction_channel.publish( trace ); + [this]( std::tuple t ) { + my->applied_transaction_channel.publish( std::get<0>(t) ); } ); my->accepted_confirmation_connection = my->chain->accepted_confirmation.connect( @@ -1191,7 +1194,7 @@ chain::chain_id_type chain_plugin::get_chain_id()const { } fc::microseconds chain_plugin::get_abi_serializer_max_time() const { - return my->abi_serializer_max_time_ms; + return my->abi_serializer_max_time_us; } void chain_plugin::log_guard_exception(const chain::guard_exception&e ) const { @@ -1259,7 +1262,7 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params uint64_t read_only::get_table_index_name(const read_only::get_table_rows_params& p, bool& primary) { using boost::algorithm::starts_with; // see multi_index packing of index name - const uint64_t table = p.table; + const uint64_t table = p.table.to_uint64_t(); uint64_t index = table & 0xFFFFFFFFFFFFFFF0ULL; EOS_ASSERT( index == table, chain::contract_table_query_exception, "Unsupported table name: ${n}", ("n", p.table) ); @@ -1312,7 +1315,7 @@ uint64_t convert_to_type(const string& str, const string& desc) { auto trimmed_str = str; boost::trim(trimmed_str); name s(trimmed_str); - return s.value; + return s.to_uint64_t(); } catch( ... ) { } if (str.find(',') != string::npos) { // fix #6274 only match formats like 4,EOS @@ -1426,18 +1429,18 @@ read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_o const auto& d = db.db(); const auto& idx = d.get_index(); - auto lower_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits::lowest(), p.table.value ); - auto upper_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits::max(), - (p.table.empty() ? std::numeric_limits::max() : p.table.value) ); + auto lower_bound_lookup_tuple = std::make_tuple( p.code, name(std::numeric_limits::lowest()), p.table ); + auto upper_bound_lookup_tuple = std::make_tuple( p.code, name(std::numeric_limits::max()), + (p.table.empty() ? name(std::numeric_limits::max()) : p.table) ); if( p.lower_bound.size() ) { uint64_t scope = convert_to_type(p.lower_bound, "lower_bound scope"); - std::get<1>(lower_bound_lookup_tuple) = scope; + std::get<1>(lower_bound_lookup_tuple) = name(scope); } if( p.upper_bound.size() ) { uint64_t scope = convert_to_type(p.upper_bound, "upper_bound scope"); - std::get<1>(upper_bound_lookup_tuple) = scope; + std::get<1>(upper_bound_lookup_tuple) = name(scope); } if( upper_bound_lookup_tuple < lower_bound_lookup_tuple ) @@ -1454,7 +1457,7 @@ read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_o ++count; } if( itr != end_itr ) { - result.more = string(itr->scope); + result.more = itr->scope.to_string(); } }; @@ -1472,7 +1475,7 @@ read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_o vector read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const { const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); - (void)get_table_type( abi, "accounts" ); + (void)get_table_type( abi, name("accounts") ); vector results; walk_key_value_table(p.code, p.account, N(accounts), [&](const key_value_object& obj){ @@ -1499,11 +1502,11 @@ fc::variant read_only::get_currency_stats( const read_only::get_currency_stats_p fc::mutable_variant_object results; const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); - (void)get_table_type( abi, "stat" ); + (void)get_table_type( abi, name("stat") ); uint64_t scope = ( eosio::chain::string_to_symbol( 0, boost::algorithm::to_upper_copy(p.symbol).c_str() ) >> 8 ); - walk_key_value_table(p.code, scope, N(stat), [&](const key_value_object& obj){ + walk_key_value_table(p.code, name(scope), N(stat), [&](const key_value_object& obj){ EOS_ASSERT( obj.value.size() >= sizeof(read_only::get_currency_stats_result), chain::asset_type_exception, "Invalid data on table"); fc::datastream ds(obj.value.data(), obj.value.size()); @@ -1534,7 +1537,7 @@ fc::variant get_global_row( const database& db, const abi_def& abi, const abi_se EOS_ASSERT(table_id, chain::contract_table_query_exception, "Missing table global"); const auto& kv_index = db.get_index(); - const auto it = kv_index.find(boost::make_tuple(table_id->id, N(global))); + const auto it = kv_index.find(boost::make_tuple(table_id->id, N(global).to_uint64_t())); EOS_ASSERT(it != kv_index.end(), chain::contract_table_query_exception, "Missing row in table global"); vector data; @@ -1555,7 +1558,7 @@ read_only::get_producers_result read_only::get_producers( const read_only::get_p const auto* const table_id = d.find( boost::make_tuple(config::system_account_name, config::system_account_name, N(producers))); const auto* const secondary_table_id = d.find( - boost::make_tuple(config::system_account_name, config::system_account_name, N(producers) | secondary_index_num)); + boost::make_tuple(config::system_account_name, config::system_account_name, name(N(producers).to_uint64_t() | secondary_index_num))); EOS_ASSERT(table_id && secondary_table_id, chain::contract_table_query_exception, "Missing producers table"); const auto& kv_index = d.get_index(); @@ -1568,13 +1571,13 @@ read_only::get_producers_result read_only::get_producers( const read_only::get_p vector data; auto it = [&]{ - if(lower.value == 0) + if(lower.to_uint64_t() == 0) return secondary_index_by_secondary.lower_bound( boost::make_tuple(secondary_table_id->id, to_softfloat64(std::numeric_limits::lowest()), 0)); else return secondary_index.project( secondary_index_by_primary.lower_bound( - boost::make_tuple(secondary_table_id->id, lower.value))); + boost::make_tuple(secondary_table_id->id, lower.to_uint64_t()))); }(); for( ; it != secondary_index_by_secondary.end() && it->t_id == secondary_table_id->id; ++it ) { @@ -1991,7 +1994,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& t_id = d.find(boost::make_tuple( config::system_account_name, params.account_name, N(userres) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, params.account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2002,7 +2005,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& t_id = d.find(boost::make_tuple( config::system_account_name, params.account_name, N(delband) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, params.account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2013,7 +2016,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& t_id = d.find(boost::make_tuple( config::system_account_name, params.account_name, N(refunds) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, params.account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2024,7 +2027,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& t_id = d.find(boost::make_tuple( config::system_account_name, config::system_account_name, N(voters) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, params.account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2044,7 +2047,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& const auto &idx = d.get_index(); name key_name{"homepage"}; - auto it = idx.find(boost::make_tuple( t_id->id, key_name.value )); + auto it = idx.find(boost::make_tuple( t_id->id, key_name.to_uint64_t())); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2084,7 +2087,7 @@ read_only::get_act_token_result read_only::get_act_token( const name& account_na } // REX const auto& d = db.db(); - const auto& code_account = db.db().get( config::system_account_name ); + const auto& code_account = db.db().get( config::system_account_name ); abi_def abi; if( abi_serializer::to_abi(code_account.abi, abi) ) { abi_serializer abis( abi, abi_serializer_max_time ); @@ -2092,7 +2095,7 @@ read_only::get_act_token_result read_only::get_act_token( const name& account_na const auto* t_id = d.find(boost::make_tuple( config::system_account_name, config::system_account_name, N(rexfund) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); @@ -2102,7 +2105,7 @@ read_only::get_act_token_result read_only::get_act_token( const name& account_na t_id = d.find(boost::make_tuple( config::system_account_name, config::system_account_name, N(rexbal) )); if (t_id != nullptr) { const auto &idx = d.get_index(); - auto it = idx.find(boost::make_tuple( t_id->id, account_name )); + auto it = idx.find(boost::make_tuple( t_id->id, account_name.to_uint64_t() )); if ( it != idx.end() ) { vector data; copy_inline_row(*it, data); diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index b397b2da0b2..29eab70f502 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -294,13 +294,14 @@ class read_only { struct get_table_rows_result { vector rows; ///< one row per item, either encoded as hex String or JSON object bool more = false; ///< true if last element in data is not the end and sizeof data() < limit + string next_key; ///< fill lower_bound with this value to fetch more rows }; get_table_rows_result get_table_rows( const get_table_rows_params& params )const; struct get_table_by_scope_params { name code; // mandatory - name table = 0; // optional, act as filter + name table; // optional, act as filter string lower_bound; // lower bound of scope, optional string upper_bound; // upper bound of scope, optional uint32_t limit = 10; @@ -411,14 +412,14 @@ class read_only { read_only::get_table_rows_result result; const auto& d = db.db(); - uint64_t scope = convert_to_type(p.scope, "scope"); + name scope{ convert_to_type(p.scope, "scope") }; abi_serializer abis; abis.set_abi(abi, abi_serializer_max_time); bool primary = false; const uint64_t table_with_index = get_table_index_name(p, primary); const auto* t_id = d.find(boost::make_tuple(p.code, scope, p.table)); - const auto* index_t_id = d.find(boost::make_tuple(p.code, scope, table_with_index)); + const auto* index_t_id = d.find(boost::make_tuple(p.code, scope, name(table_with_index))); if( t_id != nullptr && index_t_id != nullptr ) { using secondary_key_type = std::result_of_t; static_assert( std::is_same::value, "Return type of conv does not match type of secondary key for IndexType" ); @@ -505,7 +506,7 @@ class read_only { abi_serializer abis; abis.set_abi(abi, abi_serializer_max_time); - const auto* t_id = d.find(boost::make_tuple(p.code, scope, p.table)); + const auto* t_id = d.find(boost::make_tuple(p.code, name(scope), p.table)); if( t_id != nullptr ) { const auto& idx = d.get_index(); auto lower_bound_lookup_tuple = std::make_tuple( t_id->id, std::numeric_limits::lowest() ); @@ -514,7 +515,7 @@ class read_only { if( p.lower_bound.size() ) { if( p.key_type == "name" ) { name s(p.lower_bound); - std::get<1>(lower_bound_lookup_tuple) = s.value; + std::get<1>(lower_bound_lookup_tuple) = s.to_uint64_t(); } else { auto lv = convert_to_type( p.lower_bound, "lower_bound" ); std::get<1>(lower_bound_lookup_tuple) = lv; @@ -524,7 +525,7 @@ class read_only { if( p.upper_bound.size() ) { if( p.key_type == "name" ) { name s(p.upper_bound); - std::get<1>(upper_bound_lookup_tuple) = s.value; + std::get<1>(upper_bound_lookup_tuple) = s.to_uint64_t(); } else { auto uv = convert_to_type( p.upper_bound, "upper_bound" ); std::get<1>(upper_bound_lookup_tuple) = uv; diff --git a/plugins/history_api_plugin/history_api_plugin.cpp b/plugins/history_api_plugin/history_api_plugin.cpp index 1a610d7a395..d76dd7fd44b 100644 --- a/plugins/history_api_plugin/history_api_plugin.cpp +++ b/plugins/history_api_plugin/history_api_plugin.cpp @@ -43,7 +43,6 @@ void history_api_plugin::plugin_startup() { // CHAIN_RO_CALL(get_transaction), CHAIN_RO_CALL(get_actions), CHAIN_RO_CALL(get_transaction), - CHAIN_RO_CALL(get_block_detail), CHAIN_RO_CALL(get_key_accounts), CHAIN_RO_CALL(get_controlled_accounts) }); diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index 5ce12dba17f..5e834db19c2 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -148,34 +148,34 @@ namespace eosio { if (bypass_filter) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, 0, 0 }) != filter_on.end()) { + if (filter_on.find({ act.receiver, {}, {} }) != filter_on.end()) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, act.act.name, 0 }) != filter_on.end()) { + if (filter_on.find({ act.receiver, act.act.name, {} }) != filter_on.end()) { pass_on = true; } for (const auto& a : act.act.authorization) { - if (filter_on.find({ act.receipt.receiver, 0, a.actor }) != filter_on.end()) { + if (filter_on.find({ act.receiver, {}, a.actor }) != filter_on.end()) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end()) { + if (filter_on.find({ act.receiver, act.act.name, a.actor }) != filter_on.end()) { pass_on = true; } } if (!pass_on) { return false; } - if (filter_out.find({ act.receipt.receiver, 0, 0 }) != filter_out.end()) { + if (filter_out.find({ act.receiver, {}, {} }) != filter_out.end()) { return false; } - if (filter_out.find({ act.receipt.receiver, act.act.name, 0 }) != filter_out.end()) { + if (filter_out.find({ act.receiver, act.act.name, {} }) != filter_out.end()) { return false; } for (const auto& a : act.act.authorization) { - if (filter_out.find({ act.receipt.receiver, 0, a.actor }) != filter_out.end()) { + if (filter_out.find({ act.receiver, {}, a.actor }) != filter_out.end()) { return false; } - if (filter_out.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_out.end()) { + if (filter_out.find({ act.receiver, act.act.name, a.actor }) != filter_out.end()) { return false; } } @@ -186,17 +186,17 @@ namespace eosio { set account_set( const action_trace& act ) { set result; - result.insert( act.receipt.receiver ); + result.insert( act.receiver ); for( const auto& a : act.act.authorization ) { if( bypass_filter || - filter_on.find({ act.receipt.receiver, 0, 0}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, 0, a.actor}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, act.act.name, 0}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end() ) { - if ((filter_out.find({ act.receipt.receiver, 0, 0 }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, 0, a.actor }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, act.act.name, 0 }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, act.act.name, a.actor }) == filter_out.end())) { + filter_on.find({ act.receiver, {}, {}}) != filter_on.end() || + filter_on.find({ act.receiver, {}, a.actor}) != filter_on.end() || + filter_on.find({ act.receiver, act.act.name, {}}) != filter_on.end() || + filter_on.find({ act.receiver, act.act.name, a.actor }) != filter_on.end() ) { + if ((filter_out.find({ act.receiver, {}, {} }) == filter_out.end()) && + (filter_out.find({ act.receiver, {}, a.actor }) == filter_out.end()) && + (filter_out.find({ act.receiver, act.act.name, {} }) == filter_out.end()) && + (filter_out.find({ act.receiver, act.act.name, a.actor }) == filter_out.end())) { result.insert( a.actor ); } } @@ -204,25 +204,23 @@ namespace eosio { return result; } - void record_account_action( account_name n, const base_action_trace& act ) { + void record_account_action( account_name n, const action_trace& act ) { auto& chain = chain_plug->chain(); chainbase::database& db = const_cast( chain.db() ); // Override read-only access to state DB (highly unrecommended practice!) const auto& idx = db.get_index(); - auto itr = idx.lower_bound( boost::make_tuple( name(n.value+1), 0 ) ); + auto itr = idx.lower_bound( boost::make_tuple( name(n.to_uint64_t()+1), 0 ) ); uint64_t asn = 0; if( itr != idx.begin() ) --itr; if( itr->account == n ) asn = itr->account_sequence_num + 1; - //idump((n)(act.receipt.global_sequence)(asn)); const auto& a = db.create( [&]( auto& aho ) { aho.account = n; - aho.action_sequence_num = act.receipt.global_sequence; + aho.action_sequence_num = act.receipt->global_sequence; aho.account_sequence_num = asn; }); - //idump((a.account)(a.action_sequence_num)(a.action_sequence_num)); } void on_system_action( const action_trace& at ) { @@ -263,8 +261,8 @@ namespace eosio { aho.packed_action_trace.resize(ps); datastream ds( aho.packed_action_trace.data(), ps ); fc::raw::pack( ds, at ); - aho.action_sequence_num = at.receipt.global_sequence; - aho.block_num = chain.pending_block_state()->block_num; + aho.action_sequence_num = at.receipt->global_sequence; + aho.block_num = chain.head_block_num() + 1; aho.block_time = chain.pending_block_time(); aho.trx_id = at.trx_id; }); @@ -274,11 +272,8 @@ namespace eosio { record_account_action( a, at ); } } - if( at.receipt.receiver == chain::config::system_account_name ) + if( at.receiver == chain::config::system_account_name ) on_system_action( at ); - for( const auto& iline : at.inline_traces ) { - on_action_trace( iline ); - } } void on_applied_transaction( const transaction_trace_ptr& trace ) { @@ -286,6 +281,7 @@ namespace eosio { trace->receipt->status != transaction_receipt_header::soft_fail) ) return; for( const auto& atrace : trace->action_traces ) { + if( !atrace.receipt ) continue; on_action_trace( atrace ); } } @@ -324,8 +320,8 @@ namespace eosio { std::vector v; boost::split( v, s, boost::is_any_of( ":" )); EOS_ASSERT( v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s", s)); - filter_entry fe{v[0], v[1], v[2]}; - EOS_ASSERT( fe.receiver.value, fc::invalid_arg_exception, + filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1]), eosio::chain::name(v[2])}; + EOS_ASSERT( fe.receiver.to_uint64_t(), fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s", s)); my->filter_on.insert( fe ); } @@ -336,8 +332,8 @@ namespace eosio { std::vector v; boost::split( v, s, boost::is_any_of( ":" )); EOS_ASSERT( v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter-out", ("s", s)); - filter_entry fe{v[0], v[1], v[2]}; - EOS_ASSERT( fe.receiver.value, fc::invalid_arg_exception, + filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1]), eosio::chain::name(v[2])}; + EOS_ASSERT( fe.receiver.to_uint64_t(), fc::invalid_arg_exception, "Invalid value ${s} for --filter-out", ("s", s)); my->filter_out.insert( fe ); } @@ -348,15 +344,15 @@ namespace eosio { auto& chain = my->chain_plug->chain(); chainbase::database& db = const_cast( chain.db() ); // Override read-only access to state DB (highly unrecommended practice!) - // TODO: Use separate chainbase database for managing the state of the history_plugin (or remove deprecated history_plugin entirely) + // TODO: Use separate chainbase database for managing the state of the history_plugin (or remove deprecated history_plugin entirely) db.add_index(); db.add_index(); db.add_index(); db.add_index(); my->applied_transaction_connection.emplace( - chain.applied_transaction.connect( [&]( const transaction_trace_ptr& p ) { - my->on_applied_transaction( p ); + chain.applied_transaction.connect( [&]( std::tuple t ) { + my->on_applied_transaction( std::get<0>(t) ); } )); } FC_LOG_AND_RETHROW() } @@ -372,9 +368,8 @@ namespace eosio { namespace history_apis { - read_only::get_actions_result read_only::get_actions( const read_only::get_actions_params& params )const { - edump((params)); + edump((params)); auto& chain = history->chain_plug->chain(); const auto& db = chain.db(); const auto abi_serializer_max_time = history->chain_plug->get_abi_serializer_max_time(); @@ -388,7 +383,7 @@ namespace eosio { auto n = params.account_name; idump((pos)); if( pos == -1 ) { - auto itr = idx.lower_bound( boost::make_tuple( name(n.value+1), 0 ) ); + auto itr = idx.lower_bound( boost::make_tuple( name(n.to_uint64_t()+1), 0 ) ); if( itr == idx.begin() ) { if( itr->account == n ) pos = itr->account_sequence_num+1; @@ -519,7 +514,7 @@ namespace eosio { break; } } - } + } } } else { auto blk = chain.fetch_block_by_number(*p.block_num_hint); @@ -593,7 +588,7 @@ namespace eosio { auto & value = get_object_value(block, TRANSACTIONS); if ( !value.is_array() ) return null_variants; - + return value.get_array(); }; @@ -614,7 +609,7 @@ namespace eosio { auto & rhs = get_tx_array(src); if ( rhs.empty() ) return src; - + auto lhs = fc::variants(); lhs.reserve(rhs.size()); @@ -674,4 +669,6 @@ namespace eosio { } /// history_apis + + } /// namespace eosio diff --git a/plugins/http_plugin/http_plugin.cpp b/plugins/http_plugin/http_plugin.cpp index f6672720ec8..0e434ffe6d9 100644 --- a/plugins/http_plugin/http_plugin.cpp +++ b/plugins/http_plugin/http_plugin.cpp @@ -283,7 +283,11 @@ namespace eosio { if( bytes_in_flight > max_bytes_in_flight ) { dlog( "503 - too many bytes in flight: ${bytes}", ("bytes", bytes_in_flight.load()) ); - error_results results{websocketpp::http::status_code::too_many_requests, "Busy", error_results::error_info()}; + error_results::error_info ei; + ei.code = websocketpp::http::status_code::too_many_requests; + ei.name = "Busy"; + ei.what = "Too many bytes in flight: " + std::to_string( bytes_in_flight ); + error_results results{websocketpp::http::status_code::too_many_requests, "Busy", ei}; con->set_body( fc::json::to_string( results )); con->set_status( websocketpp::http::status_code::too_many_requests ); return; @@ -294,7 +298,6 @@ namespace eosio { auto handler_itr = url_handlers.find( resource ); if( handler_itr != url_handlers.end()) { con->defer_http_response(); - bytes_in_flight += body.size(); handler_itr->second( resource, body, [&bytes_in_flight = this->bytes_in_flight, con]( int code, fc::variant response_body ) { std::string json = fc::json::to_string( response_body ); response_body.clear(); diff --git a/plugins/kafka_plugin/kafka.cpp b/plugins/kafka_plugin/kafka.cpp index 86abbb6d62c..415e6774da6 100644 --- a/plugins/kafka_plugin/kafka.cpp +++ b/plugins/kafka_plugin/kafka.cpp @@ -136,27 +136,23 @@ void kafka::push_transaction_trace(const chain::transaction_trace_ptr& tx_trace) void kafka::push_action(const chain::action_trace& action_trace, uint64_t parent_seq, const TransactionTracePtr& tx) { auto a = std::make_shared(); - a->global_seq = action_trace.receipt.global_sequence; - a->recv_seq = action_trace.receipt.recv_sequence; + a->global_seq = action_trace.receipt->global_sequence; + a->recv_seq = action_trace.receipt->recv_sequence; a->parent_seq = parent_seq; - a->account = action_trace.act.account; - a->name = action_trace.act.name; + a->account = action_trace.act.account.to_uint64_t(); + a->name = action_trace.act.name.to_uint64_t(); if (not action_trace.act.authorization.empty()) a->auth = fc::raw::pack(action_trace.act.authorization); a->data = action_trace.act.data; - a->receiver = action_trace.receipt.receiver; - if (not action_trace.receipt.auth_sequence.empty()) a->auth_seq = fc::raw::pack(action_trace.receipt.auth_sequence); - a->code_seq = action_trace.receipt.code_sequence; - a->abi_seq = action_trace.receipt.abi_sequence; + a->receiver = action_trace.receipt->receiver.to_uint64_t(); + if (not action_trace.receipt->auth_sequence.empty()) a->auth_seq = fc::raw::pack(action_trace.receipt->auth_sequence); + a->code_seq = action_trace.receipt->code_sequence; + a->abi_seq = action_trace.receipt->abi_sequence; a->block_num = action_trace.block_num; a->block_time = action_trace.block_time; a->tx_id = checksum_bytes(action_trace.trx_id); if (not action_trace.console.empty()) a->console = action_trace.console; consume_action(a); - - for (auto& inline_trace: action_trace.inline_traces) { - push_action(inline_trace, action_trace.receipt.global_sequence, tx); - } } void kafka::consume_block(BlockPtr block) { diff --git a/plugins/kafka_plugin/kafka_plugin.cpp b/plugins/kafka_plugin/kafka_plugin.cpp index 901fd57a29e..858fbf4c86b 100644 --- a/plugins/kafka_plugin/kafka_plugin.cpp +++ b/plugins/kafka_plugin/kafka_plugin.cpp @@ -126,16 +126,16 @@ void kafka_plugin::plugin_initialize(const variables_map& options) { } handle([=] { kafka_->push_block(b, false); }, "push block"); }); - irreversible_block_conn_ = chain.irreversible_block.connect([=](const chain::block_state_ptr& b) { + irreversible_block_conn_ = chain.new_irreversible_block.connect([=](const chain::block_state_ptr& b) { if (not start_sync_) { if (b->block_num >= start_block_num) start_sync_ = true; else return; } handle([=] { kafka_->push_block(b, true); }, "push irreversible block"); }); - transaction_conn_ = chain.applied_transaction.connect([=](const chain::transaction_trace_ptr& t) { + transaction_conn_ = chain.applied_transaction.connect([=]( std::tuple t) { if (not start_sync_) return; - handle([=] { kafka_->push_transaction_trace(t); }, "push transaction"); + handle([=] { kafka_->push_transaction_trace(std::get<0>(t)); }, "push transaction"); }); } diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 70327c3d96b..e0a88e8f438 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -60,9 +60,9 @@ struct filter_entry { // receiver action actor bool match( const name& rr, const name& an, const name& ar ) const { - return (receiver.value == 0 || receiver == rr) && - (action.value == 0 || action == an) && - (actor.value == 0 || actor == ar); + return (receiver.to_uint64_t() == 0 || receiver == rr) && + (action.to_uint64_t() == 0 || action == an) && + (actor.to_uint64_t() == 0 || actor == ar); } }; @@ -229,7 +229,7 @@ bool mongo_db_plugin_impl::filter_include( const account_name& receiver, const a include = true; } else { auto itr = std::find_if( filter_on.cbegin(), filter_on.cend(), [&receiver, &act_name]( const auto& filter ) { - return filter.match( receiver, act_name, 0 ); + return filter.match( receiver, act_name, {} ); } ); if( itr != filter_on.cend() ) { include = true; @@ -250,7 +250,7 @@ bool mongo_db_plugin_impl::filter_include( const account_name& receiver, const a if( filter_out.empty() ) { return true; } auto itr = std::find_if( filter_out.cbegin(), filter_out.cend(), [&receiver, &act_name]( const auto& filter ) { - return filter.match( receiver, act_name, 0 ); + return filter.match( receiver, act_name, {} ); } ); if( itr != filter_out.cend() ) { return false; } @@ -816,22 +816,20 @@ mongo_db_plugin_impl::add_action_trace( mongocxx::bulk_write& bulk_action_traces using namespace bsoncxx::types; using bsoncxx::builder::basic::kvp; - if( executed && atrace.receipt.receiver == chain::config::system_account_name ) { + if( executed && atrace.receiver == chain::config::system_account_name ) { update_account( atrace.act ); } bool added = false; const bool in_filter = (store_action_traces || store_transaction_traces) && start_block_reached && - filter_include( atrace.receipt.receiver, atrace.act.name, atrace.act.authorization ); + filter_include( atrace.receiver, atrace.act.name, atrace.act.authorization ); write_ttrace |= in_filter; if( start_block_reached && store_action_traces && in_filter ) { auto action_traces_doc = bsoncxx::builder::basic::document{}; - const chain::base_action_trace& base = atrace; // without inline action traces - // improve data distributivity when using mongodb sharding action_traces_doc.append( kvp( "_id", make_custom_oid() ) ); - auto v = to_variant_with_abi( base ); + auto v = to_variant_with_abi( atrace ); string json = fc::json::to_string( v ); try { const auto& value = bsoncxx::from_json( json ); @@ -857,10 +855,6 @@ mongo_db_plugin_impl::add_action_trace( mongocxx::bulk_write& bulk_action_traces added = true; } - for( const auto& iline_atrace : atrace.inline_traces ) { - added |= add_action_trace( bulk_action_traces, iline_atrace, t, executed, now, write_ttrace ); - } - return added; } @@ -1063,7 +1057,6 @@ void mongo_db_plugin_impl::_process_irreversible_block(const chain::block_state_ } auto update_doc = make_document( kvp( "$set", make_document( kvp( "irreversible", b_bool{true} ), - kvp( "validated", b_bool{bs->validated} ), kvp( "updatedAt", b_date{now} ) ) ) ); _blocks.update_one( make_document( kvp( "_id", ir_block->view()["_id"].get_oid() ) ), update_doc.view() ); @@ -1078,7 +1071,6 @@ void mongo_db_plugin_impl::_process_irreversible_block(const chain::block_state_ } auto update_doc = make_document( kvp( "$set", make_document( kvp( "irreversible", b_bool{true} ), - kvp( "validated", b_bool{bs->validated} ), kvp( "updatedAt", b_date{now} ) ) ) ); _block_states.update_one( make_document( kvp( "_id", ir_block->view()["_id"].get_oid() ) ), update_doc.view() ); @@ -1573,7 +1565,7 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) std::vector v; boost::split( v, s, boost::is_any_of( ":" )); EOS_ASSERT( v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --mongodb-filter-on", ("s", s)); - filter_entry fe{v[0], v[1], v[2]}; + filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1]), eosio::chain::name(v[2])}; my->filter_on.insert( fe ); } } else { @@ -1585,7 +1577,7 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) std::vector v; boost::split( v, s, boost::is_any_of( ":" )); EOS_ASSERT( v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --mongodb-filter-out", ("s", s)); - filter_entry fe{v[0], v[1], v[2]}; + filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1]), eosio::chain::name(v[2])}; my->filter_out.insert( fe ); } } @@ -1616,7 +1608,7 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) my->accepted_block( bs ); } )); my->irreversible_block_connection.emplace( - chain.irreversible_block.connect( [&]( const chain::block_state_ptr& bs ) { + chain.new_irreversible_block.connect( [&]( const chain::block_state_ptr& bs ) { my->applied_irreversible_block( bs ); } )); my->accepted_transaction_connection.emplace( @@ -1624,8 +1616,8 @@ void mongo_db_plugin::plugin_initialize(const variables_map& options) my->accepted_transaction( t ); } )); my->applied_transaction_connection.emplace( - chain.applied_transaction.connect( [&]( const chain::transaction_trace_ptr& t ) { - my->applied_transaction( t ); + chain.applied_transaction.connect( [&]( std::tuple t ) { + my->applied_transaction( std::get<0>(t) ); } )); if( my->wipe_database_on_startup ) { diff --git a/plugins/notify_plugin/notify_plugin.cpp b/plugins/notify_plugin/notify_plugin.cpp index 377daf8e5ef..1b09b1b02ff 100644 --- a/plugins/notify_plugin/notify_plugin.cpp +++ b/plugins/notify_plugin/notify_plugin.cpp @@ -111,11 +111,11 @@ class notify_plugin_impl bool notify_plugin_impl::filter(const action_trace &act) { - if (filter_on.find({act.receipt.receiver, act.act.name}) != filter_on.end()) + if (filter_on.find({act.receipt->receiver, act.act.name}) != filter_on.end()) { return true; } - else if (filter_on.find({act.receipt.receiver, 0}) != filter_on.end()) + else if (filter_on.find({act.receipt->receiver, {}}) != filter_on.end()) { return true; } @@ -126,7 +126,7 @@ fc::variant notify_plugin_impl::deserialize_action_data(action act) { auto &chain = chain_plug->chain(); auto serializer = chain.get_abi_serializer(act.account, max_deserialization_time); - FC_ASSERT(serializer.valid() && serializer->get_action_type(act.name) != action_name(), + FC_ASSERT(serializer.valid() && serializer->get_action_type(act.name) != "", "Unable to get abi for account: ${acc}, action: ${a} Not sending notification.", ("acc", act.account)("a", act.name)); return serializer->binary_to_variant(act.name.to_string(), act.data, max_deserialization_time); @@ -161,17 +161,13 @@ action_seq_type notify_plugin_impl::on_action_trace(const action_trace &act, con { if (filter(act)) { - const auto pair = std::make_pair(tx_id, sequenced_action(act.act, act_s, act.receipt.receiver)); + const auto pair = std::make_pair(tx_id, sequenced_action(act.act, act_s, act.receipt->receiver)); action_queue.insert(pair); irreversible_action_queue.insert(pair); // dlog("on_action_trace: ${a}", ("a", fc::json::to_pretty_string(act.act))); } act_s++; - for (const auto &iline : act.inline_traces) - { - act_s = on_action_trace(iline, tx_id, act_s); - } return act_s; } @@ -307,8 +303,8 @@ void notify_plugin::plugin_initialize(const variables_map &options) EOS_ASSERT(v.size() == 2, fc::invalid_arg_exception, "Invalid value ${s} for --notify-filter-on", ("s", s)); - notify_plugin_impl::filter_entry fe{v[0], v[1]}; - EOS_ASSERT(fe.receiver.value, fc::invalid_arg_exception, "Invalid value ${s} for --notify-filter-on", ("s", s)); + notify_plugin_impl::filter_entry fe{eosio::chain::name(v[0]), eosio::chain::name(v[1])}; + EOS_ASSERT(fe.receiver.to_uint64_t(), fc::invalid_arg_exception, "Invalid value ${s} for --notify-filter-on", ("s", s)); my->filter_on.insert(fe); } } @@ -327,14 +323,14 @@ void notify_plugin::plugin_initialize(const variables_map &options) my->on_accepted_block(b_state); })); - my->irreversible_block_conn.emplace(chain.irreversible_block.connect( + my->irreversible_block_conn.emplace(chain.new_irreversible_block.connect( [&](const block_state_ptr &bs) { my->on_irreversible_block(bs); })); my->applied_tx_conn.emplace(chain.applied_transaction.connect( - [&](const transaction_trace_ptr &tx) { - my->on_applied_tx(tx); + [&](std::tuple t) { + my->on_applied_tx(std::get<0>(t)); })); } FC_LOG_AND_RETHROW() diff --git a/plugins/pbft_api_plugin/README.md b/plugins/pbft_api_plugin/README.md index 54d3552089a..e94bcea1e9d 100644 --- a/plugins/pbft_api_plugin/README.md +++ b/plugins/pbft_api_plugin/README.md @@ -84,4 +84,25 @@ ``` curl --request POST --data uint32_t --url http://localhost:8888/v1/pbft/set_pbft_current_view + ``` +* **get_view_change_missing_bps** + + -- To get missing bp names of a given pbft view on my node, empty will be returned if all have been collected or not in view change state + + ``` + curl --request POST --data uint32_t --url http://localhost:8888/v1/pbft/get_view_change_missing_bps + ``` +* **get_prepare_missing_bps** + + -- To get missing bp names of prepare messages of a given block id at the highest view on my node, empty will be returned if all have been collected or the block id is unreachable + + ``` + curl --request POST --data string --url http://localhost:8888/v1/pbft/get_prepare_missing_bps + ``` +* **get_commit_missing_bps** + + -- To get missing bp names of commit messages of a given block id at the highest view on my node, empty will be returned if all have been collected or the block id is unreachable + + ``` + curl --request POST --data string --url http://localhost:8888/v1/pbft/get_commit_missing_bps ``` \ No newline at end of file diff --git a/plugins/pbft_api_plugin/pbft_api_plugin.cpp b/plugins/pbft_api_plugin/pbft_api_plugin.cpp index 33fcd7b8654..321761165f6 100644 --- a/plugins/pbft_api_plugin/pbft_api_plugin.cpp +++ b/plugins/pbft_api_plugin/pbft_api_plugin.cpp @@ -59,6 +59,9 @@ void pbft_api_plugin::plugin_startup() { CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), CALL(pbft, pbft, get_pbft_prepared_id, INVOKE_R(pbft, get_pbft_prepared_id), 200), CALL(pbft, pbft, get_pbft_my_prepare_id, INVOKE_R(pbft, get_pbft_my_prepare_id), 200), + CALL(pbft, pbft, get_view_change_missing_bps, INVOKE_R_P(pbft, get_view_change_missing_bps, pbft_view_type), 200), + CALL(pbft, pbft, get_prepare_missing_bps, INVOKE_R_P(pbft, get_prepare_missing_bps, block_id_type), 200), + CALL(pbft, pbft, get_commit_missing_bps, INVOKE_R_P(pbft, get_commit_missing_bps, block_id_type), 200), CALL(pbft, pbft, set_pbft_current_view, INVOKE_W_P(pbft, set_pbft_current_view, pbft_view_type), 201), }); } diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index 726e4d43591..bb449bf0d85 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace eosio { @@ -33,12 +34,15 @@ class pbft_plugin : public appbase::plugin { const char* get_pbft_status()const; block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; - + vector get_view_change_missing_bps(pbft_view_type view)const; + vector get_prepare_missing_bps(const block_id_type& bid)const; + vector get_commit_missing_bps(const block_id_type& bid)const; void set_pbft_current_view(pbft_view_type view); private: std::unique_ptr my; + chain_plugin* chain_plug = nullptr; }; } diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 7d27f1607bd..4790dd2b3a4 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -51,6 +51,7 @@ namespace eosio { bool is_replaying(); bool is_syncing(); bool pbft_ready(); + bool is_production_paused(); }; void pbft_plugin_impl::on_committed_transition() { @@ -142,6 +143,10 @@ namespace eosio { return app().get_plugin().is_syncing(); } + bool pbft_plugin_impl::is_production_paused() { + return app().get_plugin().paused(); + } + bool pbft_plugin_impl::pbft_ready() { // only trigger pbft related logic if I am in sync and replayed. @@ -162,7 +167,7 @@ namespace eosio { upgraded = true; } - return enabled && !is_syncing() && !is_replaying(); + return enabled && !is_syncing() && !is_replaying() && !is_production_paused(); } pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} @@ -178,6 +183,7 @@ namespace eosio { my->commit_timer = std::make_unique(app().get_io_service()); my->view_change_timer = std::make_unique(app().get_io_service()); my->checkpoint_timer = std::make_unique(app().get_io_service()); + chain_plug = app().find_plugin(); } void pbft_plugin::plugin_startup() { @@ -198,53 +204,126 @@ namespace eosio { void pbft_plugin::plugin_shutdown() {} pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); if (record) return *record; return pbft_state(); } vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); if (!records.empty()) return records; return vector(); } pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); if (record) return *record; return pbft_view_change_state(); } vector pbft_plugin::get_watermarks() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); return pbft_ctrl.pbft_db.get_pbft_watermarks(); } flat_map pbft_plugin::get_fork_schedules() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); } const char* pbft_plugin::get_pbft_status() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto& pbft_ctrl = chain_plug->pbft_ctrl(); return pbft_ctrl.state_machine.get_current()->get_name(); } block_id_type pbft_plugin::get_pbft_prepared_id() const { - auto& ctrl = app().get_plugin().chain(); + auto& ctrl = chain_plug->chain(); return ctrl.get_pbft_prepared(); } block_id_type pbft_plugin::get_pbft_my_prepare_id() const { - auto& ctrl = app().get_plugin().chain(); + auto& ctrl = chain_plug->chain(); return ctrl.get_pbft_my_prepare(); } + vector pbft_plugin::get_view_change_missing_bps(pbft_view_type view) const { + auto& pbft_ctrl = chain_plug->pbft_ctrl(); + auto missing_bps = vector{}; + auto records = get_view_change_record(view); + if (!records.view_changes.empty() && !records.is_view_changed) { + auto lscb_bps = pbft_ctrl.pbft_db.lscb_active_producers().producers; + missing_bps.reserve(lscb_bps.size()); + for (const auto& bp: lscb_bps) { + auto found = false; + for (const auto& v: records.view_changes) { + if (bp.block_signing_key == v.first) found = true; + } + if (!found) missing_bps.emplace_back(bp); + } + } + return missing_bps; + } + + vector pbft_plugin::get_prepare_missing_bps(const block_id_type& bid) const { + auto& ctrl = chain_plug->chain(); + auto missing_bps = vector{}; + auto blk = ctrl.fetch_block_state_by_id(bid); + if (blk) { + auto records = get_pbft_record(bid); + if (!records.prepares.empty() && !records.is_prepared) { + pbft_view_type highest_view; + for (const auto &p: records.prepares) { + if (p.first.first > highest_view) highest_view = p.first.first; + } + auto active_bps = blk->active_schedule.producers;; + missing_bps.reserve(active_bps.size()); + for (const auto &bp: active_bps) { + auto found = false; + for (const auto &p: records.prepares) { + if (p.first.first == highest_view && bp.block_signing_key == p.first.second) { + found = true; + } + } + if (!found) missing_bps.emplace_back(bp); + } + } + + } + return missing_bps; + } + + vector pbft_plugin::get_commit_missing_bps(const block_id_type& bid) const { + auto& ctrl = chain_plug->chain(); + auto missing_bps = vector{}; + auto blk = ctrl.fetch_block_state_by_id(bid); + if (blk) { + auto records = get_pbft_record(bid); + if (!records.commits.empty() && !records.is_committed) { + pbft_view_type highest_view; + for (const auto &p: records.commits) { + if (p.first.first > highest_view) highest_view = p.first.first; + } + auto active_bps = blk->active_schedule.producers;; + missing_bps.reserve(active_bps.size()); + for (const auto &bp: active_bps) { + auto found = false; + for (const auto &c: records.commits) { + if (c.first.first == highest_view && bp.block_signing_key == c.first.second) { + found = true; + } + } + if (!found) missing_bps.emplace_back(bp); + } + } + } + return missing_bps; + } + void pbft_plugin::set_pbft_current_view(pbft_view_type view) { + auto& pbft_ctrl = chain_plug->pbft_ctrl(); //this is used to boost the recovery from a disaster, do not set this unless you have to do so. - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.state_machine.manually_set_current_view(view); } } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 9a5ad5f64ba..b485cb1c432 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -599,10 +599,12 @@ T dejsonify(const string& s) { return fc::json::from_string(s).as(); } -#define LOAD_VALUE_SET(options, name, container, type) \ -if( options.count(name) ) { \ - const std::vector& ops = options[name].as>(); \ - std::copy(ops.begin(), ops.end(), std::inserter(container, container.end())); \ +#define LOAD_VALUE_SET(options, op_name, container) \ +if( options.count(op_name) ) { \ + const std::vector& ops = options[op_name].as>(); \ + for( const auto& v : ops ) { \ + container.emplace( eosio::chain::name( v ) ); \ + } \ } static producer_plugin_impl::signature_provider_type @@ -641,7 +643,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->chain_plug = app().find_plugin(); EOS_ASSERT( my->chain_plug, plugin_config_exception, "chain_plugin not found" ); my->_options = &options; - LOAD_VALUE_SET(options, "producer-name", my->_producers, types::account_name) + LOAD_VALUE_SET(options, "producer-name", my->_producers) if( options.count("private-key") ) { diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp index 1644d29a404..065a59638bc 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp @@ -1,13 +1,10 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ #pragma once #include #include #include +#include #include #include #include @@ -21,47 +18,37 @@ namespace eosio { * +---------+----------------+-----------+------------------+-----+---------+----------------+ * * *.index: - * +-----------+-------------+-----+-----------+ - * | Summary i | Summary i+1 | ... | Summary z | - * +-----------+-------------+-----+-----------+ + * +----------------+------------------+-----+----------------+ + * | Pos of Entry i | Pos of Entry i+1 | ... | Pos of Entry z | + * +----------------+------------------+-----+----------------+ * * each entry: - * uint32_t block_num - * block_id_type block_id - * uint64_t size of payload - * uint8_t version - * payload - * - * each summary: - * uint64_t position of entry in *.log - * - * state payload: - * uint32_t size of deltas - * char[] deltas + * state_history_log_header + * payload */ -// todo: look into switching this to serialization instead of memcpy -// todo: consider reworking versioning -// todo: consider dropping block_num since it's included in block_id -// todo: currently only checks version on the first record. Need in recover_blocks +inline uint64_t ship_magic(uint32_t version) { return N(ship).to_uint64_t() | version; } +inline bool is_ship(uint64_t magic) { return (magic & 0xffff'ffff'0000'0000) == N(ship).to_uint64_t(); } +inline uint32_t get_ship_version(uint64_t magic) { return magic; } +inline bool is_ship_supported_version(uint64_t magic) { return get_ship_version(magic) == 0; } +static const uint32_t ship_current_version = 0; + struct state_history_log_header { - uint32_t block_num = 0; - chain::block_id_type block_id; + uint64_t magic = ship_magic(ship_current_version); + chain::block_id_type block_id = {}; uint64_t payload_size = 0; - uint8_t version = 0; -}; - -struct state_history_summary { - uint64_t pos = 0; }; +static const int state_history_log_header_serial_size = sizeof(state_history_log_header::magic) + + sizeof(state_history_log_header::block_id) + + sizeof(state_history_log_header::payload_size); class state_history_log { private: const char* const name = ""; std::string log_filename; std::string index_filename; - std::fstream log; - std::fstream index; + std::fstream log; + std::fstream index; uint32_t _begin_block = 0; uint32_t _end_block = 0; chain::block_id_type last_block_id; @@ -78,44 +65,63 @@ class state_history_log { uint32_t begin_block() const { return _begin_block; } uint32_t end_block() const { return _end_block; } + void read_header(state_history_log_header& header, bool assert_version = true) { + char bytes[state_history_log_header_serial_size]; + log.read(bytes, sizeof(bytes)); + fc::datastream ds(bytes, sizeof(bytes)); + fc::raw::unpack(ds, header); + EOS_ASSERT(!ds.remaining(), chain::plugin_exception, "state_history_log_header_serial_size mismatch"); + if (assert_version) + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic), chain::plugin_exception, + "corrupt ${name}.log (0)", ("name", name)); + } + + void write_header(const state_history_log_header& header) { + char bytes[state_history_log_header_serial_size]; + fc::datastream ds(bytes, sizeof(bytes)); + fc::raw::pack(ds, header); + EOS_ASSERT(!ds.remaining(), chain::plugin_exception, "state_history_log_header_serial_size mismatch"); + log.write(bytes, sizeof(bytes)); + } + template void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) { - EOS_ASSERT(_begin_block == _end_block || header.block_num <= _end_block, chain::plugin_exception, + auto block_num = chain::block_header::num_from_id(header.block_id); + EOS_ASSERT(_begin_block == _end_block || block_num <= _end_block, chain::plugin_exception, "missed a block in ${name}.log", ("name", name)); - if (_begin_block != _end_block && header.block_num > _begin_block) { - if (header.block_num == _end_block) { + if (_begin_block != _end_block && block_num > _begin_block) { + if (block_num == _end_block) { EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log", ("name", name)); } else { state_history_log_header prev; - get_entry(header.block_num - 1, prev); + get_entry(block_num - 1, prev); EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log", ("name", name)); } } - if (header.block_num < _end_block) - truncate(header.block_num); + if (block_num < _end_block) + truncate(block_num); log.seekg(0, std::ios_base::end); - uint64_t pos = log.tellg(); - log.write((char*)&header, sizeof(header)); + uint64_t pos = log.tellp(); + write_header(header); write_payload(log); - uint64_t end = log.tellg(); - EOS_ASSERT(end == pos + sizeof(header) + header.payload_size, chain::plugin_exception, + uint64_t end = log.tellp(); + EOS_ASSERT(end == pos + state_history_log_header_serial_size + header.payload_size, chain::plugin_exception, "wrote payload with incorrect size to ${name}.log", ("name", name)); log.write((char*)&pos, sizeof(pos)); index.seekg(0, std::ios_base::end); - state_history_summary summary{.pos = pos}; - index.write((char*)&summary, sizeof(summary)); + index.write((char*)&pos, sizeof(pos)); if (_begin_block == _end_block) - _begin_block = header.block_num; - _end_block = header.block_num + 1; + _begin_block = block_num; + _end_block = block_num + 1; last_block_id = header.block_id; } - // returns stream positioned at payload + // returns cfile positioned at payload std::fstream& get_entry(uint32_t block_num, state_history_log_header& header) { EOS_ASSERT(block_num >= _begin_block && block_num < _end_block, chain::plugin_exception, "read non-existing block in ${name}.log", ("name", name)); @@ -136,17 +142,18 @@ class state_history_log { uint64_t suffix; log.seekg(size - sizeof(suffix)); log.read((char*)&suffix, sizeof(suffix)); - if (suffix > size || suffix + sizeof(header) > size) { + if (suffix > size || suffix + state_history_log_header_serial_size > size) { elog("corrupt ${name}.log (2)", ("name", name)); return false; } log.seekg(suffix); - log.read((char*)&header, sizeof(header)); - if (suffix + sizeof(header) + header.payload_size + sizeof(suffix) != size) { + read_header(header, false); + if (!is_ship(header.magic) || !is_ship_supported_version(header.magic) || + suffix + state_history_log_header_serial_size + header.payload_size + sizeof(suffix) != size) { elog("corrupt ${name}.log (3)", ("name", name)); return false; } - _end_block = header.block_num + 1; + _end_block = chain::block_header::num_from_id(header.block_id) + 1; last_block_id = header.block_id; if (_begin_block >= _end_block) { elog("corrupt ${name}.log (4)", ("name", name)); @@ -161,18 +168,22 @@ class state_history_log { uint32_t num_found = 0; while (true) { state_history_log_header header; - if (pos + sizeof(header) > size) + if (pos + state_history_log_header_serial_size > size) break; log.seekg(pos); - log.read((char*)&header, sizeof(header)); + read_header(header, false); uint64_t suffix; - if (header.payload_size > size || pos + sizeof(header) + header.payload_size + sizeof(suffix) > size) + if (!is_ship(header.magic) || !is_ship_supported_version(header.magic) || header.payload_size > size || + pos + state_history_log_header_serial_size + header.payload_size + sizeof(suffix) > size) { + EOS_ASSERT(!is_ship(header.magic) || is_ship_supported_version(header.magic), chain::plugin_exception, + "${name}.log has an unsupported version", ("name", name)); break; - log.seekg(pos + sizeof(header) + header.payload_size); + } + log.seekg(pos + state_history_log_header_serial_size + header.payload_size); log.read((char*)&suffix, sizeof(suffix)); if (suffix != pos) break; - pos = pos + sizeof(header) + header.payload_size + sizeof(suffix); + pos = pos + state_history_log_header_serial_size + header.payload_size + sizeof(suffix); if (!(++num_found % 10000)) { printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); fflush(stdout); @@ -180,21 +191,22 @@ class state_history_log { } log.flush(); boost::filesystem::resize_file(log_filename, pos); - log.sync(); + log.flush(); EOS_ASSERT(get_last_block(pos), chain::plugin_exception, "recover ${name}.log failed", ("name", name)); } void open_log() { log.open(log_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); log.seekg(0, std::ios_base::end); - uint64_t size = log.tellg(); - if (size >= sizeof(state_history_log_header)) { + uint64_t size = log.tellp(); + if (size >= state_history_log_header_serial_size) { state_history_log_header header; log.seekg(0); - log.read((char*)&header, sizeof(header)); - EOS_ASSERT(header.version == 0 && sizeof(header) + header.payload_size + sizeof(uint64_t) <= size, + read_header(header, false); + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic) && + state_history_log_header_serial_size + header.payload_size + sizeof(uint64_t) <= size, chain::plugin_exception, "corrupt ${name}.log (1)", ("name", name)); - _begin_block = header.block_num; + _begin_block = chain::block_header::num_from_id(header.block_id); last_block_id = header.block_id; if (!get_last_block(size)) recover_blocks(size); @@ -208,33 +220,34 @@ class state_history_log { void open_index() { index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); index.seekg(0, std::ios_base::end); - if (index.tellg() == (_end_block - _begin_block) * sizeof(state_history_summary)) - return; - ilog("Regenerate ${name}.index", ("name", name)); - index.close(); - index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc); + if (index.tellp() == (static_cast(_end_block) - _begin_block) * sizeof(uint64_t)) + return; + ilog("Regenerate ${name}.index", ("name", name)); + index.close(); + index.open( "w+b" ); // std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc log.seekg(0, std::ios_base::end); - uint64_t size = log.tellg(); + uint64_t size = log.tellp(); uint64_t pos = 0; uint32_t num_found = 0; while (pos < size) { state_history_log_header header; - EOS_ASSERT(pos + sizeof(header) <= size, chain::plugin_exception, "corrupt ${name}.log (6)", ("name", name)); + EOS_ASSERT(pos + state_history_log_header_serial_size <= size, chain::plugin_exception, + "corrupt ${name}.log (6)", ("name", name)); log.seekg(pos); - log.read((char*)&header, sizeof(header)); - uint64_t suffix_pos = pos + sizeof(header) + header.payload_size; + read_header(header, false); + uint64_t suffix_pos = pos + state_history_log_header_serial_size + header.payload_size; uint64_t suffix; - EOS_ASSERT(suffix_pos + sizeof(suffix) <= size, chain::plugin_exception, "corrupt ${name}.log (7)", - ("name", name)); + EOS_ASSERT(is_ship(header.magic) && is_ship_supported_version(header.magic) && + suffix_pos + sizeof(suffix) <= size, + chain::plugin_exception, "corrupt ${name}.log (7)", ("name", name)); log.seekg(suffix_pos); log.read((char*)&suffix, sizeof(suffix)); // ilog("block ${b} at ${pos}-${end} suffix=${suffix} file_size=${fs}", // ("b", header.block_num)("pos", pos)("end", suffix_pos + sizeof(suffix))("suffix", suffix)("fs", size)); EOS_ASSERT(suffix == pos, chain::plugin_exception, "corrupt ${name}.log (8)", ("name", name)); - state_history_summary summary{.pos = pos}; - index.write((char*)&summary, sizeof(summary)); + index.write((char*)&pos, sizeof(pos)); pos = suffix_pos + sizeof(suffix); if (!(++num_found % 10000)) { printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); @@ -244,10 +257,10 @@ class state_history_log { } uint64_t get_pos(uint32_t block_num) { - state_history_summary summary; - index.seekg((block_num - _begin_block) * sizeof(summary)); - index.read((char*)&summary, sizeof(summary)); - return summary.pos; + uint64_t pos; + index.seekg((block_num - _begin_block) * sizeof(pos)); + index.read((char*)&pos, sizeof(pos)); + return pos; } void truncate(uint32_t block_num) { @@ -267,13 +280,15 @@ class state_history_log { log.seekg(0); index.seekg(0); boost::filesystem::resize_file(log_filename, pos); - boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(state_history_summary)); + boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(uint64_t)); _end_block = block_num; } - log.sync(); - index.sync(); + log.flush(); + index.flush(); ilog("fork or replay: removed ${n} blocks from ${name}.log", ("n", num_removed)("name", name)); } }; // state_history_log } // namespace eosio + +FC_REFLECT(eosio::state_history_log_header, (magic)(block_id)(payload_size)) diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp index f3429e2d190..a682b205e00 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp @@ -22,6 +22,53 @@ using std::shared_ptr; typedef shared_ptr state_history_ptr; +struct partial_transaction { + chain::time_point_sec expiration = {}; + uint16_t ref_block_num = {}; + uint32_t ref_block_prefix = {}; + fc::unsigned_int max_net_usage_words = {}; + uint8_t max_cpu_usage_ms = {}; + fc::unsigned_int delay_sec = {}; + chain::extensions_type transaction_extensions = {}; + vector signatures = {}; + vector context_free_data = {}; + + partial_transaction(const chain::signed_transaction& t) + : expiration(t.expiration) + , ref_block_num(t.ref_block_num) + , ref_block_prefix(t.ref_block_prefix) + , max_net_usage_words(t.max_net_usage_words) + , max_cpu_usage_ms(t.max_cpu_usage_ms) + , delay_sec(t.delay_sec) + , transaction_extensions(t.transaction_extensions) + , signatures(t.signatures) + , context_free_data(t.context_free_data) {} +}; + +struct augmented_transaction_trace { + chain::transaction_trace_ptr trace; + std::shared_ptr partial; + + augmented_transaction_trace() = default; + augmented_transaction_trace(const augmented_transaction_trace&) = default; + augmented_transaction_trace(augmented_transaction_trace&&) = default; + + augmented_transaction_trace(const chain::transaction_trace_ptr& trace) + : trace{trace} {} + + augmented_transaction_trace(const chain::transaction_trace_ptr& trace, + const std::shared_ptr& partial) + : trace{trace} + , partial{partial} {} + + augmented_transaction_trace(const chain::transaction_trace_ptr& trace, const chain::signed_transaction& t) + : trace{trace} + , partial{std::make_shared(t)} {} + + augmented_transaction_trace& operator=(const augmented_transaction_trace&) = default; + augmented_transaction_trace& operator=(augmented_transaction_trace&&) = default; +}; + struct table_delta { fc::unsigned_int struct_version = 0; std::string name{}; diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp index 8ddb118c383..6149c381f06 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ #pragma once #include @@ -11,12 +7,15 @@ #include #include #include +#include #include #include #include #include #include +#include + template struct history_serial_wrapper { const chainbase::database& db; @@ -24,7 +23,7 @@ struct history_serial_wrapper { }; template -history_serial_wrapper make_history_serial_wrapper(const chainbase::database& db, const T& obj) { +history_serial_wrapper> make_history_serial_wrapper(const chainbase::database& db, const T& obj) { return {db, obj}; } @@ -36,7 +35,8 @@ struct history_context_wrapper { }; template -history_context_wrapper make_history_context_wrapper(const chainbase::database& db, P& context, const T& obj) { +history_context_wrapper, std::decay_t> +make_history_context_wrapper(const chainbase::database& db, const P& context, const T& obj) { return {db, context, obj}; } @@ -66,6 +66,16 @@ datastream& history_serialize_container(datastream& ds, const chainbase: return ds; } +template +datastream& history_context_serialize_container(datastream& ds, const chainbase::database& db, const P& context, + const std::vector& v) { + fc::raw::pack(ds, unsigned_int(v.size())); + for (const auto& x : v) { + ds << make_history_context_wrapper(db, context, x); + } + return ds; +} + template datastream& operator<<(datastream& ds, const history_serial_big_vector_wrapper& obj) { FC_ASSERT(obj.obj.size() <= 1024 * 1024 * 1024); @@ -75,10 +85,19 @@ datastream& operator<<(datastream& ds, const history_serial_big_vector_w return ds; } +template +inline void history_pack_varuint64(datastream& ds, uint64_t val) { + do { + uint8_t b = uint8_t(val) & 0x7f; + val >>= 7; + b |= ((val > 0) << 7); + ds.write((char*)&b, 1); + } while (val); +} + template void history_pack_big_bytes(datastream& ds, const eosio::chain::bytes& v) { - FC_ASSERT(v.size() <= 1024 * 1024 * 1024); - fc::raw::pack(ds, unsigned_int((uint32_t)v.size())); + history_pack_varuint64(ds, v.size()); if (v.size()) ds.write(&v.front(), (uint32_t)v.size()); } @@ -95,6 +114,11 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper +datastream& operator<<(datastream& ds, const history_context_wrapper>& obj) { + return history_context_serialize_container(ds, obj.db, obj.context, obj.obj); +} + template datastream& operator<<(datastream& ds, const history_serial_wrapper>& obj) { fc::raw::pack(ds, obj.obj.first); @@ -103,7 +127,7 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); fc::raw::pack(ds, as_type(obj.obj.name.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.creation_date)); @@ -150,14 +174,14 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.context.code.value)); - fc::raw::pack(ds, as_type(obj.context.scope.value)); - fc::raw::pack(ds, as_type(obj.context.table.value)); + fc::raw::pack(ds, as_type(obj.context.code.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.context.scope.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.context.table.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.primary_key)); - fc::raw::pack(ds, as_type(obj.obj.payer.value)); + fc::raw::pack(ds, as_type(obj.obj.payer.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.value)); return ds; } @@ -196,65 +220,50 @@ template datastream& serialize_secondary_index(datastream& ds, const eosio::chain::table_id_object& context, const T& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(context.code.value)); - fc::raw::pack(ds, as_type(context.scope.value)); - fc::raw::pack(ds, as_type(context.table.value)); + fc::raw::pack(ds, as_type(context.code.to_uint64_t())); + fc::raw::pack(ds, as_type(context.scope.to_uint64_t())); + fc::raw::pack(ds, as_type(context.table.to_uint64_t())); fc::raw::pack(ds, as_type(obj.primary_key)); - fc::raw::pack(ds, as_type(obj.payer.value)); + fc::raw::pack(ds, as_type(obj.payer.to_uint64_t())); serialize_secondary_index_data(ds, obj.secondary_key); return ds; } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& -operator<<(datastream& ds, - const history_context_wrapper& obj) { +operator<<(datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } template datastream& operator<<( - datastream& ds, - const history_context_wrapper& obj) { + datastream& ds, + const history_context_wrapper& obj) { return serialize_secondary_index(ds, obj.context, obj.obj); } -template -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.producer_name.value)); - fc::raw::pack(ds, as_type(obj.obj.block_signing_key)); - return ds; -} - -template -datastream& operator<<(datastream& ds, - const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.version)); - history_serialize_container(ds, obj.db, - as_type>(obj.obj.producers)); - return ds; -} template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { @@ -279,10 +288,26 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.producer_name.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.block_signing_key)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.version)); + history_serialize_container(ds, obj.db, + as_type>(obj.obj.producers)); + return ds; +} + template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, fc::unsigned_int(1)); fc::raw::pack(ds, as_type>(obj.obj.proposed_schedule_block_num)); fc::raw::pack(ds, make_history_serial_wrapper( obj.db, as_type(obj.obj.proposed_schedule))); @@ -295,9 +320,9 @@ template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.sender.value)); + fc::raw::pack(ds, as_type(obj.obj.sender.to_uint64_t())); fc::raw::pack(ds, as_type<__uint128_t>(obj.obj.sender_id)); - fc::raw::pack(ds, as_type(obj.obj.payer.value)); + fc::raw::pack(ds, as_type(obj.obj.payer.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.trx_id)); fc::raw::pack(ds, as_type(obj.obj.packed_trx)); return ds; @@ -310,10 +335,19 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + /// TODO +// history_serialize_container(ds, obj.db, obj.obj.activated_protocol_features); + return ds; +} + + template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.actor.value)); - fc::raw::pack(ds, as_type(obj.obj.permission.value)); + fc::raw::pack(ds, as_type(obj.obj.actor.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.permission.to_uint64_t())); return ds; } @@ -344,8 +378,8 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.owner.value)); - fc::raw::pack(ds, as_type(obj.obj.name.value)); + fc::raw::pack(ds, as_type(obj.obj.owner.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.name.to_uint64_t())); if (obj.obj.parent._id) { auto& index = obj.db.get_index(); const auto* parent = index.find(obj.obj.parent); @@ -356,7 +390,7 @@ datastream& operator<<(datastream& ds, const history_serial_wrappersecond; } - fc::raw::pack(ds, as_type(parent->name.value)); + fc::raw::pack(ds, as_type(parent->name.to_uint64_t())); } else { fc::raw::pack(ds, as_type(0)); } @@ -369,10 +403,10 @@ template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.account.value)); - fc::raw::pack(ds, as_type(obj.obj.code.value)); - fc::raw::pack(ds, as_type(obj.obj.message_type.value)); - fc::raw::pack(ds, as_type(obj.obj.required_permission.value)); + fc::raw::pack(ds, as_type(obj.obj.account.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.code.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.message_type.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.required_permission.to_uint64_t())); return ds; } @@ -382,7 +416,7 @@ datastream& operator<<(datastream& EOS_ASSERT(!obj.obj.pending, eosio::chain::plugin_exception, "accepted_block sent while resource_limits_object in pending state"); fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, as_type(obj.obj.owner.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.net_weight)); fc::raw::pack(ds, as_type(obj.obj.cpu_weight)); fc::raw::pack(ds, as_type(obj.obj.ram_bytes)); @@ -403,7 +437,7 @@ template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, as_type(obj.obj.owner.to_uint64_t())); fc::raw::pack(ds, make_history_serial_wrapper( obj.db, as_type(obj.obj.net_usage))); fc::raw::pack(ds, make_history_serial_wrapper( @@ -471,8 +505,8 @@ operator<<(datastream& template datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.account.value)); - fc::raw::pack(ds, as_type(obj.obj.name.value)); + fc::raw::pack(ds, as_type(obj.obj.account.to_uint64_t())); + fc::raw::pack(ds, as_type(obj.obj.name.to_uint64_t())); history_serialize_container(ds, obj.db, as_type>(obj.obj.authorization)); fc::raw::pack(ds, as_type(obj.obj.data)); return ds; @@ -481,7 +515,7 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.receiver.value)); + fc::raw::pack(ds, as_type(obj.obj.receiver.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.act_digest)); fc::raw::pack(ds, as_type(obj.obj.global_sequence)); fc::raw::pack(ds, as_type(obj.obj.recv_sequence)); @@ -493,73 +527,139 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - fc::raw::pack(ds, as_type(obj.obj.account.value)); + fc::raw::pack(ds, as_type(obj.obj.account.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.delta)); return ds; } +inline fc::optional cap_error_code( const fc::optional& error_code ) { + fc::optional result; + + if (!error_code) return result; + + const uint64_t upper_limit = static_cast(eosio::chain::system_error_code::generic_system_error); + + if (*error_code >= upper_limit) { + result = upper_limit; + return result; + } + + result = error_code; + return result; +} + template -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { +datastream& operator<<(datastream& ds, const history_context_wrapper& obj) { + bool debug_mode = obj.context; fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.receipt))); + fc::raw::pack(ds, as_type(obj.obj.action_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.creator_action_ordinal)); + fc::raw::pack(ds, bool(obj.obj.receipt)); + if (obj.obj.receipt) { + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(*obj.obj.receipt))); + } + fc::raw::pack(ds, as_type(obj.obj.receiver.to_uint64_t())); fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.act))); fc::raw::pack(ds, as_type(obj.obj.context_free)); - fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); - fc::raw::pack(ds, as_type(obj.obj.console)); + fc::raw::pack(ds, as_type(debug_mode ? obj.obj.elapsed.count() : 0)); + if (debug_mode) + fc::raw::pack(ds, as_type(obj.obj.console)); + else + fc::raw::pack(ds, std::string{}); history_serialize_container(ds, obj.db, as_type>(obj.obj.account_ram_deltas)); fc::optional e; - if (obj.obj.except) - e = obj.obj.except->to_string(); + if (obj.obj.except) { + if (debug_mode) + e = obj.obj.except->to_string(); + else + e = "Y"; + } fc::raw::pack(ds, as_type>(e)); + fc::raw::pack(ds, as_type>(debug_mode ? obj.obj.error_code + : cap_error_code(obj.obj.error_code))); - history_serialize_container(ds, obj.db, as_type>(obj.obj.inline_traces)); return ds; } template -datastream& operator<<(datastream& ds, - const history_context_wrapper& obj) { +datastream& operator<<(datastream& ds, + const history_context_wrapper, + eosio::augmented_transaction_trace>& obj) { + auto& trace = *obj.obj.trace; + bool debug_mode = obj.context.second; fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.id)); - if (obj.obj.receipt) { - if (obj.obj.failed_dtrx_trace && - obj.obj.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) + fc::raw::pack(ds, as_type(trace.id)); + if (trace.receipt) { + if (trace.failed_dtrx_trace && trace.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) fc::raw::pack(ds, uint8_t(eosio::chain::transaction_receipt_header::executed)); else - fc::raw::pack(ds, as_type(obj.obj.receipt->status.value)); - fc::raw::pack(ds, as_type(obj.obj.receipt->cpu_usage_us)); - fc::raw::pack(ds, as_type(obj.obj.receipt->net_usage_words)); + fc::raw::pack(ds, as_type(trace.receipt->status.value)); + fc::raw::pack(ds, as_type(trace.receipt->cpu_usage_us)); + fc::raw::pack(ds, as_type(trace.receipt->net_usage_words)); } else { - fc::raw::pack(ds, uint8_t(obj.context)); + fc::raw::pack(ds, uint8_t(obj.context.first)); fc::raw::pack(ds, uint32_t(0)); fc::raw::pack(ds, fc::unsigned_int(0)); } - fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); - fc::raw::pack(ds, as_type(obj.obj.net_usage)); - fc::raw::pack(ds, as_type(obj.obj.scheduled)); - history_serialize_container(ds, obj.db, as_type>(obj.obj.action_traces)); + fc::raw::pack(ds, as_type(debug_mode ? trace.elapsed.count() : 0)); + fc::raw::pack(ds, as_type(trace.net_usage)); + fc::raw::pack(ds, as_type(trace.scheduled)); + history_context_serialize_container(ds, obj.db, debug_mode, + as_type>(trace.action_traces)); + + fc::raw::pack(ds, bool(trace.account_ram_delta)); + if (trace.account_ram_delta) { + fc::raw::pack( + ds, make_history_serial_wrapper(obj.db, as_type(*trace.account_ram_delta))); + } fc::optional e; - if (obj.obj.except) - e = obj.obj.except->to_string(); + if (trace.except) { + if (debug_mode) + e = trace.except->to_string(); + else + e = "Y"; + } fc::raw::pack(ds, as_type>(e)); + fc::raw::pack(ds, as_type>(debug_mode ? trace.error_code + : cap_error_code(trace.error_code))); - fc::raw::pack(ds, bool(obj.obj.failed_dtrx_trace)); - if (obj.obj.failed_dtrx_trace) { + fc::raw::pack(ds, bool(trace.failed_dtrx_trace)); + if (trace.failed_dtrx_trace) { uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; - if (obj.obj.receipt && obj.obj.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) + if (trace.receipt && trace.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) stat = eosio::chain::transaction_receipt_header::soft_fail; - fc::raw::pack(ds, make_history_context_wrapper(obj.db, stat, *obj.obj.failed_dtrx_trace)); + std::pair context = std::make_pair(stat, debug_mode); + fc::raw::pack( // + ds, make_history_context_wrapper( + obj.db, context, eosio::augmented_transaction_trace{trace.failed_dtrx_trace, obj.obj.partial})); + } + + bool include_partial = obj.obj.partial && !trace.failed_dtrx_trace; + fc::raw::pack(ds, include_partial); + if (include_partial) { + auto& partial = *obj.obj.partial; + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(partial.expiration)); + fc::raw::pack(ds, as_type(partial.ref_block_num)); + fc::raw::pack(ds, as_type(partial.ref_block_prefix)); + fc::raw::pack(ds, as_type(partial.max_net_usage_words)); + fc::raw::pack(ds, as_type(partial.max_cpu_usage_ms)); + fc::raw::pack(ds, as_type(partial.delay_sec)); + fc::raw::pack(ds, as_type(partial.transaction_extensions)); + fc::raw::pack(ds, as_type>(partial.signatures)); + fc::raw::pack(ds, as_type>(partial.context_free_data)); } return ds; } template -datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { - uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; - ds << make_history_context_wrapper(obj.db, stat, obj.obj); +datastream& operator<<(datastream& ds, + const history_context_wrapper& obj) { + std::pair context = std::make_pair(eosio::chain::transaction_receipt_header::hard_fail, obj.context); + ds << make_history_context_wrapper(obj.db, context, obj.obj); return ds; } diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp index e4a51e632ae..61794edfac7 100644 --- a/plugins/state_history_plugin/state_history_plugin.cpp +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -111,18 +111,25 @@ bool include_delta(const eosio::chain::code_object& old, const eosio::chain::cod return false; } +bool include_delta(const eosio::chain::protocol_state_object& old, const eosio::chain::protocol_state_object& curr) { +// return old.activated_protocol_features != curr.activated_protocol_features; +/// TODO + return true; +} + struct state_history_plugin_impl : std::enable_shared_from_this { - chain_plugin* chain_plug = nullptr; - fc::optional trace_log; - fc::optional chain_state_log; - bool stopping = false; - fc::optional applied_transaction_connection; - fc::optional accepted_block_connection; - string endpoint_address = "0.0.0.0"; - uint16_t endpoint_port = 8080; - std::unique_ptr acceptor; - std::map cached_traces; - transaction_trace_ptr onblock_trace; + chain_plugin* chain_plug = nullptr; + fc::optional trace_log; + fc::optional chain_state_log; + bool trace_debug_mode = false; + bool stopping = false; + fc::optional applied_transaction_connection; + fc::optional accepted_block_connection; + string endpoint_address = "0.0.0.0"; + uint16_t endpoint_port = 8080; + std::unique_ptr acceptor; + std::map cached_traces; + fc::optional onblock_trace; void get_log_entry(state_history_log& log, uint32_t block_num, fc::optional& result) { if (block_num < log.begin_block() || block_num >= log.end_block()) @@ -131,20 +138,21 @@ struct state_history_plugin_impl : std::enable_shared_from_thisresize(s); + bytes compressed(s); if (s) - stream.read(result->data(), s); + stream.read(compressed.data(), s); + result = zlib_decompress(compressed); } void get_block(uint32_t block_num, fc::optional& result) { chain::signed_block_ptr p; try { - p = chain_plug->chain().fetch_block_by_number(block_num); + p = chain_plug->chain().fetch_block_by_number_state_history(block_num); } catch (...) { return; } - result = fc::raw::pack(*p); + if (p) + result = fc::raw::pack(*p); } fc::optional get_block_id(uint32_t block_num) { @@ -153,7 +161,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this= chain_state_log->begin_block() && block_num < chain_state_log->end_block()) return chain_state_log->get_block_id(block_num); try { - auto block = chain_plug->chain().fetch_block_by_number(block_num); + auto block = chain_plug->chain().fetch_block_by_number_state_history(block_num); if (block) return block->id(); } catch (...) { @@ -180,10 +188,10 @@ struct state_history_plugin_impl : std::enable_shared_from_thisnext_layer().set_option(boost::asio::ip::tcp::no_delay(true)); socket_stream->next_layer().set_option(boost::asio::socket_base::send_buffer_size(1024 * 1024)); socket_stream->next_layer().set_option(boost::asio::socket_base::receive_buffer_size(1024 * 1024)); - socket_stream->async_accept([self = shared_from_this(), this](boost::system::error_code ec) { - callback(ec, "async_accept", [&] { - start_read(); - send(state_history_plugin_abi); + socket_stream->async_accept([self = shared_from_this()](boost::system::error_code ec) { + self->callback(ec, "async_accept", [self] { + self->start_read(); + self->send(state_history_plugin_abi); }); }); } @@ -191,15 +199,15 @@ struct state_history_plugin_impl : std::enable_shared_from_this(); socket_stream->async_read( - *in_buffer, [self = shared_from_this(), this, in_buffer](boost::system::error_code ec, size_t) { - callback(ec, "async_read", [&] { + *in_buffer, [self = shared_from_this(), in_buffer](boost::system::error_code ec, size_t) { + self->callback(ec, "async_read", [self, in_buffer] { auto d = boost::asio::buffer_cast(boost::beast::buffers_front(in_buffer->data())); auto s = boost::asio::buffer_size(in_buffer->data()); fc::datastream ds(d, s); state_request req; fc::raw::unpack(ds, req); - req.visit(*this); - start_read(); + req.visit(*self); + self->start_read(); }); }); } @@ -225,11 +233,11 @@ struct state_history_plugin_impl : std::enable_shared_from_thisasync_write( // boost::asio::buffer(send_queue[0]), - [self = shared_from_this(), this](boost::system::error_code ec, size_t) { - callback(ec, "async_write", [&] { - send_queue.erase(send_queue.begin()); - sending = false; - send(); + [self = shared_from_this()](boost::system::error_code ec, size_t) { + self->callback(ec, "async_write", [self] { + self->send_queue.erase(self->send_queue.begin()); + self->sending = false; + self->send(); }); }); } @@ -271,18 +279,14 @@ struct state_history_plugin_impl : std::enable_shared_from_thismax_messages_in_flight) + void send_update(get_blocks_result_v0 result) { + need_to_send_update = true; + if (!send_queue.empty() || !current_request || !current_request->max_messages_in_flight) return; - auto& chain = plugin->chain_plug->chain(); - get_blocks_result_v0 result; - result.head = {chain.head_block_num(), chain.head_block_id()}; + auto& chain = plugin->chain_plug->chain(); result.last_irreversible = {chain.last_irreversible_block_num(), chain.last_irreversible_block_id()}; uint32_t current = - current_request->irreversible_only ? result.last_irreversible.block_num : result.head.block_num; + current_request->irreversible_only ? result.last_irreversible.block_num : result.head.block_num; if (current_request->start_block_num <= current && current_request->start_block_num < current_request->end_block_num) { auto block_id = plugin->get_block_id(current_request->start_block_num); @@ -306,6 +310,27 @@ struct state_history_plugin_impl : std::enable_shared_from_thisstart_block_num < current_request->end_block_num; } + void send_update(const block_state_ptr& block_state) { + need_to_send_update = true; + if (!send_queue.empty() || !current_request || !current_request->max_messages_in_flight) + return; + get_blocks_result_v0 result; + result.head = {block_state->block_num, block_state->id}; + send_update(std::move(result)); + } + + void send_update(bool changed = false) { + if (changed) + need_to_send_update = true; + if (!send_queue.empty() || !need_to_send_update || !current_request || + !current_request->max_messages_in_flight) + return; + auto& chain = plugin->chain_plug->chain(); + get_blocks_result_v0 result; + result.head = {chain.head_block_num(), chain.head_block_id()}; + send_update(std::move(result)); + } + template void catch_and_close(F f) { try { @@ -373,7 +398,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this(app().get_io_service()); - acceptor->async_accept(*socket, [self = shared_from_this(), socket, this](auto ec) { + acceptor->async_accept(*socket, [self = shared_from_this(), socket, this](const boost::system::error_code& ec) { if (stopping) return; if (ec) { @@ -402,14 +427,14 @@ struct state_history_plugin_impl : std::enable_shared_from_thisreceipt && trace_log) { if (is_onblock(p)) - onblock_trace = p; + onblock_trace.emplace(p, t); else if (p->failed_dtrx_trace) - cached_traces[p->failed_dtrx_trace->id] = p; + cached_traces[p->failed_dtrx_trace->id] = augmented_transaction_trace{p, t}; else - cached_traces[p->id] = p; + cached_traces[p->id] = augmented_transaction_trace{p, t}; } } @@ -421,7 +446,7 @@ struct state_history_plugin_impl : std::enable_shared_from_thiscurrent_request && block_state->block_num < p->current_request->start_block_num) p->current_request->start_block_num = block_state->block_num; - p->send_update(true); + p->send_update(block_state); } } } @@ -429,9 +454,9 @@ struct state_history_plugin_impl : std::enable_shared_from_this traces; + std::vector traces; if (onblock_trace) - traces.push_back(onblock_trace); + traces.push_back(*onblock_trace); for (auto& r : block_state->block->transactions) { transaction_id_type id; if (r.trx.contains()) @@ -439,7 +464,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this().id(); auto it = cached_traces.find(id); - EOS_ASSERT(it != cached_traces.end() && it->second->receipt, plugin_exception, + EOS_ASSERT(it != cached_traces.end() && it->second.trace->receipt, plugin_exception, "missing trace for transaction ${id}", ("id", id)); traces.push_back(it->second); } @@ -447,10 +472,10 @@ struct state_history_plugin_impl : std::enable_shared_from_thischain().db(); - auto traces_bin = zlib_compress_bytes(fc::raw::pack(make_history_serial_wrapper(db, traces))); + auto traces_bin = zlib_compress_bytes(fc::raw::pack(make_history_context_wrapper(db, trace_debug_mode, traces))); EOS_ASSERT(traces_bin.size() == (uint32_t)traces_bin.size(), plugin_exception, "traces is too big"); - state_history_log_header header{.block_num = block_state->block->block_num(), + state_history_log_header header{.magic = ship_magic(ship_current_version), .block_id = block_state->block->id(), .payload_size = sizeof(uint32_t) + traces_bin.size()}; trace_log->write_entry(header, block_state->block->previous, [&](auto& stream) { @@ -511,7 +536,8 @@ struct state_history_plugin_impl : std::enable_shared_from_this(), pack_row); + process_table("account", db.get_index(), pack_row); process_table("account_metadata", db.get_index(), pack_row); process_table("code", db.get_index(), pack_row); @@ -536,6 +562,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this(), pack_row); process_table("generated_transaction", db.get_index(), pack_row); + process_table("protocol_state", db.get_index(), pack_row); process_table("permission", db.get_index(), pack_row); process_table("permission_link", db.get_index(), pack_row); @@ -547,7 +574,7 @@ struct state_history_plugin_impl : std::enable_shared_from_thisblock->block_num(), + state_history_log_header header{.magic = ship_magic(ship_current_version), .block_id = block_state->block->id(), .payload_size = sizeof(uint32_t) + deltas_bin.size()}; chain_state_log->write_entry(header, block_state->block->previous, [&](auto& stream) { @@ -571,8 +598,11 @@ void state_history_plugin::set_program_options(options_description& cli, options cli.add_options()("delete-state-history", bpo::bool_switch()->default_value(false), "clear state history files"); options("trace-history", bpo::bool_switch()->default_value(false), "enable trace history"); options("chain-state-history", bpo::bool_switch()->default_value(false), "enable chain state history"); - options("state-history-endpoint", bpo::value()->default_value("0.0.0.0:8080"), - "the endpoint upon which to listen for incoming connections"); + options("state-history-endpoint", bpo::value()->default_value("127.0.0.1:8080"), + "the endpoint upon which to listen for incoming connections. Caution: only expose this port to " + "your internal network."); + options("trace-history-debug-mode", bpo::bool_switch()->default_value(false), + "enable debug mode for trace history"); } void state_history_plugin::plugin_initialize(const variables_map& options) { @@ -584,7 +614,9 @@ void state_history_plugin::plugin_initialize(const variables_map& options) { EOS_ASSERT(my->chain_plug, chain::missing_chain_plugin_exception, ""); auto& chain = my->chain_plug->chain(); my->applied_transaction_connection.emplace( - chain.applied_transaction.connect([&](const transaction_trace_ptr& p) { my->on_applied_transaction(p); })); + chain.applied_transaction.connect([&](std::tuple t) { + my->on_applied_transaction(std::get<0>(t), std::get<1>(t)); + })); my->accepted_block_connection.emplace( chain.accepted_block.connect([&](const block_state_ptr& p) { my->on_accepted_block(p); })); @@ -608,6 +640,10 @@ void state_history_plugin::plugin_initialize(const variables_map& options) { } boost::filesystem::create_directories(state_history_dir); + if (options.at("trace-history-debug-mode").as()) { + my->trace_debug_mode = true; + } + if (options.at("trace-history").as()) my->trace_log.emplace("trace_history", (state_history_dir / "trace_history.log").string(), (state_history_dir / "trace_history.index").string()); diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp index bdedcc81cd9..a5ff928f52c 100644 --- a/plugins/state_history_plugin/state_history_plugin_abi.cpp +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -93,14 +93,30 @@ extern const char* const state_history_plugin_abi = R"({ }, { "name": "action_trace_v0", "fields": [ - { "name": "receipt", "type": "action_receipt" }, + { "name": "action_ordinal", "type": "varuint32" }, + { "name": "creator_action_ordinal", "type": "varuint32" }, + { "name": "receipt", "type": "action_receipt?" }, + { "name": "receiver", "type": "name" }, { "name": "act", "type": "action" }, { "name": "context_free", "type": "bool" }, { "name": "elapsed", "type": "int64" }, { "name": "console", "type": "string" }, { "name": "account_ram_deltas", "type": "account_delta[]" }, { "name": "except", "type": "string?" }, - { "name": "inline_traces", "type": "action_trace[]" } + { "name": "error_code", "type": "uint64?" } + ] + }, + { + "name": "partial_transaction_v0", "fields": [ + { "name": "expiration", "type": "time_point_sec" }, + { "name": "ref_block_num", "type": "uint16" }, + { "name": "ref_block_prefix", "type": "uint32" }, + { "name": "max_net_usage_words", "type": "varuint32" }, + { "name": "max_cpu_usage_ms", "type": "uint8" }, + { "name": "delay_sec", "type": "varuint32" }, + { "name": "transaction_extensions", "type": "extension[]" }, + { "name": "signatures", "type": "signature[]" }, + { "name": "context_free_data", "type": "bytes[]" } ] }, { @@ -113,8 +129,11 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "net_usage", "type": "uint64" }, { "name": "scheduled", "type": "bool" }, { "name": "action_traces", "type": "action_trace[]" }, + { "name": "account_ram_delta", "type": "account_delta?" }, { "name": "except", "type": "string?" }, - { "name": "failed_dtrx_trace", "type": "transaction_trace?" } + { "name": "error_code", "type": "uint64?" }, + { "name": "failed_dtrx_trace", "type": "transaction_trace?" }, + { "name": "partial", "type": "partial_transaction?" } ] }, { @@ -183,18 +202,35 @@ extern const char* const state_history_plugin_abi = R"({ ] }, { - "name": "account_v0", "fields": [ - { "type": "name", "name": "name" }, + "name": "code_id", "fields": [ { "type": "uint8", "name": "vm_type" }, { "type": "uint8", "name": "vm_version" }, - { "type": "bool", "name": "privileged" }, - { "type": "time_point", "name": "last_code_update" }, - { "type": "checksum256", "name": "code_version" }, + { "type": "checksum256", "name": "code_hash" } + ] + }, + { + "name": "account_v0", "fields": [ + { "type": "name", "name": "name" }, { "type": "block_timestamp_type", "name": "creation_date" }, - { "type": "bytes", "name": "code" }, { "type": "bytes", "name": "abi" } ] }, + { + "name": "account_metadata_v0", "fields": [ + { "type": "name", "name": "name" }, + { "type": "bool", "name": "privileged" }, + { "type": "time_point", "name": "last_code_update" }, + { "type": "code_id?", "name": "code" } + ] + }, + { + "name": "code_v0", "fields": [ + { "type": "uint8", "name": "vm_type" }, + { "type": "uint8", "name": "vm_version" }, + { "type": "checksum256", "name": "code_hash" }, + { "type": "bytes", "name": "code" } + ] + }, { "name": "contract_table_v0", "fields": [ { "type": "name", "name": "code" }, @@ -429,11 +465,14 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "action_receipt", "types": ["action_receipt_v0"] }, { "name": "action_trace", "types": ["action_trace_v0"] }, + { "name": "partial_transaction", "types": ["partial_transaction_v0"] }, { "name": "transaction_trace", "types": ["transaction_trace_v0"] }, { "name": "transaction_variant", "types": ["transaction_id", "packed_transaction"] }, { "name": "table_delta", "types": ["table_delta_v0"] }, { "name": "account", "types": ["account_v0"] }, + { "name": "account_metadata", "types": ["account_metadata_v0"] }, + { "name": "code", "types": ["code_v0"] }, { "name": "contract_table", "types": ["contract_table_v0"] }, { "name": "contract_row", "types": ["contract_row_v0"] }, { "name": "contract_index64", "types": ["contract_index64_v0"] }, @@ -456,6 +495,8 @@ extern const char* const state_history_plugin_abi = R"({ ], "tables": [ { "name": "account", "type": "account", "key_names": ["name"] }, + { "name": "account_metadata", "type": "account_metadata", "key_names": ["name"] }, + { "name": "code", "type": "code", "key_names": ["vm_type", "vm_version", "code_hash"] }, { "name": "contract_table", "type": "contract_table", "key_names": ["code", "scope", "table"] }, { "name": "contract_row", "type": "contract_row", "key_names": ["code", "scope", "table", "primary_key"] }, { "name": "contract_index64", "type": "contract_index64", "key_names": ["code", "scope", "table", "primary_key"] }, diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index 30a1acb9b28..018867968ec 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -164,7 +164,7 @@ struct txn_test_gen_plugin_impl { auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountA, owner_auth, active_auth}); + trx.actions.emplace_back(vector{{creator,name("active")}}, newaccount{creator, newaccountA, owner_auth, active_auth}); //delegate cpu net and buyram auto act_delegatebw = create_action_delegatebw(creator, newaccountA,net,cpu,abi_serializer_max_time); @@ -179,7 +179,7 @@ struct txn_test_gen_plugin_impl { auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountB, owner_auth, active_auth}); + trx.actions.emplace_back(vector{{creator,name("active")}}, newaccount{creator, newaccountB, owner_auth, active_auth}); //delegate cpu net and buyram auto act_delegatebw = create_action_delegatebw(creator, newaccountB,net,cpu,abi_serializer_max_time); @@ -193,7 +193,7 @@ struct txn_test_gen_plugin_impl { auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountC, owner_auth, active_auth}); + trx.actions.emplace_back(vector{{creator,name("active")}}, newaccount{creator, newaccountC, owner_auth, active_auth}); //delegate cpu net and buyram auto act_delegatebw = create_action_delegatebw(creator, newaccountC,net,cpu,abi_serializer_max_time); @@ -220,13 +220,13 @@ struct txn_test_gen_plugin_impl { handler.account = newaccountC; handler.code.assign(wasm.begin(), wasm.end()); - trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); + trx.actions.emplace_back( vector{{newaccountC,name("active")}}, handler); { setabi handler; handler.account = newaccountC; handler.abi = fc::raw::pack(eosio_token_abi); - trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); + trx.actions.emplace_back( vector{{newaccountC,name("active")}}, handler); } { @@ -289,7 +289,7 @@ struct txn_test_gen_plugin_impl { abi_serializer eosio_system_serializer(eosio_abi, abi_serializer_max_time); auto payload_delegate = eosio_system_serializer.variant_to_binary( "delegatebw", variant_delegate, abi_serializer_max_time); - eosio::chain::action act_delegate{vector{{from,"active"}}, + eosio::chain::action act_delegate{vector{{from,name("active")}}, config::system_account_name, N(delegatebw), payload_delegate}; return act_delegate; @@ -306,7 +306,7 @@ struct txn_test_gen_plugin_impl { abi_serializer eosio_system_serializer(eosio_abi, abi_serializer_max_time); auto payload_buyram = eosio_system_serializer.variant_to_binary( "buyram", variant_buyram, abi_serializer_max_time); - eosio::chain::action act_buyram{vector{{from,"active"}}, + eosio::chain::action act_buyram{vector{{from,name("active")}}, config::system_account_name, N(buyram), payload_buyram}; return act_buyram; @@ -411,7 +411,7 @@ struct txn_test_gen_plugin_impl { { signed_transaction trx; trx.actions.push_back(act_a_to_b); - trx.context_free_actions.emplace_back(action({}, config::null_account_name, "nonce", fc::raw::pack(nonce++))); + trx.context_free_actions.emplace_back(action({}, config::null_account_name, name("nonce"), fc::raw::pack(nonce++))); trx.set_reference_block(reference_block_id); trx.expiration = cc.head_block_time() + fc::seconds(30); trx.max_net_usage_words = 100; @@ -422,7 +422,7 @@ struct txn_test_gen_plugin_impl { { signed_transaction trx; trx.actions.push_back(act_b_to_a); - trx.context_free_actions.emplace_back(action({}, config::null_account_name, "nonce", fc::raw::pack(nonce++))); + trx.context_free_actions.emplace_back(action({}, config::null_account_name, name("nonce"), fc::raw::pack(nonce++))); trx.set_reference_block(reference_block_id); trx.expiration = cc.head_block_time() + fc::seconds(30); trx.max_net_usage_words = 100; diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 28f05c77e5b..92279ec651f 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -225,7 +225,7 @@ vector get_account_permissions(const vector& pe vector pieces; split(pieces, p, boost::algorithm::is_any_of("@")); if( pieces.size() == 1 ) pieces.push_back( "active" ); - return chain::permission_level{ .actor = pieces[0], .permission = pieces[1] }; + return chain::permission_level{ .actor = name(pieces[0]), .permission = name(pieces[1]) }; }); vector accountPermissions; boost::range::copy(fixedPermissions, back_inserter(accountPermissions)); @@ -273,7 +273,7 @@ string generate_nonce_string() { } chain::action generate_nonce_action() { - return chain::action( {}, config::null_account_name, "nonce", fc::raw::pack(fc::time_point::now().time_since_epoch().count())); + return chain::action( {}, config::null_account_name, name("nonce"), fc::raw::pack(fc::time_point::now().time_since_epoch().count())); } void prompt_for_wallet_password(string& pw, const string& name) { @@ -577,8 +577,8 @@ chain::action create_open(const string& contract, const name& owner, symbol sym, ("symbol", sym) ("ram_payer", ram_payer); return action { - get_account_permissions(tx_permission, {ram_payer,config::active_name}), - contract, "open", variant_to_bin( contract, N(open), open_ ) + get_account_permissions(tx_permission, {ram_payer, config::active_name}), + name(contract), N(open), variant_to_bin( name(contract), N(open), open_ ) }; } @@ -592,7 +592,7 @@ chain::action create_transfer(const string& contract, const name& sender, const return action { get_account_permissions(tx_permission, {sender,config::active_name}), - contract, "transfer", variant_to_bin( contract, N(transfer), transfer ) + name(contract), N(transfer), variant_to_bin( name(contract), N(transfer), transfer ) }; } @@ -693,10 +693,10 @@ inline asset to_asset( const string& s ) { } struct set_account_permission_subcommand { - name account; - name permission; + string account; + string permission; string authority_json_or_file; - name parent; + string parent; bool add_code; bool remove_code; @@ -717,34 +717,34 @@ struct set_account_permission_subcommand { authority auth; - bool need_parent = parent.empty() && (permission != name("owner")); + bool need_parent = parent.empty() && (name(permission) != name("owner")); bool need_auth = add_code || remove_code; if ( !need_auth && boost::iequals(authority_json_or_file, "null") ) { - send_actions( { create_deleteauth(account, permission) } ); + send_actions( { create_deleteauth(name(account), name(permission)) } ); return; } if ( need_parent || need_auth ) { - fc::variant json = call(get_account_func, fc::mutable_variant_object("account_name", account.to_string())); + fc::variant json = call(get_account_func, fc::mutable_variant_object("account_name", account)); auto res = json.as(); auto itr = std::find_if(res.permissions.begin(), res.permissions.end(), [&](const auto& perm) { - return perm.perm_name == permission; + return perm.perm_name == name(permission); }); if ( need_parent ) { // see if we can auto-determine the proper parent if ( itr != res.permissions.end() ) { - parent = (*itr).parent; + parent = (*itr).parent.to_string(); } else { // if this is a new permission and there is no parent we default to "active" - parent = name(config::active_name); + parent = config::active_name.to_string(); } } if ( need_auth ) { - auto actor = (authority_json_or_file.empty()) ? account : name(authority_json_or_file); - auto code_name = name(config::eosio_code_name); + auto actor = (authority_json_or_file.empty()) ? name(account) : name(authority_json_or_file); + auto code_name = config::eosio_code_name; if ( itr != res.permissions.end() ) { // fetch existing authority @@ -787,7 +787,7 @@ struct set_account_permission_subcommand { // remove code permission, if authority becomes empty by the removal of code permission, delete permission auth.accounts.erase( itr2 ); if ( auth.keys.empty() && auth.accounts.empty() && auth.waits.empty() ) { - send_actions( { create_deleteauth(account, permission) } ); + send_actions( { create_deleteauth(name(account), name(permission)) } ); return; } } else { @@ -818,7 +818,7 @@ struct set_account_permission_subcommand { auth = parse_json_authority_or_key(authority_json_or_file); } - send_actions( { create_updateauth(account, permission, parent, auth) } ); + send_actions( { create_updateauth(name(account), name(permission), name(parent), auth) } ); }); } }; @@ -994,8 +994,8 @@ struct register_producer_subcommand { producer_key = public_key_type(producer_key_str); } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid producer public key: ${public_key}", ("public_key", producer_key_str)) - auto regprod_var = regproducer_variant(producer_str, producer_key, url, loc ); - auto accountPermissions = get_account_permissions(tx_permission, {producer_str,config::active_name}); + auto regprod_var = regproducer_variant(name(producer_str), producer_key, url, loc ); + auto accountPermissions = get_account_permissions(tx_permission, {name(producer_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(regproducer), regprod_var)}); }); } @@ -1052,16 +1052,16 @@ struct create_account_subcommand { try { active_key = public_key_type(active_key_str); } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid active public key: ${public_key}", ("public_key", active_key_str)); - auto create = create_newaccount(creator, account_name, owner_key, active_key); + auto create = create_newaccount(name(creator), name(account_name), owner_key, active_key); if (!simple) { EOSC_ASSERT( buy_ram_eos.size() || buy_ram_bytes_in_kbytes || buy_ram_bytes, "ERROR: One of --buy-ram, --buy-ram-kbytes or --buy-ram-bytes should have non-zero value" ); EOSC_ASSERT( !buy_ram_bytes_in_kbytes || !buy_ram_bytes, "ERROR: --buy-ram-kbytes and --buy-ram-bytes cannot be set at the same time" ); - action buyram = !buy_ram_eos.empty() ? create_buyram(creator, account_name, to_asset(buy_ram_eos)) - : create_buyrambytes(creator, account_name, (buy_ram_bytes_in_kbytes) ? (buy_ram_bytes_in_kbytes * 1024) : buy_ram_bytes); + action buyram = !buy_ram_eos.empty() ? create_buyram(name(creator), name(account_name), to_asset(buy_ram_eos)) + : create_buyrambytes(name(creator), name(account_name), (buy_ram_bytes_in_kbytes) ? (buy_ram_bytes_in_kbytes * 1024) : buy_ram_bytes); auto net = to_asset(stake_net); auto cpu = to_asset(stake_cpu); if ( net.get_amount() != 0 || cpu.get_amount() != 0 ) { - action delegate = create_delegate( creator, account_name, net, cpu, transfer); + action delegate = create_delegate( name(creator), name(account_name), net, cpu, transfer); send_actions( { create, buyram, delegate } ); } else { send_actions( { create, buyram } ); @@ -1085,7 +1085,7 @@ struct unregister_producer_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("producer", producer_str); - auto accountPermissions = get_account_permissions(tx_permission, {producer_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(producer_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(unregprod), act_payload)}); }); } @@ -1106,7 +1106,7 @@ struct vote_producer_proxy_subcommand { ("voter", voter_str) ("proxy", proxy_str) ("producers", std::vector{}); - auto accountPermissions = get_account_permissions(tx_permission, {voter_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(voter_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } @@ -1114,7 +1114,7 @@ struct vote_producer_proxy_subcommand { struct vote_producers_subcommand { string voter_str; - vector producer_names; + vector producer_names; vote_producers_subcommand(CLI::App* actionRoot) { auto vote_producers = actionRoot->add_subcommand("prods", localized("Vote for one or more producers")); @@ -1130,15 +1130,15 @@ struct vote_producers_subcommand { ("voter", voter_str) ("proxy", "") ("producers", producer_names); - auto accountPermissions = get_account_permissions(tx_permission, {voter_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(voter_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; struct approve_producer_subcommand { - eosio::name voter; - eosio::name producer_name; + string voter; + string producer_name; approve_producer_subcommand(CLI::App* actionRoot) { auto approve_producer = actionRoot->add_subcommand("approve", localized("Add one producer to list of voted producers")); @@ -1152,8 +1152,8 @@ struct approve_producer_subcommand { ("scope", name(config::system_account_name).to_string()) ("table", "voters") ("table_key", "owner") - ("lower_bound", voter.value) - ("upper_bound", voter.value + 1) + ("lower_bound", name(voter).to_uint64_t()) + ("upper_bound", name(voter).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to voter.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -1172,7 +1172,7 @@ struct approve_producer_subcommand { for ( auto& x : prod_vars ) { prods.push_back( name(x.as_string()) ); } - prods.push_back( producer_name ); + prods.push_back( name(producer_name) ); std::sort( prods.begin(), prods.end() ); auto it = std::unique( prods.begin(), prods.end() ); if (it != prods.end() ) { @@ -1183,15 +1183,15 @@ struct approve_producer_subcommand { ("voter", voter) ("proxy", "") ("producers", prods); - auto accountPermissions = get_account_permissions(tx_permission, {voter,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(voter), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; struct unapprove_producer_subcommand { - eosio::name voter; - eosio::name producer_name; + string voter; + string producer_name; unapprove_producer_subcommand(CLI::App* actionRoot) { auto approve_producer = actionRoot->add_subcommand("unapprove", localized("Remove one producer from list of voted producers")); @@ -1205,8 +1205,8 @@ struct unapprove_producer_subcommand { ("scope", name(config::system_account_name).to_string()) ("table", "voters") ("table_key", "owner") - ("lower_bound", voter.value) - ("upper_bound", voter.value + 1) + ("lower_bound", name(voter).to_uint64_t()) + ("upper_bound", name(voter).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to voter.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -1225,7 +1225,7 @@ struct unapprove_producer_subcommand { for ( auto& x : prod_vars ) { prods.push_back( name(x.as_string()) ); } - auto it = std::remove( prods.begin(), prods.end(), producer_name ); + auto it = std::remove( prods.begin(), prods.end(), name(producer_name) ); if (it == prods.end() ) { std::cerr << "Cannot remove: producer \"" << producer_name << "\" is not on the list." << std::endl; return; @@ -1235,7 +1235,7 @@ struct unapprove_producer_subcommand { ("voter", voter) ("proxy", "") ("producers", prods); - auto accountPermissions = get_account_permissions(tx_permission, {voter,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(voter), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } @@ -1397,13 +1397,13 @@ struct delegate_bandwidth_subcommand { ("stake_net_quantity", to_asset(stake_net_amount)) ("stake_cpu_quantity", to_asset(stake_cpu_amount)) ("transfer", transfer); - auto accountPermissions = get_account_permissions(tx_permission, {from_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); std::vector acts{create_action(accountPermissions, config::system_account_name, N(delegatebw), act_payload)}; EOSC_ASSERT( !(buy_ram_amount.size()) || !buy_ram_bytes, "ERROR: --buyram and --buy-ram-bytes cannot be set at the same time" ); if (buy_ram_amount.size()) { - acts.push_back( create_buyram(from_str, receiver_str, to_asset(buy_ram_amount)) ); + acts.push_back( create_buyram(name(from_str), name(receiver_str), to_asset(buy_ram_amount)) ); } else if (buy_ram_bytes) { - acts.push_back( create_buyrambytes(from_str, receiver_str, buy_ram_bytes) ); + acts.push_back( create_buyrambytes(name(from_str), name(receiver_str), buy_ram_bytes) ); } send_actions(std::move(acts)); }); @@ -1431,7 +1431,7 @@ struct undelegate_bandwidth_subcommand { ("receiver", receiver_str) ("unstake_net_quantity", to_asset(unstake_net_amount)) ("unstake_cpu_quantity", to_asset(unstake_cpu_amount)); - auto accountPermissions = get_account_permissions(tx_permission, {from_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(undelegatebw), act_payload)}); }); } @@ -1452,7 +1452,7 @@ struct bidname_subcommand { ("bidder", bidder_str) ("newname", newname_str) ("bid", to_asset(bid_amount)); - auto accountPermissions = get_account_permissions(tx_permission, {bidder_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(bidder_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(bidname), act_payload)}); }); } @@ -1460,7 +1460,7 @@ struct bidname_subcommand { struct bidname_info_subcommand { bool print_json = false; - name newname; + string newname; bidname_info_subcommand(CLI::App* actionRoot) { auto list_producers = actionRoot->add_subcommand("bidnameinfo", localized("Get bidname info")); list_producers->add_flag("--json,-j", print_json, localized("Output in JSON format")); @@ -1468,19 +1468,18 @@ struct bidname_info_subcommand { list_producers->set_callback([this] { auto rawResult = call(get_table_func, fc::mutable_variant_object("json", true) ("code", "eosio")("scope", "eosio")("table", "namebids") - ("lower_bound", newname.value) - ("upper_bound", newname.value + 1) + ("lower_bound", name(newname).to_uint64_t()) + ("upper_bound", name(newname).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to newname.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1)); - if ( print_json ) { std::cout << fc::json::to_pretty_string(rawResult) << std::endl; return; } auto result = rawResult.as(); // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 - if( result.rows.empty() || result.rows[0].get_object()["newname"].as_string() != newname.to_string() ) { + if( result.rows.empty() || result.rows[0].get_object()["newname"].as_string() != name(newname).to_string() ) { std::cout << "No bidname record found" << std::endl; return; } @@ -1501,7 +1500,7 @@ struct bidname_info_subcommand { }; struct list_bw_subcommand { - eosio::name account; + string account; bool print_json = false; list_bw_subcommand(CLI::App* actionRoot) { @@ -1513,7 +1512,7 @@ struct list_bw_subcommand { //get entire table in scope of user account auto result = call(get_table_func, fc::mutable_variant_object("json", true) ("code", name(config::system_account_name).to_string()) - ("scope", account.to_string()) + ("scope", name(account).to_string()) ("table", "delband") ); if (!print_json) { @@ -1555,9 +1554,9 @@ struct buyram_subcommand { buyram->set_callback([this] { EOSC_ASSERT( !kbytes || !bytes, "ERROR: --kbytes and --bytes cannot be set at the same time" ); if (kbytes || bytes) { - send_actions( { create_buyrambytes(from_str, receiver_str, fc::to_uint64(amount) * ((kbytes) ? 1024ull : 1ull)) } ); + send_actions( { create_buyrambytes(name(from_str), name(receiver_str), fc::to_uint64(amount) * ((kbytes) ? 1024ull : 1ull)) } ); } else { - send_actions( { create_buyram(from_str, receiver_str, to_asset(amount)) } ); + send_actions( { create_buyram(name(from_str), name(receiver_str), to_asset(amount)) } ); } }); } @@ -1578,7 +1577,7 @@ struct sellram_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("account", receiver_str) ("bytes", amount); - auto accountPermissions = get_account_permissions(tx_permission, {receiver_str,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(receiver_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(sellram), act_payload)}); }); } @@ -1595,7 +1594,7 @@ struct claimrewards_subcommand { claim_rewards->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner); - auto accountPermissions = get_account_permissions(tx_permission, {owner,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(claimrewards), act_payload)}); }); } @@ -1613,7 +1612,7 @@ struct regproxy_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("proxy", proxy) ("isproxy", true); - auto accountPermissions = get_account_permissions(tx_permission, {proxy,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(proxy), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(regproxy), act_payload)}); }); } @@ -1631,7 +1630,7 @@ struct unregproxy_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("proxy", proxy) ("isproxy", false); - auto accountPermissions = get_account_permissions(tx_permission, {proxy,config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(proxy), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, N(regproxy), act_payload)}); }); } @@ -1650,7 +1649,7 @@ struct canceldelay_subcommand { add_standard_transaction_options(cancel_delay, "canceling_account@canceling_permission"); cancel_delay->set_callback([this] { - auto canceling_auth = permission_level{canceling_account, canceling_permission}; + auto canceling_auth = permission_level{name(canceling_account), name(canceling_permission)}; fc::variant act_payload = fc::mutable_variant_object() ("canceling_auth", canceling_auth) ("trx_id", trx_id); @@ -1674,7 +1673,7 @@ struct deposit_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1694,7 +1693,7 @@ struct withdraw_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1714,7 +1713,7 @@ struct buyrex_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("from", from_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1738,7 +1737,7 @@ struct lendrex_subcommand { fc::variant act_payload2 = fc::mutable_variant_object() ("from", from_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name1, act_payload1), create_action(accountPermissions, config::system_account_name, act_name2, act_payload2)}); }); @@ -1756,8 +1755,8 @@ struct unstaketorex_subcommand { auto unstaketorex = actionRoot->add_subcommand("unstaketorex", localized("Buy REX using staked tokens")); unstaketorex->add_option("owner", owner_str, localized("Account buying REX tokens"))->required(); unstaketorex->add_option("receiver", receiver_str, localized("Account that tokens have been staked to"))->required(); - unstaketorex->add_option("from_net", from_net_str, localized("Amount to be unstaked from CPU resources and used in REX purchase"))->required(); - unstaketorex->add_option("from_cpu", from_cpu_str, localized("Amount to be unstaked from Net resources and used in REX purchase"))->required(); + unstaketorex->add_option("from_net", from_net_str, localized("Amount to be unstaked from Net resources and used in REX purchase"))->required(); + unstaketorex->add_option("from_cpu", from_cpu_str, localized("Amount to be unstaked from CPU resources and used in REX purchase"))->required(); add_standard_transaction_options(unstaketorex, "owner@active"); unstaketorex->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() @@ -1765,7 +1764,7 @@ struct unstaketorex_subcommand { ("receiver", receiver_str) ("from_net", from_net_str) ("from_cpu", from_cpu_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1785,7 +1784,7 @@ struct sellrex_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("from", from_str) ("rex", rex_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1801,7 +1800,7 @@ struct cancelrexorder_subcommand { add_standard_transaction_options(cancelrexorder, "owner@active"); cancelrexorder->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1827,7 +1826,7 @@ struct rentcpu_subcommand { ("receiver", receiver_str) ("loan_payment", loan_payment_str) ("loan_fund", loan_fund_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1853,7 +1852,7 @@ struct rentnet_subcommand { ("receiver", receiver_str) ("loan_payment", loan_payment_str) ("loan_fund", loan_fund_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1876,7 +1875,7 @@ struct fundcpuloan_subcommand { ("from", from_str) ("loan_num", loan_num_str) ("payment", payment_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1899,7 +1898,7 @@ struct fundnetloan_subcommand { ("from", from_str) ("loan_num", loan_num_str) ("payment", payment_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1922,7 +1921,7 @@ struct defcpuloan_subcommand { ("from", from_str) ("loan_num", loan_num_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1945,7 +1944,7 @@ struct defnetloan_subcommand { ("from", from_str) ("loan_num", loan_num_str) ("amount", amount_str); - auto accountPermissions = get_account_permissions(tx_permission, {from_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(from_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1965,7 +1964,7 @@ struct mvtosavings_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner_str) ("rex", rex_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -1985,7 +1984,7 @@ struct mvfrsavings_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner_str) ("rex", rex_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2001,7 +2000,7 @@ struct updaterex_subcommand { add_standard_transaction_options(updaterex, "owner@active"); updaterex->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2017,7 +2016,7 @@ struct consolidate_subcommand { add_standard_transaction_options(consolidate, "owner@active"); consolidate->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2037,7 +2036,7 @@ struct rexexec_subcommand { fc::variant act_payload = fc::mutable_variant_object() ("user", user_str) ("max", max_str); - auto accountPermissions = get_account_permissions(tx_permission, {user_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(user_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2053,7 +2052,7 @@ struct closerex_subcommand { add_standard_transaction_options(closerex, "owner@active"); closerex->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object()("owner", owner_str); - auto accountPermissions = get_account_permissions(tx_permission, {owner_str, config::active_name}); + auto accountPermissions = get_account_permissions(tx_permission, {name(owner_str), config::active_name}); send_actions({create_action(accountPermissions, config::system_account_name, act_name, act_payload)}); }); } @@ -2108,7 +2107,7 @@ void get_account( const string& accountName, const string& coresym, bool json_fo sep = ", "; } for ( auto& acc : p.required_auth.accounts ) { - std::cout << sep << acc.weight << ' ' << string(acc.permission.actor) << '@' << string(acc.permission.permission); + std::cout << sep << acc.weight << ' ' << acc.permission.actor.to_string() << '@' << acc.permission.permission.to_string(); sep = ", "; } std::cout << std::endl; @@ -2304,7 +2303,7 @@ void get_account( const string& accountName, const string& coresym, bool json_fo auto& prods = obj["producers"].get_array(); std::cout << "producers:"; if ( !prods.empty() ) { - for ( int i = 0; i < prods.size(); ++i ) { + for ( size_t i = 0; i < prods.size(); ++i ) { if ( i%3 == 0 ) { std::cout << std::endl << indent; } @@ -2467,11 +2466,11 @@ int main( int argc, char** argv ) { pack_action_data->add_option("name", unpacked_action_data_name_string, localized("The name of the function that's called by this action"))->required(); pack_action_data->add_option("unpacked_action_data", unpacked_action_data_string, localized("The action data expressed as json"))->required(); pack_action_data->set_callback([&] { - fc::variant unpacked_action_data_json; + fc::variant unpacked_action_data_json = json_from_file_or_string(unpacked_action_data_string); + bytes packed_action_data_string; try { - unpacked_action_data_json = json_from_file_or_string(unpacked_action_data_string); + packed_action_data_string = variant_to_bin(name(unpacked_action_data_account_string), name(unpacked_action_data_name_string), unpacked_action_data_json); } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse unpacked action data JSON") - bytes packed_action_data_string = variant_to_bin(unpacked_action_data_account_string, unpacked_action_data_name_string, unpacked_action_data_json); std::cout << fc::to_hex(packed_action_data_string.data(), packed_action_data_string.size()) << std::endl; }); @@ -2487,7 +2486,7 @@ int main( int argc, char** argv ) { EOS_ASSERT( packed_action_data_string.size() >= 2, transaction_type_exception, "No packed_action_data found" ); vector packed_action_data_blob(packed_action_data_string.size()/2); fc::from_hex(packed_action_data_string, packed_action_data_blob.data(), packed_action_data_blob.size()); - fc::variant unpacked_action_data_json = bin_to_variant(packed_action_data_account_string, packed_action_data_name_string, packed_action_data_blob); + fc::variant unpacked_action_data_json = bin_to_variant(name(packed_action_data_account_string), name(packed_action_data_name_string), packed_action_data_blob); std::cout << fc::json::to_pretty_string(unpacked_action_data_json) << std::endl; }); @@ -2621,7 +2620,6 @@ int main( int argc, char** argv ) { getTable->add_option( "account", code, localized("The account who owns the table") )->required(); getTable->add_option( "scope", scope, localized("The scope within the contract in which the table is found") )->required(); getTable->add_option( "table", table, localized("The name of the table as specified by the contract abi") )->required(); - getTable->add_option( "-b,--binary", binary, localized("Return the value as BINARY rather than using abi to interpret as JSON") ); getTable->add_option( "-l,--limit", limit, localized("The maximum number of rows to return") ); getTable->add_option( "-k,--key", table_key, localized("Deprecated") ); getTable->add_option( "-L,--lower", lower, localized("JSON representation of lower bound value of key, defaults to first") ); @@ -2635,6 +2633,7 @@ int main( int argc, char** argv ) { getTable->add_option( "--encode-type", encode_type, localized("The encoding type of key_type (i64 , i128 , float64, float128) only support decimal encoding e.g. 'dec'" "i256 - supports both 'dec' and 'hex', ripemd160 and sha256 is 'hex' only")); + getTable->add_flag("-b,--binary", binary, localized("Return the value as BINARY rather than using abi to interpret as JSON")); getTable->add_flag("-r,--reverse", reverse, localized("Iterate in reverse order")); getTable->add_flag("--show-payer", show_payer, localized("show RAM payer")); @@ -2681,23 +2680,28 @@ int main( int argc, char** argv ) { // currency accessors // get currency balance string symbol; + bool currency_balance_print_json = false; auto get_currency = get->add_subcommand( "currency", localized("Retrieve information related to standard currencies"), true); get_currency->require_subcommand(); auto get_balance = get_currency->add_subcommand( "balance", localized("Retrieve the balance of an account for a given currency"), false); get_balance->add_option( "contract", code, localized("The contract that operates the currency") )->required(); get_balance->add_option( "account", accountName, localized("The account to query balances for") )->required(); get_balance->add_option( "symbol", symbol, localized("The symbol for the currency if the contract operates multiple currencies") ); + get_balance->add_flag("--json,-j", currency_balance_print_json, localized("Output in JSON format") ); get_balance->set_callback([&] { auto result = call(get_currency_balance_func, fc::mutable_variant_object ("account", accountName) ("code", code) ("symbol", symbol.empty() ? fc::variant() : symbol) ); - - const auto& rows = result.get_array(); - for( const auto& r : rows ) { - std::cout << r.as_string() - << std::endl; + if (!currency_balance_print_json) { + const auto& rows = result.get_array(); + for( const auto& r : rows ) { + std::cout << r.as_string() + << std::endl; + } + } else { + std::cout << fc::json::to_pretty_string(result) << std::endl; } }); @@ -2994,7 +2998,7 @@ int main( int argc, char** argv ) { } if (!duplicate) { - actions.emplace_back( create_setcode(account, code_bytes ) ); + actions.emplace_back( create_setcode(name(account), code_bytes ) ); if ( shouldSend ) { std::cerr << localized("Setting Code...") << std::endl; send_actions(std::move(actions), 10000, packed_transaction::zlib); @@ -3041,7 +3045,7 @@ int main( int argc, char** argv ) { if (!duplicate) { try { - actions.emplace_back( create_setabi(account, abi_bytes) ); + actions.emplace_back( create_setabi(name(account), abi_bytes) ); } EOS_RETHROW_EXCEPTIONS(abi_type_exception, "Fail to parse ABI JSON") if ( shouldSend ) { std::cerr << localized("Setting ABI...") << std::endl; @@ -3108,12 +3112,12 @@ int main( int argc, char** argv ) { tx_force_unique = false; } - auto transfer_amount = to_asset(con, amount); - auto transfer = create_transfer(con, sender, recipient, transfer_amount, memo); + auto transfer_amount = to_asset(name(con), amount); + auto transfer = create_transfer(con, name(sender), name(recipient), transfer_amount, memo); if (!pay_ram) { send_actions( { transfer }); } else { - auto open_ = create_open(con, recipient, transfer_amount.get_symbol(), sender); + auto open_ = create_open(con, name(recipient), transfer_amount.get_symbol(), name(sender)); send_actions( { open_, transfer } ); } }); @@ -3380,7 +3384,8 @@ int main( int argc, char** argv ) { } auto accountPermissions = get_account_permissions(tx_permission); - send_actions({chain::action{accountPermissions, contract_account, action, variant_to_bin( contract_account, action, action_args_var ) }}); + send_actions({chain::action{accountPermissions, name(contract_account), name(action), + variant_to_bin( name(contract_account), name(action), action_args_var ) }}); }); // push transaction @@ -3467,7 +3472,7 @@ int main( int argc, char** argv ) { trx_var = json_from_file_or_string(proposed_transaction); } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse transaction JSON '${data}'", ("data",proposed_transaction)) transaction proposed_trx = trx_var.as(); - bytes proposed_trx_serialized = variant_to_bin( proposed_contract, proposed_action, trx_var ); + bytes proposed_trx_serialized = variant_to_bin( name(proposed_contract), name(proposed_action), trx_var ); vector reqperm; try { @@ -3482,7 +3487,7 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if (accountPermissions.empty()) { if (!proposer.empty()) { - accountPermissions = vector{{proposer, config::active_name}}; + accountPermissions = vector{{name(proposer), config::active_name}}; } else { EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); } @@ -3509,7 +3514,7 @@ int main( int argc, char** argv ) { ("requested", requested_perm_var) ("trx", trx_var); - send_actions({chain::action{accountPermissions, "eosio.msig", "propose", variant_to_bin( N(eosio.msig), N(propose), args ) }}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(propose), variant_to_bin( N(eosio.msig), N(propose), args ) }}); }); //multisig propose transaction @@ -3534,7 +3539,7 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if (accountPermissions.empty()) { if (!proposer.empty()) { - accountPermissions = vector{{proposer, config::active_name}}; + accountPermissions = vector{{name(proposer), config::active_name}}; } else { EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); } @@ -3549,7 +3554,7 @@ int main( int argc, char** argv ) { ("requested", requested_perm_var) ("trx", trx_var); - send_actions({chain::action{accountPermissions, "eosio.msig", "propose", variant_to_bin( N(eosio.msig), N(propose), args ) }}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(propose), variant_to_bin( N(eosio.msig), N(propose), args ) }}); }); @@ -3566,8 +3571,8 @@ int main( int argc, char** argv ) { ("scope", proposer) ("table", "proposal") ("table_key", "") - ("lower_bound", name(proposal_name).value) - ("upper_bound", name(proposal_name).value + 1) + ("lower_bound", name(proposal_name).to_uint64_t()) + ("upper_bound", name(proposal_name).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3604,8 +3609,8 @@ int main( int argc, char** argv ) { ("scope", proposer) ("table", "approvals2") ("table_key", "") - ("lower_bound", name(proposal_name).value) - ("upper_bound", name(proposal_name).value + 1) + ("lower_bound", name(proposal_name).to_uint64_t()) + ("upper_bound", name(proposal_name).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3621,7 +3626,7 @@ int main( int argc, char** argv ) { for( const auto& ra : approvals_object["requested_approvals"].get_array() ) { const auto& ra_obj = ra.get_object(); auto pl = ra["level"].as(); - auto res = all_approvals.emplace( pl, std::make_pair(ra["time"].as(), approval_status::unapproved) ); + all_approvals.emplace( pl, std::make_pair(ra["time"].as(), approval_status::unapproved) ); } for( const auto& pa : approvals_object["provided_approvals"].get_array() ) { @@ -3636,8 +3641,8 @@ int main( int argc, char** argv ) { ("scope", proposer) ("table", "approvals") ("table_key", "") - ("lower_bound", name(proposal_name).value) - ("upper_bound", name(proposal_name).value + 1) + ("lower_bound", name(proposal_name).to_uint64_t()) + ("upper_bound", name(proposal_name).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3652,7 +3657,7 @@ int main( int argc, char** argv ) { for( const auto& ra : approvals_object["requested_approvals"].get_array() ) { auto pl = ra.as(); - auto res = all_approvals.emplace( pl, std::make_pair(fc::time_point{}, approval_status::unapproved) ); + all_approvals.emplace( pl, std::make_pair(fc::time_point{}, approval_status::unapproved) ); } for( const auto& pa : approvals_object["provided_approvals"].get_array() ) { @@ -3669,8 +3674,8 @@ int main( int argc, char** argv ) { ("scope", "eosio.msig") ("table", "invals") ("table_key", "") - ("lower_bound", a.first.value) - ("upper_bound", a.first.value + 1) + ("lower_bound", a.first.to_uint64_t()) + ("upper_bound", a.first.to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3699,8 +3704,8 @@ int main( int argc, char** argv ) { ("scope", proposer) ("table", "opposes") ("table_key", "") - ("lower_bound", name(proposal_name).value) - ("upper_bound", name(proposal_name).value + 1) + ("lower_bound", name(proposal_name).to_uint64_t()) + ("upper_bound", name(proposal_name).to_uint64_t() + 1) // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) @@ -3820,8 +3825,8 @@ int main( int argc, char** argv ) { args("proposal_hash", proposal_hash); } - auto accountPermissions = get_account_permissions(tx_permission, {proposer,config::active_name}); - send_actions({chain::action{accountPermissions, "eosio.msig", action, variant_to_bin( N(eosio.msig), action, args ) }}); + auto accountPermissions = get_account_permissions(tx_permission, {name(proposer), config::active_name}); + send_actions({chain::action{accountPermissions, N(eosio.msig), name(action), variant_to_bin( N(eosio.msig), name(action), args ) }}); }; // multisig approve @@ -3884,8 +3889,8 @@ int main( int argc, char** argv ) { auto args = fc::mutable_variant_object() ("account", invalidator); - auto accountPermissions = get_account_permissions(tx_permission, {invalidator,config::active_name}); - send_actions({chain::action{accountPermissions, "eosio.msig", "invalidate", variant_to_bin( N(eosio.msig), "invalidate", args ) }}); + auto accountPermissions = get_account_permissions(tx_permission, {name(invalidator), config::active_name}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(invalidate), variant_to_bin( N(eosio.msig), N(invalidate), args ) }}); }); // multisig cancel @@ -3899,7 +3904,7 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if (accountPermissions.empty()) { if (!canceler.empty()) { - accountPermissions = vector{{canceler, config::active_name}}; + accountPermissions = vector{{name(canceler), config::active_name}}; } else { EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); } @@ -3912,7 +3917,7 @@ int main( int argc, char** argv ) { ("proposal_name", proposal_name) ("canceler", canceler); - send_actions({chain::action{accountPermissions, "eosio.msig", "cancel", variant_to_bin( N(eosio.msig), N(cancel), args ) }}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(cancel), variant_to_bin( N(eosio.msig), N(cancel), args ) }}); } ); @@ -3927,7 +3932,7 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if (accountPermissions.empty()) { if (!executer.empty()) { - accountPermissions = vector{{executer, config::active_name}}; + accountPermissions = vector{{name(executer), config::active_name}}; } else { EOS_THROW(missing_auth_exception, "Authority is not provided (either by multisig parameter or -p)"); } @@ -3941,7 +3946,7 @@ int main( int argc, char** argv ) { ("proposal_name", proposal_name) ("executer", executer); - send_actions({chain::action{accountPermissions, "eosio.msig", "exec", variant_to_bin( N(eosio.msig), N(exec), args ) }}); + send_actions({chain::action{accountPermissions, N(eosio.msig), N(exec), variant_to_bin( N(eosio.msig), N(exec), args ) }}); } ); @@ -3967,14 +3972,14 @@ int main( int argc, char** argv ) { auto accountPermissions = get_account_permissions(tx_permission); if( accountPermissions.empty() ) { - accountPermissions = vector{{executer, config::active_name}, {wrap_con, config::active_name}}; + accountPermissions = vector{{name(executer), config::active_name}, {name(wrap_con), config::active_name}}; } auto args = fc::mutable_variant_object() ("executer", executer ) ("trx", trx_var); - send_actions({chain::action{accountPermissions, wrap_con, "exec", variant_to_bin( wrap_con, N(exec), args ) }}); + send_actions({chain::action{accountPermissions, name(wrap_con), N(exec), variant_to_bin( name(wrap_con), N(exec), args ) }}); }); // system subcommand @@ -4000,7 +4005,7 @@ int main( int argc, char** argv ) { auto bidname = bidname_subcommand(system); auto bidnameinfo = bidname_info_subcommand(system); - auto biyram = buyram_subcommand(system); + auto buyram = buyram_subcommand(system); auto sellram = sellram_subcommand(system); auto claimRewards = claimrewards_subcommand(system); diff --git a/scripts/eosio_build_amazon.sh b/scripts/eosio_build_amazon.sh index a6dac190959..1ccab5fbbe3 100644 --- a/scripts/eosio_build_amazon.sh +++ b/scripts/eosio_build_amazon.sh @@ -535,8 +535,20 @@ fi printf "\\tMongo C++ driver found at /usr/local/lib64/libmongocxx-static.a.\\n" fi - printf "\\n\\tChecking LLVM with WASM support.\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then + printf "\\n\\tChecking for LLVM with WASM support.\\n" + CLANG_INSTALL=false + if ! type clang > /dev/null ; then + CLANG_INSTALL=true + echo "Failed to find clang, it will install automatically." + else + CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1) + if [ "${CLANG_V}" -lt 7 ] ; then + echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically." + CLANG_INSTALL=true + fi + fi + + if [ $CLANG_INSTALL == true ]; then printf "\\tInstalling LLVM & WASM.\\n" if ! cd "${TEMP_DIR}" then @@ -556,7 +568,7 @@ fi printf "\\n\\tExiting now.\\n" exit 1; fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git + if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/llvm.git then printf "\\tUnable to clone llvm repo @ https://github.com/llvm-mirror/llvm.git.\\n" printf "\\tExiting now.\\n\\n" @@ -568,7 +580,7 @@ fi printf "\\n\\tExiting now.\\n" exit 1; fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git + if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/clang.git then printf "\\tUnable to clone clang repo @ https://github.com/llvm-mirror/clang.git.\\n" printf "\\tExiting now.\\n\\n" diff --git a/scripts/eosio_build_centos.sh b/scripts/eosio_build_centos.sh index f392fe5ef53..347fb0f1031 100644 --- a/scripts/eosio_build_centos.sh +++ b/scripts/eosio_build_centos.sh @@ -610,8 +610,20 @@ mongodconf printf "\\n" - printf "\\tChecking LLVM with WASM support installation...\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then + printf "\\n\\tChecking for LLVM with WASM support.\\n" + CLANG_INSTALL=false + if ! type clang > /dev/null ; then + CLANG_INSTALL=true + echo "Failed to find clang, it will install automatically." + else + CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1) + if [ "${CLANG_V}" -lt 7 ] ; then + echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically." + CLANG_INSTALL=true + fi + fi + + if [ $CLANG_INSTALL == true ]; then printf "\\tInstalling LLVM with WASM...\\n" if ! cd "${TEMP_DIR}"; then printf "\\t!! Unable to enter directory %s !!\\n" "${TEMP_DIR}" @@ -629,7 +641,7 @@ mongodconf exit 1; fi LLVMURL="https://github.com/llvm-mirror/llvm.git" - if ! git clone --depth 1 --single-branch --branch release_40 "${LLVMURL}"; then + if ! git clone --depth 1 --single-branch --branch release_90 "${LLVMURL}"; then printf "\\t!! Unable to clone llvm repo from ${LLVMURL} !!\\n" printf "\\tExiting now.\\n" exit 1; @@ -641,7 +653,7 @@ mongodconf exit 1; fi CLANGURL="https://github.com/llvm-mirror/clang.git" - if ! git clone --depth 1 --single-branch --branch release_40 "${CLANGURL}"; then + if ! git clone --depth 1 --single-branch --branch release_90 "${CLANGURL}"; then printf "\\t!! Unable to clone clang repo from ${CLANGURL} !!\\n" printf "\\tExiting now.\\n" exit 1; @@ -663,7 +675,7 @@ mongodconf exit 1; fi if ! "${CMAKE}" -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="${HOME}/opt/wasm" \ - -DLLVM_TARGETS_TO_BUILD="host" -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="WebAssembly" \ + -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="WebAssembly" \ -DLLVM_ENABLE_RTTI=1 -DCMAKE_BUILD_TYPE="Release" ..; then printf "\\t!! CMake has exited with the above error !!\\n" printf "\\tExiting now.\\n" diff --git a/scripts/eosio_build_fedora.sh b/scripts/eosio_build_fedora.sh index ca201600116..91dc16506dd 100644 --- a/scripts/eosio_build_fedora.sh +++ b/scripts/eosio_build_fedora.sh @@ -394,8 +394,20 @@ printf "\\tMongo C++ driver found at /usr/local/lib64/libmongocxx-static.a.\\n" fi - printf "\\n\\tChecking LLVM with WASM support installation.\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then + printf "\\n\\tChecking for LLVM with WASM support.\\n" + CLANG_INSTALL=false + if ! type clang > /dev/null ; then + CLANG_INSTALL=true + echo "Failed to find clang, it will install automatically." + else + CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1) + if [ "${CLANG_V}" -lt 7 ] ; then + echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically." + CLANG_INSTALL=true + fi + fi + + if [ $CLANG_INSTALL == true ]; then printf "\\tInstalling LLVM & WASM\\n" if ! cd "${TEMP_DIR}" then @@ -415,7 +427,7 @@ printf "\\n\\tExiting now.\\n" exit 1; fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git + if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/llvm.git then printf "\\tUnable to clone llvm repo @ https://github.com/llvm-mirror/llvm.git.\\n" printf "\\n\\tExiting now.\\n" @@ -439,7 +451,7 @@ printf "\\n\\tExiting now.\\n" exit 1; fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git + if ! git clone --depth 1 --single-branch --branch release_90 https://github.com/llvm-mirror/clang.git then printf "\\tUnable to clone clang repo @ https://github.com/llvm-mirror/clang.git.\\n" printf "\\n\\tExiting now.\\n" diff --git a/scripts/eosio_build_ubuntu.sh b/scripts/eosio_build_ubuntu.sh index c5ca90528b7..f63340753d7 100644 --- a/scripts/eosio_build_ubuntu.sh +++ b/scripts/eosio_build_ubuntu.sh @@ -421,19 +421,31 @@ mongodconf else printf "\\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\\n" fi - + printf "\\n\\tChecking for LLVM with WASM support.\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then + CLANG_INSTALL=false + if ! type clang > /dev/null ; then + CLANG_INSTALL=true + echo "Failed to find clang, it will install automatically." + else + CLANG_V=$(clang --version | grep version 2>/dev/null | sed 's/[^0-9]*//g' | head -c1) + if [ "${CLANG_V}" -lt 7 ] ; then + echo "BOSCore need clange version high than v7, current install $CLANG_V, it will install automatically." + CLANG_INSTALL=true + fi + fi + + if [ $CLANG_INSTALL == true ]; then # Build LLVM and clang with WASM support: printf "\\tInstalling LLVM with WASM\\n" if ! cd "${TEMP_DIR}" - then + then printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" printf "\\n\\tExiting now.\\n" exit 1; fi if ! mkdir "${TEMP_DIR}/llvm-compiler" 2>/dev/null - then + then printf "\\n\\tUnable to create directory %s/llvm-compiler.\\n" "${TEMP_DIR}" printf "\\n\\tExiting now.\\n" exit 1; @@ -480,7 +492,8 @@ mongodconf printf "\\n\\tExiting now.\\n" exit 1; fi - if ! cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="${HOME}/opt/wasm" -DLLVM_TARGETS_TO_BUILD= \ + # Refer : https://llvm.org/docs/CMake.html + if ! cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="${HOME}/opt/wasm" -DLLVM_ENABLE_RTTI=1 \ -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../ then printf "\\tError compiling LLVM and clang with EXPERIMENTAL WASM support.0\\n" diff --git a/tests/Cluster.py b/tests/Cluster.py index b1c3baa3a66..91afc193d16 100644 --- a/tests/Cluster.py +++ b/tests/Cluster.py @@ -152,7 +152,7 @@ def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", p2pPlugin="ne if self.staging: cmdArr.append("--nogen") - nodeosArgs="--max-transaction-time -1 --abi-serializer-max-time-ms 990000 --filter-on * --p2p-max-nodes-per-host %d" % (totalNodes) + nodeosArgs="--max-transaction-time -1 --abi-serializer-max-time-us 990000 --filter-on * --p2p-max-nodes-per-host %d" % (totalNodes) if not self.walletd: nodeosArgs += " --plugin eosio::wallet_api_plugin" if self.enableMongo: diff --git a/tests/chain_plugin_tests.cpp b/tests/chain_plugin_tests.cpp index af44e2a2950..038ac905211 100644 --- a/tests/chain_plugin_tests.cpp +++ b/tests/chain_plugin_tests.cpp @@ -47,7 +47,7 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, TESTER ) try { auto resolver = [&,this]( const account_name& name ) -> fc::optional { try { - const auto& accnt = this->control->db().get( name ); + const auto& accnt = this->control->db().get( name ); abi_def abi; if (abi_serializer::to_abi(accnt.abi, abi)) { return abi_serializer(abi, abi_serializer_max_time); diff --git a/tests/get_table_tests.cpp b/tests/get_table_tests.cpp index f806edc76ae..1a202e5113e 100644 --- a/tests/get_table_tests.cpp +++ b/tests/get_table_tests.cpp @@ -34,6 +34,34 @@ using namespace fc; BOOST_AUTO_TEST_SUITE(get_table_tests) +transaction_trace_ptr +issue_tokens( TESTER& t, account_name issuer, account_name to, const asset& amount, + std::string memo = "", account_name token_contract = N(eosio.token) ) +{ + signed_transaction trx; + + trx.actions.emplace_back( t.get_action( token_contract, N(issue), + vector{{issuer, config::active_name}}, + mutable_variant_object() + ("to", issuer.to_string()) + ("quantity", amount) + ("memo", memo) + ) ); + + trx.actions.emplace_back( t.get_action( token_contract, N(transfer), + vector{{issuer, config::active_name}}, + mutable_variant_object() + ("from", issuer.to_string()) + ("to", to.to_string()) + ("quantity", amount) + ("memo", memo) + ) ); + + t.set_transaction_headers(trx); + trx.sign( t.get_private_key( issuer, "active" ), t.control->get_chain_id() ); + return t.push_transaction( trx ); +} + BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { produce_blocks(2); @@ -56,11 +84,7 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("999.0000 SYS") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("999.0000 SYS") ); } produce_blocks(1); @@ -132,11 +156,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("10000.0000 SYS") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("10000.0000 SYS") ); } produce_blocks(1); @@ -147,11 +167,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { push_action(N(eosio.token), N(create), N(eosio.token), act ); // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("9999.0000 AAA") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("9999.0000 AAA") ); } produce_blocks(1); @@ -162,11 +178,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { push_action(N(eosio.token), N(create), N(eosio.token), act ); // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("7777.0000 CCC") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("7777.0000 CCC") ); } produce_blocks(1); @@ -177,11 +189,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { push_action(N(eosio.token), N(create), N(eosio.token), act ); // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("8888.0000 BBB") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("8888.0000 BBB") ); } produce_blocks(1); @@ -327,11 +335,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { // issue for (account_name a: accs) { - push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() - ("to", name(a) ) - ("quantity", eosio::chain::asset::from_string("10000.0000 SYS") ) - ("memo", "") - ); + issue_tokens( *this, config::system_account_name, a, eosio::chain::asset::from_string("10000.0000 SYS") ); } produce_blocks(1); @@ -341,7 +345,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { base_tester::push_action(config::system_account_name, N(init), config::system_account_name, mutable_variant_object() ("version", 0) - ("core", CORE_SYM_STR)); + ("core", "4,SYS")); // bidname auto bidname = [this]( const account_name& bidder, const account_name& newname, const asset& bid ) { diff --git a/unittests/abi_tests.cpp b/unittests/abi_tests.cpp index f41f664968e..316f7a1d2d6 100644 --- a/unittests/abi_tests.cpp +++ b/unittests/abi_tests.cpp @@ -818,10 +818,10 @@ BOOST_AUTO_TEST_CASE(linkauth_test) auto var = fc::json::from_string(test_data); auto lauth = var.as(); - BOOST_TEST("lnkauth.acct" == lauth.account); - BOOST_TEST("lnkauth.code" == lauth.code); - BOOST_TEST("lnkauth.type" == lauth.type); - BOOST_TEST("lnkauth.rqm" == lauth.requirement); + BOOST_TEST(name("lnkauth.acct") == lauth.account); + BOOST_TEST(name("lnkauth.code") == lauth.code); + BOOST_TEST(name("lnkauth.type") == lauth.type); + BOOST_TEST(name("lnkauth.rqm") == lauth.requirement); auto var2 = verify_byte_round_trip_conversion( abis, "linkauth", var ); auto linkauth2 = var2.as(); @@ -851,9 +851,9 @@ BOOST_AUTO_TEST_CASE(unlinkauth_test) auto var = fc::json::from_string(test_data); auto unlauth = var.as(); - BOOST_TEST("lnkauth.acct" == unlauth.account); - BOOST_TEST("lnkauth.code" == unlauth.code); - BOOST_TEST("lnkauth.type" == unlauth.type); + BOOST_TEST(name("lnkauth.acct") == unlauth.account); + BOOST_TEST(name("lnkauth.code") == unlauth.code); + BOOST_TEST(name("lnkauth.type") == unlauth.type); auto var2 = verify_byte_round_trip_conversion( abis, "unlinkauth", var ); auto unlinkauth2 = var2.as(); @@ -890,9 +890,9 @@ BOOST_AUTO_TEST_CASE(updateauth_test) auto var = fc::json::from_string(test_data); auto updauth = var.as(); - BOOST_TEST("updauth.acct" == updauth.account); - BOOST_TEST("updauth.prm" == updauth.permission); - BOOST_TEST("updauth.prnt" == updauth.parent); + BOOST_TEST(name("updauth.acct") == updauth.account); + BOOST_TEST(name("updauth.prm") == updauth.permission); + BOOST_TEST(name("updauth.prnt") == updauth.parent); BOOST_TEST(2147483145u == updauth.auth.threshold); BOOST_TEST_REQUIRE(2 == updauth.auth.keys.size()); @@ -901,12 +901,12 @@ BOOST_AUTO_TEST_CASE(updateauth_test) BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == (std::string)updauth.auth.keys[1].key); BOOST_TEST(57605u == updauth.auth.keys[1].weight); - BOOST_TEST_REQUIRE(2 == updauth.auth.accounts.size()); - BOOST_TEST("prm.acct1" == updauth.auth.accounts[0].permission.actor); - BOOST_TEST("prm.prm1" == updauth.auth.accounts[0].permission.permission); + BOOST_TEST_REQUIRE(2u == updauth.auth.accounts.size()); + BOOST_TEST(name("prm.acct1") == updauth.auth.accounts[0].permission.actor); + BOOST_TEST(name("prm.prm1") == updauth.auth.accounts[0].permission.permission); BOOST_TEST(53005u == updauth.auth.accounts[0].weight); - BOOST_TEST("prm.acct2" == updauth.auth.accounts[1].permission.actor); - BOOST_TEST("prm.prm2" == updauth.auth.accounts[1].permission.permission); + BOOST_TEST(name("prm.acct2") == updauth.auth.accounts[1].permission.actor); + BOOST_TEST(name("prm.prm2") == updauth.auth.accounts[1].permission.permission); BOOST_TEST(53405u == updauth.auth.accounts[1].weight); auto var2 = verify_byte_round_trip_conversion( abis, "updateauth", var ); @@ -951,8 +951,8 @@ BOOST_AUTO_TEST_CASE(deleteauth_test) auto var = fc::json::from_string(test_data); auto delauth = var.as(); - BOOST_TEST("delauth.acct" == delauth.account); - BOOST_TEST("delauth.prm" == delauth.permission); + BOOST_TEST(name("delauth.acct") == delauth.account); + BOOST_TEST(name("delauth.prm") == delauth.permission); auto var2 = verify_byte_round_trip_conversion( abis, "deleteauth", var ); auto deleteauth2 = var2.as(); @@ -994,39 +994,39 @@ BOOST_AUTO_TEST_CASE(newaccount_test) auto var = fc::json::from_string(test_data); auto newacct = var.as(); - BOOST_TEST("newacct.crtr" == newacct.creator); - BOOST_TEST("newacct.name" == newacct.name); + BOOST_TEST(name("newacct.crtr") == newacct.creator); + BOOST_TEST(name("newacct.name") == newacct.name); BOOST_TEST(2147483145u == newacct.owner.threshold); - BOOST_TEST_REQUIRE(2 == newacct.owner.keys.size()); + BOOST_TEST_REQUIRE(2u == newacct.owner.keys.size()); BOOST_TEST("EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im" == (std::string)newacct.owner.keys[0].key); BOOST_TEST(57005u == newacct.owner.keys[0].weight); BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == (std::string)newacct.owner.keys[1].key); BOOST_TEST(57605u == newacct.owner.keys[1].weight); - BOOST_TEST_REQUIRE(2 == newacct.owner.accounts.size()); - BOOST_TEST("prm.acct1" == newacct.owner.accounts[0].permission.actor); - BOOST_TEST("prm.prm1" == newacct.owner.accounts[0].permission.permission); + BOOST_TEST_REQUIRE(2u == newacct.owner.accounts.size()); + BOOST_TEST(name("prm.acct1") == newacct.owner.accounts[0].permission.actor); + BOOST_TEST(name("prm.prm1") == newacct.owner.accounts[0].permission.permission); BOOST_TEST(53005u == newacct.owner.accounts[0].weight); - BOOST_TEST("prm.acct2" == newacct.owner.accounts[1].permission.actor); - BOOST_TEST("prm.prm2" == newacct.owner.accounts[1].permission.permission); + BOOST_TEST(name("prm.acct2") == newacct.owner.accounts[1].permission.actor); + BOOST_TEST(name("prm.prm2") == newacct.owner.accounts[1].permission.permission); BOOST_TEST(53405u == newacct.owner.accounts[1].weight); BOOST_TEST(2146483145u == newacct.active.threshold); - BOOST_TEST_REQUIRE(2 == newacct.active.keys.size()); + BOOST_TEST_REQUIRE(2u == newacct.active.keys.size()); BOOST_TEST("EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im" == (std::string)newacct.active.keys[0].key); BOOST_TEST(57005u == newacct.active.keys[0].weight); BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == (std::string)newacct.active.keys[1].key); BOOST_TEST(57605u == newacct.active.keys[1].weight); - BOOST_TEST_REQUIRE(2 == newacct.active.accounts.size()); - BOOST_TEST("prm.acct1" == newacct.active.accounts[0].permission.actor); - BOOST_TEST("prm.prm1" == newacct.active.accounts[0].permission.permission); + BOOST_TEST_REQUIRE(2u == newacct.active.accounts.size()); + BOOST_TEST(name("prm.acct1") == newacct.active.accounts[0].permission.actor); + BOOST_TEST(name("prm.prm1") == newacct.active.accounts[0].permission.permission); BOOST_TEST(53005u == newacct.active.accounts[0].weight); - BOOST_TEST("prm.acct2" == newacct.active.accounts[1].permission.actor); - BOOST_TEST("prm.prm2" == newacct.active.accounts[1].permission.permission); + BOOST_TEST(name("prm.acct2") == newacct.active.accounts[1].permission.actor); + BOOST_TEST(name("prm.prm2") == newacct.active.accounts[1].permission.permission); BOOST_TEST(53405u == newacct.active.accounts[1].weight); @@ -1090,7 +1090,7 @@ BOOST_AUTO_TEST_CASE(setcode_test) auto var = fc::json::from_string(test_data); auto set_code = var.as(); - BOOST_TEST("setcode.acc" == set_code.account); + BOOST_TEST(name("setcode.acc") == set_code.account); BOOST_TEST(0 == set_code.vmtype); BOOST_TEST(0 == set_code.vmversion); BOOST_TEST("0061736d0100000001390a60037e7e7f017f60047e7e7f7f017f60017e0060057e7e7e7f7f" == fc::to_hex(set_code.code.data(), set_code.code.size())); @@ -1303,22 +1303,22 @@ BOOST_AUTO_TEST_CASE(setabi_test) auto var = fc::json::from_string(abi_string); auto abi = var.as(); - BOOST_TEST_REQUIRE(1 == abi.types.size()); + BOOST_TEST_REQUIRE(1u == abi.types.size()); BOOST_TEST("account_name" == abi.types[0].new_type_name); BOOST_TEST("name" == abi.types[0].type); - BOOST_TEST_REQUIRE(3 == abi.structs.size()); + BOOST_TEST_REQUIRE(3u == abi.structs.size()); BOOST_TEST("transfer_base" == abi.structs[0].name); BOOST_TEST("" == abi.structs[0].base); - BOOST_TEST_REQUIRE(1 == abi.structs[0].fields.size()); + BOOST_TEST_REQUIRE(1u == abi.structs[0].fields.size()); BOOST_TEST("memo" == abi.structs[0].fields[0].name); BOOST_TEST("string" == abi.structs[0].fields[0].type); BOOST_TEST("transfer" == abi.structs[1].name); BOOST_TEST("transfer_base" == abi.structs[1].base); - BOOST_TEST_REQUIRE(3 == abi.structs[1].fields.size()); + BOOST_TEST_REQUIRE(3u == abi.structs[1].fields.size()); BOOST_TEST("from" == abi.structs[1].fields[0].name); BOOST_TEST("account_name" == abi.structs[1].fields[0].type); BOOST_TEST("to" == abi.structs[1].fields[1].name); @@ -1328,23 +1328,23 @@ BOOST_AUTO_TEST_CASE(setabi_test) BOOST_TEST("account" == abi.structs[2].name); BOOST_TEST("" == abi.structs[2].base); - BOOST_TEST_REQUIRE(2 == abi.structs[2].fields.size()); + BOOST_TEST_REQUIRE(2u == abi.structs[2].fields.size()); BOOST_TEST("account" == abi.structs[2].fields[0].name); BOOST_TEST("name" == abi.structs[2].fields[0].type); BOOST_TEST("balance" == abi.structs[2].fields[1].name); BOOST_TEST("uint64" == abi.structs[2].fields[1].type); - BOOST_TEST_REQUIRE(1 == abi.actions.size()); - BOOST_TEST("transfer" == abi.actions[0].name); + BOOST_TEST_REQUIRE(1u == abi.actions.size()); + BOOST_TEST(name("transfer") == abi.actions[0].name); BOOST_TEST("transfer" == abi.actions[0].type); - BOOST_TEST_REQUIRE(1 == abi.tables.size()); - BOOST_TEST("account" == abi.tables[0].name); + BOOST_TEST_REQUIRE(1u == abi.tables.size()); + BOOST_TEST(name("account") == abi.tables[0].name); BOOST_TEST("account" == abi.tables[0].type); BOOST_TEST("i64" == abi.tables[0].index_type); - BOOST_TEST_REQUIRE(1 == abi.tables[0].key_names.size()); + BOOST_TEST_REQUIRE(1u == abi.tables[0].key_names.size()); BOOST_TEST("account" == abi.tables[0].key_names[0]); - BOOST_TEST_REQUIRE(1 == abi.tables[0].key_types.size()); + BOOST_TEST_REQUIRE(1u == abi.tables[0].key_types.size()); BOOST_TEST("name" == abi.tables[0].key_types[0]); auto var2 = verify_byte_round_trip_conversion( abis, "abi_def", var ); @@ -1446,20 +1446,20 @@ struct action2 { template void verify_action_equal(const chain::action& exp, const chain::action& act) { - BOOST_REQUIRE_EQUAL((std::string)exp.account, (std::string)act.account); - BOOST_REQUIRE_EQUAL((std::string)exp.name, (std::string)act.name); + BOOST_REQUIRE_EQUAL(exp.account.to_string(), act.account.to_string()); + BOOST_REQUIRE_EQUAL(exp.name.to_string(), act.name.to_string()); BOOST_REQUIRE_EQUAL(exp.authorization.size(), act.authorization.size()); for(unsigned int i = 0; i < exp.authorization.size(); ++i) { - BOOST_REQUIRE_EQUAL((std::string)exp.authorization[i].actor, (std::string)act.authorization[i].actor); - BOOST_REQUIRE_EQUAL((std::string)exp.authorization[i].permission, (std::string)act.authorization[i].permission); + BOOST_REQUIRE_EQUAL(exp.authorization[i].actor.to_string(), act.authorization[i].actor.to_string()); + BOOST_REQUIRE_EQUAL(exp.authorization[i].permission.to_string(), act.authorization[i].permission.to_string()); } BOOST_REQUIRE_EQUAL(exp.data.size(), act.data.size()); BOOST_REQUIRE(!memcmp(exp.data.data(), act.data.data(), exp.data.size())); } private_key_type get_private_key( name keyname, string role ) { - return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); + return private_key_type::regenerate(fc::sha256::hash(keyname.to_string()+role)); } public_key_type get_public_key( name keyname, string role ) { diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index bd0336b69f3..c42457a8c26 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -93,13 +93,13 @@ struct dtt_action { return WASM_TEST_ACTION("test_transaction", "send_deferred_tx_with_dtt_action"); } static uint64_t get_account() { - return N(testapi); + return N(testapi).to_uint64_t(); } - uint64_t payer = N(testapi); - uint64_t deferred_account = N(testapi); + uint64_t payer = N(testapi).to_uint64_t(); + uint64_t deferred_account = N(testapi).to_uint64_t(); uint64_t deferred_action = WASM_TEST_ACTION("test_transaction", "deferred_print"); - uint64_t permission_name = N(active); + uint64_t permission_name = N(active).to_uint64_t(); uint32_t delay_sec = 2; }; @@ -246,6 +246,7 @@ transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, #define CALL_TEST_FUNCTION(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_api_action{}, DATA) #define CALL_TEST_FUNCTION_SYSTEM(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_chain_action{}, DATA, {config::system_account_name} ) #define CALL_TEST_FUNCTION_SCOPE(_TESTER, CLS, MTH, DATA, ACCOUNT) CallFunction(_TESTER, test_api_action{}, DATA, ACCOUNT) +#define CALL_TEST_FUNCTION_NO_THROW(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_api_action{}, DATA, {N(testapi)}, true) #define CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION(_TESTER, CLS, MTH, DATA, EXC, EXC_MESSAGE) \ BOOST_CHECK_EXCEPTION( \ CALL_TEST_FUNCTION( _TESTER, CLS, MTH, DATA), \ @@ -303,107 +304,107 @@ struct MySink : public bio::sink uint32_t last_fnc_err = 0; BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { - produce_blocks(2); - create_account( N(test) ); - set_code( N(test), contracts::payloadless_wasm() ); - produce_blocks(1); + produce_blocks(2); + create_account( N(test) ); + set_code( N(test), contracts::payloadless_wasm() ); + produce_blocks(1); + + auto call_doit_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { + signed_transaction trx; + trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(doit), bytes{} ); + this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); + trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); + auto res = this->push_transaction(trx); + checker( res ); + }; - auto call_doit_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { - signed_transaction trx; - trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(doit), bytes{} ); - this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); - trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); - auto res = this->push_transaction(trx); - checker( res ); - }; - - auto call_provereset_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { - signed_transaction trx; - trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(provereset), bytes{} ); - this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); - trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); - auto res = this->push_transaction(trx); - checker( res ); - }; - - auto result = push_reqauth( config::system_account_name, "active" ); - BOOST_REQUIRE_EQUAL( result->receipt->status, transaction_receipt::executed ); - BOOST_REQUIRE( result->action_traces[0].receipt.auth_sequence.find( config::system_account_name ) - != result->action_traces[0].receipt.auth_sequence.end() ); - auto base_global_sequence_num = result->action_traces[0].receipt.global_sequence; - auto base_system_recv_seq_num = result->action_traces[0].receipt.recv_sequence; - auto base_system_auth_seq_num = result->action_traces[0].receipt.auth_sequence[config::system_account_name]; - auto base_system_code_seq_num = result->action_traces[0].receipt.code_sequence.value; - auto base_system_abi_seq_num = result->action_traces[0].receipt.abi_sequence.value; - - uint64_t base_test_recv_seq_num = 0; - uint64_t base_test_auth_seq_num = 0; - call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { - BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 0 ); - base_test_recv_seq_num = res->action_traces[0].receipt.recv_sequence; - BOOST_CHECK( base_test_recv_seq_num > 0 ); - base_test_recv_seq_num--; - const auto& m = res->action_traces[0].receipt.auth_sequence; - BOOST_CHECK_EQUAL( m.size(), 1 ); - BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); - base_test_auth_seq_num = m.begin()->second; - BOOST_CHECK( base_test_auth_seq_num > 0 ); - --base_test_auth_seq_num; - } ); - - set_code( N(test), contracts::asserter_wasm() ); - set_code( config::system_account_name, contracts::payloadless_wasm() ); - - call_provereset_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { - BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_test_recv_seq_num + 2 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 2 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 0 ); - const auto& m = res->action_traces[0].receipt.auth_sequence; - BOOST_CHECK_EQUAL( m.size(), 1 ); - BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); - BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 3 ); - } ); - - produce_blocks(1); // Added to avoid the last doit transaction from being considered a duplicate. - // Adding a block also retires an onblock action which increments both the global sequence number - // and the recv and auth sequences numbers for the system account. - - call_doit_and_check( config::system_account_name, N(test), [&]( const transaction_trace_ptr& res ) { - BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 6 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_system_recv_seq_num + 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, base_system_code_seq_num + 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, base_system_abi_seq_num ); - const auto& m = res->action_traces[0].receipt.auth_sequence; - BOOST_CHECK_EQUAL( m.size(), 1 ); - BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); - BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 4 ); - } ); - - set_code( config::system_account_name, contracts::eosio_bios_wasm() ); - - set_code( N(test), contracts::eosio_bios_wasm() ); - set_abi( N(test), contracts::eosio_bios_abi().data() ); + auto call_provereset_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { + signed_transaction trx; + trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(provereset), bytes{} ); + this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); + trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); + auto res = this->push_transaction(trx); + checker( res ); + }; + + auto result = push_reqauth( config::system_account_name, "active" ); + BOOST_REQUIRE_EQUAL( result->receipt->status, transaction_receipt::executed ); + BOOST_REQUIRE( result->action_traces[0].receipt->auth_sequence.find( config::system_account_name ) + != result->action_traces[0].receipt->auth_sequence.end() ); + auto base_global_sequence_num = result->action_traces[0].receipt->global_sequence; + auto base_system_recv_seq_num = result->action_traces[0].receipt->recv_sequence; + auto base_system_auth_seq_num = result->action_traces[0].receipt->auth_sequence[config::system_account_name]; + auto base_system_code_seq_num = result->action_traces[0].receipt->code_sequence.value; + auto base_system_abi_seq_num = result->action_traces[0].receipt->abi_sequence.value; + + uint64_t base_test_recv_seq_num = 0; + uint64_t base_test_auth_seq_num = 0; + call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 0 ); + base_test_recv_seq_num = res->action_traces[0].receipt->recv_sequence; + BOOST_CHECK( base_test_recv_seq_num > 0 ); + base_test_recv_seq_num--; + const auto& m = res->action_traces[0].receipt->auth_sequence; + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); + base_test_auth_seq_num = m.begin()->second; + BOOST_CHECK( base_test_auth_seq_num > 0 ); + --base_test_auth_seq_num; + } ); + + set_code( N(test), contracts::asserter_wasm() ); + set_code( config::system_account_name, contracts::payloadless_wasm() ); + + call_provereset_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_test_recv_seq_num + 2 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 2 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 0 ); + const auto& m = res->action_traces[0].receipt->auth_sequence; + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); + BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 3 ); + } ); + + produce_blocks(1); // Added to avoid the last doit transaction from being considered a duplicate. + // Adding a block also retires an onblock action which increments both the global sequence number + // and the recv and auth sequences numbers for the system account. + + call_doit_and_check( config::system_account_name, N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 6 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_system_recv_seq_num + 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, base_system_code_seq_num + 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, base_system_abi_seq_num ); + const auto& m = res->action_traces[0].receipt->auth_sequence; + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); + BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 4 ); + } ); + + set_code( config::system_account_name, contracts::eosio_bios_wasm() ); + + set_code( N(test), contracts::eosio_bios_wasm() ); + set_abi( N(test), contracts::eosio_bios_abi().data() ); set_code( N(test), contracts::payloadless_wasm() ); - call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { - BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 11 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_test_recv_seq_num + 3 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 1 ); - const auto& m = res->action_traces[0].receipt.auth_sequence; - BOOST_CHECK_EQUAL( m.size(), 1 ); - BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); - BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 8 ); - } ); + call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 11 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_test_recv_seq_num + 3 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 1 ); + const auto& m = res->action_traces[0].receipt->auth_sequence; + BOOST_CHECK_EQUAL( m.size(), 1 ); + BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); + BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 8 ); + } ); - } FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() } /************************************************************************************* * action_tests test case @@ -592,13 +593,13 @@ BOOST_FIXTURE_TEST_CASE(ram_billing_in_notify_tests, TESTER) { try { set_code( N(testapi2), contracts::test_api_wasm() ); produce_blocks(1); - BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2) << 64) | N(testapi) ) ), + BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2).to_uint64_t() << 64) | N(testapi).to_uint64_t() ) ), subjective_block_production_exception, fc_exception_message_is("Cannot charge RAM to other accounts during notify.") ); - CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2) << 64) | 0 ) ); + CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2).to_uint64_t() << 64) | 0 ) ); - CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2) << 64) | N(testapi2) ) ); + CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2).to_uint64_t() << 64) | N(testapi2).to_uint64_t() ) ); BOOST_REQUIRE_EQUAL( validate(), true ); } FC_LOG_AND_RETHROW() } @@ -629,9 +630,6 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { trx.context_free_data.emplace_back(fc::raw::pack(200)); set_transaction_headers(trx); - // signing a transaction with only context_free_actions should not be allowed - // auto sigs = trx.sign(get_private_key(N(testapi), "active"), control->get_chain_id()); - BOOST_CHECK_EXCEPTION(push_transaction(trx), tx_no_auths, [](const fc::exception& e) { return expect_assert_message(e, "transaction must have at least one authorization"); @@ -700,12 +698,12 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { // test send context free action auto ttrace = CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action", {} ); - BOOST_CHECK_EQUAL(ttrace->action_traces.size(), 1); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces.size(), 1); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].receipt.receiver, account_name("dummy")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.account, account_name("dummy")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.name, account_name("event1")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.authorization.size(), 0); + BOOST_REQUIRE_EQUAL(ttrace->action_traces.size(), 2); + BOOST_CHECK_EQUAL((int)(ttrace->action_traces[1].creator_action_ordinal), 1); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].receiver, account_name("dummy")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.account, account_name("dummy")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.name, account_name("event1")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.authorization.size(), 0); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action_fail", {} ), eosio_assert_message_exception, @@ -729,7 +727,7 @@ BOOST_FIXTURE_TEST_CASE(cfa_tx_signature, TESTER) try { tx2.context_free_actions.push_back(cfa); set_transaction_headers(tx2); - const private_key_type& priv_key = get_private_key("dummy", "active"); + const private_key_type& priv_key = get_private_key(name("dummy"), "active"); BOOST_TEST((std::string)tx1.sign(priv_key, control->get_chain_id()) != (std::string)tx2.sign(priv_key, control->get_chain_id())); BOOST_REQUIRE_EQUAL( validate(), true ); @@ -981,42 +979,42 @@ BOOST_FIXTURE_TEST_CASE(checktime_hashing_fail, TESTER) { try { //hit deadline exception, but cache the contract BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); #warning TODO validate that the contract was successfully cached //the contract should be cached, now we should get deadline_exception because of calls to checktime() from hashing function BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( *this, test_api_action{}, - 5000, 10 ), + 5000, 3 ), deadline_exception, is_deadline_exception ); BOOST_REQUIRE_EQUAL( validate(), true ); @@ -1039,7 +1037,7 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { action act({}, tm); trx.actions.push_back(act); - set_transaction_headers(trx); + set_transaction_headers(trx); BOOST_CHECK_EXCEPTION(push_transaction(trx), transaction_exception, [](const fc::exception& e) { return expect_assert_message(e, "transaction must have at least one authorization"); @@ -1078,8 +1076,10 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { { produce_blocks(10); transaction_trace_ptr trace; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->receipt && t->receipt->status != transaction_receipt::executed) { trace = t; } } ); - + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->receipt && t->receipt->status != transaction_receipt::executed) { trace = t; } + } ); // test error handling on deferred transaction failure CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction_trigger_error_handler", {}); @@ -1122,7 +1122,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { //schedule { transaction_trace_ptr trace; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } ); + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t->scheduled) { trace = t; } + } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {} ); BOOST_CHECK(!trace); produce_block( fc::seconds(2) ); @@ -1142,7 +1145,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { { transaction_trace_ptr trace; uint32_t count = 0; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->scheduled) { trace = t; ++count; } } ); + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->scheduled) { trace = t; ++count; } + } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {}); BOOST_CHECK_THROW(CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {}), deferred_tx_duplicate); produce_blocks( 3 ); @@ -1167,7 +1173,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { { transaction_trace_ptr trace; uint32_t count = 0; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->scheduled) { trace = t; ++count; } } ); + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->scheduled) { trace = t; ++count; } + } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction_replace", {}); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction_replace", {}); produce_blocks( 3 ); @@ -1190,7 +1199,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { //schedule and cancel { transaction_trace_ptr trace; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->scheduled) { trace = t; } } ); + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); + if (t && t->scheduled) { trace = t; } + } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {}); CALL_TEST_FUNCTION(*this, "test_transaction", "cancel_deferred_transaction_success", {}); produce_block( fc::seconds(2) ); @@ -1210,7 +1222,8 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { //repeated deferred transactions { vector traces; - auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { + auto c = control->applied_transaction.connect([&](std::tuple x) { + auto& t = std::get<0>(x); if (t && t->scheduled) { traces.push_back( t ); } @@ -1231,27 +1244,27 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { // Trigger a tx which in turn sends a deferred tx with payer != receiver // Payer is alice in this case, this tx should fail since we don't have the authorization of alice dtt_action dtt_act1; - dtt_act1.payer = N(alice); + dtt_act1.payer = N(alice).to_uint64_t(); BOOST_CHECK_THROW(CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_tx_with_dtt_action", fc::raw::pack(dtt_act1)), missing_auth_exception); // Send a tx which in turn sends a deferred tx with the deferred tx's receiver != this tx receiver // This will include the authorization of the receiver, and impose any related delay associated with the authority // We set the authorization delay to be 10 sec here, and since the deferred tx delay is set to be 5 sec, so this tx should fail dtt_action dtt_act2; - dtt_act2.deferred_account = N(testapi2); - dtt_act2.permission_name = N(additional); + dtt_act2.deferred_account = N(testapi2).to_uint64_t(); + dtt_act2.permission_name = N(additional).to_uint64_t(); dtt_act2.delay_sec = 5; - auto auth = authority(get_public_key("testapi", name(dtt_act2.permission_name).to_string()), 10); + auto auth = authority(get_public_key(name("testapi"), name(dtt_act2.permission_name).to_string()), 10); auth.accounts.push_back( permission_level_weight{{N(testapi), config::eosio_code_name}, 1} ); - push_action(config::system_account_name, updateauth::get_name(), "testapi", fc::mutable_variant_object() + push_action(config::system_account_name, updateauth::get_name(), name("testapi"), fc::mutable_variant_object() ("account", "testapi") ("permission", name(dtt_act2.permission_name)) ("parent", "active") ("auth", auth) ); - push_action(config::system_account_name, linkauth::get_name(), "testapi", fc::mutable_variant_object() + push_action(config::system_account_name, linkauth::get_name(), name("testapi"), fc::mutable_variant_object() ("account", "testapi") ("code", name(dtt_act2.deferred_account)) ("type", name(dtt_act2.deferred_action)) @@ -1263,11 +1276,12 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_tx_with_dtt_action", fc::raw::pack(dtt_act2)); // If the deferred tx receiver == this tx receiver, the authorization checking would originally be bypassed. - // But not anymore. Now it should subjectively fail because testapi@additional permission is not unilaterally satisfied by testapi@eosio.code. + // But not anymore. With the RESTRICT_ACTION_TO_SELF protocol feature activated, it should now objectively + // fail because testapi@additional permission is not unilaterally satisfied by testapi@eosio.code. dtt_action dtt_act3; - dtt_act3.deferred_account = N(testapi); - dtt_act3.permission_name = N(additional); - push_action(config::system_account_name, linkauth::get_name(), "testapi", fc::mutable_variant_object() + dtt_act3.deferred_account = N(testapi).to_uint64_t(); + dtt_act3.permission_name = N(additional).to_uint64_t(); + push_action(config::system_account_name, linkauth::get_name(), name("testapi"), fc::mutable_variant_object() ("account", "testapi") ("code", name(dtt_act3.deferred_account)) ("type", name(dtt_act3.deferred_action)) diff --git a/unittests/auth_tests.cpp b/unittests/auth_tests.cpp index e54964b87b4..ea0ed49814d 100644 --- a/unittests/auth_tests.cpp +++ b/unittests/auth_tests.cpp @@ -96,272 +96,273 @@ BOOST_FIXTURE_TEST_CASE( delegate_auth, TESTER ) { try { BOOST_AUTO_TEST_CASE(update_auths) { try { TESTER chain; - chain.create_account("alice"); - chain.create_account("bob"); + chain.create_account(name("alice")); + chain.create_account(name("bob")); // Deleting active or owner should fail - BOOST_CHECK_THROW(chain.delete_authority("alice", "active"), action_validate_exception); - BOOST_CHECK_THROW(chain.delete_authority("alice", "owner"), action_validate_exception); + BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("active")), action_validate_exception); + BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("owner")), action_validate_exception); // Change owner permission - const auto new_owner_priv_key = chain.get_private_key("alice", "new_owner"); + const auto new_owner_priv_key = chain.get_private_key(name("alice"), "new_owner"); const auto new_owner_pub_key = new_owner_priv_key.get_public_key(); - chain.set_authority("alice", "owner", authority(new_owner_pub_key), ""); + chain.set_authority(name("alice"), name("owner"), authority(new_owner_pub_key), {}); chain.produce_blocks(); // Ensure the permission is updated permission_object::id_type owner_id; { - auto obj = chain.find(boost::make_tuple("alice", "owner")); + auto obj = chain.find(boost::make_tuple(name("alice"), name("owner"))); BOOST_TEST(obj != nullptr); - BOOST_TEST(obj->owner == "alice"); - BOOST_TEST(obj->name == "owner"); + BOOST_TEST(obj->owner == name("alice")); + BOOST_TEST(obj->name == name("owner")); BOOST_TEST(obj->parent == 0); owner_id = obj->id; auto auth = obj->auth.to_authority(); - BOOST_TEST(auth.threshold == 1); - BOOST_TEST(auth.keys.size() == 1); - BOOST_TEST(auth.accounts.size() == 0); + BOOST_TEST(auth.threshold == 1u); + BOOST_TEST(auth.keys.size() == 1u); + BOOST_TEST(auth.accounts.size() == 0u); BOOST_TEST(auth.keys[0].key == new_owner_pub_key); BOOST_TEST(auth.keys[0].weight == 1); } // Change active permission, remember that the owner key has been changed - const auto new_active_priv_key = chain.get_private_key("alice", "new_active"); + const auto new_active_priv_key = chain.get_private_key(name("alice"), "new_active"); const auto new_active_pub_key = new_active_priv_key.get_public_key(); - chain.set_authority("alice", "active", authority(new_active_pub_key), "owner", - { permission_level{"alice", "active"} }, { chain.get_private_key("alice", "active") }); + chain.set_authority(name("alice"), name("active"), authority(new_active_pub_key), name("owner"), + { permission_level{name("alice"), name("active")} }, { chain.get_private_key(name("alice"), "active") }); chain.produce_blocks(); { - auto obj = chain.find(boost::make_tuple("alice", "active")); + auto obj = chain.find(boost::make_tuple(name("alice"), name("active"))); BOOST_TEST(obj != nullptr); - BOOST_TEST(obj->owner == "alice"); - BOOST_TEST(obj->name == "active"); + BOOST_TEST(obj->owner == name("alice")); + BOOST_TEST(obj->name == name("active")); BOOST_TEST(obj->parent == owner_id); auto auth = obj->auth.to_authority(); - BOOST_TEST(auth.threshold == 1); - BOOST_TEST(auth.keys.size() == 1); - BOOST_TEST(auth.accounts.size() == 0); + BOOST_TEST(auth.threshold == 1u); + BOOST_TEST(auth.keys.size() == 1u); + BOOST_TEST(auth.accounts.size() == 0u); BOOST_TEST(auth.keys[0].key == new_active_pub_key); - BOOST_TEST(auth.keys[0].weight == 1); + BOOST_TEST(auth.keys[0].weight == 1u); } - auto spending_priv_key = chain.get_private_key("alice", "spending"); + auto spending_priv_key = chain.get_private_key(name("alice"), "spending"); auto spending_pub_key = spending_priv_key.get_public_key(); - auto trading_priv_key = chain.get_private_key("alice", "trading"); + auto trading_priv_key = chain.get_private_key(name("alice"), "trading"); auto trading_pub_key = trading_priv_key.get_public_key(); // Bob attempts to create new spending auth for Alice - BOOST_CHECK_THROW( chain.set_authority( "alice", "spending", authority(spending_pub_key), "active", - { permission_level{"bob", "active"} }, { chain.get_private_key("bob", "active") } ), + BOOST_CHECK_THROW( chain.set_authority( name("alice"), name("spending"), authority(spending_pub_key), name("active"), + { permission_level{name("bob"), name("active")} }, + { chain.get_private_key(name("bob"), "active") } ), irrelevant_auth_exception ); // Create new spending auth - chain.set_authority("alice", "spending", authority(spending_pub_key), "active", - { permission_level{"alice", "active"} }, { new_active_priv_key }); + chain.set_authority(name("alice"), name("spending"), authority(spending_pub_key), name("active"), + { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); chain.produce_blocks(); { - auto obj = chain.find(boost::make_tuple("alice", "spending")); + auto obj = chain.find(boost::make_tuple(name("alice"), name("spending"))); BOOST_TEST(obj != nullptr); - BOOST_TEST(obj->owner == "alice"); - BOOST_TEST(obj->name == "spending"); - BOOST_TEST(chain.get(obj->parent).owner == "alice"); - BOOST_TEST(chain.get(obj->parent).name == "active"); + BOOST_TEST(obj->owner == name("alice")); + BOOST_TEST(obj->name == name("spending")); + BOOST_TEST(chain.get(obj->parent).owner == name("alice")); + BOOST_TEST(chain.get(obj->parent).name == name("active")); } // Update spending auth parent to be its own, should fail - BOOST_CHECK_THROW(chain.set_authority("alice", "spending", spending_pub_key, "spending", - { permission_level{"alice", "spending"} }, { spending_priv_key }), action_validate_exception); + BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("spending"), + { permission_level{name("alice"), name("spending")} }, { spending_priv_key }), action_validate_exception); // Update spending auth parent to be owner, should fail - BOOST_CHECK_THROW(chain.set_authority("alice", "spending", spending_pub_key, "owner", - { permission_level{"alice", "spending"} }, { spending_priv_key }), action_validate_exception); + BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("owner"), + { permission_level{name("alice"), name("spending")} }, { spending_priv_key }), action_validate_exception); // Remove spending auth - chain.delete_authority("alice", "spending", { permission_level{"alice", "active"} }, { new_active_priv_key }); + chain.delete_authority(name("alice"), name("spending"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); { - auto obj = chain.find(boost::make_tuple("alice", "spending")); + auto obj = chain.find(boost::make_tuple(name("alice"), name("spending"))); BOOST_TEST(obj == nullptr); } chain.produce_blocks(); // Create new trading auth - chain.set_authority("alice", "trading", trading_pub_key, "active", - { permission_level{"alice", "active"} }, { new_active_priv_key }); + chain.set_authority(name("alice"), name("trading"), trading_pub_key, name("active"), + { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); // Recreate spending auth again, however this time, it's under trading instead of owner - chain.set_authority("alice", "spending", spending_pub_key, "trading", - { permission_level{"alice", "trading"} }, { trading_priv_key }); + chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("trading"), + { permission_level{name("alice"), name("trading")} }, { trading_priv_key }); chain.produce_blocks(); // Verify correctness of trading and spending { - const auto* trading = chain.find(boost::make_tuple("alice", "trading")); - const auto* spending = chain.find(boost::make_tuple("alice", "spending")); + const auto* trading = chain.find(boost::make_tuple(name("alice"), name("trading"))); + const auto* spending = chain.find(boost::make_tuple(name("alice"), name("spending"))); BOOST_TEST(trading != nullptr); BOOST_TEST(spending != nullptr); - BOOST_TEST(trading->owner == "alice"); - BOOST_TEST(spending->owner == "alice"); - BOOST_TEST(trading->name == "trading"); - BOOST_TEST(spending->name == "spending"); + BOOST_TEST(trading->owner == name("alice")); + BOOST_TEST(spending->owner == name("alice")); + BOOST_TEST(trading->name == name("trading")); + BOOST_TEST(spending->name == name("spending")); BOOST_TEST(spending->parent == trading->id); - BOOST_TEST(chain.get(trading->parent).owner == "alice"); - BOOST_TEST(chain.get(trading->parent).name == "active"); + BOOST_TEST(chain.get(trading->parent).owner == name("alice")); + BOOST_TEST(chain.get(trading->parent).name == name("active")); } // Delete trading, should fail since it has children (spending) - BOOST_CHECK_THROW(chain.delete_authority("alice", "trading", - { permission_level{"alice", "active"} }, { new_active_priv_key }), action_validate_exception); + BOOST_CHECK_THROW(chain.delete_authority(name("alice"), name("trading"), + { permission_level{name("alice"), name("active")} }, { new_active_priv_key }), action_validate_exception); // Update trading parent to be spending, should fail since changing parent authority is not supported - BOOST_CHECK_THROW(chain.set_authority("alice", "trading", trading_pub_key, "spending", - { permission_level{"alice", "trading"} }, { trading_priv_key }), action_validate_exception); + BOOST_CHECK_THROW(chain.set_authority(name("alice"), name("trading"), trading_pub_key, name("spending"), + { permission_level{name("alice"), name("trading")} }, { trading_priv_key }), action_validate_exception); // Delete spending auth - chain.delete_authority("alice", "spending", { permission_level{"alice", "active"} }, { new_active_priv_key }); - BOOST_TEST((chain.find(boost::make_tuple("alice", "spending"))) == nullptr); + chain.delete_authority(name("alice"), name("spending"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); + BOOST_TEST((chain.find(boost::make_tuple(name("alice"), name("spending")))) == nullptr); // Delete trading auth, now it should succeed since it doesn't have any children anymore - chain.delete_authority("alice", "trading", { permission_level{"alice", "active"} }, { new_active_priv_key }); - BOOST_TEST((chain.find(boost::make_tuple("alice", "trading"))) == nullptr); + chain.delete_authority(name("alice"), name("trading"), { permission_level{name("alice"), name("active")} }, { new_active_priv_key }); + BOOST_TEST((chain.find(boost::make_tuple(name("alice"), name("trading")))) == nullptr); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(link_auths) { try { TESTER chain; - chain.create_accounts({"alice","bob"}); + chain.create_accounts({name("alice"),name("bob")}); - const auto spending_priv_key = chain.get_private_key("alice", "spending"); + const auto spending_priv_key = chain.get_private_key(name("alice"), "spending"); const auto spending_pub_key = spending_priv_key.get_public_key(); - const auto scud_priv_key = chain.get_private_key("alice", "scud"); + const auto scud_priv_key = chain.get_private_key(name("alice"), "scud"); const auto scud_pub_key = scud_priv_key.get_public_key(); - chain.set_authority("alice", "spending", spending_pub_key, "active"); - chain.set_authority("alice", "scud", scud_pub_key, "spending"); + chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("active")); + chain.set_authority(name("alice"), name("scud"), scud_pub_key, name("spending")); // Send req auth action with alice's spending key, it should fail - BOOST_CHECK_THROW(chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }), irrelevant_auth_exception); + BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }), irrelevant_auth_exception); // Link authority for eosio reqauth action with alice's spending key - chain.link_authority("alice", "eosio", "spending", "reqauth"); + chain.link_authority(name("alice"), name("eosio"), name("spending"), name("reqauth")); // Now, req auth action with alice's spending key should succeed - chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }); chain.produce_block(); // Relink the same auth should fail - BOOST_CHECK_THROW( chain.link_authority("alice", "eosio", "spending", "reqauth"), action_validate_exception); + BOOST_CHECK_THROW( chain.link_authority(name("alice"), name("eosio"), name("spending"), name("reqauth")), action_validate_exception); // Unlink alice with eosio reqauth - chain.unlink_authority("alice", "eosio", "reqauth"); + chain.unlink_authority(name("alice"), name("eosio"), name("reqauth")); // Now, req auth action with alice's spending key should fail - BOOST_CHECK_THROW(chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }), irrelevant_auth_exception); + BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }), irrelevant_auth_exception); chain.produce_block(); // Send req auth action with scud key, it should fail - BOOST_CHECK_THROW(chain.push_reqauth("alice", { permission_level{N(alice), "scud"} }, { scud_priv_key }), irrelevant_auth_exception); + BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{N(alice), name("scud")} }, { scud_priv_key }), irrelevant_auth_exception); // Link authority for any eosio action with alice's scud key - chain.link_authority("alice", "eosio", "scud"); + chain.link_authority(name("alice"), name("eosio"), name("scud")); // Now, req auth action with alice's scud key should succeed - chain.push_reqauth("alice", { permission_level{N(alice), "scud"} }, { scud_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("scud")} }, { scud_priv_key }); // req auth action with alice's spending key should also be fine, since it is the parent of alice's scud key - chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(link_then_update_auth) { try { TESTER chain; - chain.create_account("alice"); + chain.create_account(name("alice")); - const auto first_priv_key = chain.get_private_key("alice", "first"); + const auto first_priv_key = chain.get_private_key(name("alice"), "first"); const auto first_pub_key = first_priv_key.get_public_key(); - const auto second_priv_key = chain.get_private_key("alice", "second"); + const auto second_priv_key = chain.get_private_key(name("alice"), "second"); const auto second_pub_key = second_priv_key.get_public_key(); - chain.set_authority("alice", "first", first_pub_key, "active"); + chain.set_authority(name("alice"), name("first"), first_pub_key, name("active")); - chain.link_authority("alice", "eosio", "first", "reqauth"); - chain.push_reqauth("alice", { permission_level{N(alice), "first"} }, { first_priv_key }); + chain.link_authority(name("alice"), name("eosio"), name("first"), name("reqauth")); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("first")} }, { first_priv_key }); chain.produce_blocks(13); // Wait at least 6 seconds for first push_reqauth transaction to expire. // Update "first" auth public key - chain.set_authority("alice", "first", second_pub_key, "active"); + chain.set_authority(name("alice"), name("first"), second_pub_key, name("active")); // Authority updated, using previous "first" auth should fail on linked auth - BOOST_CHECK_THROW(chain.push_reqauth("alice", { permission_level{N(alice), "first"} }, { first_priv_key }), unsatisfied_authorization); + BOOST_CHECK_THROW(chain.push_reqauth(name("alice"), { permission_level{N(alice), name("first")} }, { first_priv_key }), unsatisfied_authorization); // Using updated authority, should succeed - chain.push_reqauth("alice", { permission_level{N(alice), "first"} }, { second_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("first")} }, { second_priv_key }); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(create_account) { try { TESTER chain; - chain.create_account("joe"); + chain.create_account(name("joe")); chain.produce_block(); // Verify account created properly - const auto& joe_owner_authority = chain.get(boost::make_tuple("joe", "owner")); - BOOST_TEST(joe_owner_authority.auth.threshold == 1); - BOOST_TEST(joe_owner_authority.auth.accounts.size() == 1); - BOOST_TEST(joe_owner_authority.auth.keys.size() == 1); - BOOST_TEST(string(joe_owner_authority.auth.keys[0].key) == string(chain.get_public_key("joe", "owner"))); - BOOST_TEST(joe_owner_authority.auth.keys[0].weight == 1); - - const auto& joe_active_authority = chain.get(boost::make_tuple("joe", "active")); - BOOST_TEST(joe_active_authority.auth.threshold == 1); - BOOST_TEST(joe_active_authority.auth.accounts.size() == 1); - BOOST_TEST(joe_active_authority.auth.keys.size() == 1); - BOOST_TEST(string(joe_active_authority.auth.keys[0].key) == string(chain.get_public_key("joe", "active"))); - BOOST_TEST(joe_active_authority.auth.keys[0].weight == 1); + const auto& joe_owner_authority = chain.get(boost::make_tuple(name("joe"), name("owner"))); + BOOST_TEST(joe_owner_authority.auth.threshold == 1u); + BOOST_TEST(joe_owner_authority.auth.accounts.size() == 1u); + BOOST_TEST(joe_owner_authority.auth.keys.size() == 1u); + BOOST_TEST(string(joe_owner_authority.auth.keys[0].key) == string(chain.get_public_key(name("joe"), "owner"))); + BOOST_TEST(joe_owner_authority.auth.keys[0].weight == 1u); + + const auto& joe_active_authority = chain.get(boost::make_tuple(name("joe"), name("active"))); + BOOST_TEST(joe_active_authority.auth.threshold == 1u); + BOOST_TEST(joe_active_authority.auth.accounts.size() == 1u); + BOOST_TEST(joe_active_authority.auth.keys.size() == 1u); + BOOST_TEST(string(joe_active_authority.auth.keys[0].key) == string(chain.get_public_key(name("joe"), "active"))); + BOOST_TEST(joe_active_authority.auth.keys[0].weight == 1u); // Create duplicate name - BOOST_CHECK_EXCEPTION(chain.create_account("joe"), action_validate_exception, + BOOST_CHECK_EXCEPTION(chain.create_account(name("joe")), action_validate_exception, fc_exception_message_is("Cannot create account named joe, as that name is already taken")); // Creating account with name more than 12 chars - BOOST_CHECK_EXCEPTION(chain.create_account("aaaaaaaaaaaaa"), action_validate_exception, + BOOST_CHECK_EXCEPTION(chain.create_account(name("aaaaaaaaaaaaa")), action_validate_exception, fc_exception_message_is("account names can only be 12 chars long")); // Creating account with eosio. prefix with privileged account - chain.create_account("eosio.test1"); + chain.create_account(name("eosio.test1")); // Creating account with eosio. prefix with non-privileged account, should fail - BOOST_CHECK_EXCEPTION(chain.create_account("eosio.test2", "joe"), action_validate_exception, + BOOST_CHECK_EXCEPTION(chain.create_account(name("eosio.test2"), name("joe")), action_validate_exception, fc_exception_message_is("only privileged accounts can have names that start with 'eosio.'")); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE( any_auth ) { try { TESTER chain; - chain.create_accounts( {"alice","bob"} ); + chain.create_accounts( {name("alice"), name("bob")} ); chain.produce_block(); - const auto spending_priv_key = chain.get_private_key("alice", "spending"); + const auto spending_priv_key = chain.get_private_key(name("alice"), "spending"); const auto spending_pub_key = spending_priv_key.get_public_key(); - const auto bob_spending_priv_key = chain.get_private_key("bob", "spending"); + const auto bob_spending_priv_key = chain.get_private_key(name("bob"), "spending"); const auto bob_spending_pub_key = spending_priv_key.get_public_key(); - chain.set_authority("alice", "spending", spending_pub_key, "active"); - chain.set_authority("bob", "spending", bob_spending_pub_key, "active"); + chain.set_authority(name("alice"), name("spending"), spending_pub_key, name("active")); + chain.set_authority(name("bob"), name("spending"), bob_spending_pub_key, name("active")); /// this should fail because spending is not active which is default for reqauth - BOOST_REQUIRE_THROW( chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }), + BOOST_REQUIRE_THROW( chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }), irrelevant_auth_exception ); chain.produce_block(); //test.push_reqauth( N(alice), { permission_level{N(alice),"spending"} }, { spending_priv_key }); - chain.link_authority( "alice", "eosio", "eosio.any", "reqauth" ); - chain.link_authority( "bob", "eosio", "eosio.any", "reqauth" ); + chain.link_authority( name("alice"), name("eosio"), name("eosio.any"), name("reqauth") ); + chain.link_authority( name("bob"), name("eosio"), name("eosio.any"), name("reqauth") ); /// this should succeed because eosio::reqauth is linked to any permission - chain.push_reqauth("alice", { permission_level{N(alice), "spending"} }, { spending_priv_key }); + chain.push_reqauth(name("alice"), { permission_level{N(alice), name("spending")} }, { spending_priv_key }); /// this should fail because bob cannot authorize for alice, the permission given must be one-of alices - BOOST_REQUIRE_THROW( chain.push_reqauth("alice", { permission_level{N(bob), "spending"} }, { spending_priv_key }), + BOOST_REQUIRE_THROW( chain.push_reqauth(name("alice"), { permission_level{N(bob), name("spending")} }, { spending_priv_key }), missing_auth_exception ); @@ -395,9 +396,9 @@ try { authority owner_auth = authority( chain.get_public_key( a, "owner" ) ); - vector pls = {{acc1, "active"}}; - pls.push_back({acc1, "owner"}); // same account but different permission names - pls.push_back({acc1a, "owner"}); + vector pls = {{acc1, name("active")}}; + pls.push_back({acc1, name("owner")}); // same account but different permission names + pls.push_back({acc1a, name("owner")}); trx.actions.emplace_back( pls, newaccount{ .creator = acc1, @@ -419,8 +420,8 @@ try { const auto &usage2 = db.get(acc1a); - BOOST_TEST(usage.cpu_usage.average() > 0); - BOOST_TEST(usage.net_usage.average() > 0); + BOOST_TEST(usage.cpu_usage.average() > 0U); + BOOST_TEST(usage.net_usage.average() > 0U); BOOST_REQUIRE_EQUAL(usage.cpu_usage.average(), usage2.cpu_usage.average()); BOOST_REQUIRE_EQUAL(usage.net_usage.average(), usage2.net_usage.average()); chain.produce_block(); @@ -449,7 +450,7 @@ try { authority invalid_auth = authority(threshold, {key_weight{chain.get_public_key( a, "owner" ), 1}}, {permission_level_weight{{creator, config::active_name}, 1}}); vector pls; - pls.push_back({creator, "active"}); + pls.push_back({creator, name("active")}); trx.actions.emplace_back( pls, newaccount{ .creator = creator, diff --git a/unittests/bootseq_tests.cpp b/unittests/bootseq_tests.cpp index ca325f86585..f5fabe1e26b 100644 --- a/unittests/bootseq_tests.cpp +++ b/unittests/bootseq_tests.cpp @@ -276,13 +276,15 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) { votepro( N(whale3), {N(proda), N(prodb), N(prodc), N(prodd), N(prode)} ); // Total Stakes = b1 + whale2 + whale3 stake = (100,000,000 - 1,000) + (20,000,000 - 1,000) + (30,000,000 - 1,000) + vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global), N(global) ); + BOOST_TEST(get_global_state()["total_activated_stake"].as() == 1499999997000); // No producers will be set, since the total activated stake is less than 150,000,000 produce_blocks_for_n_rounds(2); // 2 rounds since new producer schedule is set when the first block of next round is irreversible auto active_schedule = control->head_block_state()->active_schedule; - BOOST_TEST(active_schedule.producers.size() == 1); - BOOST_TEST(active_schedule.producers.front().producer_name == "eosio"); + BOOST_TEST(active_schedule.producers.size() == 1u); + BOOST_TEST(active_schedule.producers.front().producer_name == name("eosio")); // Spend some time so the producer pay pool is filled by the inflation rate produce_min_num_of_blocks_to_spend_time_wo_inactive_prod(fc::seconds(30 * 24 * 3600)); // 30 days @@ -297,27 +299,27 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) { produce_blocks_for_n_rounds(2); // 2 rounds since new producer schedule is set when the first block of next round is irreversible active_schedule = control->head_block_state()->active_schedule; BOOST_REQUIRE(active_schedule.producers.size() == 21); - BOOST_TEST(active_schedule.producers.at(0).producer_name == "proda"); - BOOST_TEST(active_schedule.producers.at(1).producer_name == "prodb"); - BOOST_TEST(active_schedule.producers.at(2).producer_name == "prodc"); - BOOST_TEST(active_schedule.producers.at(3).producer_name == "prodd"); - BOOST_TEST(active_schedule.producers.at(4).producer_name == "prode"); - BOOST_TEST(active_schedule.producers.at(5).producer_name == "prodf"); - BOOST_TEST(active_schedule.producers.at(6).producer_name == "prodg"); - BOOST_TEST(active_schedule.producers.at(7).producer_name == "prodh"); - BOOST_TEST(active_schedule.producers.at(8).producer_name == "prodi"); - BOOST_TEST(active_schedule.producers.at(9).producer_name == "prodj"); - BOOST_TEST(active_schedule.producers.at(10).producer_name == "prodk"); - BOOST_TEST(active_schedule.producers.at(11).producer_name == "prodl"); - BOOST_TEST(active_schedule.producers.at(12).producer_name == "prodm"); - BOOST_TEST(active_schedule.producers.at(13).producer_name == "prodn"); - BOOST_TEST(active_schedule.producers.at(14).producer_name == "prodo"); - BOOST_TEST(active_schedule.producers.at(15).producer_name == "prodp"); - BOOST_TEST(active_schedule.producers.at(16).producer_name == "prodq"); - BOOST_TEST(active_schedule.producers.at(17).producer_name == "prodr"); - BOOST_TEST(active_schedule.producers.at(18).producer_name == "prods"); - BOOST_TEST(active_schedule.producers.at(19).producer_name == "prodt"); - BOOST_TEST(active_schedule.producers.at(20).producer_name == "produ"); + BOOST_TEST(active_schedule.producers.at( 0).producer_name == name("proda")); + BOOST_TEST(active_schedule.producers.at( 1).producer_name == name("prodb")); + BOOST_TEST(active_schedule.producers.at( 2).producer_name == name("prodc")); + BOOST_TEST(active_schedule.producers.at( 3).producer_name == name("prodd")); + BOOST_TEST(active_schedule.producers.at( 4).producer_name == name("prode")); + BOOST_TEST(active_schedule.producers.at( 5).producer_name == name("prodf")); + BOOST_TEST(active_schedule.producers.at( 6).producer_name == name("prodg")); + BOOST_TEST(active_schedule.producers.at( 7).producer_name == name("prodh")); + BOOST_TEST(active_schedule.producers.at( 8).producer_name == name("prodi")); + BOOST_TEST(active_schedule.producers.at( 9).producer_name == name("prodj")); + BOOST_TEST(active_schedule.producers.at(10).producer_name == name("prodk")); + BOOST_TEST(active_schedule.producers.at(11).producer_name == name("prodl")); + BOOST_TEST(active_schedule.producers.at(12).producer_name == name("prodm")); + BOOST_TEST(active_schedule.producers.at(13).producer_name == name("prodn")); + BOOST_TEST(active_schedule.producers.at(14).producer_name == name("prodo")); + BOOST_TEST(active_schedule.producers.at(15).producer_name == name("prodp")); + BOOST_TEST(active_schedule.producers.at(16).producer_name == name("prodq")); + BOOST_TEST(active_schedule.producers.at(17).producer_name == name("prodr")); + BOOST_TEST(active_schedule.producers.at(18).producer_name == name("prods")); + BOOST_TEST(active_schedule.producers.at(19).producer_name == name("prodt")); + BOOST_TEST(active_schedule.producers.at(20).producer_name == name("produ")); // Spend some time so the producer pay pool is filled by the inflation rate produce_min_num_of_blocks_to_spend_time_wo_inactive_prod(fc::seconds(30 * 24 * 3600)); // 30 days diff --git a/unittests/database_gmr_blklst_tests.cpp b/unittests/database_gmr_blklst_tests.cpp index e856de77ea8..9b5e01ef2b5 100644 --- a/unittests/database_gmr_blklst_tests.cpp +++ b/unittests/database_gmr_blklst_tests.cpp @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(set_name_list_test) flat_set nameset(list.begin(), list.end()); // Create an account db.create([](account_object2 &a) { - a.name = "alice"; + a.name = name("alice"); }); @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(set_name_list_test) auto convert_names = [&](const shared_vector& namevec, flat_set& nameset) -> void { for(const auto& a :namevec) { - nameset.insert(uint64_t(a)); + nameset.insert(a); } }; diff --git a/unittests/database_tests.cpp b/unittests/database_tests.cpp index 316ef7a5b24..079330f49c0 100644 --- a/unittests/database_tests.cpp +++ b/unittests/database_tests.cpp @@ -34,18 +34,18 @@ BOOST_AUTO_TEST_SUITE(database_tests) // Create an account db.create([](account_object2 &a) { - a.name = "billy"; + a.name = name("billy"); }); // Make sure we can retrieve that account by name - auto ptr = db.find("billy"); + auto ptr = db.find(name("billy")); BOOST_TEST(ptr != nullptr); // Undo creation of the account ses.undo(); // Make sure we can no longer find the account - ptr = db.find("billy"); + ptr = db.find(name("billy")); BOOST_TEST(ptr == nullptr); } FC_LOG_AND_RETHROW() } diff --git a/unittests/eosio_system_tester.hpp b/unittests/eosio_system_tester.hpp index 9b3fb642c3b..74c64822f41 100644 --- a/unittests/eosio_system_tester.hpp +++ b/unittests/eosio_system_tester.hpp @@ -56,7 +56,7 @@ class eosio_system_tester : public TESTER { create_currency( N(eosio.token), config::system_account_name, core_from_string("10000000000.0000") ); issue(config::system_account_name, core_from_string("1000000000.0000")); - BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance( "eosio" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance( name("eosio") ) ); set_code( config::system_account_name, contracts::eosio_system_wasm() ); set_abi( config::system_account_name, contracts::eosio_system_abi().data() ); @@ -79,7 +79,8 @@ class eosio_system_tester : public TESTER { create_account_with_resources( N(bob111111111), config::system_account_name, core_from_string("0.4500"), false ); create_account_with_resources( N(carol1111111), config::system_account_name, core_from_string("1.0000"), false ); - BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance("eosio") + get_balance("eosio.ramfee") + get_balance("eosio.stake") + get_balance("eosio.ram") ); + BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), + get_balance(name("eosio")) + get_balance(name("eosio.ramfee")) + get_balance(name("eosio.stake")) + get_balance(name("eosio.ram")) ); } @@ -228,7 +229,8 @@ class eosio_system_tester : public TESTER { act.name = name; act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer_max_time ); - return base_tester::push_action( std::move(act), auth ? uint64_t(signer) : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111) ); + return base_tester::push_action( std::move(act), auth ? signer.to_uint64_t() : + signer == N(bob111111111) ? N(alice1111111).to_uint64_t() : N(bob111111111).to_uint64_t() ); } action_result stake( const account_name& from, const account_name& to, const asset& net, const asset& cpu ) { @@ -326,7 +328,7 @@ class eosio_system_tester : public TESTER { } asset get_balance( const account_name& act ) { - vector data = get_row_by_account( N(eosio.token), act, N(accounts), symbol(CORE_SYMBOL).to_symbol_code().value ); + vector data = get_row_by_account( N(eosio.token), act, N(accounts), name(symbol(CORE_SYMBOL).to_symbol_code().value) ); return data.empty() ? asset(0, symbol(CORE_SYMBOL)) : token_abi_ser.binary_to_variant("account", data, abi_serializer_max_time)["balance"].as(); } @@ -381,7 +383,7 @@ class eosio_system_tester : public TESTER { fc::variant get_stats( const string& symbolname ) { auto symb = eosio::chain::symbol::from_string(symbolname); auto symbol_code = symb.to_symbol_code().value; - vector data = get_row_by_account( N(eosio.token), symbol_code, N(stat), symbol_code ); + vector data = get_row_by_account( N(eosio.token), name(symbol_code), N(stat), name(symbol_code) ); return data.empty() ? fc::variant() : token_abi_ser.binary_to_variant( "currency_stats", data, abi_serializer_max_time ); } @@ -405,7 +407,7 @@ class eosio_system_tester : public TESTER { abi_serializer msig_abi_ser; { create_account_with_resources( N(eosio.msig), config::system_account_name ); - BOOST_REQUIRE_EQUAL( success(), buyram( "eosio", "eosio.msig", core_from_string("5000.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), buyram( name("eosio"), name("eosio.msig"), core_from_string("5000.0000") ) ); produce_block(); auto trace = base_tester::push_action(config::system_account_name, N(setpriv), @@ -428,8 +430,8 @@ class eosio_system_tester : public TESTER { vector active_and_vote_producers() { //stake more than 15% of total EOS supply to activate chain - transfer( "eosio", "alice1111111", core_from_string("650000000.0000"), "eosio" ); - BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("300000000.0000"), core_from_string("300000000.0000") ) ); + transfer( name("eosio"), name("alice1111111"), core_from_string("650000000.0000"), name("eosio") ); + BOOST_REQUIRE_EQUAL( success(), stake( name("alice1111111"), name("alice1111111"), core_from_string("300000000.0000"), core_from_string("300000000.0000") ) ); // create accounts {defproducera, defproducerb, ..., defproducerz} and register as producers std::vector producer_names; @@ -461,9 +463,9 @@ class eosio_system_tester : public TESTER { //vote for producers { - transfer( config::system_account_name, "alice1111111", core_from_string("100000000.0000"), config::system_account_name ); - BOOST_REQUIRE_EQUAL(success(), stake( "alice1111111", core_from_string("30000000.0000"), core_from_string("30000000.0000") ) ); - BOOST_REQUIRE_EQUAL(success(), buyram( "alice1111111", "alice1111111", core_from_string("30000000.0000") ) ); + transfer( config::system_account_name, name("alice1111111"), core_from_string("100000000.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL(success(), stake( name("alice1111111"), core_from_string("30000000.0000"), core_from_string("30000000.0000") ) ); + BOOST_REQUIRE_EQUAL(success(), buyram( name("alice1111111"), name("alice1111111"), core_from_string("30000000.0000") ) ); BOOST_REQUIRE_EQUAL(success(), push_action(N(alice1111111), N(voteproducer), mvo() ("voter", "alice1111111") ("proxy", name(0).to_string()) diff --git a/unittests/forked_tests.cpp b/unittests/forked_tests.cpp index b1e5a6c9c6a..ea16c41a1d4 100644 --- a/unittests/forked_tests.cpp +++ b/unittests/forked_tests.cpp @@ -15,14 +15,6 @@ using namespace eosio::chain; using namespace eosio::testing; -private_key_type get_private_key( name keyname, string role ) { - return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); -} - -public_key_type get_public_key( name keyname, string role ){ - return get_private_key( keyname, role ).get_public_key(); -} - void push_blocks( tester& from, tester& to ) { while( to.control->fork_db_head_block_num() < from.control->fork_db_head_block_num() ) { auto fb = from.control->fetch_block_by_number( to.control->fork_db_head_block_num()+1 ); @@ -37,15 +29,11 @@ BOOST_AUTO_TEST_CASE( irrblock ) try { c.produce_blocks(10); auto r = c.create_accounts( {N(dan),N(sam),N(pam),N(scott)} ); auto res = c.set_producers( {N(dan),N(sam),N(pam),N(scott)} ); - vector sch = { {N(dan),get_public_key(N(dan), "active")}, - {N(sam),get_public_key(N(sam), "active")}, - {N(scott),get_public_key(N(scott), "active")}, - {N(pam),get_public_key(N(pam), "active")} - }; + wlog("set producer schedule to [dan,sam,pam]"); c.produce_blocks(50); -} FC_LOG_AND_RETHROW() +} FC_LOG_AND_RETHROW() struct fork_tracker { vector blocks; @@ -145,15 +133,14 @@ BOOST_AUTO_TEST_CASE( fork_with_bad_block ) try { BOOST_AUTO_TEST_CASE( forking ) try { tester c; - c.produce_block(); - c.produce_block(); + while (c.control->head_block_num() < 3) { + c.produce_block(); + } auto r = c.create_accounts( {N(dan),N(sam),N(pam)} ); wdump((fc::json::to_pretty_string(r))); c.produce_block(); auto res = c.set_producers( {N(dan),N(sam),N(pam)} ); - vector sch = { {N(dan),get_public_key(N(dan), "active")}, - {N(sam),get_public_key(N(sam), "active")}, - {N(pam),get_public_key(N(pam), "active")}}; + wdump((fc::json::to_pretty_string(res))); wlog("set producer schedule to [dan,sam,pam]"); c.produce_blocks(30); @@ -170,15 +157,19 @@ BOOST_AUTO_TEST_CASE( forking ) try { ("maximum_supply", core_from_string("10000000.0000")) ); - wdump((fc::json::to_pretty_string(cr))); - cr = c.push_action( N(eosio.token), N(issue), config::system_account_name, mutable_variant_object() + ("to", "eosio" ) + ("quantity", core_from_string("100.0000")) + ("memo", "") + ); + + cr = c.push_action( N(eosio.token), N(transfer), config::system_account_name, mutable_variant_object() + ("from", "eosio") ("to", "dan" ) ("quantity", core_from_string("100.0000")) ("memo", "") ); - wdump((fc::json::to_pretty_string(cr))); tester c2; diff --git a/unittests/misc_tests.cpp b/unittests/misc_tests.cpp index 563c1922e9e..d7b8fe5fd16 100644 --- a/unittests/misc_tests.cpp +++ b/unittests/misc_tests.cpp @@ -30,7 +30,8 @@ namespace eosio using namespace chain; using namespace std; -static constexpr uint64_t name_suffix( uint64_t n ) { +static constexpr uint64_t name_suffix( name nv ) { + uint64_t n = nv.to_uint64_t(); uint32_t remaining_bits_after_last_actual_dot = 0; uint32_t tmp = 0; for( int32_t remaining_bits = 59; remaining_bits >= 4; remaining_bits -= 5 ) { // Note: remaining_bits must remain signed integer @@ -64,7 +65,7 @@ BOOST_AUTO_TEST_SUITE(misc_tests) BOOST_AUTO_TEST_CASE(name_suffix_tests) { - BOOST_CHECK_EQUAL( name{name_suffix(0)}, name{0} ); + BOOST_CHECK_EQUAL( name{name_suffix(name(0))}, name{0} ); BOOST_CHECK_EQUAL( name{name_suffix(N(abcdehijklmn))}, name{N(abcdehijklmn)} ); BOOST_CHECK_EQUAL( name{name_suffix(N(abcdehijklmn1))}, name{N(abcdehijklmn1)} ); BOOST_CHECK_EQUAL( name{name_suffix(N(abc.def))}, name{N(def)} ); @@ -233,9 +234,9 @@ struct permission_visitor { BOOST_AUTO_TEST_CASE(authority_checker) { try { testing::TESTER test; - auto a = test.get_public_key("a", "active"); - auto b = test.get_public_key("b", "active"); - auto c = test.get_public_key("c", "active"); + auto a = test.get_public_key(name("a"), "active"); + auto b = test.get_public_key(name("b"), "active"); + auto c = test.get_public_key(name("c"), "active"); auto GetNullAuthority = [](auto){abort(); return authority();}; @@ -244,31 +245,31 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetNullAuthority, 2, {a, b}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.unused_keys().size() == 0); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().size() == 0u); } { auto checker = make_auth_checker(GetNullAuthority, 2, {a, c}); BOOST_TEST(!checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 0); - BOOST_TEST(checker.unused_keys().size() == 2); + BOOST_TEST(checker.used_keys().size() == 0u); + BOOST_TEST(checker.unused_keys().size() == 2u); } { auto checker = make_auth_checker(GetNullAuthority, 2, {a, b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.used_keys().count(a) == 1); - BOOST_TEST(checker.used_keys().count(b) == 1); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.used_keys().count(a) == 1u); + BOOST_TEST(checker.used_keys().count(b) == 1u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } { auto checker = make_auth_checker(GetNullAuthority, 2, {b, c}); BOOST_TEST(!checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 0); + BOOST_TEST(checker.used_keys().size() == 0u); } A = authority(3, {key_weight{a, 1}, key_weight{b, 1}, key_weight{c, 1}}); @@ -291,7 +292,7 @@ BOOST_AUTO_TEST_CASE(authority_checker) return authority(1, {key_weight{c, 1}}); }; - A = authority(2, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 1}}); + A = authority(2, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{name("hello"), name("world")}, 1}}); { auto checker = make_auth_checker(GetCAuthority, 2, {a}); BOOST_TEST(checker.satisfied(A)); @@ -300,38 +301,38 @@ BOOST_AUTO_TEST_CASE(authority_checker) { auto checker = make_auth_checker(GetCAuthority, 2, {b}); BOOST_TEST(!checker.satisfied(A)); - BOOST_TEST(checker.used_keys().size() == 0); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.unused_keys().count(b) == 1); + BOOST_TEST(checker.used_keys().size() == 0u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().count(b) == 1u); } { auto checker = make_auth_checker(GetCAuthority, 2, {c}); BOOST_TEST(!checker.satisfied(A)); - BOOST_TEST(checker.used_keys().size() == 0); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 0u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } { auto checker = make_auth_checker(GetCAuthority, 2, {b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.unused_keys().size() == 0); - BOOST_TEST(checker.used_keys().count(b) == 1); - BOOST_TEST(checker.used_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().size() == 0u); + BOOST_TEST(checker.used_keys().count(b) == 1u); + BOOST_TEST(checker.used_keys().count(c) == 1u); } { auto checker = make_auth_checker(GetCAuthority, 2, {b, c, a}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 1); - BOOST_TEST(checker.used_keys().count(a) == 1); - BOOST_TEST(checker.unused_keys().size() == 2); - BOOST_TEST(checker.unused_keys().count(b) == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 1u); + BOOST_TEST(checker.used_keys().count(a) == 1u); + BOOST_TEST(checker.unused_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().count(b) == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } - A = authority(3, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 3}}); + A = authority(3, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{name("hello"), name("world")}, 3}}); { auto checker = make_auth_checker(GetCAuthority, 2, {a, b}); BOOST_TEST(checker.satisfied(A)); @@ -341,14 +342,14 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetCAuthority, 2, {a, b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 1); - BOOST_TEST(checker.used_keys().count(c) == 1); - BOOST_TEST(checker.unused_keys().size() == 2); - BOOST_TEST(checker.unused_keys().count(a) == 1); - BOOST_TEST(checker.unused_keys().count(b) == 1); + BOOST_TEST(checker.used_keys().size() == 1u); + BOOST_TEST(checker.used_keys().count(c) == 1u); + BOOST_TEST(checker.unused_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().count(a) == 1u); + BOOST_TEST(checker.unused_keys().count(b) == 1u); } - A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 1}}); + A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{name("hello"), name("world")}, 1}}); BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {a}).satisfied(A)); BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {b}).satisfied(A)); BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {c}).satisfied(A)); @@ -359,12 +360,12 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetCAuthority, 2, {a, b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } - A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 2}}); + A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{name("hello"), name("world")}, 2}}); BOOST_TEST(make_auth_checker(GetCAuthority, 2, {a, b}).satisfied(A)); BOOST_TEST(make_auth_checker(GetCAuthority, 2, {c}).satisfied(A)); BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {a}).satisfied(A)); @@ -373,21 +374,21 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetCAuthority, 2, {a, b, c}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 1); - BOOST_TEST(checker.unused_keys().size() == 2); - BOOST_TEST(checker.used_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 1u); + BOOST_TEST(checker.unused_keys().size() == 2u); + BOOST_TEST(checker.used_keys().count(c) == 1u); } - auto d = test.get_public_key("d", "active"); - auto e = test.get_public_key("e", "active"); + auto d = test.get_public_key(name("d"), "active"); + auto e = test.get_public_key(name("e"), "active"); auto GetAuthority = [d, e] (const permission_level& perm) { - if (perm.actor == "top") - return authority(2, {key_weight{d, 1}}, {permission_level_weight{{"bottom", "bottom"}, 1}}); + if (perm.actor == name("top")) + return authority(2, {key_weight{d, 1}}, {permission_level_weight{{name("bottom"), name("bottom")}, 1}}); return authority{1, {{e, 1}}, {}}; }; - A = authority(5, {key_weight{a, 2}, key_weight{b, 2}, key_weight{c, 2}}, {permission_level_weight{{"top", "top"}, 5}}); + A = authority(5, {key_weight{a, 2}, key_weight{b, 2}, key_weight{c, 2}}, {permission_level_weight{{name("top"), name("top")}, 5}}); { auto checker = make_auth_checker(GetAuthority, 2, {d, e}); BOOST_TEST(checker.satisfied(A)); @@ -397,20 +398,20 @@ BOOST_AUTO_TEST_CASE(authority_checker) auto checker = make_auth_checker(GetAuthority, 2, {a, b, c, d, e}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 2); - BOOST_TEST(checker.unused_keys().size() == 3); - BOOST_TEST(checker.used_keys().count(d) == 1); - BOOST_TEST(checker.used_keys().count(e) == 1); + BOOST_TEST(checker.used_keys().size() == 2u); + BOOST_TEST(checker.unused_keys().size() == 3u); + BOOST_TEST(checker.used_keys().count(d) == 1u); + BOOST_TEST(checker.used_keys().count(e) == 1u); } { auto checker = make_auth_checker(GetAuthority, 2, {a, b, c, e}); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.used_keys().size() == 3); - BOOST_TEST(checker.unused_keys().size() == 1); - BOOST_TEST(checker.used_keys().count(a) == 1); - BOOST_TEST(checker.used_keys().count(b) == 1); - BOOST_TEST(checker.used_keys().count(c) == 1); + BOOST_TEST(checker.used_keys().size() == 3u); + BOOST_TEST(checker.unused_keys().size() == 1u); + BOOST_TEST(checker.used_keys().count(a) == 1u); + BOOST_TEST(checker.used_keys().count(b) == 1u); + BOOST_TEST(checker.used_keys().count(c) == 1u); } BOOST_TEST(make_auth_checker(GetAuthority, 1, {a, b, c}).satisfied(A)); // Fails due to short recursion depth limit @@ -442,50 +443,50 @@ BOOST_AUTO_TEST_CASE(authority_checker) BOOST_TEST(!validate(F)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.unused_keys().count(b) == 1); - BOOST_TEST(checker.unused_keys().count(a) == 1); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.unused_keys().count(b) == 1u); + BOOST_TEST(checker.unused_keys().count(a) == 1u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); BOOST_TEST(checker.satisfied(A)); BOOST_TEST(checker.satisfied(B)); BOOST_TEST(!checker.all_keys_used()); - BOOST_TEST(checker.unused_keys().count(b) == 0); - BOOST_TEST(checker.unused_keys().count(a) == 0); - BOOST_TEST(checker.unused_keys().count(c) == 1); + BOOST_TEST(checker.unused_keys().count(b) == 0u); + BOOST_TEST(checker.unused_keys().count(a) == 0u); + BOOST_TEST(checker.unused_keys().count(c) == 1u); } { auto A2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"a", "world"}, 1}, - permission_level_weight{{"hello", "world"}, 1}, - permission_level_weight{{"hi", "world"}, 1} + { permission_level_weight{{name("a"), name("world")}, 1}, + permission_level_weight{{name("hello"), name("world")}, 1}, + permission_level_weight{{name("hi"), name("world")}, 1} }); auto B2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - {permission_level_weight{{"hello", "world"}, 1} + {permission_level_weight{{name("hello"), name("world")}, 1} }); auto C2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"hello", "there"}, 1}, - permission_level_weight{{"hello", "world"}, 1} + { permission_level_weight{{name("hello"), name("there")}, 1}, + permission_level_weight{{name("hello"), name("world")}, 1} }); // invalid: duplicate auto D2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"hello", "world"}, 1}, - permission_level_weight{{"hello", "world"}, 2} + { permission_level_weight{{name("hello"), name("world")}, 1}, + permission_level_weight{{name("hello"), name("world")}, 2} }); // invalid: wrong order auto E2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"hello", "world"}, 2}, - permission_level_weight{{"hello", "there"}, 1} + { permission_level_weight{{name("hello"), name("world")}, 2}, + permission_level_weight{{name("hello"), name("there")}, 1} }); // invalid: wrong order auto F2 = authority(4, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"hi", "world"}, 2}, - permission_level_weight{{"hello", "world"}, 1} + { permission_level_weight{{name("hi"), name("world")}, 2}, + permission_level_weight{{name("hello"), name("world")}, 1} }); // invalid: insufficient weight auto G2 = authority(7, {key_weight{b, 1}, key_weight{a, 1}, key_weight{c, 1}}, - { permission_level_weight{{"a", "world"}, 1}, - permission_level_weight{{"hello", "world"}, 1}, - permission_level_weight{{"hi", "world"}, 1} + { permission_level_weight{{name("a"), name("world")}, 1}, + permission_level_weight{{name("hello"), name("world")}, 1}, + permission_level_weight{{name("hi"), name("world")}, 1} }); BOOST_TEST(validate(A2)); @@ -530,7 +531,7 @@ BOOST_AUTO_TEST_CASE(alphabetic_sort) vector uwords; for(const auto w: words) { auto n = name(w.c_str()); - uwords.push_back(n.value); + uwords.push_back(n.to_uint64_t()); } std::sort(uwords.begin(), uwords.end(), std::less()); @@ -541,7 +542,7 @@ BOOST_AUTO_TEST_CASE(alphabetic_sort) tmp.push_back(str); } - for(int i = 0; i < words.size(); ++i ) { + for(size_t i = 0; i < words.size(); ++i ) { BOOST_TEST(tmp[i] == words[i]); } @@ -583,7 +584,7 @@ BOOST_AUTO_TEST_CASE(transaction_test) { try { trx.expiration = fc::time_point::now(); trx.validate(); - BOOST_CHECK_EQUAL(0, trx.signatures.size()); + BOOST_CHECK_EQUAL(0u, trx.signatures.size()); ((const signed_transaction &)trx).sign( test.get_private_key( config::system_account_name, "active" ), test.control->get_chain_id()); BOOST_CHECK_EQUAL(0, trx.signatures.size()); trx.sign( test.get_private_key( config::system_account_name, "active" ), test.control->get_chain_id() ); diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index c87708d2685..34b7da32e7f 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -444,7 +444,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo private_key_type get_private_key( name keyname, string role ) { - return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); + return private_key_type::regenerate(fc::sha256::hash(keyname.to_string()+role)); } public_key_type get_public_key( name keyname, string role ){ diff --git a/unittests/ram_tests.cpp b/unittests/ram_tests.cpp index f85d3a41ea4..288422e5229 100644 --- a/unittests/ram_tests.cpp +++ b/unittests/ram_tests.cpp @@ -36,7 +36,7 @@ BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try { create_account_with_resources(N(testram11111),config::system_account_name, init_request_bytes + 40); create_account_with_resources(N(testram22222),config::system_account_name, init_request_bytes + 1190); produce_blocks(10); - BOOST_REQUIRE_EQUAL( success(), stake( "eosio.stake", "testram11111", core_from_string("10.0000"), core_from_string("5.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), stake( name("eosio.stake"), name("testram11111"), core_from_string("10.0000"), core_from_string("5.0000") ) ); produce_blocks(10); for (auto i = 0; i < 10; ++i) { diff --git a/unittests/special_accounts_tests.cpp b/unittests/special_accounts_tests.cpp index 2c4b6d8bc27..ec66c40430c 100644 --- a/unittests/special_accounts_tests.cpp +++ b/unittests/special_accounts_tests.cpp @@ -38,14 +38,14 @@ BOOST_FIXTURE_TEST_CASE(accounts_exists, tester) auto nobody = chain1_db.find(config::null_account_name); BOOST_CHECK(nobody != nullptr); const auto& nobody_active_authority = chain1_db.get(boost::make_tuple(config::null_account_name, config::active_name)); - BOOST_CHECK_EQUAL(nobody_active_authority.auth.threshold, 1); - BOOST_CHECK_EQUAL(nobody_active_authority.auth.accounts.size(), 0); - BOOST_CHECK_EQUAL(nobody_active_authority.auth.keys.size(), 0); + BOOST_CHECK_EQUAL(nobody_active_authority.auth.threshold, 1u); + BOOST_CHECK_EQUAL(nobody_active_authority.auth.accounts.size(), 0u); + BOOST_CHECK_EQUAL(nobody_active_authority.auth.keys.size(), 0u); const auto& nobody_owner_authority = chain1_db.get(boost::make_tuple(config::null_account_name, config::owner_name)); - BOOST_CHECK_EQUAL(nobody_owner_authority.auth.threshold, 1); - BOOST_CHECK_EQUAL(nobody_owner_authority.auth.accounts.size(), 0); - BOOST_CHECK_EQUAL(nobody_owner_authority.auth.keys.size(), 0); + BOOST_CHECK_EQUAL(nobody_owner_authority.auth.threshold, 1u); + BOOST_CHECK_EQUAL(nobody_owner_authority.auth.accounts.size(), 0u); + BOOST_CHECK_EQUAL(nobody_owner_authority.auth.keys.size(), 0u); auto producers = chain1_db.find(config::producers_account_name); BOOST_CHECK(producers != nullptr); @@ -56,7 +56,7 @@ BOOST_FIXTURE_TEST_CASE(accounts_exists, tester) auto expected_threshold = (active_producers.producers.size() * 2)/3 + 1; BOOST_CHECK_EQUAL(producers_active_authority.auth.threshold, expected_threshold); BOOST_CHECK_EQUAL(producers_active_authority.auth.accounts.size(), active_producers.producers.size()); - BOOST_CHECK_EQUAL(producers_active_authority.auth.keys.size(), 0); + BOOST_CHECK_EQUAL(producers_active_authority.auth.keys.size(), 0u); std::vector active_auth; for(auto& apw : producers_active_authority.auth.accounts) { @@ -64,10 +64,10 @@ BOOST_FIXTURE_TEST_CASE(accounts_exists, tester) } std::vector diff; - for (int i = 0; i < std::max(active_auth.size(), active_producers.producers.size()); ++i) { + for (size_t i = 0; i < std::max(active_auth.size(), active_producers.producers.size()); ++i) { account_name n1 = i < active_auth.size() ? active_auth[i] : (account_name)0; account_name n2 = i < active_producers.producers.size() ? active_producers.producers[i].producer_name : (account_name)0; - if (n1 != n2) diff.push_back((uint64_t)n2 - (uint64_t)n1); + if (n1 != n2) diff.push_back(name(n2.to_uint64_t() - n1.to_uint64_t())); } BOOST_CHECK_EQUAL(diff.size(), 0); diff --git a/unittests/wasm_tests.cpp b/unittests/wasm_tests.cpp index 1e3d31b24c9..ff0cb91b674 100644 --- a/unittests/wasm_tests.cpp +++ b/unittests/wasm_tests.cpp @@ -90,11 +90,11 @@ BOOST_FIXTURE_TEST_CASE( basic_test, TESTER ) try { trx.sign( get_private_key( N(asserter), "active" ), control->get_chain_id() ); auto result = push_transaction( trx ); BOOST_CHECK_EQUAL(result->receipt->status, transaction_receipt::executed); - BOOST_CHECK_EQUAL(result->action_traces.size(), 1); - BOOST_CHECK_EQUAL(result->action_traces.at(0).receipt.receiver.to_string(), name(N(asserter)).to_string() ); + BOOST_CHECK_EQUAL(result->action_traces.size(), 1u); + BOOST_CHECK_EQUAL(result->action_traces.at(0).receiver.to_string(), name(N(asserter)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.account.to_string(), name(N(asserter)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.name.to_string(), name(N(procassert)).to_string() ); - BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.size(), 1 ); + BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.size(), 1u ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.at(0).actor.to_string(), name(N(asserter)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.at(0).permission.to_string(), name(config::active_name).to_string() ); no_assert_id = trx.id(); @@ -382,23 +382,23 @@ BOOST_FIXTURE_TEST_CASE( f32_f64_overflow_tests, tester ) try { int count = 0; auto check = [&](const char *wast_template, const char *op, const char *param) -> bool { count+=16; - create_accounts( {N(f_tests)+count} ); + create_accounts( {name(N(f_tests).to_uint64_t()+count)} ); produce_blocks(1); std::vector wast; wast.resize(strlen(wast_template) + 128); sprintf(&(wast[0]), wast_template, op, param); - set_code(N(f_tests)+count, &(wast[0])); + set_code(name(N(f_tests).to_uint64_t()+count), &(wast[0])); produce_blocks(10); signed_transaction trx; action act; - act.account = N(f_tests)+count; + act.account = name(N(f_tests).to_uint64_t()+count); act.name = N(); - act.authorization = vector{{N(f_tests)+count,config::active_name}}; + act.authorization = vector{{name(N(f_tests).to_uint64_t()+count),config::active_name}}; trx.actions.push_back(act); set_transaction_headers(trx); - trx.sign(get_private_key( N(f_tests)+count, "active" ), control->get_chain_id()); + trx.sign(get_private_key( name(N(f_tests).to_uint64_t()+count), "active" ), control->get_chain_id()); try { push_transaction(trx); @@ -624,7 +624,7 @@ BOOST_FIXTURE_TEST_CASE( check_global_reset, TESTER ) try { { action act; act.account = N(globalreset); - act.name = 1ULL; + act.name = name(1ULL); act.authorization = vector{{N(globalreset),config::active_name}}; trx.actions.push_back(act); } @@ -1103,7 +1103,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 555ULL<<32 | 0ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(555ULL<<32 | 0ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1117,7 +1117,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 555ULL<<32 | 1022ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(555ULL<<32 | 1022ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1131,7 +1131,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 7777ULL<<32 | 1023ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(7777ULL<<32 | 1023ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1145,7 +1145,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 7778ULL<<32 | 1023ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(7778ULL<<32 | 1023ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1161,7 +1161,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 133ULL<<32 | 5ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(133ULL<<32 | 5ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1177,7 +1177,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = eosio::chain::wasm_constraints::maximum_table_elements+54334; + act.name = name(eosio::chain::wasm_constraints::maximum_table_elements+54334); act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1197,7 +1197,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 555ULL<<32 | 1022ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(555ULL<<32 | 1022ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1210,7 +1210,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 7777ULL<<32 | 1023ULL; //top 32 is what we assert against, bottom 32 is indirect call index + act.name = name(7777ULL<<32 | 1023ULL); //top 32 is what we assert against, bottom 32 is indirect call index act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); @@ -1224,7 +1224,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, TESTER ) try { { signed_transaction trx; action act; - act.name = 888ULL; + act.name = name(888ULL); act.account = N(tbl); act.authorization = vector{{N(tbl),config::active_name}}; trx.actions.push_back(act); diff --git a/unittests/whitelist_blacklist_tests.cpp b/unittests/whitelist_blacklist_tests.cpp index d2734681f60..db6a433b7bf 100644 --- a/unittests/whitelist_blacklist_tests.cpp +++ b/unittests/whitelist_blacklist_tests.cpp @@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { tester1.chain->set_abi( N(charlie), contracts::deferred_test_abi().data() ); tester1.chain->produce_blocks(); - auto auth = authority(eosio::testing::base_tester::get_public_key("alice", "active")); + auto auth = authority(eosio::testing::base_tester::get_public_key(name("alice"), "active")); auth.accounts.push_back( permission_level_weight{{N(alice), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(alice), mvo() @@ -463,7 +463,7 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { ( "auth", auth ) ); - auth = authority(eosio::testing::base_tester::get_public_key("bob", "active")); + auth = authority(eosio::testing::base_tester::get_public_key(name("bob"), "active")); auth.accounts.push_back( permission_level_weight{{N(alice), config::eosio_code_name}, 1} ); auth.accounts.push_back( permission_level_weight{{N(bob), config::eosio_code_name}, 1} ); @@ -474,7 +474,7 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { ( "auth", auth ) ); - auth = authority(eosio::testing::base_tester::get_public_key("charlie", "active")); + auth = authority(eosio::testing::base_tester::get_public_key(name("charlie"), "active")); auth.accounts.push_back( permission_level_weight{{N(charlie), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(charlie), mvo() @@ -499,7 +499,8 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { tester2.chain->push_block( b ); } - auto log_trxs = [&]( const transaction_trace_ptr& t) { + auto log_trxs = [&](std::tuple x) { + auto& t = std::get<0>(x); if( !t || t->action_traces.size() == 0 ) return; const auto& act = t->action_traces[0].act; @@ -527,7 +528,7 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { auto num_deferred = tester1.chain->control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(0, num_deferred); + BOOST_REQUIRE_EQUAL(0u, num_deferred); // Schedule a deferred transaction authorized by charlie@active tester1.chain->push_action( N(charlie), N(defercall), N(alice), mvo() @@ -538,14 +539,14 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { ); num_deferred = tester1.chain->control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1, num_deferred); + BOOST_REQUIRE_EQUAL(1u, num_deferred); // Do not allow that deferred transaction to retire yet tester1.chain->finish_block(); tester1.chain->produce_blocks(2, true); // Produce 2 empty blocks (other than onblock of course). num_deferred = tester1.chain->control->db().get_index().size(); - BOOST_REQUIRE_EQUAL(1, num_deferred); + BOOST_REQUIRE_EQUAL(1u, num_deferred); c1.disconnect(); @@ -596,7 +597,7 @@ BOOST_AUTO_TEST_CASE( blacklist_sender_bypass ) { try { tester1.chain->set_abi( N(charlie), contracts::deferred_test_abi().data() ); tester1.chain->produce_blocks(); - auto auth = authority(eosio::testing::base_tester::get_public_key("alice", "active")); + auto auth = authority(eosio::testing::base_tester::get_public_key(name("alice"), "active")); auth.accounts.push_back( permission_level_weight{{N(alice), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(alice), mvo() @@ -606,7 +607,7 @@ BOOST_AUTO_TEST_CASE( blacklist_sender_bypass ) { try { ( "auth", auth ) ); - auth = authority(eosio::testing::base_tester::get_public_key("bob", "active")); + auth = authority(eosio::testing::base_tester::get_public_key(name("bob"), "active")); auth.accounts.push_back( permission_level_weight{{N(bob), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(bob), mvo() @@ -616,7 +617,7 @@ BOOST_AUTO_TEST_CASE( blacklist_sender_bypass ) { try { ( "auth", auth ) ); - auth = authority(eosio::testing::base_tester::get_public_key("charlie", "active")); + auth = authority(eosio::testing::base_tester::get_public_key(name("charlie"), "active")); auth.accounts.push_back( permission_level_weight{{N(charlie), config::eosio_code_name}, 1} ); tester1.chain->push_action( N(eosio), N(updateauth), N(charlie), mvo() From c242cbcbfaddc75e224ab38f7807abb2c8ae5726 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Wed, 10 Jun 2020 09:54:37 +0800 Subject: [PATCH 23/25] Add: account query database --- plugins/chain_api_plugin/chain_api_plugin.cpp | 43 +- plugins/chain_plugin/CMakeLists.txt | 1 + plugins/chain_plugin/account_query_db.cpp | 479 ++++++++++++++++++ plugins/chain_plugin/chain_plugin.cpp | 38 ++ .../eosio/chain_plugin/account_query_db.hpp | 136 +++++ .../eosio/chain_plugin/chain_plugin.hpp | 16 +- .../include/eosio/http_plugin/http_plugin.hpp | 5 + tests/chain_plugin_tests.cpp | 2 +- tests/get_table_tests.cpp | 6 +- 9 files changed, 717 insertions(+), 9 deletions(-) create mode 100644 plugins/chain_plugin/account_query_db.cpp create mode 100644 plugins/chain_plugin/include/eosio/chain_plugin/account_query_db.hpp diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index 8243765783d..dedf8d31f81 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -35,6 +35,23 @@ struct async_result_visitor : public fc::visitor { } }; +namespace { + template + T parse_params(const std::string& body) { + if (body.empty()) { + EOS_THROW(chain::invalid_http_request, "A Request body is required"); + } + + try { + try { + return fc::json::from_string(body).as(); + } catch (const chain::chain_exception& e) { // EOS_RETHROW_EXCEPTIONS does not re-type these so, re-code it + throw fc::exception(e); + } + } EOS_RETHROW_EXCEPTIONS(chain::invalid_http_request, "Unable to parse valid input from POST body"); + } +} + #define CALL(api_name, api_handle, api_namespace, call_name, http_response_code) \ {std::string("/v1/" #api_name "/" #call_name), \ [api_handle](string, string body, url_response_callback cb) mutable { \ @@ -48,6 +65,19 @@ struct async_result_visitor : public fc::visitor { } \ }} +#define CALL_WITH_400(api_name, api_handle, api_namespace, call_name, http_response_code) \ +{std::string("/v1/" #api_name "/" #call_name), \ + [api_handle](string, string body, url_response_callback cb) mutable { \ + api_handle.validate(); \ + try { \ + auto params = parse_params(body);\ + fc::variant result( api_handle.call_name( std::move(params) ) ); \ + cb(http_response_code, std::move(result)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + }} + #define CALL_ASYNC(api_name, api_handle, api_namespace, call_name, call_result, http_response_code) \ {std::string("/v1/" #api_name "/" #call_name), \ [api_handle](string, string body, url_response_callback cb) mutable { \ @@ -73,11 +103,14 @@ struct async_result_visitor : public fc::visitor { #define CHAIN_RO_CALL_ASYNC(call_name, call_result, http_response_code) CALL_ASYNC(chain, ro_api, chain_apis::read_only, call_name, call_result, http_response_code) #define CHAIN_RW_CALL_ASYNC(call_name, call_result, http_response_code) CALL_ASYNC(chain, rw_api, chain_apis::read_write, call_name, call_result, http_response_code) +#define CHAIN_RO_CALL_WITH_400(call_name, http_response_code) CALL_WITH_400(chain, ro_api, chain_apis::read_only, call_name, http_response_code) + void chain_api_plugin::plugin_startup() { ilog( "starting chain_api_plugin" ); my.reset(new chain_api_plugin_impl(app().get_plugin().chain())); - auto ro_api = app().get_plugin().get_read_only_api(); - auto rw_api = app().get_plugin().get_read_write_api(); + auto& chain = app().get_plugin(); + auto ro_api = chain.get_read_only_api(); + auto rw_api = chain.get_read_write_api(); auto& _http_plugin = app().get_plugin(); ro_api.set_shorten_abi_errors( !_http_plugin.verbose_errors() ); @@ -107,6 +140,12 @@ void chain_api_plugin::plugin_startup() { CHAIN_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202), CHAIN_RW_CALL_ASYNC(push_transactions, chain_apis::read_write::push_transactions_results, 202) }); + + if (chain.account_queries_enabled()) { + _http_plugin.add_async_api({ + CHAIN_RO_CALL_WITH_400(get_accounts_by_authorizers, 200), + }); + } } void chain_api_plugin::plugin_shutdown() {} diff --git a/plugins/chain_plugin/CMakeLists.txt b/plugins/chain_plugin/CMakeLists.txt index d98df1322bf..592f3abfc65 100644 --- a/plugins/chain_plugin/CMakeLists.txt +++ b/plugins/chain_plugin/CMakeLists.txt @@ -1,5 +1,6 @@ file(GLOB HEADERS "include/eosio/chain_plugin/*.hpp") add_library( chain_plugin + account_query_db.cpp chain_plugin.cpp ${HEADERS} ) diff --git a/plugins/chain_plugin/account_query_db.cpp b/plugins/chain_plugin/account_query_db.cpp new file mode 100644 index 00000000000..d91c00c0129 --- /dev/null +++ b/plugins/chain_plugin/account_query_db.cpp @@ -0,0 +1,479 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace eosio; +using namespace boost::multi_index; +using namespace boost::bimaps; + +namespace { + /** + * Structure to hold indirect reference to a `property_object` via {owner,name} as well as a non-standard + * index over `last_updated` for roll-back support + */ + struct permission_info { + // indexed data + chain::name owner; + chain::name name; + fc::time_point last_updated; + + // un-indexed data + uint32_t threshold; + + using cref = std::reference_wrapper; + }; + + struct by_owner_name; + struct by_last_updated; + + /** + * Multi-index providing fast lookup for {owner,name} as well as {last_updated} + */ + using permission_info_index_t = multi_index_container< + permission_info, + indexed_by< + ordered_unique< + tag, + composite_key, + member + > + >, + ordered_non_unique< + tag, + member + > + > + >; + + /** + * Utility function to identify on-block action + * @param p + * @return + */ + bool is_onblock(const chain::transaction_trace_ptr& p) { + if (p->action_traces.empty()) + return false; + const auto& act = p->action_traces[0].act; + if (act.account != eosio::chain::config::system_account_name || act.name != N(onblock) || + act.authorization.size() != 1) + return false; + const auto& auth = act.authorization[0]; + return auth.actor == eosio::chain::config::system_account_name && + auth.permission == eosio::chain::config::active_name; + } + + template + struct weighted { + T value; + chain::weight_type weight; + + static weighted lower_bound_for( const T& value ) { + return {value, std::numeric_limits::min()}; + } + + static weighted upper_bound_for( const T& value ) { + return {value, std::numeric_limits::max()}; + } + }; + + template + auto make_optional_authorizer(const Input& authorizer) -> fc::optional { + if constexpr (std::is_same_v) { + return authorizer; + } else { + return {}; + } + } +} + +namespace std { + /** + * support for using `permission_info::cref` in ordered containers + */ + template<> + struct less { + bool operator()( const permission_info::cref& lhs, const permission_info::cref& rhs ) const { + return std::uintptr_t(&lhs.get()) < std::uintptr_t(&rhs.get()); + } + }; + + /** + * support for using `weighted` in ordered containers + */ + template + struct less> { + bool operator()( const weighted& lhs, const weighted& rhs ) const { + return std::tie(lhs.value, lhs.weight) < std::tie(rhs.value, rhs.weight); + } + }; + +} + +namespace eosio::chain_apis { + /** + * Implementation details of the account query DB + */ + struct account_query_db_impl { + account_query_db_impl(const chain::controller& controller) + :controller(controller) + {} + + /** + * Build the initial database from the chain controller by extracting the information contained in the + * blockchain state at the current HEAD + */ + void build_account_query_map() { + std::unique_lock write_lock(rw_mutex); + + ilog("Building account query DB"); + auto start = fc::time_point::now(); + const auto& index = controller.db().get_index().indices().get(); + + for (const auto& po : index ) { + const auto& pi = permission_info_index.emplace( permission_info{ po.owner, po.name, po.last_updated, po.auth.threshold } ).first; + add_to_bimaps(*pi, po); + } + auto duration = fc::time_point::now() - start; + ilog("Finished building account query DB in ${sec}", ("sec", (duration.count() / 1'000'000.0 ))); + } + + /** + * Add a permission to the bimaps for keys and accounts + * @param pi - the ephemeral permission info structure being added + * @param po - the chain data associted with this permission + */ + void add_to_bimaps( const permission_info& pi, const chain::permission_object& po ) { + // For each account, add this permission info's non-owning reference to the bimap for accounts + for (const auto& a : po.auth.accounts) { + name_bimap.insert(name_bimap_t::value_type {{a.permission, a.weight}, pi}); + } + + // for each key, add this permission info's non-owning reference to the bimap for keys + for (const auto& k: po.auth.keys) { + chain::public_key_type key = k.key; + key_bimap.insert(key_bimap_t::value_type {{std::move(key), k.weight}, pi}); + } + } + + /** + * Remove a permission from the bimaps for keys and accounts + * @param pi - the ephemeral permission info structure being removed + */ + void remove_from_bimaps( const permission_info& pi ) { + // remove all entries from the name bimap that refer to this permission_info's reference + const auto name_range = name_bimap.right.equal_range(pi); + name_bimap.right.erase(name_range.first, name_range.second); + + // remove all entries from the key bimap that refer to this permission_info's reference + const auto key_range = key_bimap.right.equal_range(pi); + key_bimap.right.erase(key_range.first, key_range.second); + } + + bool is_rollback_required( const chain::block_state_ptr& bsp ) const { + std::shared_lock read_lock(rw_mutex); + const auto t = bsp->block->timestamp.to_time_point(); + const auto& index = permission_info_index.get(); + + if (index.empty()) { + return false; + } else { + const auto& pi = (*index.rbegin()); + if (pi.last_updated < t) { + return false; + } + } + + return true; + } + + /** + * Given a time_point, remove all permissions that were last updated at or after that time_point + * this will effectively remove any updates that happened at or after that time point + * + * For each removed entry, this will create a new entry if there exists an equivalent {owner, name} permission + * at the HEAD state of the chain. + * @param bsp - the block to rollback before + */ + void rollback_to_before( const chain::block_state_ptr& bsp ) { + const auto t = bsp->block->timestamp.to_time_point(); + auto& index = permission_info_index.get(); + const auto& permission_by_owner = controller.db().get_index().indices().get(); + + while (!index.empty()) { + const auto& pi = (*index.rbegin()); + if (pi.last_updated < t) { + break; + } + + // remove this entry from the bimaps + remove_from_bimaps(pi); + + auto itr = permission_by_owner.find(std::make_tuple(pi.owner, pi.name)); + if (itr == permission_by_owner.end()) { + // this permission does not exist at this point in the chains history + index.erase(index.iterator_to(pi)); + } else { + const auto& po = *itr; + index.modify(index.iterator_to(pi), [&po](auto& mutable_pi) { + mutable_pi.last_updated = po.last_updated; + mutable_pi.threshold = po.auth.threshold; + }); + add_to_bimaps(pi, po); + } + } + } + + /** + * Store a potentially relevant transaction trace in a short lived cache so that it can be processed if its + * committed to by a block + * @param trace + */ + void cache_transaction_trace( const chain::transaction_trace_ptr& trace ) { + if( !trace->receipt ) return; + // include only executed transactions; soft_fail included so that onerror (and any inlines via onerror) are included + if((trace->receipt->status != chain::transaction_receipt_header::executed && + trace->receipt->status != chain::transaction_receipt_header::soft_fail)) { + return; + } + if( is_onblock( trace )) { + onblock_trace.emplace( trace ); + } else if( trace->failed_dtrx_trace ) { + cached_trace_map[trace->failed_dtrx_trace->id] = trace; + } else { + cached_trace_map[trace->id] = trace; + } + } + + using permission_set_t = std::set; + /** + * Pre-Commit step with const qualifier to guarantee it does not mutate + * the thread-safe data set + * @param bsp + */ + auto commit_block_prelock( const chain::block_state_ptr& bsp ) const { + permission_set_t updated; + permission_set_t deleted; + + /** + * process traces to find `updateauth` and `deleteauth` calls maintaining a final set of + * permissions to either update or delete. Intra-block changes are discarded + */ + auto process_trace = [&](const chain::transaction_trace_ptr& trace) { + for( const auto& at : trace->action_traces ) { + if (std::tie(at.receiver, at.act.account) != std::tie(chain::config::system_account_name,chain::config::system_account_name)) { + continue; + } + + if (at.act.name == chain::updateauth::get_name()) { + auto data = at.act.data_as(); + auto itr = updated.emplace(chain::permission_level{data.account, data.permission}).first; + deleted.erase(*itr); + } else if (at.act.name == chain::deleteauth::get_name()) { + auto data = at.act.data_as(); + auto itr = deleted.emplace(chain::permission_level{data.account, data.permission}).first; + updated.erase(*itr); + } + } + }; + + if( onblock_trace ) + process_trace(*onblock_trace); + + for( const auto& r : bsp->block->transactions ) { + chain::transaction_id_type id; + if( r.trx.contains()) { + id = r.trx.get(); + } else { + id = r.trx.get().id(); + } + + const auto it = cached_trace_map.find( id ); + if( it != cached_trace_map.end() ) { + process_trace( it->second ); + } + } + + return std::make_tuple(std::move(updated), std::move(deleted), is_rollback_required(bsp)); + } + + /** + * Commit a block of transactions to the account query DB + * transaction traces need to be in the cache prior to this call + * @param bsp + */ + void commit_block(const chain::block_state_ptr& bsp ) { + permission_set_t updated; + permission_set_t deleted; + bool rollback_required = false; + + std::tie(updated, deleted, rollback_required) = commit_block_prelock(bsp); + + // optimistic skip of locking section if there is nothing to do + if (!updated.empty() || !deleted.empty() || rollback_required) { + std::unique_lock write_lock(rw_mutex); + + rollback_to_before(bsp); + auto& index = permission_info_index.get(); + const auto& permission_by_owner = controller.db().get_index().indices().get(); + + // for each updated permission, find the new values and update the account query db + for (const auto& up: updated) { + auto key = std::make_tuple(up.actor, up.permission); + auto source_itr = permission_by_owner.find(key); + EOS_ASSERT(source_itr != permission_by_owner.end(), chain::plugin_exception, "chain data is missing"); + auto itr = index.find(key); + if (itr == index.end()) { + const auto& po = *source_itr; + itr = index.emplace(permission_info{ po.owner, po.name, po.last_updated, po.auth.threshold }).first; + } else { + remove_from_bimaps(*itr); + index.modify(itr, [&](auto& mutable_pi){ + mutable_pi.last_updated = source_itr->last_updated; + mutable_pi.threshold = source_itr->auth.threshold; + }); + } + + add_to_bimaps(*itr, *source_itr); + } + + // for all deleted permissions, process their removal from the account query DB + for (const auto& dp: deleted) { + auto key = std::make_tuple(dp.actor, dp.permission); + auto itr = index.find(key); + if (itr != index.end()) { + remove_from_bimaps(*itr); + index.erase(itr); + } + } + } + + // drop any unprocessed cached traces + cached_trace_map.clear(); + onblock_trace.reset(); + } + + account_query_db::get_accounts_by_authorizers_result + get_accounts_by_authorizers( const account_query_db::get_accounts_by_authorizers_params& args) const { + std::shared_lock read_lock(rw_mutex); + + using result_t = account_query_db::get_accounts_by_authorizers_result; + result_t result; + + // deduplicate inputs + auto account_set = std::set(args.accounts.begin(), args.accounts.end()); + const auto key_set = std::set(args.keys.begin(), args.keys.end()); + + /** + * Add a range of results + */ + auto push_results = [&result](const auto& begin, const auto& end) { + for (auto itr = begin; itr != end; ++itr) { + const auto& pi = itr->second.get(); + const auto& authorizer = itr->first.value; + auto weight = itr->first.weight; + + result.accounts.emplace_back(result_t::account_result{ + pi.owner, + pi.name, + make_optional_authorizer(authorizer), + make_optional_authorizer(authorizer), + weight, + pi.threshold + }); + } + }; + + + for (const auto& a: account_set) { + if (a.permission.empty()) { + // empty permission is a wildcard + // construct a range between the lower bound of the given account and the lower bound of the + // next possible account name + const auto begin = name_bimap.left.lower_bound(weighted::lower_bound_for({a.actor, a.permission})); + const auto next_account_name = chain::name(a.actor.to_uint64_t() + 1); + const auto end = name_bimap.left.lower_bound(weighted::lower_bound_for({next_account_name, a.permission})); + push_results(begin, end); + } else { + // construct a range of all possible weights for an account/permission pair + const auto p = chain::permission_level{a.actor, a.permission}; + const auto begin = name_bimap.left.lower_bound(weighted::lower_bound_for(p)); + const auto end = name_bimap.left.upper_bound(weighted::upper_bound_for(p)); + push_results(begin, end); + } + } + + for (const auto& k: key_set) { + // construct a range of all possible weights for a key + const auto begin = key_bimap.left.lower_bound(weighted::lower_bound_for(k)); + const auto end = key_bimap.left.upper_bound(weighted::upper_bound_for(k)); + push_results(begin, end); + } + + return result; + } + + /** + * Convenience aliases + */ + using cached_trace_map_t = std::map; + using onblock_trace_t = std::optional; + + const chain::controller& controller; ///< the controller to read data from + cached_trace_map_t cached_trace_map; ///< temporary cache of uncommitted traces + onblock_trace_t onblock_trace; ///< temporary cache of on_block trace + + + using name_bimap_t = bimap>, multiset_of>; + using key_bimap_t = bimap>, multiset_of>; + + /* + * The structures below are shared between the writing thread and the reading thread(s) and must be protected + * by the `rw_mutex` + */ + permission_info_index_t permission_info_index; ///< multi-index that holds ephemeral indices + name_bimap_t name_bimap; ///< many:many bimap of names:permission_infos + key_bimap_t key_bimap; ///< many:many bimap of keys:permission_infos + + mutable std::shared_mutex rw_mutex; ///< mutex for read/write locking on the Multi-index and bimaps + }; + + account_query_db::account_query_db( const chain::controller& controller ) + :_impl(std::make_unique(controller)) + { + _impl->build_account_query_map(); + } + + account_query_db::~account_query_db() = default; + account_query_db & account_query_db::operator=(account_query_db &&) = default; + + void account_query_db::cache_transaction_trace( const chain::transaction_trace_ptr& trace ) { + try { + _impl->cache_transaction_trace(trace); + } FC_LOG_AND_DROP(("ACCOUNT DB cache_transaction_trace ERROR")); + } + + void account_query_db::commit_block(const chain::block_state_ptr& block ) { + try { + _impl->commit_block(block); + } FC_LOG_AND_DROP(("ACCOUNT DB commit_block ERROR")); + } + + account_query_db::get_accounts_by_authorizers_result account_query_db::get_accounts_by_authorizers( const account_query_db::get_accounts_by_authorizers_params& args) const { + return _impl->get_accounts_by_authorizers(args); + } + +} diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 35b6af33083..d4d20e0b248 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -167,6 +167,7 @@ class chain_plugin_impl { bfs::path blocks_dir; bool readonly = false; flat_map loaded_checkpoints; + bool account_queries_enabled = false; fc::optional fork_db; fc::optional block_logger; @@ -241,6 +242,8 @@ class chain_plugin_impl { pbft::incoming::checkpoint_channel::channel_type::handle pbft_incoming_checkpoint_subscription; pbft::outgoing::checkpoint_channel::channel_type& pbft_outgoing_checkpoint_channel; pbft::incoming::checkpoint_channel::channel_type& pbft_incoming_checkpoint_channel; + + fc::optional _account_query_db; }; chain_plugin::chain_plugin() @@ -314,6 +317,7 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip }), "Number of threads to use for EOS VM OC tier-up") ("eos-vm-oc-enable", bpo::bool_switch(), "Enable EOS VM OC tier-up runtime") #endif + ("enable-account-queries", bpo::value()->default_value(false), "enable queries to find accounts by various metadata.") ; // TODO: rate limiting @@ -766,6 +770,8 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->chain_config->eosvmoc_tierup = true; #endif + my->account_queries_enabled = options.at("enable-account-queries").as(); + my->chain.emplace( *my->chain_config ); my->chain_id.emplace( my->chain->get_chain_id()); @@ -812,6 +818,9 @@ void chain_plugin::plugin_initialize(const variables_map& options) { } ); my->accepted_block_connection = my->chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { + if (my->_account_query_db) { + my->_account_query_db->commit_block(blk); + } my->accepted_block_channel.publish( blk ); } ); @@ -830,6 +839,9 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->applied_transaction_connection = my->chain->applied_transaction.connect( [this]( std::tuple t ) { + if (my->_account_query_db) { + my->_account_query_db->cache_transaction_trace(std::get<0>(t)); + } my->applied_transaction_channel.publish( std::get<0>(t) ); } ); @@ -940,6 +952,16 @@ void chain_plugin::plugin_startup() ("num", my->chain->head_block_num())("ts", (std::string)my->chain_config->genesis.initial_timestamp)); my->chain_config.reset(); + + if (my->account_queries_enabled) { + my->account_queries_enabled = false; + try { + my->_account_query_db.emplace(*my->chain); + my->account_queries_enabled = true; + } FC_LOG_AND_DROP(("Unable to enable account queries")); + } + + } FC_CAPTURE_AND_RETHROW() } void chain_plugin::plugin_shutdown() { @@ -966,6 +988,10 @@ void chain_apis::read_write::validate() const { EOS_ASSERT( db.get_read_mode() != chain::db_read_mode::READ_ONLY, missing_chain_api_plugin_exception, "Not allowed, node in read-only mode" ); } +chain_apis::read_only chain_plugin::get_read_only_api() const { + return chain_apis::read_only(chain(), my->_account_query_db, get_abi_serializer_max_time(), pbft_ctrl()); +} + void chain_plugin::accept_block(const signed_block_ptr& block ) { my->incoming_block_sync_method(block); } @@ -1222,6 +1248,12 @@ void chain_plugin::handle_db_exhaustion() { std::_Exit(1); } + +bool chain_plugin::account_queries_enabled() const { + return my->account_queries_enabled; +} + + namespace chain_apis { const string read_only::KEYi64 = "i64"; @@ -2176,6 +2208,12 @@ read_only::get_transaction_id_result read_only::get_transaction_id( const read_o return params.id(); } +account_query_db::get_accounts_by_authorizers_result read_only::get_accounts_by_authorizers( const account_query_db::get_accounts_by_authorizers_params& args) const +{ + EOS_ASSERT(aqdb.valid(), plugin_config_exception, "Account Queries being accessed when not enabled"); + return aqdb->get_accounts_by_authorizers(args); +} + namespace detail { struct ram_market_exchange_state_t { asset ignore1; diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/account_query_db.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/account_query_db.hpp new file mode 100644 index 00000000000..3fc7e5df0cf --- /dev/null +++ b/plugins/chain_plugin/include/eosio/chain_plugin/account_query_db.hpp @@ -0,0 +1,136 @@ +#pragma once +#include +#include +#include + +namespace eosio::chain_apis { + /** + * This class manages the ephemeral indices and data that provide the `get_accounts_by_authorizers` RPC call + * There is no persistence and the indices/caches are recreated when the class is instantiated based on the + * current state of the chain. + */ + class account_query_db { + public: + + /** + * Instantiate a new account query DB from the given chain controller + * The caller is expected to manage lifetimes such that this controller reference does not go stale + * for the life of the account query DB + * @param chain - controller to read data from + */ + account_query_db( const class eosio::chain::controller& chain ); + ~account_query_db(); + + /** + * Allow moving the account query DB (including by assignment) + */ + account_query_db(account_query_db&&); + account_query_db& operator=(account_query_db&&); + + /** + * Add a transaction trace to the account query DB that has been applied to the contoller even though it may + * not yet be committed to by a block. + * + * @param trace + */ + void cache_transaction_trace( const chain::transaction_trace_ptr& trace ); + + /** + * Add a block to the account query DB, committing all the cached traces it represents and dumping any + * uncommitted traces. + * @param block + */ + void commit_block(const chain::block_state_ptr& block ); + + /** + * parameters for the get_accounts_by_authorizers RPC + */ + struct get_accounts_by_authorizers_params{ + /** + * This structure is an concrete alias of `chain::permission_level` to facilitate + * specialized rules when transforming to/from variants. + */ + struct permission_level : public chain::permission_level { + }; + + std::vector accounts; + std::vector keys; + }; + + /** + * Result of the get_accounts_by_authorizers RPC + */ + struct get_accounts_by_authorizers_result{ + struct account_result { + chain::name account_name; + chain::name permission_name; + fc::optional authorizing_account; + fc::optional authorizing_key; + chain::weight_type weight; + uint32_t threshold; + }; + + std::vector accounts; + }; + /** + * Given a set of account names and public keys, find all account permission authorities that are, in part or whole, + * satisfiable. + * + * @param args + * @return + */ + get_accounts_by_authorizers_result get_accounts_by_authorizers( const get_accounts_by_authorizers_params& args) const; + + private: + std::unique_ptr _impl; + }; + +} + +namespace fc { + using params = eosio::chain_apis::account_query_db::get_accounts_by_authorizers_params; + /** + * Overloaded to_variant so that permission is only present if it is set + * @param a + * @param v + */ + inline void to_variant(const params::permission_level& a, fc::variant& v) { + if (a.permission.empty()) { + v = a.actor.to_string(); + } else { + v = mutable_variant_object() + ("actor", a.actor.to_string()) + ("permission", a.permission.to_string()); + } + } + + /** + * Overloaded from_variant to allow parsing an account with a permission wildcard (empty) from a string + * instead of an object + * @param v + * @param a + */ + inline void from_variant(const fc::variant& v, params::permission_level& a) { + if (v.is_string()) { + from_variant(v, a.actor); + a.permission = {}; + } else if (v.is_object()) { + const auto& vo = v.get_object(); + if(vo.contains("actor")) + from_variant(vo["actor"], a.actor); + else + EOS_THROW(eosio::chain::invalid_http_request, "Missing Actor field"); + + if(vo.contains("permission") && vo.size() == 2) + from_variant(vo["permission"], a.permission); + else if (vo.size() == 1) + a.permission = {}; + else + EOS_THROW(eosio::chain::invalid_http_request, "Unrecognized fields in account"); + } + } +} + +FC_REFLECT( eosio::chain_apis::account_query_db::get_accounts_by_authorizers_params, (accounts)(keys)) +FC_REFLECT( eosio::chain_apis::account_query_db::get_accounts_by_authorizers_result::account_result, (account_name)(permission_name)(authorizing_account)(authorizing_key)(weight)(threshold)) +FC_REFLECT( eosio::chain_apis::account_query_db::get_accounts_by_authorizers_result, (accounts)) diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 29eab70f502..75725240ef1 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -19,6 +19,8 @@ #include #include +#include + #include #include @@ -72,6 +74,7 @@ double convert_to_type(const string& str, const string& desc); class read_only { const controller& db; + const fc::optional& aqdb; const fc::microseconds abi_serializer_max_time; bool shorten_abi_errors = true; const chain::pbft_controller& pbft_ctrl; @@ -79,8 +82,8 @@ class read_only { public: static const string KEYi64; - read_only(const controller& db, const fc::microseconds& abi_serializer_max_time, const chain::pbft_controller& pbft_ctrl) - : db(db), abi_serializer_max_time(abi_serializer_max_time), pbft_ctrl(pbft_ctrl) {} + read_only(const controller& db, const fc::optional& aqdb, const fc::microseconds& abi_serializer_max_time, const chain::pbft_controller& pbft_ctrl) + : db(db), aqdb(aqdb), abi_serializer_max_time(abi_serializer_max_time), pbft_ctrl(pbft_ctrl) {} void validate() const {} @@ -571,6 +574,10 @@ class read_only { return result; } + using get_accounts_by_authorizers_result = account_query_db::get_accounts_by_authorizers_result; + using get_accounts_by_authorizers_params = account_query_db::get_accounts_by_authorizers_params; + get_accounts_by_authorizers_result get_accounts_by_authorizers( const get_accounts_by_authorizers_params& args) const; + chain::symbol extract_core_symbol()const; friend struct resolver_factory; @@ -675,7 +682,7 @@ class chain_plugin : public plugin { void plugin_startup(); void plugin_shutdown(); - chain_apis::read_only get_read_only_api() const { return chain_apis::read_only(chain(), get_abi_serializer_max_time(), pbft_ctrl()); } + chain_apis::read_only get_read_only_api() const; chain_apis::read_write get_read_write_api() { return chain_apis::read_write(chain(), get_abi_serializer_max_time()); } void accept_block( const chain::signed_block_ptr& block ); @@ -715,6 +722,8 @@ class chain_plugin : public plugin { void handle_guard_exception(const chain::guard_exception& e) const; static void handle_db_exhaustion(); + + bool account_queries_enabled() const; private: void log_guard_exception(const chain::guard_exception& e) const; @@ -777,3 +786,4 @@ FC_REFLECT( eosio::chain_apis::read_only::abi_bin_to_json_params, (code)(action) FC_REFLECT( eosio::chain_apis::read_only::abi_bin_to_json_result, (args) ) FC_REFLECT( eosio::chain_apis::read_only::get_required_keys_params, (transaction)(available_keys) ) FC_REFLECT( eosio::chain_apis::read_only::get_required_keys_result, (required_keys) ) + diff --git a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp index d89ee72ffc8..6aecda7b7a7 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp @@ -86,6 +86,11 @@ namespace eosio { add_handler(call.first, call.second); } + void add_async_api(const api_description& api) { + for (const auto& call : api) + add_handler(call.first, call.second); + } + // standard exception handling for api handlers static void handle_exception( const char *api_name, const char *call_name, const string& body, url_response_callback cb ); diff --git a/tests/chain_plugin_tests.cpp b/tests/chain_plugin_tests.cpp index 038ac905211..5315603ec67 100644 --- a/tests/chain_plugin_tests.cpp +++ b/tests/chain_plugin_tests.cpp @@ -89,7 +89,7 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, TESTER ) try { char headnumstr[20]; sprintf(headnumstr, "%d", headnum); chain_apis::read_only::get_block_params param{headnumstr}; - chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX), *(this->pbft_ctrl)); + chain_apis::read_only plugin(*(this->control), {}, fc::microseconds(INT_MAX), *(this->pbft_ctrl)); // block should be decoded successfully std::string block_str = json::to_pretty_string(plugin.get_block(param)); diff --git a/tests/get_table_tests.cpp b/tests/get_table_tests.cpp index 1a202e5113e..443e2d768c6 100644 --- a/tests/get_table_tests.cpp +++ b/tests/get_table_tests.cpp @@ -89,7 +89,7 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { produce_blocks(1); // iterate over scope - eosio::chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX), *(this->pbft_ctrl)); + eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds(INT_MAX), *(this->pbft_ctrl)); eosio::chain_apis::read_only::get_table_by_scope_params param{N(eosio.token), N(accounts), "inita", "", 10}; eosio::chain_apis::read_only::get_table_by_scope_result result = plugin.read_only::get_table_by_scope(param); @@ -194,7 +194,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { produce_blocks(1); // get table: normal case - eosio::chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX), *(this->pbft_ctrl)); + eosio::chain_apis::read_only plugin(*(this->control), {} fc::microseconds(INT_MAX), *(this->pbft_ctrl)); eosio::chain_apis::read_only::get_table_rows_params p; p.code = N(eosio.token); p.scope = "inita"; @@ -363,7 +363,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { produce_blocks(1); // get table: normal case - eosio::chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX), *(this->pbft_ctrl)); + eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds(INT_MAX), *(this->pbft_ctrl)); eosio::chain_apis::read_only::get_table_rows_params p; p.code = N(eosio); p.scope = "eosio"; From 9397c0c3cc5bcb717fac78ca984006a6e844c7a5 Mon Sep 17 00:00:00 2001 From: Thaipanda Date: Fri, 12 Jun 2020 11:50:16 +0800 Subject: [PATCH 24/25] update the version --- CMakeLists.txt | 2 +- Docker/README.md | 4 ++-- README.md | 2 +- README_CN.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c20d9d03540..2cf514a4764 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 3) set(VERSION_MINOR 0) -set(VERSION_PATCH 8) +set(VERSION_PATCH 9) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/Docker/README.md b/Docker/README.md index be937e39857..8f2af84b6cd 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.8 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.9 tag, you could do the following: ```bash -docker build -t boscore/bos:v3.0.8 --build-arg branch=v3.0.8 . +docker build -t boscore/bos:v3.0.9 --build-arg branch=v3.0.9 . ``` diff --git a/README.md b/README.md index 90fa46654ef..13bf0ec6153 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BOSCore - Blockchain financial center building a trusted business ecosystem. -## BOSCore Version: v3.0.8 +## BOSCore Version: v3.0.9 ### Basic EOSIO Version: v2.0 (support REX & EOSVM, llvm v90) # Background diff --git a/README_CN.md b/README_CN.md index acad87eeda2..4916a441857 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@ # BOSCore - 区块链自由港,构建可信商业生态。 -## BOSCore Version: v3.0.8 +## BOSCore Version: v3.0.9 ### Basic EOSIO Version: v2.0 (support REX & EOSVM, llvm v90) # 背景 From 57aa42adea5c62254626d7670ed404e78df93a99 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Fri, 12 Jun 2020 18:39:31 +0800 Subject: [PATCH 25/25] Fix: test build bug --- tests/get_table_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/get_table_tests.cpp b/tests/get_table_tests.cpp index 443e2d768c6..be1d6949268 100644 --- a/tests/get_table_tests.cpp +++ b/tests/get_table_tests.cpp @@ -194,7 +194,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { produce_blocks(1); // get table: normal case - eosio::chain_apis::read_only plugin(*(this->control), {} fc::microseconds(INT_MAX), *(this->pbft_ctrl)); + eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds(INT_MAX), *(this->pbft_ctrl)); eosio::chain_apis::read_only::get_table_rows_params p; p.code = N(eosio.token); p.scope = "inita";