Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get_code_hash #12

Merged
merged 6 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,27 @@ bool apply_context::is_account( const account_name& account )const {
return nullptr != db.find<account_object,by_name>( 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_metadata_object,by_name>(account);
if(!obj || obj->code_hash == fc::sha256{}) {
swatanabe marked this conversation as resolved.
Show resolved Hide resolved
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 ) {
Expand Down
8 changes: 8 additions & 0 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ struct controller_impl {
set_activation_handler<builtin_protocol_feature_t::wtmsig_block_signatures>();
set_activation_handler<builtin_protocol_feature_t::action_return_value>();
set_activation_handler<builtin_protocol_feature_t::configurable_wasm_limits>();
set_activation_handler<builtin_protocol_feature_t::get_code_hash>();

self.irreversible_block.connect([this](const block_state_ptr& bsp) {
wasmif.current_lib(bsp->block_num);
Expand Down Expand Up @@ -3419,6 +3420,13 @@ void controller_impl::on_activation<builtin_protocol_feature_t::configurable_was
} );
}

template<>
void controller_impl::on_activation<builtin_protocol_feature_t::get_code_hash>() {
db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "get_code_hash" );
} );
}

/// End of protocol feature activation handlers

} } /// eosio::chain
3 changes: 3 additions & 0 deletions libraries/chain/include/eosio/chain/apply_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
32 changes: 26 additions & 6 deletions libraries/chain/include/eosio/chain/webassembly/interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
swatanabe marked this conversation as resolved.
Show resolved Hide resolved
*/
bool get_code_hash(
account_name account,
vm::argument_proxy<uint64_t*> code_sequence,
vm::argument_proxy<fc::sha256*> code_hash,
vm::argument_proxy<uint8_t*> vm_type,
vm::argument_proxy<uint8_t*> vm_version) const;
swatanabe marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns the time in microseconds from 1970 of the current block.
*
Expand Down Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ namespace eosio { namespace chain { namespace webassembly {
struct is_whitelisted_type<vm::argument_proxy<T*, 0>> {
static constexpr bool value = is_wasm_arithmetic_type_v<std::remove_const_t<T>>;
};
template <>
struct is_whitelisted_type<vm::argument_proxy<digest_type*, 0>> {
static constexpr bool value = true;
};
}

template <typename T>
Expand All @@ -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<std::uintptr_t>(s1.data());
std::uintptr_t a_end = a_begin + s1.size_bytes();

std::uintptr_t b_begin = reinterpret_cast<std::uintptr_t>(s2.data());
std::uintptr_t b_end = b_begin + s2.size_bytes();

Expand All @@ -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;
Expand Down Expand Up @@ -120,8 +124,8 @@ namespace eosio { namespace chain { namespace webassembly {

namespace detail {
template<typename T>
vm::span<const char> to_span(const vm::argument_proxy<T*>& val) {
return {static_cast<const char*>(val.get_original_pointer()), sizeof(T)};
vm::span<const char> to_span(const vm::argument_proxy<T*>& val) {
return {static_cast<const char*>(val.get_original_pointer()), sizeof(T)};
}

template<typename T>
Expand Down
11 changes: 11 additions & 0 deletions libraries/chain/protocol_feature_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<digest_type>(),
// 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.
*/
{}
} )
Expand Down
10 changes: 10 additions & 0 deletions libraries/chain/webassembly/authorization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t*> code_sequence,
vm::argument_proxy<fc::sha256*> code_hash,
vm::argument_proxy<uint8_t*> vm_type,
vm::argument_proxy<uint8_t*> vm_version
) const {
return context.get_code_hash( account, code_sequence, code_hash, vm_type, vm_version );
}
}}} // ns eosio::chain::webassembly
3 changes: 2 additions & 1 deletion libraries/chain/webassembly/runtimes/eos-vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_runtime<Impl>::instan
template class eos_vm_runtime<eosio::vm::interpreter>;
template class eos_vm_runtime<eosio::vm::jit>;

}
}

template <auto HostFunction, typename... Preconditions>
struct host_function_registrator {
Expand Down Expand Up @@ -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);
Expand Down
81 changes: 75 additions & 6 deletions unittests/api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down Expand Up @@ -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 );

Expand All @@ -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<account_metadata_object,by_name>(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<permission_level>{{"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<uint8_t>{});
check("test"_n, false, 3);
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_SUITE_END()