From b2c417bfe9caca923810c375f6fe58f205328c5a Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Sat, 12 May 2018 22:51:53 -0400 Subject: [PATCH] Fix eosio.system abi & skip sig checks - signature checks are skipped while replaying - abi of eosio.system contract was inconsistant, Fix #2999 - reduced console spam while syncing and replaying - add max usage of resources when querying account --- contracts/eosio.system/eosio.system.abi | 5 +- contracts/eosio.system/eosio.system.cpp | 2 +- libraries/chain/block_header_state.cpp | 59 +++---------------- libraries/chain/block_state.cpp | 4 +- libraries/chain/controller.cpp | 38 ++++++------ libraries/chain/eosio_contract.cpp | 9 --- libraries/chain/fork_database.cpp | 4 +- .../eosio/chain/block_header_state.hpp | 4 +- .../chain/include/eosio/chain/block_state.hpp | 2 +- .../chain/include/eosio/chain/controller.hpp | 2 +- .../include/eosio/chain/fork_database.hpp | 2 +- .../include/eosio/chain/resource_limits.hpp | 4 +- libraries/chain/resource_limits.cpp | 6 +- plugins/producer_plugin/producer_plugin.cpp | 21 +++++-- 14 files changed, 63 insertions(+), 99 deletions(-) diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi index 234a9776f..d18f920fc 100644 --- a/contracts/eosio.system/eosio.system.abi +++ b/contracts/eosio.system/eosio.system.abi @@ -54,9 +54,8 @@ "fields": [ {"name":"from", "type":"account_name"}, {"name":"to", "type":"account_name"}, - {"name":"net_weight", "type":"uint64"}, - {"name":"cpu_weight", "type":"uint64"}, - {"name":"ram_bytes", "type":"uint64"} + {"name":"net_weight", "type":"asset"}, + {"name":"cpu_weight", "type":"asset"}, ] },{ "name": "user_resources", diff --git a/contracts/eosio.system/eosio.system.cpp b/contracts/eosio.system/eosio.system.cpp index efaaccc28..a24d0bf10 100644 --- a/contracts/eosio.system/eosio.system.cpp +++ b/contracts/eosio.system/eosio.system.cpp @@ -81,8 +81,8 @@ EOSIO_ABI( eosiosystem::system_contract, (delegatebw)(undelegatebw)(refund) (buyram)(buyrambytes)(sellram) // voting.cpp - (regproxy)(regproducer)(unregprod)(voteproducer) // producer_pay.cpp + (regproxy)(regproducer)(unregprod)(voteproducer) (claimrewards) // native.hpp //XXX diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 172b22b09..ae2e29f09 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -4,60 +4,17 @@ namespace eosio { namespace chain { - /* - uint32_t block_header_state::calc_dpos_last_irreversible()const { - if( producer_to_last_produced.size() == 0 ) - return 0; - - vector irb; - irb.reserve( producer_to_last_produced.size() ); - for( const auto& item : producer_to_last_produced ) - irb.push_back(item.second); - - size_t offset = EOS_PERCENT(irb.size(), config::percent_100- config::irreversible_threshold_percent); - std::nth_element( irb.begin(), irb.begin() + offset, irb.end() ); - - return irb[offset]; - } - */ bool block_header_state::is_active_producer( account_name n )const { return producer_to_last_produced.find(n) != producer_to_last_produced.end(); } - /* - block_timestamp_type block_header_state::get_slot_time( uint32_t slot_num )const { - auto t = header.timestamp; - FC_ASSERT( std::numeric_limits::max() - t.slot >= slot_num, "block timestamp overflow" ); - t.slot += slot_num; - return t; - } - - uint32_t block_header_state::get_slot_at_time( block_timestamp_type t )const { - auto first_slot_time = get_slot_time(1); - if( t < first_slot_time ) - return 0; - return (t.slot - first_slot_time.slot + 1); - } - - producer_key block_header_state::get_scheduled_producer( uint32_t slot_num )const { - return get_scheduled_producer( get_slot_time(slot_num) ); - } - */ - producer_key block_header_state::get_scheduled_producer( block_timestamp_type t )const { auto index = t.slot % (active_schedule.producers.size() * config::producer_repetitions); index /= config::producer_repetitions; return active_schedule.producers[index]; } - /* - uint32_t block_header_state::producer_participation_rate()const - { - return static_cast(config::percent_100); // Ignore participation rate for now until we construct a better metric. - } - */ - /** * Generate a template block header state for a given block time, it will not @@ -153,7 +110,7 @@ namespace eosio { namespace chain { * * If the header specifies new_producers then apply them accordingly. */ - block_header_state block_header_state::next( const signed_block_header& h )const { + block_header_state block_header_state::next( const signed_block_header& h, bool trust )const { FC_ASSERT( h.timestamp != block_timestamp_type(), "", ("h",h) ); FC_ASSERT( h.header_extensions.size() == 0, "no supported extensions" ); @@ -178,16 +135,16 @@ namespace eosio { namespace chain { result.set_confirmed( h.confirmed ); - // idump( (result.confirm_count.size()) ); result.header.action_mroot = h.action_mroot; result.header.transaction_mroot = h.transaction_mroot; result.header.producer_signature = h.producer_signature; - //idump((result.header)); result.id = result.header.id(); - FC_ASSERT( result.block_signing_key == result.signee(), "block not signed by expected key", - ("result.block_signing_key", result.block_signing_key)("signee", result.signee() ) ); + if( !trust ) { + FC_ASSERT( result.block_signing_key == result.signee(), "block not signed by expected key", + ("result.block_signing_key", result.block_signing_key)("signee", result.signee() ) ); + } return result; } /// next @@ -232,10 +189,12 @@ namespace eosio { namespace chain { return digest_type::hash( std::make_pair(header_bmroot, pending_schedule_hash) ); } - void block_header_state::sign( const std::function& signer ) { + void block_header_state::sign( const std::function& signer, bool trust ) { auto d = sig_digest(); header.producer_signature = signer( d ); - FC_ASSERT( block_signing_key == fc::crypto::public_key( header.producer_signature, d ) ); + if( !trust ) { + FC_ASSERT( block_signing_key == fc::crypto::public_key( header.producer_signature, d ) ); + } } public_key_type block_header_state::signee()const { diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index c85fe4502..f62da8655 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -10,8 +10,8 @@ namespace eosio { namespace chain { static_cast(*block) = header; } - block_state::block_state( const block_header_state& prev, signed_block_ptr b ) - :block_header_state( prev.next( *b )), block( move(b) ) + block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool trust ) + :block_header_state( prev.next( *b, trust )), block( move(b) ) { } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index abd2cc8f0..6eb89b52c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -260,14 +260,14 @@ struct controller_impl { auto start = fc::time_point::now(); while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) { - self.push_block( next ); - if( next->block_num() % 10 == 0 ) { + self.push_block( next, true ); + if( next->block_num() % 100 == 0 ) { std::cerr << std::setw(10) << next->block_num() << " of " << end->block_num() <<"\r"; } } std::cerr<< "\n"; auto end = fc::time_point::now(); - ilog( "replayed blocks in ${n} seconds", ("n", (end-start).count()/1000000.0) ); + ilog( "replayed blocks in ${n} seconds, ${spb} spb", ("n", (end-start).count()/1000000.0)("spb", ((end-start).count()/1000000.0)/head->block_num) ); replaying = false; } else if( !end ) { @@ -700,18 +700,20 @@ struct controller_impl { - void sign_block( const std::function& signer_callback ) { + void sign_block( const std::function& signer_callback, bool trust ) { auto p = pending->_pending_block_state; + try { - p->sign( signer_callback ); + p->sign( signer_callback, false); //trust ); } catch ( ... ) { - edump(( fc::json::to_pretty_string( *p->block ) ) ); + edump(( fc::json::to_pretty_string( p->header ) ) ); throw; } + static_cast(*p->block) = p->header; } /// sign_block - void apply_block( const signed_block_ptr& b ) { try { + void apply_block( const signed_block_ptr& b, bool trust ) { try { try { FC_ASSERT( b->block_extensions.size() == 0, "no supported extensions" ); start_block( b->timestamp, b->confirmed ); @@ -728,7 +730,7 @@ struct controller_impl { } finalize_block(); - sign_block( [&]( const auto& ){ return b->producer_signature; } ); + sign_block( [&]( const auto& ){ return b->producer_signature; }, trust ); // this is implied by the signature passing //FC_ASSERT( b->id() == pending->_pending_block_state->block->id(), @@ -744,14 +746,14 @@ struct controller_impl { } FC_CAPTURE_AND_RETHROW() } /// apply_block - void push_block( const signed_block_ptr& b ) { + void push_block( const signed_block_ptr& b, bool trust ) { // idump((fc::json::to_pretty_string(*b))); FC_ASSERT(!pending, "it is not valid to push a block when there is a pending block"); try { FC_ASSERT( b ); - auto new_header_state = fork_db.add( b ); + auto new_header_state = fork_db.add( b, trust ); emit( self.accepted_block_header, new_header_state ); - maybe_switch_forks(); + maybe_switch_forks( trust ); } FC_LOG_AND_RETHROW( ) } @@ -762,12 +764,12 @@ struct controller_impl { maybe_switch_forks(); } - void maybe_switch_forks() { + void maybe_switch_forks( bool trust = false ) { auto new_head = fork_db.head(); if( new_head->header.previous == head->id ) { try { - apply_block( new_head->block ); + apply_block( new_head->block, trust ); fork_db.mark_in_current_chain( new_head, true ); fork_db.set_validity( new_head, true ); head = new_head; @@ -790,7 +792,7 @@ struct controller_impl { for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) { optional except; try { - apply_block( (*ritr)->block ); + apply_block( (*ritr)->block, false /*don't trust*/ ); head = *ritr; fork_db.mark_in_current_chain( *ritr, true ); } @@ -813,7 +815,7 @@ struct controller_impl { // re-apply good blocks for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) { - apply_block( (*ritr)->block ); + apply_block( (*ritr)->block, true /* we previously validated these blocks*/ ); head = *ritr; fork_db.mark_in_current_chain( *ritr, true ); } @@ -1046,7 +1048,7 @@ void controller::finalize_block() { } void controller::sign_block( const std::function& signer_callback ) { - my->sign_block( signer_callback ); + my->sign_block( signer_callback, false /* don't trust */); } void controller::commit_block() { @@ -1057,8 +1059,8 @@ void controller::abort_block() { my->abort_block(); } -void controller::push_block( const signed_block_ptr& b ) { - my->push_block( b ); +void controller::push_block( const signed_block_ptr& b, bool trust ) { + my->push_block( b, trust ); log_irreversible_blocks(); } diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index b552eddca..06e61badc 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -121,7 +121,6 @@ void apply_eosio_newaccount(apply_context& context) { void apply_eosio_setcode(apply_context& context) { const auto& cfg = context.control.get_global_properties().configuration; - context.checktime( cfg.base_setcode_cpu_usage ); auto& db = context.db; auto act = context.act.data_as(); @@ -131,7 +130,6 @@ void apply_eosio_setcode(apply_context& context) { FC_ASSERT( act.vmtype == 0 ); FC_ASSERT( act.vmversion == 0 ); - context.checktime( act.code.size() * 20 ); auto code_id = fc::sha256::hash( act.code.data(), (uint32_t)act.code.size() ); @@ -180,7 +178,6 @@ void apply_eosio_setabi(apply_context& context) { int64_t old_size = (int64_t)account.abi.size(); int64_t new_size = (int64_t)fc::raw::pack_size(act.abi); - context.checktime( new_size * 2 ); db.modify( account, [&]( auto& a ) { a.set_abi( act.abi ); @@ -223,7 +220,6 @@ void apply_eosio_updateauth(apply_context& context) { validate_authority_precondition(context, update.auth); - context.checktime( 5000 ); auto permission = authorization.find_permission({update.account, update.permission}); @@ -284,7 +280,6 @@ void apply_eosio_deleteauth(apply_context& context) { context.trx_context.add_ram_usage( remove.account, -old_size ); - context.checktime( 3000 ); } void apply_eosio_linkauth(apply_context& context) { @@ -332,7 +327,6 @@ void apply_eosio_linkauth(apply_context& context) { ); } - context.checktime( 3000 ); } FC_CAPTURE_AND_RETHROW((requirement)) } @@ -353,7 +347,6 @@ void apply_eosio_unlinkauth(apply_context& context) { ); db.remove(*link); - context.checktime( 3000 ); } static const abi_serializer& get_abi_serializer() { @@ -373,8 +366,6 @@ void apply_eosio_canceldelay(apply_context& context) { const auto& trx_id = cancel.trx_id; context.cancel_deferred_transaction(transaction_id_to_sender_id(trx_id), account_name()); - - context.checktime( 1000 ); } } } // namespace eosio::chain diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index dca3bea88..c8d65d2bf 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -141,7 +141,7 @@ namespace eosio { namespace chain { return n; } - block_state_ptr fork_database::add( signed_block_ptr b ) { + block_state_ptr fork_database::add( signed_block_ptr b, bool trust ) { FC_ASSERT( b, "attempt to add null block" ); FC_ASSERT( my->head, "no head block set" ); @@ -152,7 +152,7 @@ namespace eosio { namespace chain { auto prior = by_id_idx.find( b->previous ); FC_ASSERT( prior != by_id_idx.end(), "unlinkable block", ("id", b->id())("previous", b->previous) ); - auto result = std::make_shared( **prior, move(b) ); + auto result = std::make_shared( **prior, move(b), trust ); FC_ASSERT( result ); return add(result); } diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 1b6cf8243..59da9f732 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -24,7 +24,7 @@ struct block_header_state { vector confirm_count; vector confirmations; - block_header_state next( const signed_block_header& h )const; + block_header_state next( const signed_block_header& h, bool trust = false )const; block_header_state generate_next( block_timestamp_type when )const; void set_new_producers( producer_schedule_type next_pending ); @@ -46,7 +46,7 @@ struct block_header_state { producer_key get_scheduled_producer( block_timestamp_type t )const; const block_id_type& prev()const { return header.previous; } digest_type sig_digest()const; - void sign( const std::function& signer ); + void sign( const std::function& signer, bool trust = false ); public_key_type signee()const; }; diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 9b5bdd1f6..52f2db8e9 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -13,7 +13,7 @@ namespace eosio { namespace chain { struct block_state : public block_header_state { block_state( const block_header_state& cur ):block_header_state(cur){} - block_state( const block_header_state& prev, signed_block_ptr b ); + block_state( const block_header_state& prev, signed_block_ptr b, bool trust = false ); block_state( const block_header_state& prev, block_timestamp_type when ); block_state() = default; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 8f965bb7b..8c23351ca 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -99,7 +99,7 @@ namespace eosio { namespace chain { void log_irreversible_blocks(); void pop_block(); - void push_block( const signed_block_ptr& b ); + void push_block( const signed_block_ptr& b, bool trust = false /* does the caller trust the block*/ ); /** * Call this method when a producer confirmation is received, this might update diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 42e6c5f29..529a43a0a 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -40,7 +40,7 @@ namespace eosio { namespace chain { * block_state and will return a pointer to the new block state or * throw on error. */ - block_state_ptr add( signed_block_ptr b ); + block_state_ptr add( signed_block_ptr b, bool trust = false ); block_state_ptr add( block_state_ptr next_block ); void remove( const block_id_type& id ); diff --git a/libraries/chain/include/eosio/chain/resource_limits.hpp b/libraries/chain/include/eosio/chain/resource_limits.hpp index ddb96bda9..6865f2ca1 100644 --- a/libraries/chain/include/eosio/chain/resource_limits.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits.hpp @@ -29,7 +29,7 @@ namespace eosio { namespace chain { namespace resource_limits { struct account_resource_limit { int64_t used = 0; ///< quantity used in current window int64_t available = 0; ///< quantity available in current window (based upon fractional reserve) - int64_t max_gauranteed = 0; ///< max per window under 100% congestion + int64_t max = 0; ///< max per window under current congestion }; class resource_limits_manager { @@ -76,4 +76,4 @@ namespace eosio { namespace chain { namespace resource_limits { }; } } } /// eosio::chain -FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (used)(available)(max_gauranteed) ) +FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (used)(available)(max) ) diff --git a/libraries/chain/resource_limits.cpp b/libraries/chain/resource_limits.cpp index 2b7a95d55..24b5c1798 100644 --- a/libraries/chain/resource_limits.cpp +++ b/libraries/chain/resource_limits.cpp @@ -401,7 +401,9 @@ account_resource_limit resource_limits_manager::get_account_cpu_limit_ex( const uint128_t user_weight = cpu_weight; uint128_t all_user_weight = state.total_cpu_weight; - auto max_user_use_in_window = (virtual_cpu_capacity_in_window * user_weight) / all_user_weight; + wdump((cpu_weight)); + + auto max_user_use_in_window = (uint128_t(virtual_cpu_capacity_in_window) * user_weight) / all_user_weight; auto cpu_used_in_window = (usage.cpu_usage.value_ex * window_size) / config::rate_limiting_precision; if( max_user_use_in_window <= cpu_used_in_window ) @@ -410,6 +412,7 @@ account_resource_limit resource_limits_manager::get_account_cpu_limit_ex( const arl.available = max_user_use_in_window - cpu_used_in_window; arl.used = cpu_used_in_window; + arl.max = max_user_use_in_window; return arl; } @@ -471,6 +474,7 @@ account_resource_limit resource_limits_manager::get_account_net_limit_ex( const arl.available = max_user_use_in_window - net_used_in_window; arl.used = net_used_in_window; + arl.max = max_user_use_in_window; return arl; } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 637947939..354f1b764 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -181,6 +181,12 @@ class producer_plugin_impl { }; void on_incoming_block(const signed_block_ptr& block) { + + if( block->timestamp > fc::time_point::now() ) { + FC_ASSERT( block->timestamp < fc::time_point::now(), "received a block from the future, ignoring it" ); + } + + chain::controller& chain = app().get_plugin().chain(); // abort the pending block chain.abort_block(); @@ -197,10 +203,13 @@ class producer_plugin_impl { if( chain.head_block_state()->header.timestamp.next().to_time_point() >= fc::time_point::now() ) _production_enabled = true; - ilog("Received block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, confirmed: ${confs}]", - ("p",block->producer)("id",fc::variant(block->id()).as_string().substr(0,16)) - ("n",block_header::num_from_id(block->id()))("t",block->timestamp) - ("count",block->transactions.size())("lib",chain.last_irreversible_block_num())("confs", block->confirmed) ); + + if( fc::time_point::now() - block->timestamp < fc::seconds(5) || (block->block_num() % 1000 == 0) ) { + ilog("Received block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, confirmed: ${confs}]", + ("p",block->producer)("id",fc::variant(block->id()).as_string().substr(0,16)) + ("n",block_header::num_from_id(block->id()))("t",block->timestamp) + ("count",block->transactions.size())("lib",chain.last_irreversible_block_num())("confs", block->confirmed) ); + } } @@ -409,8 +418,8 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { if((block_time - now) < fc::microseconds(config::block_interval_us/10) ) { // we must sleep for at least 50ms - ilog("Less than ${t}us to next block time, time_to_next_block_time ${bt}", - ("t", config::block_interval_us/10)("bt", block_time)); +// ilog("Less than ${t}us to next block time, time_to_next_block_time ${bt}", +// ("t", config::block_interval_us/10)("bt", block_time)); block_time += fc::microseconds(config::block_interval_us); } -- GitLab