diff --git a/.gitignore b/.gitignore index 9ffb796260d..db49e70c299 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ tests/plugin_test unittests/unit_test doxygen +eos.doxygen wallet.json witness_node_data_dir diff --git a/CMakeLists.txt b/CMakeLists.txt index 659ed3892a6..70368b6d555 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) -set(VERSION_PATCH 6) +set(VERSION_PATCH 7) set( CLI_CLIENT_EXECUTABLE_NAME cleos ) set( GUI_CLIENT_EXECUTABLE_NAME eosio ) diff --git a/Docker/README.md b/Docker/README.md index 2a34c221684..1d143598ac8 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd eos/Docker docker build . -t eosio/eos ``` -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 v1.0.6 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 v1.0.7 tag, you could do the following: ```bash -docker build -t eosio/eos:v1.0.6 --build-arg branch=v1.0.6 . +docker build -t eosio/eos:v1.0.7 --build-arg branch=v1.0.7 . ``` By default, the symbol in eosio.system is set to SYS. You can override this using the symbol argument while building the docker image. @@ -181,7 +181,7 @@ Note: if you want to use the mongo db plugin, you have to enable it in your `dat ``` # pull images -docker pull eosio/eos:v1.0.6 +docker pull eosio/eos:v1.0.7 # create volume docker volume create --name=nodeos-data-volume diff --git a/Docker/docker-compose-eosio1.0.yaml b/Docker/docker-compose-eosio1.0.yaml index 27e3aa0af45..9df363c6010 100644 --- a/Docker/docker-compose-eosio1.0.yaml +++ b/Docker/docker-compose-eosio1.0.yaml @@ -2,7 +2,7 @@ version: "3" services: nodeosd: - image: eosio/eos:v1.0.6 + image: eosio/eos:v1.0.7 command: /opt/eosio/bin/nodeosd.sh --data-dir /opt/eosio/bin/data-dir -e hostname: nodeosd ports: @@ -14,7 +14,7 @@ services: - nodeos-data-volume:/opt/eosio/bin/data-dir keosd: - image: eosio/eos:v1.0.6 + image: eosio/eos:v1.0.7 command: /opt/eosio/bin/keosd --wallet-dir /opt/eosio/bin/data-dir --http-server-address=127.0.0.1:8900 hostname: keosd links: diff --git a/contracts/eosio.system/delegate_bandwidth.cpp b/contracts/eosio.system/delegate_bandwidth.cpp index a0eafaf4661..1e190e9fe3c 100644 --- a/contracts/eosio.system/delegate_bandwidth.cpp +++ b/contracts/eosio.system/delegate_bandwidth.cpp @@ -154,9 +154,10 @@ namespace eosiosystem { /** - * While buying ram uses the current market price according to the bancor-algorithm, selling ram only - * refunds the purchase price to the account. In this way there is no profit to be made through buying - * and selling ram. + * The system contract now buys and sells RAM allocations at prevailing market prices. + * This may result in traders buying RAM today in anticipation of potential shortages + * tomorrow. Overall this will result in the market balancing the supply and demand + * for RAM over time. */ void system_contract::sellram( account_name account, int64_t bytes ) { require_auth( account ); @@ -174,6 +175,8 @@ namespace eosiosystem { tokens_out = es.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL); }); + eosio_assert( tokens_out.amount > 1, "token amount received from selling ram is too low" ); + _gstate.total_ram_bytes_reserved -= static_cast(bytes); // bytes > 0 is asserted above _gstate.total_ram_stake -= tokens_out.amount; @@ -187,7 +190,10 @@ namespace eosiosystem { INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.ram),N(active)}, { N(eosio.ram), account, asset(tokens_out), std::string("sell ram") } ); - auto fee = tokens_out.amount / 200; + + auto fee = ( tokens_out.amount + 199 ) / 200; /// .5% fee (round up) + // since tokens_out.amount was asserted to be at least 2 earlier, fee.amount < tokens_out.amount + if( fee > 0 ) { INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {account,N(active)}, { account, N(eosio.ramfee), asset(fee), std::string("sell ram fee") } ); @@ -207,6 +213,9 @@ namespace eosiosystem { { require_auth( from ); eosio_assert( stake_net_delta != asset(0) || stake_cpu_delta != asset(0), "should stake non-zero amount" ); + eosio_assert( std::abs( (stake_net_delta + stake_cpu_delta).amount ) + >= std::max( std::abs( stake_net_delta.amount ), std::abs( stake_cpu_delta.amount ) ), + "net and cpu deltas cannot be opposite signs" ); account_name source_stake_from = from; if ( transfer ) { @@ -273,8 +282,16 @@ namespace eosiosystem { auto net_balance = stake_net_delta; auto cpu_balance = stake_cpu_delta; bool need_deferred_trx = false; - if ( req != refunds_tbl.end() ) { //need to update refund - refunds_tbl.modify( req, 0, [&]( refund_request& r ) { + + + // net and cpu are same sign by assertions in delegatebw and undelegatebw + // redundant assertion also at start of changebw to protect against misuse of changebw + bool is_undelegating = (net_balance.amount + cpu_balance.amount ) < 0; + bool is_delegating_to_self = (!transfer && from == receiver); + + if( is_delegating_to_self || is_undelegating ) { + if ( req != refunds_tbl.end() ) { //need to update refund + refunds_tbl.modify( req, 0, [&]( refund_request& r ) { if ( net_balance < asset(0) || cpu_balance < asset(0) ) { r.request_time = now(); } @@ -293,17 +310,19 @@ namespace eosiosystem { cpu_balance = asset(0); } }); - eosio_assert( asset(0) <= req->net_amount, "negative net refund amount" ); //should never happen - eosio_assert( asset(0) <= req->cpu_amount, "negative cpu refund amount" ); //should never happen - if ( req->net_amount == asset(0) && req->cpu_amount == asset(0) ) { - refunds_tbl.erase( req ); - need_deferred_trx = false; - } else { - need_deferred_trx = true; - } - } else if ( net_balance < asset(0) || cpu_balance < asset(0) ) { //need to create refund - refunds_tbl.emplace( from, [&]( refund_request& r ) { + eosio_assert( asset(0) <= req->net_amount, "negative net refund amount" ); //should never happen + eosio_assert( asset(0) <= req->cpu_amount, "negative cpu refund amount" ); //should never happen + + if ( req->net_amount == asset(0) && req->cpu_amount == asset(0) ) { + refunds_tbl.erase( req ); + need_deferred_trx = false; + } else { + need_deferred_trx = true; + } + + } else if ( net_balance < asset(0) || cpu_balance < asset(0) ) { //need to create refund + refunds_tbl.emplace( from, [&]( refund_request& r ) { r.owner = from; if ( net_balance < asset(0) ) { r.net_amount = -net_balance; @@ -315,8 +334,9 @@ namespace eosiosystem { } // else r.cpu_amount = 0 by default constructor r.request_time = now(); }); - need_deferred_trx = true; - } // else stake increase requested with no existing row in refunds_tbl -> nothing to do with refunds_tbl + need_deferred_trx = true; + } // else stake increase requested with no existing row in refunds_tbl -> nothing to do with refunds_tbl + } /// end if is_delegating_to_self || is_undelegating if ( need_deferred_trx ) { eosio::transaction out; @@ -367,6 +387,7 @@ namespace eosiosystem { eosio_assert( stake_cpu_quantity >= asset(0), "must stake a positive amount" ); eosio_assert( stake_net_quantity >= asset(0), "must stake a positive amount" ); eosio_assert( stake_net_quantity + stake_cpu_quantity > asset(0), "must stake a positive amount" ); + eosio_assert( !transfer || from != receiver, "cannot use transfer flag if delegating to self" ); changebw( from, receiver, stake_net_quantity, stake_cpu_quantity, transfer); } // delegatebw diff --git a/contracts/eosio.system/eosio.system.cpp b/contracts/eosio.system/eosio.system.cpp index d6cc50c16de..f5392b168bb 100644 --- a/contracts/eosio.system/eosio.system.cpp +++ b/contracts/eosio.system/eosio.system.cpp @@ -97,6 +97,9 @@ namespace eosiosystem { void system_contract::bidname( account_name bidder, account_name newname, asset bid ) { require_auth( bidder ); eosio_assert( eosio::name_suffix(newname) == newname, "you can only bid on top-level suffix" ); + eosio_assert( newname != 0, "the empty name is not a valid account name to bid on" ); + eosio_assert( (newname & 0xFull) == 0, "13 character names are not valid account names to bid on" ); + eosio_assert( (newname & 0x1F0ull) == 0, "accounts with 12 character names and no dots can be created without bidding required" ); eosio_assert( !is_account( newname ), "account already exists" ); eosio_assert( bid.symbol == asset().symbol, "asset must be system token" ); eosio_assert( bid.amount > 0, "insufficient bid" ); diff --git a/libraries/chain/abi_serializer.cpp b/libraries/chain/abi_serializer.cpp index 68111d231f2..7262fdb495f 100644 --- a/libraries/chain/abi_serializer.cpp +++ b/libraries/chain/abi_serializer.cpp @@ -16,6 +16,9 @@ using namespace boost; namespace eosio { namespace chain { + const size_t abi_serializer::max_recursion_depth; + fc::microseconds abi_serializer::max_serialization_time = fc::microseconds(15*1000); // 15 ms + using boost::algorithm::ends_with; using std::string; @@ -238,21 +241,26 @@ namespace eosio { namespace chain { return type; } - void abi_serializer::_binary_to_variant(const type_name& type, fc::datastream& stream, - fc::mutable_variant_object& obj, size_t recursion_depth)const { - FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); + void abi_serializer::_binary_to_variant( const type_name& type, fc::datastream& stream, + fc::mutable_variant_object& obj, size_t recursion_depth, + const fc::time_point& deadline )const + { + FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); const auto& st = get_struct(type); if( st.base != type_name() ) { - _binary_to_variant(resolve_type(st.base), stream, obj, recursion_depth); + _binary_to_variant(resolve_type(st.base), stream, obj, recursion_depth, deadline); } for( const auto& field : st.fields ) { - obj( field.name, _binary_to_variant(resolve_type(field.type), stream, recursion_depth) ); + obj( field.name, _binary_to_variant(resolve_type(field.type), stream, recursion_depth, deadline) ); } } - fc::variant abi_serializer::_binary_to_variant(const type_name& type, fc::datastream& stream, size_t recursion_depth)const + fc::variant abi_serializer::_binary_to_variant( const type_name& type, fc::datastream& stream, + size_t recursion_depth, const fc::time_point& deadline )const { - FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); type_name rtype = resolve_type(type); auto ftype = fundamental_type(rtype); auto btype = built_in_types.find(ftype ); @@ -263,31 +271,41 @@ namespace eosio { namespace chain { fc::unsigned_int size; fc::raw::unpack(stream, size); vector vars; - vars.resize(size); - for (auto& var : vars) { - var = _binary_to_variant(ftype, stream, recursion_depth); + for( decltype(size.value) i = 0; i < size; ++i ) { + auto v = _binary_to_variant(ftype, stream, recursion_depth, deadline); + FC_ASSERT( !v.is_null(), "Invalid packed array" ); + vars.emplace_back(std::move(v)); } + FC_ASSERT( vars.size() == size.value, + "packed size does not match unpacked array size, packed size ${p} actual size ${a}", + ("p", size)("a", vars.size()) ); return fc::variant( std::move(vars) ); } else if ( is_optional(rtype) ) { char flag; fc::raw::unpack(stream, flag); - return flag ? _binary_to_variant(ftype, stream, recursion_depth) : fc::variant(); + return flag ? _binary_to_variant(ftype, stream, recursion_depth, deadline) : fc::variant(); } fc::mutable_variant_object mvo; - _binary_to_variant(rtype, stream, mvo, recursion_depth); + _binary_to_variant(rtype, stream, mvo, recursion_depth, deadline); + FC_ASSERT( mvo.size() > 0, "Unable to unpack stream ${type}", ("type", type) ); return fc::variant( std::move(mvo) ); } - fc::variant abi_serializer::_binary_to_variant(const type_name& type, const bytes& binary, size_t recursion_depth)const{ - FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); + fc::variant abi_serializer::_binary_to_variant( const type_name& type, const bytes& binary, + size_t recursion_depth, const fc::time_point& deadline )const + { + FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); fc::datastream ds( binary.data(), binary.size() ); - return _binary_to_variant(type, ds, recursion_depth); + return _binary_to_variant(type, ds, recursion_depth, deadline); } - void abi_serializer::_variant_to_binary(const type_name& type, const fc::variant& var, fc::datastream& ds, size_t recursion_depth)const + void abi_serializer::_variant_to_binary( const type_name& type, const fc::variant& var, fc::datastream& ds, + size_t recursion_depth, const fc::time_point& deadline )const { try { - FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); auto rtype = resolve_type(type); auto btype = built_in_types.find(fundamental_type(rtype)); @@ -297,7 +315,7 @@ namespace eosio { namespace chain { vector vars = var.get_array(); fc::raw::pack(ds, (fc::unsigned_int)vars.size()); for (const auto& var : vars) { - _variant_to_binary(fundamental_type(rtype), var, ds, recursion_depth); + _variant_to_binary(fundamental_type(rtype), var, ds, recursion_depth, deadline); } } else { const auto& st = get_struct(rtype); @@ -306,14 +324,14 @@ namespace eosio { namespace chain { const auto& vo = var.get_object(); if( st.base != type_name() ) { - _variant_to_binary(resolve_type(st.base), var, ds, recursion_depth); + _variant_to_binary(resolve_type(st.base), var, ds, recursion_depth, deadline); } for( const auto& field : st.fields ) { if( vo.contains( string(field.name).c_str() ) ) { - _variant_to_binary(field.type, vo[field.name], ds, recursion_depth); + _variant_to_binary(field.type, vo[field.name], ds, recursion_depth, deadline); } else { - _variant_to_binary(field.type, fc::variant(), ds, recursion_depth); + _variant_to_binary(field.type, fc::variant(), ds, recursion_depth, deadline); /// TODO: default construct field and write it out FC_THROW( "Missing '${f}' in variant object", ("f",field.name) ); } @@ -330,9 +348,9 @@ namespace eosio { namespace chain { if (va.size() > 0) { for( const auto& field : st.fields ) { if( va.size() > i ) - _variant_to_binary(field.type, va[i], ds, recursion_depth); + _variant_to_binary(field.type, va[i], ds, recursion_depth, deadline); else - _variant_to_binary(field.type, fc::variant(), ds, recursion_depth); + _variant_to_binary(field.type, fc::variant(), ds, recursion_depth, deadline); ++i; } } @@ -340,15 +358,18 @@ namespace eosio { namespace chain { } } FC_CAPTURE_AND_RETHROW( (type)(var) ) } - bytes abi_serializer::_variant_to_binary(const type_name& type, const fc::variant& var, size_t recursion_depth)const { try { - FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); + bytes abi_serializer::_variant_to_binary( const type_name& type, const fc::variant& var, + size_t recursion_depth, const fc::time_point& deadline )const + { try { + FC_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", max_serialization_time) ); if( !is_type(type) ) { return var.as(); } bytes temp( 1024*1024 ); fc::datastream ds(temp.data(), temp.size() ); - _variant_to_binary(type, var, ds, recursion_depth); + _variant_to_binary(type, var, ds, recursion_depth, deadline); temp.resize(ds.tellp()); return temp; } FC_CAPTURE_AND_RETHROW( (type)(var) ) } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index abb57aad348..f7e943bdf81 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -57,6 +57,7 @@ struct controller_impl { controller::config conf; chain_id_type chain_id; bool replaying = false; + bool in_trx_requiring_checks = false; ///< if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped typedef pair handler_key; map< account_name, map > apply_handlers; @@ -532,6 +533,11 @@ struct controller_impl { signed_transaction dtrx; fc::raw::unpack(ds,static_cast(dtrx) ); + auto reset_in_trx_requiring_checks = fc::make_scoped_exit([old_value=in_trx_requiring_checks,this](){ + in_trx_requiring_checks = old_value; + }); + in_trx_requiring_checks = true; + transaction_context trx_context( self, dtrx, gto.trx_id ); trx_context.deadline = deadline; trx_context.billed_cpu_time_us = billed_cpu_time_us; @@ -760,6 +766,10 @@ struct controller_impl { try { auto onbtrx = std::make_shared( get_on_block_transaction() ); + auto reset_in_trx_requiring_checks = fc::make_scoped_exit([old_value=in_trx_requiring_checks,this](){ + in_trx_requiring_checks = old_value; + }); + in_trx_requiring_checks = true; push_transaction( onbtrx, fc::time_point::maximum(), true, self.get_global_properties().configuration.min_transaction_cpu_usage ); } catch( const boost::interprocess::bad_alloc& e ) { elog( "on block transaction failed due to a bad allocation" ); @@ -1395,7 +1405,7 @@ optional controller::proposed_producers()const { } bool controller::skip_auth_check()const { - return my->replaying && !my->conf.force_all_checks; + return my->replaying && !my->conf.force_all_checks && !my->in_trx_requiring_checks; } bool controller::contracts_console()const { diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 605522dc0f7..875be1a2037 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -27,20 +27,15 @@ namespace impl { */ struct abi_serializer { abi_serializer(){ configure_built_in_types(); } - abi_serializer( const abi_def& abi ); + explicit abi_serializer( const abi_def& abi ); void set_abi(const abi_def& abi); - map typedefs; - map structs; - map actions; - map tables; - map error_messages; - - typedef std::function&, bool, bool)> unpack_function; - typedef std::function&, bool, bool)> pack_function; - - map> built_in_types; - void configure_built_in_types(); + static void set_max_serialization_time(const fc::microseconds& max) { + max_serialization_time = max; + } + static fc::microseconds get_max_serialization_time() { + return max_serialization_time; + } void validate()const; @@ -64,17 +59,17 @@ struct abi_serializer { optional get_error_message( uint64_t error_code )const; fc::variant binary_to_variant(const type_name& type, const bytes& binary)const { - return _binary_to_variant(type, binary, 0); + return _binary_to_variant(type, binary, 0, fc::time_point::now() + max_serialization_time); } bytes variant_to_binary(const type_name& type, const fc::variant& var)const { - return _variant_to_binary(type, var, 0); + return _variant_to_binary(type, var, 0, fc::time_point::now() + max_serialization_time); } fc::variant binary_to_variant(const type_name& type, fc::datastream& binary)const { - return _binary_to_variant(type, binary, 0); + return _binary_to_variant(type, binary, 0, fc::time_point::now() + max_serialization_time); } void variant_to_binary(const type_name& type, const fc::variant& var, fc::datastream& ds)const { - _variant_to_binary(type, var, ds, 0); + _variant_to_binary(type, var, ds, 0, fc::time_point::now() + max_serialization_time); } template @@ -100,17 +95,36 @@ struct abi_serializer { return false; } - static constexpr size_t max_recursion_depth = 128; // arbitrary depth to prevent infinite recursion + static const size_t max_recursion_depth = 32; // arbitrary depth to prevent infinite recursion + + typedef std::function&, bool, bool)> unpack_function; + typedef std::function&, bool, bool)> pack_function; private: - fc::variant _binary_to_variant(const type_name& type, const bytes& binary, size_t recursion_depth)const; - bytes _variant_to_binary(const type_name& type, const fc::variant& var, size_t recursion_depth)const; + map typedefs; + map structs; + map actions; + map tables; + map error_messages; + + map> built_in_types; + void configure_built_in_types(); - fc::variant _binary_to_variant(const type_name& type, fc::datastream& binary, size_t recursion_depth)const; - void _variant_to_binary(const type_name& type, const fc::variant& var, fc::datastream& ds, size_t recursion_depth)const; + static fc::microseconds max_serialization_time; - void _binary_to_variant(const type_name& type, fc::datastream& stream, fc::mutable_variant_object& obj, size_t recursion_depth)const; + fc::variant _binary_to_variant(const type_name& type, const bytes& binary, + size_t recursion_depth, const fc::time_point& deadline)const; + bytes _variant_to_binary(const type_name& type, const fc::variant& var, + size_t recursion_depth, const fc::time_point& deadline)const; + + fc::variant _binary_to_variant(const type_name& type, fc::datastream& binary, + size_t recursion_depth, const fc::time_point& deadline)const; + void _variant_to_binary(const type_name& type, const fc::variant& var, fc::datastream& ds, + size_t recursion_depth, const fc::time_point& deadline)const; + + void _binary_to_variant(const type_name& type, fc::datastream& stream, fc::mutable_variant_object& obj, + size_t recursion_depth, const fc::time_point& deadline)const; bool _is_type(const type_name& type, size_t recursion_depth)const; @@ -177,9 +191,11 @@ namespace impl { * and can be degraded to the normal ::to_variant(...) processing */ template = 1> - static void add( mutable_variant_object &mvo, const char* name, const M& v, Resolver, size_t recursion_depth ) + static void add( mutable_variant_object &mvo, const char* name, const M& v, Resolver, + size_t recursion_depth, const fc::time_point& deadline ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); mvo(name,v); } @@ -188,22 +204,25 @@ namespace impl { * for these types we create new ABI aware visitors */ template = 1> - static void add( mutable_variant_object &mvo, const char* name, const M& v, Resolver resolver, size_t recursion_depth ); + static void add( mutable_variant_object &mvo, const char* name, const M& v, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ); /** * template which overloads add for vectors of types which contain ABI information in their trees * for these members we call ::add in order to trigger further processing */ template = 1> - static void add( mutable_variant_object &mvo, const char* name, const vector& v, Resolver resolver, size_t recursion_depth ) + static void add( mutable_variant_object &mvo, const char* name, const vector& v, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); vector array; array.reserve(v.size()); for (const auto& iter: v) { mutable_variant_object elem_mvo; - add(elem_mvo, "_", iter, resolver, recursion_depth); + add(elem_mvo, "_", iter, resolver, recursion_depth, deadline); array.emplace_back(std::move(elem_mvo["_"])); } mvo(name, std::move(array)); @@ -214,12 +233,14 @@ namespace impl { * for these members we call ::add in order to trigger further processing */ template = 1> - static void add( mutable_variant_object &mvo, const char* name, const std::shared_ptr& v, Resolver resolver, size_t recursion_depth ) + static void add( mutable_variant_object &mvo, const char* name, const std::shared_ptr& v, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); if( !v ) return; mutable_variant_object obj_mvo; - add(obj_mvo, "_", *v, resolver, recursion_depth); + add(obj_mvo, "_", *v, resolver, recursion_depth, deadline); mvo(name, std::move(obj_mvo["_"])); } @@ -229,22 +250,25 @@ namespace impl { mutable_variant_object& obj_mvo; Resolver& resolver; size_t recursion_depth; - add_static_variant( mutable_variant_object& o, Resolver& r, size_t recursion_depth) - :obj_mvo(o), resolver(r), recursion_depth(recursion_depth){} + fc::time_point deadline; + add_static_variant( mutable_variant_object& o, Resolver& r, size_t recursion_depth, const fc::time_point& deadline ) + :obj_mvo(o), resolver(r), recursion_depth(recursion_depth), deadline(deadline){} typedef void result_type; template void operator()( T& v )const { - add(obj_mvo, "_", v, resolver, recursion_depth); + add(obj_mvo, "_", v, resolver, recursion_depth, deadline); } }; template - static void add( mutable_variant_object &mvo, const char* name, const fc::static_variant& v, Resolver resolver, size_t recursion_depth ) + static void add( mutable_variant_object &mvo, const char* name, const fc::static_variant& v, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); mutable_variant_object obj_mvo; - add_static_variant adder(obj_mvo, resolver, recursion_depth); + add_static_variant adder(obj_mvo, resolver, recursion_depth, deadline); v.visit(adder); mvo(name, std::move(obj_mvo["_"])); } @@ -257,8 +281,11 @@ namespace impl { * @return */ template - static void add(mutable_variant_object &out, const char* name, const action& act, Resolver resolver, size_t recursion_depth) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + static void add( mutable_variant_object &out, const char* name, const action& act, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) + { + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); mutable_variant_object mvo; mvo("account", act.account); mvo("name", act.name); @@ -269,7 +296,7 @@ namespace impl { auto type = abi->get_action_type(act.name); if (!type.empty()) { try { - mvo( "data", abi->_binary_to_variant( type, act.data, recursion_depth )); + mvo( "data", abi->_binary_to_variant( type, act.data, recursion_depth, deadline )); mvo("hex_data", act.data); } catch(...) { // any failure to serialize data, then leave as not serailzed @@ -292,8 +319,11 @@ namespace impl { * @return */ template - static void add(mutable_variant_object &out, const char* name, const packed_transaction& ptrx, Resolver resolver, size_t recursion_depth) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + static void add( mutable_variant_object &out, const char* name, const packed_transaction& ptrx, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) + { + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); mutable_variant_object mvo; auto trx = ptrx.get_transaction(); mvo("id", trx.id()); @@ -302,7 +332,7 @@ namespace impl { mvo("packed_context_free_data", ptrx.packed_context_free_data); mvo("context_free_data", ptrx.get_context_free_data()); mvo("packed_trx", ptrx.packed_trx); - add(mvo, "transaction", trx, resolver, recursion_depth); + add(mvo, "transaction", trx, resolver, recursion_depth, deadline); out(name, std::move(mvo)); } @@ -319,11 +349,13 @@ namespace impl { class abi_to_variant_visitor { public: - abi_to_variant_visitor( mutable_variant_object& _mvo, const T& _val, Resolver _resolver, size_t _recursion_depth ) + abi_to_variant_visitor( mutable_variant_object& _mvo, const T& _val, Resolver _resolver, + size_t _recursion_depth, const fc::time_point& _deadline ) :_vo(_mvo) ,_val(_val) ,_resolver(_resolver) ,_recursion_depth(_recursion_depth) + ,_deadline(_deadline) {} /** @@ -336,7 +368,7 @@ namespace impl { template void operator()( const char* name )const { - abi_to_variant::add(_vo, name, (_val.*member), _resolver, _recursion_depth); + abi_to_variant::add( _vo, name, (_val.*member), _resolver, _recursion_depth, _deadline ); } private: @@ -344,6 +376,7 @@ namespace impl { const T& _val; Resolver _resolver; size_t _recursion_depth; + fc::time_point _deadline; }; struct abi_from_variant { @@ -352,9 +385,11 @@ namespace impl { * and can be degraded to the normal ::from_variant(...) processing */ template = 1> - static void extract( const variant& v, M& o, Resolver, size_t recursion_depth ) + static void extract( const variant& v, M& o, Resolver, + size_t recursion_depth, const fc::time_point& deadline ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); from_variant(v, o); } @@ -363,22 +398,25 @@ namespace impl { * for these types we create new ABI aware visitors */ template = 1> - static void extract( const variant& v, M& o, Resolver resolver, size_t recursion_depth ); + static void extract( const variant& v, M& o, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ); /** * template which overloads extract for vectors of types which contain ABI information in their trees * for these members we call ::extract in order to trigger further processing */ template = 1> - static void extract( const variant& v, vector& o, Resolver resolver, size_t recursion_depth ) + static void extract( const variant& v, vector& o, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); const variants& array = v.get_array(); o.clear(); o.reserve( array.size() ); for( auto itr = array.begin(); itr != array.end(); ++itr ) { M o_iter; - extract(*itr, o_iter, resolver, recursion_depth); + extract(*itr, o_iter, resolver, recursion_depth, deadline); o.emplace_back(std::move(o_iter)); } } @@ -388,12 +426,14 @@ namespace impl { * for these members we call ::extract in order to trigger further processing */ template = 1> - static void extract( const variant& v, std::shared_ptr& o, Resolver resolver, size_t recursion_depth ) + static void extract( const variant& v, std::shared_ptr& o, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); const variant_object& vo = v.get_object(); M obj; - extract(vo, obj, resolver, recursion_depth); + extract(vo, obj, resolver, recursion_depth, deadline); o = std::make_shared(obj); } @@ -403,9 +443,11 @@ namespace impl { * exploded and processed explicitly */ template - static void extract( const variant& v, action& act, Resolver resolver, size_t recursion_depth ) + static void extract( const variant& v, action& act, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); const variant_object& vo = v.get_object(); EOS_ASSERT(vo.contains("account"), packed_transaction_type_exception, "Missing account"); EOS_ASSERT(vo.contains("name"), packed_transaction_type_exception, "Missing name"); @@ -427,7 +469,7 @@ namespace impl { if (abi.valid()) { auto type = abi->get_action_type(act.name); if (!type.empty()) { - act.data = std::move( abi->_variant_to_binary( type, data, recursion_depth )); + act.data = std::move( abi->_variant_to_binary( type, data, recursion_depth, deadline )); valid_empty_data = act.data.empty(); } } @@ -448,8 +490,11 @@ namespace impl { } template - static void extract( const variant& v, packed_transaction& ptrx, Resolver resolver, size_t recursion_depth ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + static void extract( const variant& v, packed_transaction& ptrx, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) + { + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); const variant_object& vo = v.get_object(); EOS_ASSERT(vo.contains("signatures"), packed_transaction_type_exception, "Missing signatures"); EOS_ASSERT(vo.contains("compression"), packed_transaction_type_exception, "Missing compression"); @@ -471,7 +516,7 @@ namespace impl { EOS_ASSERT(vo.contains("transaction"), packed_transaction_type_exception, "Missing transaction"); transaction trx; vector context_free_data; - extract(vo["transaction"], trx, resolver, recursion_depth); + extract(vo["transaction"], trx, resolver, recursion_depth, deadline); if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) { from_variant(vo["packed_context_free_data"], ptrx.packed_context_free_data ); context_free_data = ptrx.get_context_free_data(); @@ -494,11 +539,13 @@ namespace impl { class abi_from_variant_visitor : reflector_verifier_visitor { public: - abi_from_variant_visitor( const variant_object& _vo, T& v, Resolver _resolver, size_t _recursion_depth ) + abi_from_variant_visitor( const variant_object& _vo, T& v, Resolver _resolver, + size_t _recursion_depth, const fc::time_point& _deadline ) : reflector_verifier_visitor(v) ,_vo(_vo) ,_resolver(_resolver) ,_recursion_depth(_recursion_depth) + ,_deadline(_deadline) {} /** @@ -513,41 +560,48 @@ namespace impl { { auto itr = _vo.find(name); if( itr != _vo.end() ) - abi_from_variant::extract( itr->value(), this->obj.*member, _resolver, _recursion_depth ); + abi_from_variant::extract( itr->value(), this->obj.*member, _resolver, _recursion_depth, _deadline ); } private: const variant_object& _vo; Resolver _resolver; size_t _recursion_depth; + fc::time_point _deadline; }; template> - void abi_to_variant::add( mutable_variant_object &mvo, const char* name, const M& v, Resolver resolver, size_t recursion_depth ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + void abi_to_variant::add( mutable_variant_object &mvo, const char* name, const M& v, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) + { + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); mutable_variant_object member_mvo; - fc::reflector::visit( impl::abi_to_variant_visitor( member_mvo, v, resolver, recursion_depth ) ); + fc::reflector::visit( impl::abi_to_variant_visitor( member_mvo, v, resolver, recursion_depth, deadline ) ); mvo(name, std::move(member_mvo)); } template> - void abi_from_variant::extract( const variant& v, M& o, Resolver resolver, size_t recursion_depth ) { - FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth" ); + void abi_from_variant::extract( const variant& v, M& o, Resolver resolver, + size_t recursion_depth, const fc::time_point& deadline ) + { + FC_ASSERT( ++recursion_depth < abi_serializer::max_recursion_depth, "recursive definition, max_recursion_depth ${r} ", ("r", abi_serializer::max_recursion_depth) ); + FC_ASSERT( fc::time_point::now() < deadline, "serialization time limit ${t}us exceeded", ("t", abi_serializer::max_serialization_time) ); const variant_object& vo = v.get_object(); - fc::reflector::visit( abi_from_variant_visitor( vo, o, resolver, recursion_depth ) ); + fc::reflector::visit( abi_from_variant_visitor( vo, o, resolver, recursion_depth, deadline ) ); } } template void abi_serializer::to_variant( const T& o, variant& vo, Resolver resolver ) try { mutable_variant_object mvo; - impl::abi_to_variant::add(mvo, "_", o, resolver, 0); + impl::abi_to_variant::add(mvo, "_", o, resolver, 0, fc::time_point::now() + max_serialization_time); vo = std::move(mvo["_"]); } FC_RETHROW_EXCEPTIONS(error, "Failed to serialize type", ("object",o)) template void abi_serializer::from_variant( const variant& v, T& o, Resolver resolver ) try { - impl::abi_from_variant::extract(v, o, resolver, 0); + impl::abi_from_variant::extract(v, o, resolver, 0, fc::time_point::now() + max_serialization_time); } FC_RETHROW_EXCEPTIONS(error, "Failed to deserialize variant", ("variant",v)) diff --git a/libraries/chainbase b/libraries/chainbase index 06b94950936..59d59b7089f 160000 --- a/libraries/chainbase +++ b/libraries/chainbase @@ -1 +1 @@ -Subproject commit 06b949509367b330481af64bbb1be5f10d364b3a +Subproject commit 59d59b7089f48be93704f10340e1b5b3615a8a85 diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 863b5d381ca..ef4602d376c 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -46,6 +46,8 @@ namespace eosio { namespace testing { cfg.genesis.initial_timestamp = fc::time_point::from_iso_string("2020-01-01T00:00:00.000"); cfg.genesis.initial_key = get_public_key( config::system_account_name, "active" ); + abi_serializer::set_max_serialization_time(fc::microseconds(100*1000)); // 100ms for slow test machines + for(int i = 0; i < boost::unit_test::framework::master_test_suite().argc; ++i) { if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--binaryen")) cfg.wasm_runtime = chain::wasm_interface::vm_type::binaryen; diff --git a/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp b/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp index 8e4b572b6b7..b74188b0c9c 100644 --- a/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp +++ b/libraries/wasm-jit/Source/WASM/WASMSerialization.cpp @@ -493,15 +493,16 @@ namespace WASM if (numBodyBytes >= max_size) throw FatalSerializationException(std::string("Function body too large")); if (numLocalSets >= 1024) - throw FatalSerializationException(std::string("too many locals")); + throw FatalSerializationException(std::string("too many local sets")); + size_t locals_accum = numBodyBytes; for(Uptr setIndex = 0;setIndex < numLocalSets;++setIndex) { LocalSet localSet; serialize(bodyStream,localSet); - - if( localSet.num > 8024 ) - throw FatalSerializationException( "localSet.num too large" ); + locals_accum += localSet.num*4; + if( locals_accum >= max_size ) + throw FatalSerializationException( "too many locals" ); for(Uptr index = 0;index < localSet.num;++index) { functionDef.nonParameterLocalTypes.push_back(localSet.type); } } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ae8e7c25a3f..5a489106d84 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -128,6 +128,7 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip "the location of the blocks directory (absolute path or relative to application data dir)") ("checkpoint", bpo::value>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.") ("wasm-runtime", bpo::value()->value_name("wavm/binaryen"), "Override default WASM runtime") + ("abi-serializer-max-time-ms", bpo::value(), "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 MB) of the chain state database") ("reversible-blocks-db-size-mb", bpo::value()->default_value(config::default_reversible_cache_size / (1024 * 1024)), "Maximum size (in MB) of the reversible blocks database") ("contracts-console", bpo::bool_switch()->default_value(false), @@ -265,6 +266,9 @@ 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")) + abi_serializer::set_max_serialization_time(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; my->chain_config->read_only = my->readonly; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index ce5cd00cad1..be2fa347cb1 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1865,7 +1865,8 @@ namespace eosio { peer_block_state entry = {blkid,0,true,true,fc::time_point()}; try { b = cc.fetch_block_by_id(blkid); - entry.block_num = b->block_num(); + if(b) + entry.block_num = b->block_num(); } catch (const assert_exception &ex) { ilog( "caught assert on fetch_block_by_id, ${ex}",("ex",ex.what())); // keep going, client can ask another peer 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 370646c27a7..63634f8e62b 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -354,7 +354,7 @@ struct txn_test_gen_plugin_impl { int32_t txn_reference_block_lag; - abi_serializer eosio_token_serializer = fc::json::from_string(eosio_token_abi).as(); + abi_serializer eosio_token_serializer{fc::json::from_string(eosio_token_abi).as()}; }; txn_test_gen_plugin::txn_test_gen_plugin() {} diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index d275a7190c6..f9ab266d1da 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -548,7 +548,7 @@ authority parse_json_authority(const std::string& authorityJsonOrFile) { } authority parse_json_authority_or_key(const std::string& authorityJsonOrFile) { - if (boost::istarts_with(authorityJsonOrFile, "EOS")) { + if (boost::istarts_with(authorityJsonOrFile, "EOS") || boost::istarts_with(authorityJsonOrFile, "PUB_R1")) { try { return authority(public_key_type(authorityJsonOrFile)); } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid public key: ${public_key}", ("public_key", authorityJsonOrFile)) diff --git a/unittests/abi_tests.cpp b/unittests/abi_tests.cpp index d6b3bd81c8c..e83ec7b34d0 100644 --- a/unittests/abi_tests.cpp +++ b/unittests/abi_tests.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -512,7 +513,7 @@ BOOST_AUTO_TEST_CASE(uint_types) auto var = fc::json::from_string(test_data); - verify_byte_round_trip_conversion(abi, "transfer", var); + verify_byte_round_trip_conversion(abi_serializer{abi}, "transfer", var); } FC_LOG_AND_RETHROW() } @@ -2000,7 +2001,7 @@ BOOST_AUTO_TEST_CASE(general) )====="; auto var = fc::json::from_string(my_other); - verify_byte_round_trip_conversion(abi, "A", var); + verify_byte_round_trip_conversion(abi_serializer{abi}, "A", var); } FC_LOG_AND_RETHROW() } @@ -3300,4 +3301,107 @@ BOOST_AUTO_TEST_CASE(abi_account_name_in_eosio_abi) } FC_LOG_AND_RETHROW() } +// Infinite recursion of abi_serializer is_type +BOOST_AUTO_TEST_CASE(abi_is_type_recursion) +{ + try { + const char* abi_str = R"=====( + { + "types": [ + { + "new_type_name": "a[]", + "type": "a[][]", + }, + ], + "structs": [ + { + "name": "a[]", + "base": "", + "fields": [] + }, + { + "name": "hi", + "base": "", + "fields": [{ + "name": "user", + "type": "name" + } + ] + } + ], + "actions": [{ + "name": "hi", + "type": "hi", + "ricardian_contract": "" + } + ], + "tables": [] + } + )====="; + + BOOST_CHECK_THROW( abi_serializer abis(fc::json::from_string(abi_str).as()), fc::exception ); + + } FC_LOG_AND_RETHROW() +} + +// Infinite recursion of abi_serializer in struct definitions +BOOST_AUTO_TEST_CASE(abi_recursive_structs) +{ + try { + const char* abi_str = R"=====( + { + "types": [], + "structs": [ + { + "name": "a" + "base": "", + "fields": [ + { + "name": "user", + "type": "b" + } + ] + }, + { + "name": "b" + "base": "", + "fields": [ + { + "name": "user", + "type": "a" + } + ] + }, + { + "name": "hi", + "base": "", + "fields": [{ + "name": "user", + "type": "name" + }, + { + "name": "arg2", + "type": "a" + } + ] + } + ], + "actions": [{ + "name": "hi", + "type": "hi", + "ricardian_contract": "" + } + ], + "tables": [] + } + )====="; + + abi_serializer abis(fc::json::from_string(abi_str).as()); + string hi_data = "{\"user\":\"eosio\",\"arg2\":{\"user\":\"1\"}}"; + auto bin = abis.variant_to_binary("hi", fc::json::from_string(hi_data)); + BOOST_CHECK_THROW( abis.binary_to_variant("hi", bin);, fc::exception ); + + } FC_LOG_AND_RETHROW() +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/eosio.system_tests.cpp b/unittests/eosio.system_tests.cpp index a619339d556..e71ae67d789 100644 --- a/unittests/eosio.system_tests.cpp +++ b/unittests/eosio.system_tests.cpp @@ -37,19 +37,19 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( true, 0 < bought_bytes ); BOOST_REQUIRE_EQUAL( success(), sellram( "alice1111111", bought_bytes ) ); - BOOST_REQUIRE_EQUAL( core_from_string("998.0050"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("998.0049"), get_balance( "alice1111111" ) ); total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( true, total["ram_bytes"].as_uint64() == init_bytes ); transfer( "eosio", "alice1111111", core_from_string("100000000.0000"), "eosio" ); - BOOST_REQUIRE_EQUAL( core_from_string("100000998.0050"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("100000998.0049"), get_balance( "alice1111111" ) ); // alice buys ram for 10000000.0000, 0.5% = 50000.0000 go to ramfee // after fee 9950000.0000 go to bought bytes // when selling back bought bytes, pay 0.5% fee and get back 99.5% of 9950000.0000 = 9900250.0000 - // expected account after that is 90000998.0050 + 9900250.0000 = 99901248.0050 with a difference + // expected account after that is 90000998.0049 + 9900250.0000 = 99901248.0049 with a difference // of order 0.0001 due to rounding errors BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10000000.0000") ) ); - BOOST_REQUIRE_EQUAL( core_from_string("90000998.0050"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("90000998.0049"), get_balance( "alice1111111" ) ); total = get_total_stake( "alice1111111" ); bytes = total["ram_bytes"].as_uint64(); @@ -64,7 +64,7 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { wdump((init_bytes)(bought_bytes)(bytes) ); BOOST_REQUIRE_EQUAL( true, total["ram_bytes"].as_uint64() == init_bytes ); - BOOST_REQUIRE_EQUAL( core_from_string("99901248.0043"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("99901248.0041"), get_balance( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100.0000") ) ); @@ -75,7 +75,7 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("30.0000") ) ); - BOOST_REQUIRE_EQUAL( core_from_string("99900688.0043"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("99900688.0041"), get_balance( "alice1111111" ) ); auto newtotal = get_total_stake( "alice1111111" ); @@ -84,7 +84,7 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { wdump((newbytes)(bytes)(bought_bytes) ); BOOST_REQUIRE_EQUAL( success(), sellram( "alice1111111", bought_bytes ) ); - BOOST_REQUIRE_EQUAL( core_from_string("99901242.4182"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("99901242.4179"), get_balance( "alice1111111" ) ); newtotal = get_total_stake( "alice1111111" ); @@ -99,7 +99,7 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("300000.0000") ) ); - BOOST_REQUIRE_EQUAL( core_from_string("49301242.4182"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("49301242.4179"), get_balance( "alice1111111" ) ); auto finaltotal = get_total_stake( "alice1111111" ); auto endbytes = finaltotal["ram_bytes"].as_uint64(); @@ -109,7 +109,7 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), sellram( "alice1111111", bought_bytes ) ); - BOOST_REQUIRE_EQUAL( core_from_string("99396507.4146"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("99396507.4142"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() @@ -212,7 +212,72 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake_with_transfer, eosio_system_tester ) try BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "alice1111111", core_from_string("400.0000"), core_from_string("200.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); - edump((get_balance( "eosio.stake" ))); + produce_block( fc::hours(3*24-1) ); + produce_blocks(1); + BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + //after 3 days funds should be released + + produce_block( fc::hours(1) ); + produce_blocks(1); + + BOOST_REQUIRE_EQUAL( core_from_string("1300.0000"), get_balance( "alice1111111" ) ); + + //stake should be equal to what was staked in constructor, voting power should be 0 + total = get_total_stake("alice1111111"); + BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["net_weight"].as()); + BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["cpu_weight"].as()); + REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("0.0000")), get_voter_info( "alice1111111" ) ); + + // Now alice stakes to bob with transfer flag + BOOST_REQUIRE_EQUAL( success(), stake_with_transfer( "alice1111111", "bob111111111", core_from_string("100.0000"), core_from_string("100.0000") ) ); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( stake_to_self_with_transfer, eosio_system_tester ) try { + cross_15_percent_threshold(); + + BOOST_REQUIRE_EQUAL( core_from_string("0.0000"), get_balance( "alice1111111" ) ); + transfer( "eosio", "alice1111111", core_from_string("1000.0000"), "eosio" ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg("cannot use transfer flag if delegating to self"), + stake_with_transfer( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) + ); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( stake_while_pending_refund, eosio_system_tester ) try { + cross_15_percent_threshold(); + + issue( "eosio", core_from_string("1000.0000"), config::system_account_name ); + issue( "eosio.stake", core_from_string("1000.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL( core_from_string("0.0000"), get_balance( "alice1111111" ) ); + + //eosio stakes for alice with transfer flag + + transfer( "eosio", "bob111111111", core_from_string("1000.0000"), "eosio" ); + BOOST_REQUIRE_EQUAL( success(), stake_with_transfer( "bob111111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); + + //check that alice has both bandwidth and voting power + auto total = get_total_stake("alice1111111"); + BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); + BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); + REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000")), get_voter_info( "alice1111111" ) ); + + BOOST_REQUIRE_EQUAL( core_from_string("0.0000"), get_balance( "alice1111111" ) ); + + //alice stakes for herself + transfer( "eosio", "alice1111111", core_from_string("1000.0000"), "eosio" ); + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); + //now alice's stake should be equal to transfered from eosio + own stake + total = get_total_stake("alice1111111"); + BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("410.0000"), total["net_weight"].as()); + BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["cpu_weight"].as()); + REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("600.0000")), get_voter_info( "alice1111111" ) ); + + //alice can unstake everything (including what was transfered) + BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "alice1111111", core_from_string("400.0000"), core_from_string("200.0000") ) ); + BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); produce_block( fc::hours(3*24-1) ); produce_blocks(1); @@ -224,7 +289,7 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake_with_transfer, eosio_system_tester ) try BOOST_REQUIRE_EQUAL( core_from_string("1300.0000"), get_balance( "alice1111111" ) ); - //stake should be equal to what was staked in constructor, votring power should be 0 + //stake should be equal to what was staked in constructor, voting power should be 0 total = get_total_stake("alice1111111"); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["cpu_weight"].as()); @@ -492,30 +557,47 @@ BOOST_FIXTURE_TEST_CASE( stake_from_refund, eosio_system_tester ) try { cross_15_percent_threshold(); issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); - BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); - auto total = get_total_stake( "bob111111111" ); + auto total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); - REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000") ), get_voter_info( "alice1111111" ) ); - BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("50.0000"), core_from_string("50.0000") ) ); - //unstake a share - BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "bob111111111", core_from_string("100.0000"), core_from_string("50.0000") ) ); total = get_total_stake( "bob111111111" ); + BOOST_REQUIRE_EQUAL( core_from_string("60.0000"), total["net_weight"].as()); + BOOST_REQUIRE_EQUAL( core_from_string("60.0000"), total["cpu_weight"].as()); + + REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("400.0000") ), get_voter_info( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("600.0000"), get_balance( "alice1111111" ) ); + + //unstake a share + BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "alice1111111", core_from_string("100.0000"), core_from_string("50.0000") ) ); + total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("60.0000"), total["cpu_weight"].as()); - REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("150.0000") ), get_voter_info( "alice1111111" ) ); - BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("250.0000") ), get_voter_info( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("600.0000"), get_balance( "alice1111111" ) ); auto refund = get_refund_request( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("100.0000"), refund["net_amount"].as() ); BOOST_REQUIRE_EQUAL( core_from_string( "50.0000"), refund["cpu_amount"].as() ); //XXX auto request_time = refund["request_time"].as_int64(); - //stake less than pending refund, entire amount should be traken from refund - BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("50.0000"), core_from_string("25.0000") ) ); - total = get_total_stake( "bob111111111" ); + //alice delegates to bob, should pull from liquid balance not refund + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("50.0000"), core_from_string("50.0000") ) ); + total = get_total_stake( "alice1111111" ); + BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["net_weight"].as()); + BOOST_REQUIRE_EQUAL( core_from_string("60.0000"), total["cpu_weight"].as()); + REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("350.0000") ), get_voter_info( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("500.0000"), get_balance( "alice1111111" ) ); + refund = get_refund_request( "alice1111111" ); + BOOST_REQUIRE_EQUAL( core_from_string("100.0000"), refund["net_amount"].as() ); + BOOST_REQUIRE_EQUAL( core_from_string( "50.0000"), refund["cpu_amount"].as() ); + + //stake less than pending refund, entire amount should be taken from refund + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("50.0000"), core_from_string("25.0000") ) ); + total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("160.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("85.0000"), total["cpu_weight"].as()); refund = get_refund_request( "alice1111111" ); @@ -523,42 +605,77 @@ BOOST_FIXTURE_TEST_CASE( stake_from_refund, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_from_string("25.0000"), refund["cpu_amount"].as() ); //request time should stay the same //BOOST_REQUIRE_EQUAL( request_time, refund["request_time"].as_int64() ); - //balance shoud stay the same - BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + //balance should stay the same + BOOST_REQUIRE_EQUAL( core_from_string("500.0000"), get_balance( "alice1111111" ) ); //stake exactly pending refund amount - BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("50.0000"), core_from_string("25.0000") ) ); - total = get_total_stake( "bob111111111" ); + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("50.0000"), core_from_string("25.0000") ) ); + total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); //pending refund should be removed refund = get_refund_request( "alice1111111" ); BOOST_TEST_REQUIRE( refund.is_null() ); - //balance shoud stay the same - BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + //balance should stay the same + BOOST_REQUIRE_EQUAL( core_from_string("500.0000"), get_balance( "alice1111111" ) ); //create pending refund again - BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); - total = get_total_stake( "bob111111111" ); + BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); + total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["cpu_weight"].as()); - BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("500.0000"), get_balance( "alice1111111" ) ); refund = get_refund_request( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("200.0000"), refund["net_amount"].as() ); BOOST_REQUIRE_EQUAL( core_from_string("100.0000"), refund["cpu_amount"].as() ); //stake more than pending refund - BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("300.0000"), core_from_string("200.0000") ) ); - total = get_total_stake( "bob111111111" ); + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("300.0000"), core_from_string("200.0000") ) ); + total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("310.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["cpu_weight"].as()); + REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("700.0000") ), get_voter_info( "alice1111111" ) ); refund = get_refund_request( "alice1111111" ); BOOST_TEST_REQUIRE( refund.is_null() ); - //200 EOS should be taken from alice's account - BOOST_REQUIRE_EQUAL( core_from_string("500.0000"), get_balance( "alice1111111" ) ); + //200 core tokens should be taken from alice's account + BOOST_REQUIRE_EQUAL( core_from_string("300.0000"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE( stake_to_another_user_not_from_refund, eosio_system_tester ) try { + cross_15_percent_threshold(); + + issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); + + auto total = get_total_stake( "alice1111111" ); + BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); + BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); + BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + + REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000") ), get_voter_info( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + + //unstake + BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); + auto refund = get_refund_request( "alice1111111" ); + BOOST_REQUIRE_EQUAL( core_from_string("200.0000"), refund["net_amount"].as() ); + BOOST_REQUIRE_EQUAL( core_from_string("100.0000"), refund["cpu_amount"].as() ); + //auto orig_request_time = refund["request_time"].as_int64(); + + //stake to another user + BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); + total = get_total_stake( "bob111111111" ); + BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); + BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); + //stake should be taken from alices' balance, and refund request should stay the same + BOOST_REQUIRE_EQUAL( core_from_string("400.0000"), get_balance( "alice1111111" ) ); + refund = get_refund_request( "alice1111111" ); + BOOST_REQUIRE_EQUAL( core_from_string("200.0000"), refund["net_amount"].as() ); + BOOST_REQUIRE_EQUAL( core_from_string("100.0000"), refund["cpu_amount"].as() ); + //BOOST_REQUIRE_EQUAL( orig_request_time, refund["request_time"].as_int64() ); + +} FC_LOG_AND_RETHROW() // Tests for voting BOOST_FIXTURE_TEST_CASE( producer_register_unregister, eosio_system_tester ) try { @@ -2094,6 +2211,23 @@ BOOST_FIXTURE_TEST_CASE( buyname, eosio_system_tester ) try { create_accounts_with_resources( { N(goodgoodgood) }, N(dan) ); /// 12 char names should succeed } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE( bid_invalid_names, eosio_system_tester ) try { + create_accounts_with_resources( { N(dan) } ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "you can only bid on top-level suffix" ), + bidname( "dan", "abcdefg.12345", core_from_string( "1.0000" ) ) ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "the empty name is not a valid account name to bid on" ), + bidname( "dan", "", core_from_string( "1.0000" ) ) ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "13 character names are not valid account names to bid on" ), + bidname( "dan", "abcdefgh12345", core_from_string( "1.0000" ) ) ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "accounts with 12 character names and no dots can be created without bidding required" ), + bidname( "dan", "abcdefg12345", core_from_string( "1.0000" ) ) ); + +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { const std::string not_closed_message("auction for name is not closed yet"); @@ -2418,9 +2552,9 @@ BOOST_FIXTURE_TEST_CASE( setram_effect, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance(name_a) ); const uint64_t bought_bytes_a = get_total_stake(name_a)["ram_bytes"].as_uint64() - init_bytes_a; - // after buying and selling balance should be 700 + 300 * 0.995 * 0.995 = 997.0075 + // after buying and selling balance should be 700 + 300 * 0.995 * 0.995 = 997.0075 (actually 997.0074 due to rounding fees up) BOOST_REQUIRE_EQUAL( success(), sellram(name_a, bought_bytes_a ) ); - BOOST_REQUIRE_EQUAL( core_from_string("997.0075"), get_balance(name_a) ); + BOOST_REQUIRE_EQUAL( core_from_string("997.0074"), get_balance(name_a) ); } { diff --git a/unittests/tic_tac_toe_tests.cpp b/unittests/tic_tac_toe_tests.cpp index cd938654c66..42925122948 100644 --- a/unittests/tic_tac_toe_tests.cpp +++ b/unittests/tic_tac_toe_tests.cpp @@ -65,7 +65,7 @@ BOOST_AUTO_TEST_SUITE(tic_tac_toe_tests) BOOST_AUTO_TEST_CASE( tic_tac_toe_game ) try { TESTER chain; - abi_serializer abi_ser = json::from_string(tic_tac_toe_abi).as(); + abi_serializer abi_ser{json::from_string(tic_tac_toe_abi).as()}; chain.create_account(N(tic.tac.toe)); chain.produce_blocks(10);