diff --git a/contracts/eosiolib/types.h b/contracts/eosiolib/types.h index eedb5926c6e6de2875d2df03f5eb07f21056f0df..e1fa894f38d8319e9db1625af7e5566848956f93 100644 --- a/contracts/eosiolib/types.h +++ b/contracts/eosiolib/types.h @@ -32,6 +32,9 @@ typedef uint64_t asset_symbol; typedef int64_t share_type; typedef uint16_t weight_type; +/* macro to align/overalign a type to ensure calls to intrinsics with pointers/references are properly aligned */ +#define ALIGNED(X) __attribute__ ((aligned (16))) X + struct public_key { char data[34]; }; @@ -40,15 +43,15 @@ struct signature { uint8_t data[66]; }; -struct checksum256 { +struct ALIGNED(checksum256) { uint8_t hash[32]; }; -struct checksum160 { +struct ALIGNED(checksum160) { uint8_t hash[20]; }; -struct checksum512 { +struct ALIGNED(checksum512) { uint8_t hash[64]; }; diff --git a/contracts/test_api/test_action.cpp b/contracts/test_api/test_action.cpp index 123582a2a33bfed8be4a8e14f9183924af70f72d..d1b37ec7d7bc564ab8fac854793a7cc7b1cbee0f 100644 --- a/contracts/test_api/test_action.cpp +++ b/contracts/test_api/test_action.cpp @@ -12,8 +12,8 @@ #include #include #include - #include "test_api.hpp" + void test_action::read_action_normal() { char buffer[100]; diff --git a/contracts/tic_tac_toe/tic_tac_toe.cpp b/contracts/tic_tac_toe/tic_tac_toe.cpp index e09c710263ec769bb3cfe2cb905c59bb7e67146c..ed183b39e57cf0b3ee5ded22376fbf101a9aaa9d 100644 --- a/contracts/tic_tac_toe/tic_tac_toe.cpp +++ b/contracts/tic_tac_toe/tic_tac_toe.cpp @@ -41,9 +41,9 @@ struct impl { (current_game.board[1] == current_game.board[4] && current_game.board[4] == current_game.board[7]) || (current_game.board[2] == current_game.board[4] && current_game.board[4] == current_game.board[6]) || (current_game.board[3] == current_game.board[4] && current_game.board[4] == current_game.board[5])) { - // - | - | x x | - | - - | - | - - | x | - - // - | x | - - | x | - x | x | x - | x | - - // x | - | - - | - | x - | - | - - | x | - + // x | - | - - | x | - - | - | x - | - | - + // - | x | - - | x | - - | x | - x | x | x + // - | - | x - | x | - x | - | - - | - | - if (current_game.board[4] == 1) { return current_game.host; } else if (current_game.board[4] == 2) { @@ -61,9 +61,9 @@ struct impl { } } else if ((current_game.board[2] == current_game.board[5] && current_game.board[5] == current_game.board[8]) || (current_game.board[6] == current_game.board[7] && current_game.board[7] == current_game.board[8])) { - // - | - | - - | - | x - // - | - | - - | - | x - // x | x | x - | - | x + // - | - | x - | - | - + // - | - | x - | - | - + // - | - | x x | x | x if (current_game.board[8] == 1) { return current_game.host; } else if (current_game.board[8] == 2) { diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 53acd0c24cd43d8bcaa49d98afd8acf7f6b8af22..96e84877926e6476e2b9df32497514f6577187f7 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -311,6 +311,11 @@ void apply_context::cancel_deferred( const uint128_t& sender_id ) { results.deferred_transaction_requests.push_back(deferred_reference(receiver, sender_id)); } +void apply_context::add_cpu_usage( const uint64_t usage ) { + // TODO for now just increase the usage, in the future check against some limit + _cpu_usage += usage; +} + const contracts::table_id_object* apply_context::find_table( name code, name scope, name table ) { require_read_lock(code, scope); return db.find(boost::make_tuple(code, scope, table)); diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index daa82f81355583619142bd1845f97d4f0ed0a148..34afaf2f13fc9f4216154de77a533a8161068e18 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -587,6 +587,8 @@ class apply_context { generic_index idx_long_double; uint32_t recurse_depth; // how deep inline actions can recurse + + void add_cpu_usage( const uint64_t usage ); private: iterator_cache keyval_cache; diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 2b822bbd96d4b6f659e496cbf3fa887589d6f144..d2cb8e2dbe1f2811924fc7d4c4b61cc18ae26096 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -15,7 +15,7 @@ typedef __uint128_t uint128_t; const static auto default_block_log_dir = "block_log"; const static auto default_shared_memory_dir = "shared_mem"; -const static auto default_shared_memory_size = 1024*1024*1024ll; +const static auto default_shared_memory_size = 32*1024*1024*1024ll; const static uint64_t system_account_name = N(eosio); const static uint64_t nobody_account_name = N(nobody); diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 49b8c75786fc758c5c1c0e3db1f74138c7170dd8..fd58f4ce5c8c24d907b339c7b824833a3f0cf002 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -100,6 +100,7 @@ namespace eosio { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( wallet_locked_exception, eosio::chain::wallet_exception, 3140003, "Locked wallet" ) FC_DECLARE_DERIVED_EXCEPTION( wallet_missing_pub_key_exception, eosio::chain::wallet_exception, 3140004, "Missing public key" ) FC_DECLARE_DERIVED_EXCEPTION( wallet_invalid_password_exception, eosio::chain::wallet_exception, 3140005, "Invalid wallet password" ) + FC_DECLARE_DERIVED_EXCEPTION( wallet_not_available_exception, eosio::chain::wallet_exception, 3140006, "No available wallet" ) FC_DECLARE_DERIVED_EXCEPTION( rate_limiting_state_inconsistent, eosio::chain::rate_limiting_invariant_exception, 3150001, "internal state is no longer consistent" ) FC_DECLARE_DERIVED_EXCEPTION( rate_limiting_overcommitment, eosio::chain::rate_limiting_invariant_exception, 3150002, "chain resource limits are overcommitted" ) diff --git a/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp b/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp index b7f54f94607d4207eee7268c59279bb88080426b..54f27191df9ab0b76b8fe883c78fe8c1b28ab1a7 100644 --- a/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp +++ b/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp @@ -57,8 +57,7 @@ namespace eosio { namespace chain { namespace wasm_injections { if ( exp.kind == IR::ObjectKind::function ) exports++; - next_function_index = module.functions.imports.size() + module.functions.defs.size() + registered_injected.size(); // + exports + registered_injected.size()-1; - ; + next_function_index = module.functions.imports.size() + module.functions.defs.size() + registered_injected.size(); next_actual_index = next_injected_index++; } @@ -75,10 +74,18 @@ namespace eosio { namespace chain { namespace wasm_injections { module.functions.imports.insert( module.functions.imports.begin()+(registered_injected.size()-1), new_import.begin(), new_import.end() ); injected_index_mapping.emplace( index, actual_index ); // shift all exported functions by 1 + bool have_updated_start = false; for ( int i=0; i < module.exports.size(); i++ ) { - if ( module.exports[i].kind == IR::ObjectKind::function ) + if ( module.exports[i].kind == IR::ObjectKind::function ) { + // update the start function + if ( !have_updated_start && module.exports[i].index == module.startFunctionIndex ) { + module.startFunctionIndex++; + have_updated_start = true; + } module.exports[i].index++; + } } + // shift all table entries for call indirect for(TableSegment& ts : module.tableSegments) { for(auto& idx : ts.indices) @@ -90,7 +97,7 @@ namespace eosio { namespace chain { namespace wasm_injections { } } }; - + struct noop_injection_visitor { static void inject( IR::Module& m ); static void initializer(); @@ -189,6 +196,7 @@ namespace eosio { namespace chain { namespace wasm_injections { static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) { wasm_ops::op_types<>::call_t* call_inst = reinterpret_cast::call_t*>(inst); auto mapped_index = injector_utils::injected_index_mapping.find(call_inst->field); + if ( mapped_index != injector_utils::injected_index_mapping.end() ) { call_inst->field = mapped_index->second; } diff --git a/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp b/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp index b90373c50af6eecca04dc40a79dc0edcf0d7faef..9942e8d2b3bbd4e041e7a112e40e1b463ccc5753 100644 --- a/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -196,18 +197,6 @@ constexpr bool is_reference_from_value_v = is_reference_from_value::value; template T convert_literal_to_native(Literal& v); -template<> -inline float64_t convert_literal_to_native(Literal& v) { - auto val = v.getf64(); - return reinterpret_cast(val); -} - -template<> -inline float32_t convert_literal_to_native(Literal& v) { - auto val = v.getf32(); - return reinterpret_cast(val); -} - template<> inline double convert_literal_to_native(Literal& v) { return v.getf64(); @@ -254,15 +243,6 @@ inline auto convert_native_to_literal(const interpreter_interface*, T val) { return Literal(val); } -inline auto convert_native_to_literal(const interpreter_interface*, const float64_t& val) { - return Literal( *((double*)(&val)) ); -} - -inline auto convert_native_to_literal(const interpreter_interface*, const float32_t& val) { - return Literal( *((float*)(&val)) ); -} - - inline auto convert_native_to_literal(const interpreter_interface*, const name &val) { return Literal(val.value); } @@ -472,10 +452,32 @@ struct intrinsic_invoker_impl> { using next_step = intrinsic_invoker_impl>; using then_type = Ret (*)(interpreter_interface*, T *, Inputs..., LiteralList&, int); - template - static Ret translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) { + template + static auto translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) -> std::enable_if_t::value, Ret> { + uint32_t ptr = args.at(offset).geti32(); + T* base = array_ptr_impl(interface, ptr, 1); + if ( reinterpret_cast(base) % alignof(T) != 0 ) { + wlog( "misaligned const pointer" ); + std::remove_const_t copy; + T* copy_ptr = © + memcpy( (void*)copy_ptr, (void*)base, sizeof(T) ); + return Then(interface, copy_ptr, rest..., args, offset - 1); + } + return Then(interface, base, rest..., args, offset - 1); + }; + + template + static auto translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) -> std::enable_if_t::value, Ret> { uint32_t ptr = args.at(offset).geti32(); T* base = array_ptr_impl(interface, ptr, 1); + if ( reinterpret_cast(base) % alignof(T) != 0 ) { + wlog( "misaligned pointer" ); + T copy; + memcpy( (void*)©, (void*)base, sizeof(T) ); + Ret ret = Then(interface, ©, rest..., args, offset - 1); + memcpy( (void*)base, (void*)©, sizeof(T) ); + return ret; + } return Then(interface, base, rest..., args, offset - 1); }; @@ -551,15 +553,40 @@ struct intrinsic_invoker_impl> { using next_step = intrinsic_invoker_impl>; using then_type = Ret (*)(interpreter_interface*, T &, Inputs..., LiteralList&, int); - template - static Ret translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) { + template + static auto translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) -> std::enable_if_t::value, Ret> { + // references cannot be created for null pointers + uint32_t ptr = args.at(offset).geti32(); + FC_ASSERT(ptr != 0); + T* base = array_ptr_impl(interface, ptr, 1); + if ( reinterpret_cast(base) % alignof(T) != 0 ) { + wlog( "misaligned const reference" ); + std::remove_const_t copy; + T* copy_ptr = © + memcpy( (void*)copy_ptr, (void*)base, sizeof(T) ); + return Then(interface, *copy_ptr, rest..., args, offset - 1); + } + return Then(interface, *base, rest..., args, offset - 1); + } + + template + static auto translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) -> std::enable_if_t::value, Ret> { // references cannot be created for null pointers uint32_t ptr = args.at(offset).geti32(); FC_ASSERT(ptr != 0); T* base = array_ptr_impl(interface, ptr, 1); + if ( reinterpret_cast(base) % alignof(T) != 0 ) { + wlog( "misaligned reference" ); + T copy; + memcpy( (void*)©, (void*)base, sizeof(T) ); + Ret ret = Then(interface, copy, rest..., args, offset - 1); + memcpy( (void*)base, (void*)©, sizeof(T) ); + return ret; + } return Then(interface, *base, rest..., args, offset - 1); } + template static const auto fn() { return next_step::template fn>(); diff --git a/libraries/chain/include/eosio/chain/webassembly/wavm.hpp b/libraries/chain/include/eosio/chain/webassembly/wavm.hpp index 35aaaf970bf4a3fc5f52f8d476c5504a7d28eb26..2091aae273631f008d632148b2fa9938de5e0b25 100644 --- a/libraries/chain/include/eosio/chain/webassembly/wavm.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/wavm.hpp @@ -475,9 +475,31 @@ struct intrinsic_invoker_impl, std::tuple, std::tuple>; using then_type = Ret (*)(running_instance_context&, T *, Inputs..., Translated...); - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) { + 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, ptr, 1); + if ( reinterpret_cast(base) % alignof(T) != 0 ) { + 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, ptr, 1); + if ( reinterpret_cast(base) % alignof(T) != 0 ) { + 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...); }; @@ -539,7 +561,6 @@ struct intrinsic_invoker_impl, std::tuple, std::tuple>; using then_type = Ret (*)(running_instance_context &, T &, Inputs..., Translated...); - template - static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) { + 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 + FC_ASSERT(ptr != 0); + MemoryInstance* mem = ctx.memory; + if(!mem || ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem)) + Runtime::causeException(Exception::Cause::accessViolation); + T &base = *(T*)(getMemoryBaseAddress(mem)+ptr); + if ( reinterpret_cast(&base) % alignof(T) != 0 ) { + 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 FC_ASSERT(ptr != 0); MemoryInstance* mem = ctx.memory; if(!mem || ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem)) Runtime::causeException(Exception::Cause::accessViolation); T &base = *(T*)(getMemoryBaseAddress(mem)+ptr); + if ( reinterpret_cast(&base) % alignof(T) != 0 ) { + 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...); } diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 779f983e47c12a7f03d19f7a7dfce7d4e7ae7661..25b88f99cb160f0522d9c4671ecbf8c88fef5403 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -686,7 +686,6 @@ class crypto_api : public context_aware_api { public: explicit crypto_api( apply_context& ctx ) :context_aware_api(ctx,true){} - /** * This method can be optimized out during replay as it has * no possible side effects other than "passing". @@ -738,7 +737,6 @@ class crypto_api : public context_aware_api { FC_ASSERT( result == hash_val, "hash miss match" ); } - void sha1(array_ptr data, size_t datalen, fc::sha1& hash_val) { hash_val = fc::sha1::hash( data, datalen ); } diff --git a/libraries/chain/webassembly/binaryen.cpp b/libraries/chain/webassembly/binaryen.cpp index 750cd65624f147721c0002f8adc5d0ef3c979920..60a590789334be0c33160108a043207a08378a5e 100644 --- a/libraries/chain/webassembly/binaryen.cpp +++ b/libraries/chain/webassembly/binaryen.cpp @@ -43,7 +43,7 @@ class binaryen_instantiated_module : public wasm_instantiated_module_interface { memset(_shared_linear_memory.data, 0, initial_memory_size); //copy back in the initial data memcpy(_shared_linear_memory.data, _initial_memory.data(), _initial_memory.size()); - + //be aware that construction of the ModuleInstance implictly fires the start function ModuleInstance instance(*_module.get(), &local_interface); instance.callExport(Name(entry_point), args); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 4cc464cc5889b6ff22c4c709bfbac229ccc5e1fd..1dd2bee37dfe8342f3486e653e0eb008a5365c69 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -40,6 +40,7 @@ public: time_point genesis_timestamp; uint32_t skip_flags = skip_nothing; bool readonly = false; + uint64_t shared_memory_size; flat_map loaded_checkpoints; fc::optional fork_db; @@ -75,6 +76,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip ("max-deferred-transaction-time", bpo::value()->default_value(20), "Limits the maximum time (in milliseconds) that is allowed a to push deferred transactions at the start of a block") ("wasm-runtime", bpo::value()->value_name("wavm/binaryen"), "Override default WASM runtime") + ("shared-memory-size-mb", bpo::value()->default_value(config::default_shared_memory_size / (1024 * 1024)), "Minimum size MB of database shared memory file") + #warning TODO: rate limiting /*("per-authorized-account-transaction-msg-rate-limit-time-frame-sec", bpo::value()->default_value(default_per_auth_account_time_frame_seconds), "The time frame, in seconds, that the per-authorized-account-transaction-msg-rate-limit is imposed over.") @@ -128,6 +131,9 @@ void chain_plugin::plugin_initialize(const variables_map& options) { else my->block_log_dir = bld; } + if (options.count("shared-memory-size-mb")) { + my->shared_memory_size = options.at("shared-memory-size-mb").as() * 1024 * 1024; + } if (options.at("replay-blockchain").as()) { ilog("Replay requested: wiping database"); @@ -182,6 +188,7 @@ void chain_plugin::plugin_startup() my->chain_config->block_log_dir = my->block_log_dir; my->chain_config->shared_memory_dir = app().data_dir() / default_shared_memory_dir; my->chain_config->read_only = my->readonly; + my->chain_config->shared_memory_size = my->shared_memory_size; my->chain_config->genesis = fc::json::from_file(my->genesis_file).as(); if (my->genesis_timestamp.sec_since_epoch() > 0) { my->chain_config->genesis.initial_timestamp = my->genesis_timestamp; diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index 59248de08f1868d0dcd8a686aa333947bd05cc9b..940ee1e9f0a92ee74164feca63c43c7e2fc2d235 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -15,7 +15,7 @@ namespace eosio { typedef std::chrono::system_clock::duration::rep tstamp; struct handshake_message { - int16_t network_version = 0; ///< derived from git commit hash, not sequential + uint16_t network_version = 0; ///< incremental value above a computed base chain_id_type chain_id; ///< used to identify chain fc::sha256 node_id; ///< used to identify peers and prevent self-connect chain::public_key_type key; ///< authentication key; may be a producer or peer key, or empty diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 3ad383d77228e2da3835afdab1ac2d7ced7c8af8..b14833b2d0ab805b90a67d16c975f97148f049cb 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -177,14 +177,12 @@ namespace eosio { const std::chrono::system_clock::duration peer_authentication_interval{std::chrono::seconds{1}}; ///< Peer clock may be no more than 1 second skewed from our clock, including network latency. - int16_t network_version = 0; bool network_version_match = false; chain_id_type chain_id; fc::sha256 node_id; string user_agent_name; chain_plugin* chain_plug; - bool send_whole_blocks = false; int started_sessions = 0; node_transaction_index local_txns; @@ -271,7 +269,7 @@ namespace eosio { */ chain::signature_type sign_compact(const chain::public_key_type& signer, const fc::sha256& digest) const; - int16_t to_net_version(int16_t v); + uint16_t to_protocol_version(uint16_t v); }; const fc::string logger_name("net_plugin_impl"); @@ -296,8 +294,7 @@ namespace eosio { constexpr auto def_txn_expire_wait = std::chrono::seconds(3); constexpr auto def_resp_expected_wait = std::chrono::seconds(5); constexpr auto def_sync_fetch_span = 100; - constexpr uint32_t def_max_just_send = 0xFFFFFFFF; //1500; // "mtu" * 1 - constexpr auto def_send_whole_blocks = true; + constexpr uint32_t def_max_just_send = 1500; // roughly 1 "mtu" constexpr auto message_header_size = 4; @@ -308,18 +305,21 @@ namespace eosio { * between ajacent commit id values is shown below. * these numbers were found with the following commands on the master branch: * - * git log | grep "^commit" | awk '{print substr($2,4,4)}' | sort -u > sorted.txt + * git log | grep "^commit" | awk '{print substr($2,5,4)}' | sort -u > sorted.txt * rm -f gap.txt; prev=0; for a in $(cat sorted.txt); do echo $prev $((0x$a - 0x$prev)) $a >> gap.txt; prev=$a; done; sort -k2 -n gap.txt | tail * * DO NOT EDIT net_version_base OR net_version_range! */ - constexpr int16_t net_version_base = 0xb1d4; - constexpr int16_t net_version_range = 133; + constexpr uint16_t net_version_base = 0x04b5; + constexpr uint16_t net_version_range = 106; /** * If there is a change to network protocol or behavior, increment net version to identify * the need for compatibility hooks */ - constexpr int16_t net_version = 1; + constexpr uint16_t proto_base = 0; + constexpr uint16_t proto_explicit_sync = 1; + + constexpr uint16_t net_version = proto_explicit_sync; /** * Index by id @@ -449,7 +449,7 @@ namespace eosio { int16_t sent_handshake_count; bool connecting; bool syncing; - bool backwards_compatibility; + uint16_t protocol_version; int write_depth; string peer_addr; unique_ptr response_expected; @@ -457,6 +457,7 @@ namespace eosio { go_away_reason no_retry; block_id_type fork_head; uint32_t fork_head_num; + optional last_req; connection_status get_status()const { connection_status stat; @@ -622,7 +623,7 @@ namespace eosio { const packed_transaction& msg); void rejected_transaction (const packed_transaction& msg); void recv_block (connection_ptr conn, const signed_block_summary& msg); - void recv_transaction(connection_ptr c); + void recv_transaction(connection_ptr c, const transaction_id_type& id); void recv_notice (connection_ptr conn, const notice_message& msg, bool generated); void retry_fetch (connection_ptr conn); @@ -641,14 +642,15 @@ namespace eosio { sent_handshake_count(0), connecting(false), syncing(false), - backwards_compatibility(false), + protocol_version(0), write_depth(0), peer_addr(endpoint), response_expected(), pending_fetch(), no_retry(no_reason), fork_head(), - fork_head_num() + fork_head_num(0), + last_req() { wlog( "created connection to ${n}", ("n", endpoint) ); initialize(); @@ -665,14 +667,15 @@ namespace eosio { sent_handshake_count(0), connecting(true), syncing(false), - backwards_compatibility(false), + protocol_version(0), write_depth(0), peer_addr(), response_expected(), pending_fetch(), no_retry(no_reason), fork_head(), - fork_head_num(0) + fork_head_num(0), + last_req() { wlog( "accepted network connection" ); initialize(); @@ -725,6 +728,9 @@ namespace eosio { flush_queues(); connecting = false; syncing = false; + if( last_req ) { + my_impl->big_msg_master->retry_fetch (shared_from_this()); + } reset(); sent_handshake_count = 0; last_handshake_recv = handshake_message(); @@ -838,8 +844,16 @@ namespace eosio { try { optional b = cc.fetch_block_by_id(blkid); if(b) { - fc_dlog(logger,"found block for id at num ${n}",("n",b->block_num())); - enqueue(*b); + uint32_t bnum = b->block_num(); + bool send_whole = bnum <= cc.last_irreversible_block_num(); + fc_dlog(logger,"found block for id at num ${n}",("n",bnum)); + if (send_whole) { + enqueue(net_message(*b)); + } + else { + signed_block_summary &sbs = *b; + enqueue(net_message(sbs)); + } } else { ilog("fetch block by id returned null, id ${id} on block ${c} of ${s} for ${p}", @@ -1350,14 +1364,14 @@ namespace eosio { if (head < peer_lib) { fc_dlog(logger, "sync check state 1"); // wait for receipt of a notice message before initiating sync - if (c->backwards_compatibility) { + if (c->protocol_version < proto_explicit_sync) { start_sync( c, peer_lib); } return; } if (lib_num > msg.head_num ) { fc_dlog(logger, "sync check state 2"); - if (msg.generation > 1 || !c->backwards_compatibility) { + if (msg.generation > 1 || c->protocol_version > proto_base) { notice_message note; note.known_trx.pending = lib_num; note.known_trx.mode = last_irr_catch_up; @@ -1376,7 +1390,7 @@ namespace eosio { } else { fc_dlog(logger, "sync check state 4"); - if (msg.generation > 1 || !c->backwards_compatibility) { + if (msg.generation > 1 || c->protocol_version > proto_base) { notice_message note; note.known_trx.mode = none; note.known_blocks.mode = catch_up; @@ -1442,7 +1456,7 @@ namespace eosio { ("n", head_num + 1)); last_repeated = 0; sync_last_requested_num = 0; - c->close(); + my_impl->close(c); } return; } @@ -1502,7 +1516,8 @@ namespace eosio { pending_notify.known_blocks.mode = normal; pending_notify.known_blocks.ids.push_back( bid ); pending_notify.known_trx.mode = none; - if (msgsiz > just_send_it_max) { + // skip will be empty if our producer emitted this block so just send it + if (msgsiz > just_send_it_max && skip) { fc_ilog(logger, "block size is ${ms}, sending notify",("ms", msgsiz)); my_impl->send_all(pending_notify, [skip, bid, bnum](connection_ptr c) -> bool { if (c == skip || !c->current()) @@ -1615,22 +1630,30 @@ namespace eosio { void big_msg_manager::recv_block (connection_ptr c, const signed_block_summary& msg) { block_id_type blk_id = msg.id(); uint32_t num = msg.block_num(); + const auto& blkstate = c->blk_state.get().find(blk_id); + if (blkstate != c->blk_state.end()) { + c->blk_state.modify(blkstate, set_is_known); + } + if (c->last_req && + c->last_req->req_blocks.mode != none && + c->last_req->req_blocks.ids.back() == blk_id) { + c->last_req.reset(); + } for (auto ref = req_blks.begin(); ref != req_blks.end(); ++ref) { - if (ref->id != blk_id) - continue; - bool is_retry = ref->local_retry; - req_blks.erase(ref); - fc_dlog(logger, "received a requested block"); + if (ref->id == blk_id) { + bool is_retry = ref->local_retry; + req_blks.erase(ref); + fc_dlog(logger, "received a requested block"); - if (is_retry) { - bcast_block(msg); - } - else { - notice_message note; - note.known_blocks.mode = normal; - note.known_blocks.ids.push_back( blk_id ); - note.known_trx.mode = none; - my_impl->send_all(note, [blk_id, num](connection_ptr conn) -> bool { + if (is_retry) { + bcast_block(msg); + } + else { + notice_message note; + note.known_blocks.mode = normal; + note.known_blocks.ids.push_back( blk_id ); + note.known_trx.mode = none; + my_impl->send_all(note, [blk_id, num](connection_ptr conn) -> bool { const auto& bs = conn->blk_state.find(blk_id); bool unknown = bs == conn->blk_state.end(); if (unknown) { @@ -1638,6 +1661,7 @@ namespace eosio { } return unknown; }); + } return; } } @@ -1652,7 +1676,7 @@ namespace eosio { if( c != conn && !conn->syncing ) { auto b = conn->blk_state.get().find(blk_id); if(b == conn->blk_state.end()) { - conn->blk_state.insert( (block_state){blk_id,num,true,true,fc::time_point()}); + conn->blk_state.insert({blk_id,num,true,true,fc::time_point()}); sendit = true; } else if (!b->is_known) { conn->blk_state.modify(b,set_is_known); @@ -1686,8 +1710,15 @@ namespace eosio { } } - void big_msg_manager::recv_transaction (connection_ptr c) { + void big_msg_manager::recv_transaction (connection_ptr c, const transaction_id_type& tid) { pending_txn_source = c; + if (c && + c->last_req && + c->last_req->req_trx.mode != none && + c->last_req->req_trx.ids.back() == tid) { + c->last_req.reset(); + } + fc_dlog(logger, "canceling wait on ${p}", ("p",c->peer_name())); c->cancel_wait(); } @@ -1751,11 +1782,56 @@ namespace eosio { if( send_req) { c->enqueue(req); c->fetch_wait(); + c->last_req = std::move(req); } - } void big_msg_manager::retry_fetch( connection_ptr c ) { + if (!c->last_req) { + return; + } + fc_wlog( logger, "failed to fetch from ${p}",("p",c->peer_name())); + transaction_id_type tid; + block_id_type bid; + bool is_txn = false; + if( c->last_req->req_trx.mode == normal ) { + is_txn = true; + tid = c->last_req->req_trx.ids.back(); + } + else if( c->last_req->req_blocks.mode == normal ) { + bid = c->last_req->req_blocks.ids.back(); + } + else { + fc_wlog( logger,"no retry, block mpde = ${b} trx mode = ${t}", + ("b",modes_str(c->last_req->req_blocks.mode))("t",modes_str(c->last_req->req_trx.mode))); + return; + } + for (auto conn : my_impl->connections) { + if (conn == c || conn->last_req) { + continue; + } + bool sendit = false; + if (is_txn) { + auto trx = conn->trx_state.get().find(tid); + sendit = trx != conn->trx_state.end() && trx->is_known_by_peer; + } + else { + auto blk = conn->blk_state.get().find(bid); + sendit = blk != conn->blk_state.end() && blk->is_known; + } + if (sendit) { + conn->enqueue(*c->last_req); + conn->fetch_wait(); + conn->last_req = c->last_req; + return; + } + } + + // at this point no other peer has it, re-request or do nothing? + if( c->connected() ) { + c->enqueue(*c->last_req); + c->fetch_wait(); + } } //------------------------------------------------------------------------ @@ -1805,7 +1881,7 @@ namespace eosio { c->send_handshake (); } else { if( endpoint_itr != tcp::resolver::iterator() ) { - c->close(); + close(c); connect( c, endpoint_itr ); } else { @@ -1836,7 +1912,7 @@ namespace eosio { if( !ec ) { uint32_t visitors = 0; for (auto &conn : connections) { - if(conn->current() && conn->peer_addr.empty()) { + if(conn->socket->is_open() && conn->peer_addr.empty()) { visitors++; } } @@ -2033,17 +2109,16 @@ namespace eosio { c->enqueue( go_away_message(go_away_reason::wrong_chain) ); return; } - if( msg.network_version != network_version) { - int16_t mnv = to_net_version(msg.network_version); - c->backwards_compatibility = mnv < net_version; + c->protocol_version = to_protocol_version(msg.network_version); + if(c->protocol_version != net_version) { if (network_version_match) { elog("Peer network version does not match expected ${nv} but got ${mnv}", - ("nv", net_version)("mnv", mnv)); + ("nv", net_version)("mnv", c->protocol_version)); c->enqueue(go_away_message(wrong_version)); return; } else { ilog("Local network version: ${nv} Remote version: ${mnv}", - ("nv", net_version)("mnv", mnv)); + ("nv", net_version)("mnv", c->protocol_version)); } } @@ -2246,12 +2321,13 @@ namespace eosio { fc_dlog(logger, "got a txn during sync - dropping"); return; } + transaction_id_type tid = msg.id(); c->cancel_wait(); - if(local_txns.get().find(msg.id()) != local_txns.end()) { + if(local_txns.get().find(tid) != local_txns.end()) { fc_dlog(logger, "got a duplicate transaction - dropping"); return; } - big_msg_master->recv_transaction(c); + big_msg_master->recv_transaction(c, tid); uint64_t code = 0; try { chain_plug->accept_transaction( msg); @@ -2270,7 +2346,7 @@ namespace eosio { } void net_plugin_impl::handle_message( connection_ptr c, const signed_transaction &msg) { - ilog("Got a signed transaction from ${p} cancel wait",("p",c->peer_name())); + fc_dlog(logger, "Got a signed transaction from ${p} cancel wait",("p",c->peer_name())); c->cancel_wait(); } @@ -2278,7 +2354,6 @@ namespace eosio { chain_controller &cc = chain_plug->chain(); block_id_type blk_id = msg.id(); uint32_t blk_num = msg.block_num(); - fc_dlog(logger, "canceling wait on ${p}", ("p",c->peer_name())); c->cancel_wait(); try { @@ -2340,11 +2415,10 @@ namespace eosio { } } + bool accepted = false; try { chain_plug->accept_block(sb, sync_master->is_active(c)); - big_msg_master->recv_block(c, msg); - sync_master->recv_block(c, blk_id, blk_num, true); - return; + accepted = true; } catch( const unlinkable_block_exception &ex) { elog( "unlinkable_block_exception accept block #${n} syncing from ${p}",("n",blk_num)("p",c->peer_name())); } catch( const block_validate_exception &ex) { @@ -2356,11 +2430,18 @@ namespace eosio { } catch( ...) { elog( "handle sync block caught something else from ${p}",("num",blk_num)("p",c->peer_name())); } +#if 0 // after reviewing my conversaion with Bart, I believe this to be improper. + // as he explained, if the the block is deemed invalid by the local chain, then this implies a + // fork by the sender. notice_message pending_notify; pending_notify.known_blocks.mode = normal; pending_notify.known_blocks.ids.push_back( blk_id ); pending_notify.known_trx.mode = none; big_msg_master->recv_notice (c, pending_notify, true); +#endif + big_msg_master->recv_block(c, msg); + sync_master->recv_block(c, blk_id, blk_num, accepted); + } void net_plugin_impl::handle_message( connection_ptr c, const signed_block &msg) { @@ -2506,7 +2587,7 @@ namespace eosio { discards.push_back( c); } } else { - if( c->peer_addr.empty()) { + if( c->socket->is_open() && c->peer_addr.empty()) { num_clients++; } } @@ -2520,11 +2601,16 @@ namespace eosio { } void net_plugin_impl::close( connection_ptr c ) { - if( c->peer_addr.empty( ) ) { - --num_clients; + if( c->peer_addr.empty( ) && c->socket->is_open() ) { + if (num_clients == 0) { + fc_wlog( logger, "num_clients already at 0"); + } + else { + --num_clients; + } } c->close(); - } + } /** * This one is necessary to hook into the boost notifier api @@ -2623,7 +2709,7 @@ namespace eosio { void handshake_initializer::populate( handshake_message &hello) { - hello.network_version = my_impl->network_version; + hello.network_version = net_version_base + net_version; hello.chain_id = my_impl->chain_id; hello.node_id = my_impl->node_id; hello.key = my_impl->get_authentication_key(); @@ -2685,9 +2771,6 @@ namespace eosio { ( "p2p-server-address", bpo::value(), "An externally accessible host:port for identifying this node. Defaults to p2p-listen-endpoint.") ( "p2p-peer-address", bpo::value< vector >()->composing(), "The public endpoint of a peer node to connect to. Use multiple p2p-peer-address options as needed to compose a network.") ( "agent-name", bpo::value()->default_value("\"EOS Test Agent\""), "The name supplied to identify this node amongst the peers.") -#if 0 //disabling block summary support - ( "send-whole-blocks", bpo::value()->default_value(def_send_whole_blocks), "True to always send full blocks, false to send block summaries" ) -#endif ( "allowed-connection", bpo::value>()->multitoken()->default_value({"any"}, "any"), "Can be 'any' or 'producers' or 'specified' or 'none'. If 'specified', peer-key must be specified at least once. If only 'producers', peer-key is not required. 'producers' and 'specified' may be combined.") ( "peer-key", bpo::value>()->composing()->multitoken(), "Optional public key of peer allowed to connect. May be used multiple times.") ( "peer-private-key", boost::program_options::value>()->composing()->multitoken(), @@ -2698,7 +2781,7 @@ namespace eosio { ( "network-version-match", bpo::value()->default_value(false), "True to require exact match of peer network version.") ( "sync-fetch-span", bpo::value()->default_value(def_sync_fetch_span), "number of blocks to retrieve in a chunk from any individual peer during synchronization") - ( "max-implicit-request", bpo::value()->default_value(def_max_just_send), "maximum sizes of transaction or block messages that are set wothout first sending a notice") + ( "max-implicit-request", bpo::value()->default_value(def_max_just_send), "maximum sizes of transaction or block messages that are sent without first sending a notice") ; } @@ -2710,9 +2793,7 @@ namespace eosio { void net_plugin::plugin_initialize( const variables_map& options ) { ilog("Initialize net plugin"); - my->network_version = net_version_base + net_version; my->network_version_match = options.at("network-version-match").as(); - my->send_whole_blocks = def_send_whole_blocks; my->sync_master.reset( new sync_manager(options.at("sync-fetch-span").as() ) ); my->big_msg_master.reset( new big_msg_manager ); @@ -2800,10 +2881,6 @@ namespace eosio { } } - if( options.count( "send-whole-blocks")) { - my->send_whole_blocks = options.at( "send-whole-blocks" ).as(); - } - my->chain_plug = app().find_plugin(); my->chain_plug->get_chain_id(my->chain_id); fc::rand_pseudo_bytes(my->node_id.data(), my->node_id.data_size()); @@ -2912,7 +2989,7 @@ namespace eosio { return connection_ptr(); } - int16_t net_plugin_impl::to_net_version (int16_t v) { + uint16_t net_plugin_impl::to_protocol_version (uint16_t v) { if (v >= net_version_base) { v -= net_version_base; return (v > net_version_range) ? 0 : v; diff --git a/plugins/wallet_plugin/wallet_manager.cpp b/plugins/wallet_plugin/wallet_manager.cpp index 9e7fc38a8187db148fc0d114a64d7431cb88bac2..9a1f89d4d06c1bcc3bd007f3d5d5d7e297652846 100644 --- a/plugins/wallet_plugin/wallet_manager.cpp +++ b/plugins/wallet_plugin/wallet_manager.cpp @@ -109,7 +109,9 @@ map wallet_manager::list_keys() { flat_set wallet_manager::get_public_keys() { check_timeout(); + EOS_ASSERT(!wallets.empty(), wallet_not_available_exception, "You don't have any wallet!"); flat_set result; + bool is_all_wallet_locked = true; for (const auto& i : wallets) { if (!i.second->is_locked()) { const auto& keys = i.second->list_keys(); @@ -117,7 +119,9 @@ flat_set wallet_manager::get_public_keys() { result.emplace(i.first); } } + is_all_wallet_locked &= i.second->is_locked(); } + EOS_ASSERT(!is_all_wallet_locked, wallet_locked_exception, "You don't have any unlocked wallet!"); return result; } diff --git a/programs/cleos/help_text.cpp b/programs/cleos/help_text.cpp index 94556534e4a91089b408ab30254a849580a2cd07..3609e80747a81c26f6f3c2887abc169af084e674 100644 --- a/programs/cleos/help_text.cpp +++ b/programs/cleos/help_text.cpp @@ -219,10 +219,11 @@ const char* error_advice_3130003 = "Ensure that you have \033[2meosio::account_ const char* error_advice_3130004 = "Ensure that you have \033[2meosio::net_api_plugin\033[0m\033[32m added to your node's configuration!"; const char* error_advice_3140001 = "Try to use different wallet name."; -const char* error_advice_3140002 = "Are you sure you typed the name correctly?"; +const char* error_advice_3140002 = "Are you sure you typed the wallet name correctly?"; const char* error_advice_3140003 = "Ensure that your wallet is unlocked before using it!"; const char* error_advice_3140004 = "Ensure that you have the relevant private key imported!"; const char* error_advice_3140005 = "Are you sure you are using the right password?"; +const char* error_advice_3140006 = "Ensure that you have created a wallet and have it open"; const std::map error_advice = { @@ -264,7 +265,8 @@ const std::map error_advice = { { 3140002, error_advice_3140002 }, { 3140003, error_advice_3140003 }, { 3140004, error_advice_3140004 }, - { 3140005, error_advice_3140005 } + { 3140005, error_advice_3140005 }, + { 3140006, error_advice_3140006 } }; diff --git a/scripts/eosio_build_centos.sh b/scripts/eosio_build_centos.sh index b1bb92abb5bf68e070c03cec8337b9f6b09d1dbd..6973ae4ed2de516220436f64fbb88f186af0f428 100644 --- a/scripts/eosio_build_centos.sh +++ b/scripts/eosio_build_centos.sh @@ -124,7 +124,7 @@ printf "\n\tYUM repository successfully updated.\n" - DEP_ARRAY=( git autoconf automake libtool ocaml.x86_64 doxygen libicu-devel.x86_64 \ + DEP_ARRAY=( git autoconf automake libtool ocaml.x86_64 doxygen graphviz-devel.x86_64 libicu-devel.x86_64 \ bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 python-devel.x86_64 gettext-devel.x86_64) COUNT=1 DISPLAY="" @@ -172,6 +172,44 @@ printf "\n\tNo required YUM dependencies to install.\n" fi + if [[ $ENABLE_CODE_COVERAGE == true ]]; then + printf "\n\tChecking perl installation." + perl_bin=$( which perl 2>/dev/null ) + if [ $? -ne 0 ]; then + printf "\n\tInstalling perl." + yum -y install perl + if [ $? -ne 0 ]; then + printf "\n\tUnable to install perl at this time.\n" + printf "\n\tExiting now.\n" + fi + else + printf "\n\tPerl installation found at ${perl_bin}." + fi + printf "\n\tChecking LCOV installation." + if [ ! -e /usr/local/bin/lcov ]; then + printf "\n\tLCOV installation not found.\n" + printf "\tInstalling LCOV.\n" + cd ${TEMP_DIR} + git clone https://github.com/linux-test-project/lcov.git + if [ $? -ne 0 ]; then + printf "\tUnable to clone LCOV at this time.\n" + printf "\tExiting now.\n\n" + exit; + fi + cd lcov + sudo make install + if [ $? -ne 0 ]; then + printf "\tUnable to install LCOV at this time.\n" + printf "\tExiting now.\n\n" + exit; + fi + rm -rf ${TEMP_DIR}/lcov + printf "\tSuccessfully installed LCOV.\n" + else + printf "\n\tLCOV installation found @ /usr/local/bin/lcov.\n" + fi + fi + printf "\n\tChecking CMAKE installation.\n" if [ ! -e ${CMAKE} ]; then printf "\tInstalling CMAKE\n" diff --git a/tests/api_tests/api_tests.cpp b/tests/api_tests/api_tests.cpp index 6480f9da83b9466d364109976c069c36e690da3c..5f6e66194007c42cb195dc2702b2a3a86e4d0164 100644 --- a/tests/api_tests/api_tests.cpp +++ b/tests/api_tests/api_tests.cpp @@ -972,7 +972,6 @@ BOOST_FIXTURE_TEST_CASE(multi_index_tests, TESTER) { try { produce_blocks(1); set_code( N(testapi), test_api_multi_index_wast ); produce_blocks(1); - CALL_TEST_FUNCTION( *this, "test_multi_index", "idx64_general", {}); CALL_TEST_FUNCTION( *this, "test_multi_index", "idx64_store_only", {}); CALL_TEST_FUNCTION( *this, "test_multi_index", "idx64_check_without_storing", {}); diff --git a/tests/wasm_tests/test_wasts.hpp b/tests/wasm_tests/test_wasts.hpp index acbad45e18c516527ed5db95d40f557b1708eb75..ba23ab3729176013688fe8fb3bd1ccae8413945e 100644 --- a/tests/wasm_tests/test_wasts.hpp +++ b/tests/wasm_tests/test_wasts.hpp @@ -16,6 +16,146 @@ static const char f32_add_wast[] = R"=====( ) )====="; */ + +static const char aligned_ref_wast[] = R"=====( +(module + (import "env" "sha256" (func $sha256 (param i32 i32 i32))) + (table 0 anyfunc) + (memory $0 32) + (data (i32.const 4) "hello") + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (call $sha256 + (i32.const 4) + (i32.const 5) + (i32.const 16) + ) + ) +) +)====="; + +static const char aligned_ptr_wast[] = R"=====( +(module + (import "env" "diveq_i128" (func $diveq_i128 (param i32 i32))) + (table 0 anyfunc) + (memory $0 32) + (data (i32.const 16) "random stuff") + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (call $diveq_i128 + (i32.const 16) + (i32.const 16) + ) + ) +) +)====="; + + +static const char aligned_const_ref_wast[] = R"=====( +(module + (import "env" "sha256" (func $sha256 (param i32 i32 i32))) + (import "env" "assert_sha256" (func $assert_sha256 (param i32 i32 i32))) + (table 0 anyfunc) + (memory $0 32) + (data (i32.const 4) "hello") + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (local $3 i32) + (call $sha256 + (i32.const 4) + (i32.const 5) + (i32.const 16) + ) + (call $assert_sha256 + (i32.const 4) + (i32.const 5) + (i32.const 16) + ) + ) +) +)====="; + +static const char misaligned_ptr_wast[] = R"=====( +(module + (import "env" "diveq_i128" (func $diveq_i128 (param i32 i32))) + (table 0 anyfunc) + (memory $0 32) + (data (i32.const 16) "random stuff") + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (call $diveq_i128 + (i32.const 17) + (i32.const 16) + ) + ) +) +)====="; + +static const char misaligned_const_ptr_wast[] = R"=====( +(module + (import "env" "diveq_i128" (func $diveq_i128 (param i32 i32))) + (table 0 anyfunc) + (memory $0 32) + (data (i32.const 16) "random stuff") + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (call $diveq_i128 + (i32.const 16) + (i32.const 17) + ) + ) +) +)====="; + +static const char misaligned_ref_wast[] = R"=====( +(module + (import "env" "sha256" (func $sha256 (param i32 i32 i32))) + (table 0 anyfunc) + (memory $0 32) + (data (i32.const 4) "hello") + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (call $sha256 + (i32.const 4) + (i32.const 5) + (i32.const 5) + ) + ) +) +)====="; + +static const char misaligned_const_ref_wast[] = R"=====( +(module + (import "env" "sha256" (func $sha256 (param i32 i32 i32))) + (import "env" "assert_sha256" (func $assert_sha256 (param i32 i32 i32))) + (import "env" "memcpy" (func $memcpy (param i32 i32 i32) (result i32))) + (table 0 anyfunc) + (memory $0 32) + (data (i32.const 4) "hello") + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (local $3 i32) + (call $sha256 + (i32.const 4) + (i32.const 5) + (i32.const 16) + ) + (set_local $3 + (call $memcpy + (i32.const 17) + (i32.const 16) + (i32.const 64) + ) + ) + (call $assert_sha256 + (i32.const 4) + (i32.const 5) + (i32.const 17) + ) + ) +) +)====="; + static const char entry_wast[] = R"=====( (module (import "env" "require_auth" (func $require_auth (param i64))) @@ -27,21 +167,25 @@ static const char entry_wast[] = R"=====( (export "entry" (func $entry)) (export "apply" (func $apply)) (func $entry - (i32.store offset=4 - (i32.const 0) - (call $now) + (block + (i32.store offset=4 + (i32.const 0) + (call $now) + ) ) ) (func $apply (param $0 i64) (param $1 i64) (param $2 i64) - (call $require_auth (i64.const 6121376101093867520)) - (call $eosio_assert - (i32.eq - (i32.load offset=4 - (i32.const 0) + (block + (call $require_auth (i64.const 6121376101093867520)) + (call $eosio_assert + (i32.eq + (i32.load offset=4 + (i32.const 0) + ) + (call $now) ) - (call $now) + (i32.const 0) ) - (i32.const 0) ) ) (start $entry) diff --git a/tests/wasm_tests/wasm_tests.cpp b/tests/wasm_tests/wasm_tests.cpp index 436d794ca026a60b220272308ef8b01d2b1ad14d..40e5baaaeecc142870af0037333c73896fe7d34d 100644 --- a/tests/wasm_tests/wasm_tests.cpp +++ b/tests/wasm_tests/wasm_tests.cpp @@ -1,4 +1,6 @@ #include +#include + #include #include #include @@ -363,7 +365,6 @@ BOOST_FIXTURE_TEST_CASE( f32_f64_conversion_tests, tester ) try { // test softfloat conversion operations 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; @@ -464,6 +465,40 @@ BOOST_FIXTURE_TEST_CASE( f32_f64_overflow_tests, tester ) try { BOOST_REQUIRE_EQUAL(false, check(i64_overflow_wast, "i64_trunc_u_f64", "f64.const 18446744073709551616")); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(misaligned_tests, tester ) try { + produce_blocks(2); + create_accounts( {N(aligncheck)} ); + produce_block(); + + auto check_aligned = [&]( auto wast ) { + set_code(N(aligncheck), wast); + produce_blocks(10); + + signed_transaction trx; + action act; + act.account = N(aligncheck); + act.name = N(); + act.authorization = vector{{N(aligncheck),config::active_name}}; + trx.actions.push_back(act); + + set_transaction_headers(trx); + trx.sign(get_private_key( N(aligncheck), "active" ), chain_id_type()); + push_transaction(trx); + auto sb = produce_block(); + block_trace trace(sb); + + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); + }; + + check_aligned(aligned_ref_wast); + check_aligned(misaligned_ref_wast); + check_aligned(aligned_const_ref_wast); + check_aligned(misaligned_const_ref_wast); + check_aligned(aligned_ptr_wast); + check_aligned(misaligned_ptr_wast); + check_aligned(misaligned_const_ptr_wast); +} FC_LOG_AND_RETHROW() + // test cpu usage BOOST_FIXTURE_TEST_CASE(cpu_usage_tests, tester ) try {