From 2a4481ff939649646bbdfb24e068b50a93b2c104 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 18 Jan 2022 11:22:35 -0500 Subject: [PATCH 1/5] get_code_hash --- libraries/chain/apply_context.cpp | 21 ++++++++++++ libraries/chain/controller.cpp | 8 +++++ .../include/eosio/chain/apply_context.hpp | 3 ++ .../eosio/chain/protocol_feature_manager.hpp | 1 + .../eos-vm-oc/intrinsic_mapping.hpp | 3 +- .../eosio/chain/webassembly/interface.hpp | 32 +++++++++++++++---- .../eosio/chain/webassembly/preconditions.hpp | 12 ++++--- libraries/chain/protocol_feature_manager.cpp | 11 +++++++ libraries/chain/webassembly/authorization.cpp | 10 ++++++ .../chain/webassembly/runtimes/eos-vm.cpp | 3 +- 10 files changed, 92 insertions(+), 12 deletions(-) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index d5991dc0ff6..598bb4549d3 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -207,6 +207,27 @@ bool apply_context::is_account( const account_name& account )const { return nullptr != db.find( account ); } +bool apply_context::get_code_hash( + account_name account, uint64_t* code_sequence, fc::sha256* code_hash, uint8_t* vm_type, uint8_t* vm_version) const { + + auto obj = db.find(account); + if(!obj || obj->code_hash == fc::sha256{}) { + if(obj) + *code_sequence = obj->code_sequence; + else + *code_sequence = 0; + *code_hash = {}; + *vm_type = 0; + *vm_version = 0; + return false; + } + *code_sequence = obj->code_sequence; + *code_hash = obj->code_hash; + *vm_type = obj->vm_type; + *vm_version = obj->vm_version; + return true; +} + 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 ) { diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 1a23d3ecce0..ff105ea02e9 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -330,6 +330,7 @@ struct controller_impl { set_activation_handler(); set_activation_handler(); set_activation_handler(); + set_activation_handler(); self.irreversible_block.connect([this](const block_state_ptr& bsp) { wasmif.current_lib(bsp->block_num); @@ -3419,6 +3420,13 @@ void controller_impl::on_activation +void controller_impl::on_activation() { + db.modify( db.get(), [&]( auto& ps ) { + add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "get_code_hash" ); + } ); +} + /// End of protocol feature activation handlers } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index e8fbc403f20..bc3dc7181fd 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -487,6 +487,9 @@ class apply_context { */ bool is_account(const account_name& account)const; + bool get_code_hash( + account_name account, uint64_t* code_sequence, fc::sha256* code_hash, uint8_t* vm_type, uint8_t* vm_version) const; + /** * Requires that the current action be delivered to account */ diff --git a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp index 6233b5a20a0..e8387b1c994 100644 --- a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp +++ b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp @@ -25,6 +25,7 @@ enum class builtin_protocol_feature_t : uint32_t { wtmsig_block_signatures, action_return_value, configurable_wasm_limits, + get_code_hash, }; struct protocol_feature_subjective_restrictions { diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp index 36c0c09d4e3..684d8b3d3d2 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp @@ -256,7 +256,8 @@ inline constexpr auto get_intrinsic_table() { "eosio_injection._eosio_ui64_to_f64", "env.set_action_return_value", "env.get_wasm_parameters_packed", - "env.set_wasm_parameters_packed" + "env.set_wasm_parameters_packed", + "env.get_code_hash" ); } inline constexpr std::size_t find_intrinsic_index(std::string_view hf) { diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index 06277d53e2e..c376d426d05 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -472,6 +472,26 @@ namespace webassembly { */ bool is_account(account_name account) const; + /** + * Retrieves the code hash for an account, if any. + * + * @ingroup authorization + * @param account - name of the account to check. + * @param code_sequence - Receives the number of times code has changed, or 0 if account does not exist. + * @param code_hash - Receives the code_hash, or empty if code not set or account does not exist. + * @param vm_type - Receives the vm type, or 0 if code not set or account does not exist. + * @param vm_version - Receives the vm version, or 0 if code not set or account does not exist. + * + * @return true if the account exists and has code. + * @return false otherwise. + */ + bool get_code_hash( + account_name account, + vm::argument_proxy code_sequence, + vm::argument_proxy code_hash, + vm::argument_proxy vm_type, + vm::argument_proxy vm_version) const; + /** * Returns the time in microseconds from 1970 of the current block. * @@ -698,13 +718,13 @@ namespace webassembly { * @param itr - iterator to the table row containing the record to update. * @param payer - the account that pays for the storage costs. * @param buffer - new updated record. - * - * @remark This function does not allow changing the primary key of a - * table row. The serialized data that is stored in the table row of a - * primary table may include a primary key and that primary key value - * could be changed by the contract calling the db_update_i64 intrinsic; + * + * @remark This function does not allow changing the primary key of a + * table row. The serialized data that is stored in the table row of a + * primary table may include a primary key and that primary key value + * could be changed by the contract calling the db_update_i64 intrinsic; * but that does not change the actual primary key of the table row. - * + * * @pre `itr` points to an existing table row in the table. * @post the record contained in the table row pointed to by `itr` is replaced with the new updated record. */ diff --git a/libraries/chain/include/eosio/chain/webassembly/preconditions.hpp b/libraries/chain/include/eosio/chain/webassembly/preconditions.hpp index 3416557904b..f37635237b5 100644 --- a/libraries/chain/include/eosio/chain/webassembly/preconditions.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/preconditions.hpp @@ -55,6 +55,10 @@ namespace eosio { namespace chain { namespace webassembly { struct is_whitelisted_type> { static constexpr bool value = is_wasm_arithmetic_type_v>; }; + template <> + struct is_whitelisted_type> { + static constexpr bool value = true; + }; } template @@ -70,7 +74,7 @@ namespace eosio { namespace chain { namespace webassembly { inline static bool is_aliasing(const T& s1, const U& s2) { std::uintptr_t a_begin = reinterpret_cast(s1.data()); std::uintptr_t a_end = a_begin + s1.size_bytes(); - + std::uintptr_t b_begin = reinterpret_cast(s2.data()); std::uintptr_t b_end = b_begin + s2.size_bytes(); @@ -86,7 +90,7 @@ namespace eosio { namespace chain { namespace webassembly { // Intersection interval is [b_begin, std::min(a_end, b_end)). - if (std::min(a_end, b_end) == b_begin) // intersection interval has zero size + if (std::min(a_end, b_end) == b_begin) // intersection interval has zero size return false; return true; @@ -120,8 +124,8 @@ namespace eosio { namespace chain { namespace webassembly { namespace detail { template - vm::span to_span(const vm::argument_proxy& val) { - return {static_cast(val.get_original_pointer()), sizeof(T)}; + vm::span to_span(const vm::argument_proxy& val) { + return {static_cast(val.get_original_pointer()), sizeof(T)}; } template diff --git a/libraries/chain/protocol_feature_manager.cpp b/libraries/chain/protocol_feature_manager.cpp index 67cb61d20ad..0af6f30eda8 100644 --- a/libraries/chain/protocol_feature_manager.cpp +++ b/libraries/chain/protocol_feature_manager.cpp @@ -207,6 +207,17 @@ Builtin protocol feature: CONFIGURABLE_WASM_LIMITS2 Allows privileged contracts to set the constraints on WebAssembly code. Includes the behavior of GET_WASM_PARAMETERS_PACKED_FIX and also removes an inadvertent restriction on custom sections. +*/ + {} + } ) + ( builtin_protocol_feature_t::get_code_hash, builtin_protocol_feature_spec{ + "GET_CODE_HASH", + fc::variant("d2596697fed14a0840013647b99045022ae6a885089f35a7e78da7a43ad76ed4").as(), + // SHA256 hash of the raw message below within the comment delimiters (do not modify message below). +/* +Builtin protocol feature: GET_CODE_HASH + +Enables new `get_code_hash` intrinsic which gets the current code hash of an account. */ {} } ) diff --git a/libraries/chain/webassembly/authorization.cpp b/libraries/chain/webassembly/authorization.cpp index ff700583878..a6fe884e1c6 100644 --- a/libraries/chain/webassembly/authorization.cpp +++ b/libraries/chain/webassembly/authorization.cpp @@ -22,4 +22,14 @@ namespace eosio { namespace chain { namespace webassembly { bool interface::is_account( account_name account ) const { return context.is_account( account ); } + + bool interface::get_code_hash( + account_name account, + vm::argument_proxy code_sequence, + vm::argument_proxy code_hash, + vm::argument_proxy vm_type, + vm::argument_proxy vm_version + ) const { + return context.get_code_hash( account, code_sequence, code_hash, vm_type, vm_version ); + } }}} // ns eosio::chain::webassembly diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index ece6041a658..43a2429e235 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -195,7 +195,7 @@ std::unique_ptr eos_vm_runtime::instan template class eos_vm_runtime; template class eos_vm_runtime; -} +} template struct host_function_registrator { @@ -356,6 +356,7 @@ REGISTER_HOST_FUNCTION(require_auth2); REGISTER_HOST_FUNCTION(has_auth); REGISTER_HOST_FUNCTION(require_recipient); REGISTER_HOST_FUNCTION(is_account); +REGISTER_HOST_FUNCTION(get_code_hash); // system api REGISTER_HOST_FUNCTION(current_time); From bcb0def7aacdaaf268c752eebb867ee87c8532b3 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 18 Jan 2022 14:19:59 -0500 Subject: [PATCH 2/5] get_code_hash tests --- unittests/api_tests.cpp | 81 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 6edbb9d2a63..7ae2b0d7c6f 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -1230,7 +1230,7 @@ BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit_failure) { try { } ); CALL_TEST_FUNCTION(chain, "test_transaction", "send_deferred_transaction_4k_action", {} ); BOOST_CHECK(!trace); - BOOST_CHECK_EXCEPTION(chain.produce_block( fc::seconds(2) ), fc::exception, + BOOST_CHECK_EXCEPTION(chain.produce_block( fc::seconds(2) ), fc::exception, [](const fc::exception& e) { return expect_assert_message(e, "inline action too big for nonprivileged account"); } @@ -3062,8 +3062,8 @@ BOOST_AUTO_TEST_CASE(action_results_tests) { try { t.set_code( config::system_account_name, contracts::action_results_wasm() ); t.produce_blocks(1); call_autoresret_and_check( config::system_account_name, - config::system_account_name, - "retmaxlim"_n, + config::system_account_name, + "retmaxlim"_n, [&]( const transaction_trace_ptr& res ) { BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); @@ -3078,13 +3078,82 @@ BOOST_AUTO_TEST_CASE(action_results_tests) { try { expected_vec.end() ); } ); t.produce_blocks(1); - BOOST_REQUIRE_THROW(call_autoresret_and_check( config::system_account_name, - config::system_account_name, - "setliminv"_n, + BOOST_REQUIRE_THROW(call_autoresret_and_check( config::system_account_name, + config::system_account_name, + "setliminv"_n, [&]( auto res ) {}), action_validate_exception); } FC_LOG_AND_RETHROW() } #endif +static const char get_code_hash_wast[] = R"=====( +(module + (import "env" "get_code_hash" (func $get_code_hash (param i64 i32 i32 i32 i32) (result i32))) + (import "env" "prints_l" (func $prints_l (param i32 i32))) + (import "env" "printui" (func $printui (param i64))) + (import "env" "printhex" (func $printhex (param i32 i32))) + (memory $0 32) + (data (i32.const 4) ":") + (data (i32.const 8) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (call $printui (i64.extend_u/i32 + (call $get_code_hash + (get_local $2) + (i32.const 8) + (i32.const 16) + (i32.const 48) + (i32.const 49) + ) + )) + (call $prints_l (i32.const 4) (i32.const 1)) + (call $printui (i64.load offset=8 (i32.const 0))) + (call $prints_l (i32.const 4) (i32.const 1)) + (call $printhex (i32.const 16) (i32.const 32)) + (call $prints_l (i32.const 4) (i32.const 1)) + (call $printui (i64.load8_u offset=48 (i32.const 0))) + (call $prints_l (i32.const 4) (i32.const 1)) + (call $printui (i64.load8_u offset=49 (i32.const 0))) + ) +) +)====="; + +BOOST_AUTO_TEST_CASE(get_code_hash_tests) { try { + TESTER t; + t.produce_blocks(2); + t.create_account("gethash"_n); + t.create_account("test"_n); + t.set_code("gethash"_n, get_code_hash_wast); + t.produce_blocks(1); + + auto check = [&](account_name acc, bool expected_ret, uint64_t expected_seq) { + fc::sha256 expected_code_hash; + auto obj = t.control->db().find(acc); + if(obj) + expected_code_hash = obj->code_hash; + auto expected = std::to_string(expected_ret) + ":" + std::to_string(expected_seq) + + ":" + expected_code_hash.str() + ":0:0"; + + signed_transaction trx; + trx.actions.emplace_back(vector{{"gethash"_n, config::active_name}}, "gethash"_n, acc, bytes{}); + t.set_transaction_headers(trx, t.DEFAULT_EXPIRATION_DELTA); + trx.sign(t.get_private_key("gethash"_n, "active"), t.control->get_chain_id()); + auto tx_trace = t.push_transaction(trx); + BOOST_CHECK_EQUAL(tx_trace->receipt->status, transaction_receipt::executed); + BOOST_REQUIRE(tx_trace->action_traces.front().console == expected); + t.produce_block(); + }; + + check("gethash"_n, true, 1); + check("nonexisting"_n, false, 0); + check("test"_n, false, 0); + t.set_code("test"_n, contracts::test_api_wasm()); + check("test"_n, true, 1); + t.set_code("test"_n, get_code_hash_wast); + check("test"_n, true, 2); + t.set_code("test"_n, std::vector{}); + check("test"_n, false, 3); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() From 8c0439bc1d19670e03c76657e0a48be2772399d4 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 18 Jan 2022 16:25:49 -0500 Subject: [PATCH 3/5] get_code_hash: single output --- libraries/chain/apply_context.cpp | 27 +++++++++--------- .../include/eosio/chain/apply_context.hpp | 4 +-- .../eosio/chain/webassembly/interface.hpp | 26 +++++++++-------- libraries/chain/webassembly/authorization.cpp | 28 +++++++++++++++---- unittests/api_tests.cpp | 23 ++++++++------- 5 files changed, 63 insertions(+), 45 deletions(-) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 598bb4549d3..dda385e33e9 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -207,25 +207,24 @@ bool apply_context::is_account( const account_name& account )const { return nullptr != db.find( account ); } -bool apply_context::get_code_hash( - account_name account, uint64_t* code_sequence, fc::sha256* code_hash, uint8_t* vm_type, uint8_t* vm_version) const { +void apply_context::get_code_hash( + account_name account, uint64_t& code_sequence, fc::sha256& code_hash, uint8_t& vm_type, uint8_t& vm_version) const { auto obj = db.find(account); if(!obj || obj->code_hash == fc::sha256{}) { if(obj) - *code_sequence = obj->code_sequence; + code_sequence = obj->code_sequence; else - *code_sequence = 0; - *code_hash = {}; - *vm_type = 0; - *vm_version = 0; - return false; - } - *code_sequence = obj->code_sequence; - *code_hash = obj->code_hash; - *vm_type = obj->vm_type; - *vm_version = obj->vm_version; - return true; + code_sequence = 0; + code_hash = {}; + vm_type = 0; + vm_version = 0; + } else { + code_sequence = obj->code_sequence; + code_hash = obj->code_hash; + vm_type = obj->vm_type; + vm_version = obj->vm_version; + } } void apply_context::require_authorization( const account_name& account ) { diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index bc3dc7181fd..9232bd07d83 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -487,8 +487,8 @@ class apply_context { */ bool is_account(const account_name& account)const; - bool get_code_hash( - account_name account, uint64_t* code_sequence, fc::sha256* code_hash, uint8_t* vm_type, uint8_t* vm_version) const; + void get_code_hash( + account_name account, uint64_t& code_sequence, fc::sha256& code_hash, uint8_t& vm_type, uint8_t& vm_version) const; /** * Requires that the current action be delivered to account diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index c376d426d05..37c2534b816 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -475,22 +475,26 @@ namespace webassembly { /** * Retrieves the code hash for an account, if any. * + * The result is the packed version of this struct: + * + * struct { + * uint64_t code_sequence; + * fc::sha256 code_hash; + * uint8_t vm_type; + * uint8_t vm_version; + * } result; + * * @ingroup authorization * @param account - name of the account to check. - * @param code_sequence - Receives the number of times code has changed, or 0 if account does not exist. - * @param code_hash - Receives the code_hash, or empty if code not set or account does not exist. - * @param vm_type - Receives the vm type, or 0 if code not set or account does not exist. - * @param vm_version - Receives the vm version, or 0 if code not set or account does not exist. + * @param struct_version - must be 0. + * @param packed_result - receives the packed result. * - * @return true if the account exists and has code. - * @return false otherwise. + * @return the size of the packed result. */ - bool get_code_hash( + uint32_t get_code_hash( account_name account, - vm::argument_proxy code_sequence, - vm::argument_proxy code_hash, - vm::argument_proxy vm_type, - vm::argument_proxy vm_version) const; + uint32_t struct_version, + vm::span packed_result) const; /** * Returns the time in microseconds from 1970 of the current block. diff --git a/libraries/chain/webassembly/authorization.cpp b/libraries/chain/webassembly/authorization.cpp index a6fe884e1c6..9d482169b2d 100644 --- a/libraries/chain/webassembly/authorization.cpp +++ b/libraries/chain/webassembly/authorization.cpp @@ -23,13 +23,29 @@ namespace eosio { namespace chain { namespace webassembly { return context.is_account( account ); } - bool interface::get_code_hash( + struct get_code_hash_result { + uint64_t code_sequence; + fc::sha256 code_hash; + uint8_t vm_type; + uint8_t vm_version; + }; + + uint32_t interface::get_code_hash( account_name account, - vm::argument_proxy code_sequence, - vm::argument_proxy code_hash, - vm::argument_proxy vm_type, - vm::argument_proxy vm_version + uint32_t struct_version, + vm::span packed_result ) const { - return context.get_code_hash( account, code_sequence, code_hash, vm_type, vm_version ); + EOS_ASSERT(struct_version == 0, contract_exception, "get_code_hash with unsupported struct_version"); + get_code_hash_result result; + context.get_code_hash(account, result.code_sequence, result.code_hash, result.vm_type, result.vm_version); + + auto s = fc::raw::pack_size(result); + if (s <= packed_result.size()) { + datastream ds(packed_result.data(), s); + fc::raw::pack(ds, result); + } + return s; } }}} // ns eosio::chain::webassembly + +FC_REFLECT(eosio::chain::webassembly::get_code_hash_result, (code_sequence)(code_hash)(vm_type)(vm_version)) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 7ae2b0d7c6f..37670ad2f04 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -3089,7 +3089,7 @@ BOOST_AUTO_TEST_CASE(action_results_tests) { try { static const char get_code_hash_wast[] = R"=====( (module - (import "env" "get_code_hash" (func $get_code_hash (param i64 i32 i32 i32 i32) (result i32))) + (import "env" "get_code_hash" (func $get_code_hash (param i64 i32 i32 i32) (result i32))) (import "env" "prints_l" (func $prints_l (param i32 i32))) (import "env" "printui" (func $printui (param i64))) (import "env" "printhex" (func $printhex (param i32 i32))) @@ -3101,10 +3101,9 @@ static const char get_code_hash_wast[] = R"=====( (call $printui (i64.extend_u/i32 (call $get_code_hash (get_local $2) + (i32.const 0) (i32.const 8) - (i32.const 16) - (i32.const 48) - (i32.const 49) + (i32.const 42) ) )) (call $prints_l (i32.const 4) (i32.const 1)) @@ -3127,12 +3126,12 @@ BOOST_AUTO_TEST_CASE(get_code_hash_tests) { try { t.set_code("gethash"_n, get_code_hash_wast); t.produce_blocks(1); - auto check = [&](account_name acc, bool expected_ret, uint64_t expected_seq) { + auto check = [&](account_name acc, uint64_t expected_seq) { fc::sha256 expected_code_hash; auto obj = t.control->db().find(acc); if(obj) expected_code_hash = obj->code_hash; - auto expected = std::to_string(expected_ret) + ":" + std::to_string(expected_seq) + + auto expected = "42:" + std::to_string(expected_seq) + ":" + expected_code_hash.str() + ":0:0"; signed_transaction trx; @@ -3145,15 +3144,15 @@ BOOST_AUTO_TEST_CASE(get_code_hash_tests) { try { t.produce_block(); }; - check("gethash"_n, true, 1); - check("nonexisting"_n, false, 0); - check("test"_n, false, 0); + check("gethash"_n, 1); + check("nonexisting"_n, 0); + check("test"_n, 0); t.set_code("test"_n, contracts::test_api_wasm()); - check("test"_n, true, 1); + check("test"_n, 1); t.set_code("test"_n, get_code_hash_wast); - check("test"_n, true, 2); + check("test"_n, 2); t.set_code("test"_n, std::vector{}); - check("test"_n, false, 3); + check("test"_n, 3); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END() From e17300ec40d2235edcf49ae68cf0a994e2af2d84 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 18 Jan 2022 16:51:55 -0500 Subject: [PATCH 4/5] no longer used --- .../chain/include/eosio/chain/webassembly/preconditions.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/chain/include/eosio/chain/webassembly/preconditions.hpp b/libraries/chain/include/eosio/chain/webassembly/preconditions.hpp index f37635237b5..93340f7d31c 100644 --- a/libraries/chain/include/eosio/chain/webassembly/preconditions.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/preconditions.hpp @@ -55,10 +55,6 @@ namespace eosio { namespace chain { namespace webassembly { struct is_whitelisted_type> { static constexpr bool value = is_wasm_arithmetic_type_v>; }; - template <> - struct is_whitelisted_type> { - static constexpr bool value = true; - }; } template From bd89c6b8e8160f363a71609c470d35a7b1160941 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 19 Jan 2022 10:12:13 -0500 Subject: [PATCH 5/5] version negotiation --- .../include/eosio/chain/webassembly/interface.hpp | 3 ++- libraries/chain/webassembly/authorization.cpp | 7 ++++--- unittests/api_tests.cpp | 12 +++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index b926a5bede1..d20a2dab147 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -514,6 +514,7 @@ namespace webassembly { * The result is the packed version of this struct: * * struct { + * varuint32 struct_version; * uint64_t code_sequence; * fc::sha256 code_hash; * uint8_t vm_type; @@ -522,7 +523,7 @@ namespace webassembly { * * @ingroup authorization * @param account - name of the account to check. - * @param struct_version - must be 0. + * @param struct_version - use 0. * @param packed_result - receives the packed result. * * @return the size of the packed result. diff --git a/libraries/chain/webassembly/authorization.cpp b/libraries/chain/webassembly/authorization.cpp index 9d482169b2d..43af5cdce6f 100644 --- a/libraries/chain/webassembly/authorization.cpp +++ b/libraries/chain/webassembly/authorization.cpp @@ -24,6 +24,7 @@ namespace eosio { namespace chain { namespace webassembly { } struct get_code_hash_result { + unsigned_int struct_version; uint64_t code_sequence; fc::sha256 code_hash; uint8_t vm_type; @@ -35,8 +36,8 @@ namespace eosio { namespace chain { namespace webassembly { uint32_t struct_version, vm::span packed_result ) const { - EOS_ASSERT(struct_version == 0, contract_exception, "get_code_hash with unsupported struct_version"); - get_code_hash_result result; + struct_version = std::min(uint32_t(0), struct_version); + get_code_hash_result result = {struct_version}; context.get_code_hash(account, result.code_sequence, result.code_hash, result.vm_type, result.vm_version); auto s = fc::raw::pack_size(result); @@ -48,4 +49,4 @@ namespace eosio { namespace chain { namespace webassembly { } }}} // ns eosio::chain::webassembly -FC_REFLECT(eosio::chain::webassembly::get_code_hash_result, (code_sequence)(code_hash)(vm_type)(vm_version)) +FC_REFLECT(eosio::chain::webassembly::get_code_hash_result, (struct_version)(code_sequence)(code_hash)(vm_type)(vm_version)) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index ca51c5ce90d..1bf8c02047f 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -3101,17 +3101,19 @@ static const char get_code_hash_wast[] = R"=====( (get_local $2) (i32.const 0) (i32.const 8) - (i32.const 42) + (i32.const 43) ) )) (call $prints_l (i32.const 4) (i32.const 1)) - (call $printui (i64.load offset=8 (i32.const 0))) + (call $printui (i64.load8_u offset=8 (i32.const 0))) (call $prints_l (i32.const 4) (i32.const 1)) - (call $printhex (i32.const 16) (i32.const 32)) + (call $printui (i64.load offset=9 (i32.const 0))) (call $prints_l (i32.const 4) (i32.const 1)) - (call $printui (i64.load8_u offset=48 (i32.const 0))) + (call $printhex (i32.const 17) (i32.const 32)) (call $prints_l (i32.const 4) (i32.const 1)) (call $printui (i64.load8_u offset=49 (i32.const 0))) + (call $prints_l (i32.const 4) (i32.const 1)) + (call $printui (i64.load8_u offset=50 (i32.const 0))) ) ) )====="; @@ -3129,7 +3131,7 @@ BOOST_AUTO_TEST_CASE(get_code_hash_tests) { try { auto obj = t.control->db().find(acc); if(obj) expected_code_hash = obj->code_hash; - auto expected = "42:" + std::to_string(expected_seq) + + auto expected = "43:0:" + std::to_string(expected_seq) + ":" + expected_code_hash.str() + ":0:0"; signed_transaction trx;