From c92d7cbc2c0c90c3325d34766497035cf359eb52 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Thu, 17 May 2018 11:39:31 -0400 Subject: [PATCH 01/55] overhaul the production loop to respect the dual purpose of speculating and producing. Move failure modes to the up front determination and change behavior of incoming transaction subjective failure depending on what mode we are in EOSIO/eos#3161 --- .../eosio/producer_plugin/producer_plugin.hpp | 15 - plugins/producer_plugin/producer_plugin.cpp | 288 +++++++----------- 2 files changed, 104 insertions(+), 199 deletions(-) diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index 7c3d52728d9..ae307b76de7 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -11,21 +11,6 @@ namespace eosio { -namespace block_production_condition { - enum block_production_condition_enum - { - produced = 0, - not_synced = 1, - not_my_turn = 2, - not_time_yet = 3, - no_private_key = 4, - low_participation = 5, - lag = 6, - exception_producing_block = 7, - fork_below_watermark = 8, - }; -} - using boost::signals2::signal; class producer_plugin : public appbase::plugin { diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index a419e3c11c2..681b47e0172 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -68,6 +68,11 @@ using blacklisted_transaction_index = multi_index_container< > >; +enum class pending_block_mode { + producing, + speculating +}; + class producer_plugin_impl { public: producer_plugin_impl(boost::asio::io_service& io) @@ -76,8 +81,8 @@ class producer_plugin_impl { {} void schedule_production_loop(); - block_production_condition::block_production_condition_enum block_production_loop(); - block_production_condition::block_production_condition_enum maybe_produce_block(fc::mutable_variant_object& capture); + void produce_block(); + bool maybe_produce_block(); boost::program_options::variables_map _options; bool _production_enabled = false; @@ -88,12 +93,10 @@ class producer_plugin_impl { std::set _producers; boost::asio::deadline_timer _timer; std::map _producer_watermarks; + pending_block_mode _pending_block_mode; int32_t _max_transaction_time_ms; - block_production_condition::block_production_condition_enum _prev_result = block_production_condition::produced; - uint32_t _prev_result_count = 0; - time_point _last_signed_block_time; time_point _start_time = fc::time_point::now(); uint32_t _last_signed_block_num = 0; @@ -191,12 +194,7 @@ class producer_plugin_impl { // exceptions throw out, make sure we restart our loop auto ensure = fc::make_scoped_exit([this](){ - if (!_producers.empty()) { - // restart our production loop - schedule_production_loop(); - } else { - start_block(); - } + schedule_production_loop(); }); // push the new block @@ -224,13 +222,19 @@ class producer_plugin_impl { auto deadline = std::min(block_time, max_deadline); auto trace = chain.push_transaction(std::make_shared(*trx), deadline); - // if we failed because the block was exhausted push the block out and try again + // if we failed because the block was exhausted push the block out and try again if it succeeds if (trace->except) { - if (failure_is_subjective(*trace->except, deadline == block_time)) { - block_production_loop(); - } else { - trace->except->dynamic_rethrow_exception(); + if (failure_is_subjective(*trace->except, deadline == block_time) && _pending_block_mode == pending_block_mode::producing) { + if (maybe_produce_block()) { + continue; + } + + // if we failed to produce a block that was not speculative (for some reason). we are going to + // throw the exception out to the caller. if they don't support any retry mechanics + // this may result in a lost transaction } + + trace->except->dynamic_rethrow_exception(); } else { return trace; } @@ -383,21 +387,17 @@ void producer_plugin::plugin_startup() chain::controller& chain = app().get_plugin().chain(); chain.accepted_block.connect( [this]( const auto& bsp ){ my->on_block( bsp ); } ); - if (!my->_producers.empty()) - { + if (!my->_producers.empty()) { ilog("Launching block production for ${n} producers.", ("n", my->_producers.size())); - if(my->_production_enabled) - { - if(chain.head_block_num() == 0) + if (my->_production_enabled) { + if (chain.head_block_num() == 0) new_chain_banner(chain); //_production_skip_flags |= eosio::chain::skip_undo_history_check; } - my->schedule_production_loop(); - } else { - ilog("No producers configured! Starting as a validator"); - my->start_block(); } + my->schedule_production_loop(); + ilog("producer plugin: plugin_startup() end"); } FC_CAPTURE_AND_RETHROW() } @@ -427,21 +427,53 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { block_time += fc::microseconds(config::block_interval_us); } + _pending_block_mode = pending_block_mode::producing; + + + // If the next block production opportunity is in the present or future, we're synced. + if( !_production_enabled ) { + _pending_block_mode = pending_block_mode::speculating; + } + + // Not our turn + const auto& scheduled_producer = hbs->get_scheduled_producer(block_time); + if( _producers.find(scheduled_producer.producer_name) != _producers.end()) { + _pending_block_mode = pending_block_mode::speculating; + } + + auto private_key_itr = _private_keys.find( scheduled_producer.block_signing_key ); + if( private_key_itr == _private_keys.end() ) { + ilog("Not producing block because I don't have the private key for ${scheduled_key}", ("scheduled_key", scheduled_producer.block_signing_key)); + _pending_block_mode = pending_block_mode::speculating; + } + + // determine if our watermark excludes us from producing at this point + auto currrent_watermark_itr = _producer_watermarks.find(scheduled_producer.producer_name); + if (currrent_watermark_itr != _producer_watermarks.end()) { + if (currrent_watermark_itr->second >= hbs->block_num + 1) { + elog( "Not producing block because \"${producer}\" signed a BFT confirmation OR block at a higher block number (${watermark}) than the current fork's head (${head_block_num})", + ("producer", scheduled_producer.producer_name) + ("watermark",currrent_watermark_itr->second) + ("head_block_num",hbs->block_num)); + _pending_block_mode = pending_block_mode::speculating; + } + } + try { - // determine how many blocks this producer can confirm - // 1) if it is not a producer from this node, assume no confirmations (we will discard this block anyway) - // 2) if it is a producer on this node that has never produced, the conservative approach is to assume no - // confirmations to make sure we don't double sign after a crash TODO: make these watermarks durable? - // 3) if it is a producer on this node where this node knows the last block it produced, safely set it -UNLESS- - // 4) the producer on this node's last watermark is higher (meaning on a different fork) - const auto& hbs = chain.head_block_state(); - auto producer_name = hbs->get_scheduled_producer(block_time).producer_name; uint16_t blocks_to_confirm = 0; - auto itr = _producer_watermarks.find(producer_name); - if (itr != _producer_watermarks.end()) { - auto watermark = itr->second; - if (watermark < hbs->block_num) { - blocks_to_confirm = std::min(std::numeric_limits::max(), (uint16_t)(hbs->block_num - watermark)); + + if (_pending_block_mode == pending_block_mode::producing) { + // determine how many blocks this producer can confirm + // 1) if it is not a producer from this node, assume no confirmations (we will discard this block anyway) + // 2) if it is a producer on this node that has never produced, the conservative approach is to assume no + // confirmations to make sure we don't double sign after a crash TODO: make these watermarks durable? + // 3) if it is a producer on this node where this node knows the last block it produced, safely set it -UNLESS- + // 4) the producer on this node's last watermark is higher (meaning on a different fork) + if (currrent_watermark_itr != _producer_watermarks.end()) { + auto watermark = currrent_watermark_itr->second; + if (watermark < hbs->block_num) { + blocks_to_confirm = std::min(std::numeric_limits::max(), (uint16_t)(hbs->block_num - watermark)); + } } } @@ -513,12 +545,8 @@ void producer_plugin_impl::schedule_production_loop() { _timer.cancel(); auto result = start_block(); - switch(result) { - case start_block_result::exhausted: - // immediately proceed to making the block - block_production_loop(); - break; - case start_block_result::failed: + + if (result == start_block_result::failed) { elog("Failed to start a pending block, will try again later"); _timer.expires_from_now( boost::posix_time::microseconds( config::block_interval_us / 10 )); @@ -528,158 +556,45 @@ void producer_plugin_impl::schedule_production_loop() { schedule_production_loop(); } }); - break; - case start_block_result::succeeded: - static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); - chain::controller& chain = app().get_plugin().chain(); - _timer.expires_at(epoch + boost::posix_time::microseconds(chain.pending_block_time().time_since_epoch().count())); + } else if (_pending_block_mode == pending_block_mode::producing) { + // we succeeded but block may be exhausted + if (result == start_block_result::succeeded) { + // ship this block off no later than its deadline + static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); + chain::controller& chain = app().get_plugin().chain(); + _timer.expires_at(epoch + boost::posix_time::microseconds(chain.pending_block_time().time_since_epoch().count())); + } else { + // ship this block off immediately + _timer.expires_from_now( boost::posix_time::microseconds( 0 )); + } - //_timer.async_wait(boost::bind(&producer_plugin_impl::block_production_loop, this)); _timer.async_wait([&](const boost::system::error_code& ec) { if (ec != boost::asio::error::operation_aborted) { - block_production_loop(); + maybe_produce_block(); } }); - break; } + } -block_production_condition::block_production_condition_enum producer_plugin_impl::block_production_loop() { - block_production_condition::block_production_condition_enum result; - fc::mutable_variant_object capture; - try - { - result = maybe_produce_block(capture); - } - catch( const fc::canceled_exception& ) - { - //We're trying to exit. Go ahead and let this one out. - throw; - } - catch( const fc::exception& e ) - { - elog("Got exception while generating block:\n${e}", ("e", e.to_detail_string())); - result = block_production_condition::exception_producing_block; - } - if(result != block_production_condition::produced && result == _prev_result) { - _prev_result_count++; - } - else { - /* - if (_prev_result_count > 1) { - ilog("Previous result occurred ${r} times",("r", _prev_result_count)); - } - */ - _prev_result_count = 1; - _prev_result = result; - switch(result) - { - case block_production_condition::produced: { - const auto& db = app().get_plugin().chain(); - auto producer = db.head_block_producer(); - auto pending = db.head_block_state(); - - ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, confirmed: ${confs}]", - ("p",producer)("id",fc::variant(pending->id).as_string().substr(0,16)) - ("n",pending->block_num)("t",pending->block->timestamp) - ("count",pending->block->transactions.size())("lib",db.last_irreversible_block_num())("confs", pending->header.confirmed)(capture) ); - break; - } - case block_production_condition::not_synced: - ilog("Not producing block because production is disabled until we receive a recent block (see: --enable-stale-production)"); - break; - case block_production_condition::not_my_turn: - // ilog("Not producing block because it isn't my turn, its ${scheduled_producer}", (capture) ); - break; - case block_production_condition::not_time_yet: - // ilog("Not producing block because slot has not yet arrived"); - break; - case block_production_condition::no_private_key: - ilog("Not producing block because I don't have the private key for ${scheduled_key}", (capture) ); - break; - case block_production_condition::low_participation: - elog("Not producing block because node appears to be on a minority fork with only ${pct}% producer participation", (capture) ); - break; - case block_production_condition::lag: - elog("Not producing block because node didn't wake up within 500ms of the slot time."); - break; - case block_production_condition::exception_producing_block: - elog( "exception producing block" ); - break; - case block_production_condition::fork_below_watermark: - elog( "Not producing block because \"${producer}\" signed a BFT confirmation OR block at a higher block number (${watermark}) than the current fork's head (${head_block_num})" ); - break; - } - } +bool producer_plugin_impl::maybe_produce_block() { + bool result = false; + try { + produce_block(); + result = true; + } FC_LOG_AND_DROP(); schedule_production_loop(); + return result; } -block_production_condition::block_production_condition_enum producer_plugin_impl::maybe_produce_block(fc::mutable_variant_object& capture) { +void producer_plugin_impl::produce_block() { chain::controller& chain = app().get_plugin().chain(); - block_state_ptr hbs = chain.head_block_state(); - fc::time_point now = fc::time_point::now(); - - /* - if (app().get_plugin().is_skipping_transaction_signatures()) { - _production_skip_flags |= skip_transaction_signatures; - } - */ - // If the next block production opportunity is in the present or future, we're synced. - if( !_production_enabled ) - { - return block_production_condition::not_synced; - } - - auto pending_block_timestamp = chain.pending_block_state()->header.timestamp; - - // - // this assert should not fail, because now <= db.head_block_time() - // should have resulted in slot == 0. - // - // if this assert triggers, there is a serious bug in get_slot_at_time() - // which would result in allowing a later block to have a timestamp - // less than or equal to the previous block - // - assert( now > chain.head_block_time() ); - - const auto& scheduled_producer = hbs->get_scheduled_producer( pending_block_timestamp ); - // we must control the producer scheduled to produce the next block. - if( _producers.find( scheduled_producer.producer_name ) == _producers.end() ) - { - capture("scheduled_producer", scheduled_producer.producer_name); - return block_production_condition::not_my_turn; - } - - auto private_key_itr = _private_keys.find( scheduled_producer.block_signing_key ); - - if( private_key_itr == _private_keys.end() ) - { - capture("scheduled_key", scheduled_producer.block_signing_key); - return block_production_condition::no_private_key; - } - - /*uint32_t prate = hbs->producer_participation_rate(); - if( prate < _required_producer_participation ) - { - capture("pct", uint32_t(prate / config::percent_1)); - return block_production_condition::low_participation; - }*/ + const auto& pbs = chain.pending_block_state(); + const auto& hbs = chain.head_block_state(); + FC_ASSERT(pbs, "pending_block_state does not exist but it should, another plugin may have corrupted it"); + auto private_key_itr = _private_keys.find( pbs->block_signing_key ); - if( llabs(( pending_block_timestamp.to_time_point() - now).count()) > fc::milliseconds( config::block_interval_ms ).count() ) - { - capture("scheduled_time", pending_block_timestamp)("now", now); - return block_production_condition::lag; - } - - // determine if our watermark excludes us from producing at this point - auto itr = _producer_watermarks.find(scheduled_producer.producer_name); - if (itr != _producer_watermarks.end()) { - if (itr->second >= hbs->block_num + 1) { - capture("producer", scheduled_producer.producer_name)("watermark",itr->second)("head_block_num",hbs->block_num); - return block_production_condition::fork_below_watermark; - } - } //idump( (fc::time_point::now() - chain.pending_block_time()) ); chain.finalize_block(); @@ -706,8 +621,13 @@ block_production_condition::block_production_condition_enum producer_plugin_impl _producer_watermarks[new_producer] = chain.head_block_num(); } } - _producer_watermarks[scheduled_producer.producer_name] = chain.head_block_num(); - return block_production_condition::produced; + _producer_watermarks[new_bs->header.producer] = chain.head_block_num(); + + ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, confirmed: ${confs}]", + ("p",new_bs->header.producer)("id",fc::variant(new_bs->id).as_string().substr(0,16)) + ("n",new_bs->block_num)("t",new_bs->header.timestamp) + ("count",new_bs->block->transactions.size())("lib",chain.last_irreversible_block_num())("confs", new_bs->header.confirmed)); + } } // namespace eosio From 54cb085e672d6741a66b6c29b27a1a397ab6df1c Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Thu, 17 May 2018 11:53:22 -0400 Subject: [PATCH 02/55] make failure modes exclusive since they no longer early-return --- plugins/producer_plugin/producer_plugin.cpp | 40 ++++++++++----------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 681b47e0172..93929910ef5 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -429,34 +429,32 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { _pending_block_mode = pending_block_mode::producing; + // Not our turn + const auto& scheduled_producer = hbs->get_scheduled_producer(block_time); + auto currrent_watermark_itr = _producer_watermarks.find(scheduled_producer.producer_name); + auto private_key_itr = _private_keys.find(scheduled_producer.block_signing_key); // If the next block production opportunity is in the present or future, we're synced. if( !_production_enabled ) { _pending_block_mode = pending_block_mode::speculating; - } - - // Not our turn - const auto& scheduled_producer = hbs->get_scheduled_producer(block_time); - if( _producers.find(scheduled_producer.producer_name) != _producers.end()) { + } else if( _producers.find(scheduled_producer.producer_name) == _producers.end()) { _pending_block_mode = pending_block_mode::speculating; - } - - auto private_key_itr = _private_keys.find( scheduled_producer.block_signing_key ); - if( private_key_itr == _private_keys.end() ) { - ilog("Not producing block because I don't have the private key for ${scheduled_key}", ("scheduled_key", scheduled_producer.block_signing_key)); - _pending_block_mode = pending_block_mode::speculating; - } - - // determine if our watermark excludes us from producing at this point - auto currrent_watermark_itr = _producer_watermarks.find(scheduled_producer.producer_name); - if (currrent_watermark_itr != _producer_watermarks.end()) { - if (currrent_watermark_itr->second >= hbs->block_num + 1) { - elog( "Not producing block because \"${producer}\" signed a BFT confirmation OR block at a higher block number (${watermark}) than the current fork's head (${head_block_num})", - ("producer", scheduled_producer.producer_name) - ("watermark",currrent_watermark_itr->second) - ("head_block_num",hbs->block_num)); + } else if (_pending_block_mode == pending_block_mode::producing) { + if (private_key_itr == _private_keys.end()) { + ilog("Not producing block because I don't have the private key for ${scheduled_key}", ("scheduled_key", scheduled_producer.block_signing_key)); _pending_block_mode = pending_block_mode::speculating; } + } else if (_pending_block_mode == pending_block_mode::producing) { + // determine if our watermark excludes us from producing at this point + if (currrent_watermark_itr != _producer_watermarks.end()) { + if (currrent_watermark_itr->second >= hbs->block_num + 1) { + elog("Not producing block because \"${producer}\" signed a BFT confirmation OR block at a higher block number (${watermark}) than the current fork's head (${head_block_num})", + ("producer", scheduled_producer.producer_name) + ("watermark", currrent_watermark_itr->second) + ("head_block_num", hbs->block_num)); + _pending_block_mode = pending_block_mode::speculating; + } + } } try { From fc4d4bb35651ff92b34c1ee9e1ba25e9ff2faf82 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Thu, 17 May 2018 13:42:53 -0400 Subject: [PATCH 03/55] bubble subjective failures to the caller through the trace not throwing. EOSIO/eos#3161 --- plugins/chain_plugin/chain_plugin.cpp | 4 ++-- .../include/eosio/chain_plugin/chain_plugin.hpp | 2 +- plugins/net_plugin/net_plugin.cpp | 15 +++++++++++---- plugins/producer_plugin/producer_plugin.cpp | 10 +++++----- .../txn_test_gen_plugin/txn_test_gen_plugin.cpp | 2 +- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 987be74be7b..a2306715754 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -273,8 +273,8 @@ void chain_plugin::accept_block(const signed_block_ptr& block ) { my->incoming_block_sync_method(block); } -void chain_plugin::accept_transaction(const packed_transaction& trx) { - my->incoming_transaction_sync_method(std::make_shared(trx)); +chain::transaction_trace_ptr chain_plugin::accept_transaction(const packed_transaction& trx) { + return my->incoming_transaction_sync_method(std::make_shared(trx)); } bool chain_plugin::block_is_on_preferred_chain(const block_id_type& block_id) { diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 8d21dff8140..cb1a263a460 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -349,7 +349,7 @@ class chain_plugin : public plugin { chain_apis::read_write get_read_write_api(); void accept_block( const chain::signed_block_ptr& block ); - void accept_transaction(const chain::packed_transaction& trx); + chain::transaction_trace_ptr accept_transaction(const chain::packed_transaction& trx); bool block_is_on_preferred_chain(const chain::block_id_type& block_id); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 91231131f22..5c437d3b9f6 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -2435,10 +2435,17 @@ namespace eosio { dispatcher->recv_transaction(c, tid); uint64_t code = 0; try { - chain_plug->accept_transaction( msg); - fc_dlog(logger, "chain accepted transaction" ); - dispatcher->bcast_transaction(msg); - return; + auto trace = chain_plug->accept_transaction( msg); + if (!trace->except) { + fc_dlog(logger, "chain accepted transaction"); + dispatcher->bcast_transaction(msg); + return; + } + + // if accept didn't throw but there was an exception on the trace + // it means that this was non-fatally rejected from the chain. + // we will mark it as "rejected" and hope someone sends it to us later + // when we are able to accept it. } catch( const fc::exception &ex) { code = ex.code(); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 93929910ef5..1ff7ba56acf 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -224,17 +224,17 @@ class producer_plugin_impl { // if we failed because the block was exhausted push the block out and try again if it succeeds if (trace->except) { - if (failure_is_subjective(*trace->except, deadline == block_time) && _pending_block_mode == pending_block_mode::producing) { - if (maybe_produce_block()) { + if (failure_is_subjective(*trace->except, deadline == block_time) ) { + if (_pending_block_mode == pending_block_mode::producing && maybe_produce_block()) { continue; } // if we failed to produce a block that was not speculative (for some reason). we are going to - // throw the exception out to the caller. if they don't support any retry mechanics + // return the trace with an exception set to the caller. if they don't support any retry mechanics // this may result in a lost transaction + } else { + trace->except->dynamic_rethrow_exception(); } - - trace->except->dynamic_rethrow_exception(); } else { return trace; } 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 8e7205d2fde..81617f0a992 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -73,7 +73,7 @@ using namespace eosio::chain; struct txn_test_gen_plugin_impl { void push_transaction( signed_transaction& trx ) { try { chain_plugin& cp = app().get_plugin(); - return cp.accept_transaction( packed_transaction(trx) ); + cp.accept_transaction( packed_transaction(trx) ); } FC_CAPTURE_AND_RETHROW( (transaction_header(trx)) ) } void create_test_accounts(const std::string& init_name, const std::string& init_priv_key) { From 5b30153ae8330e0d1a9a4fb6fd758f48ffdb521f Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Thu, 17 May 2018 13:55:03 -0400 Subject: [PATCH 04/55] this time with less infinite looping --- plugins/producer_plugin/producer_plugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 1ff7ba56acf..f9481087e93 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -235,9 +235,9 @@ class producer_plugin_impl { } else { trace->except->dynamic_rethrow_exception(); } - } else { - return trace; } + + return trace; } }); } From 477fd3d1cb57e3fd693609e04ef5afed404fb5ca Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Thu, 17 May 2018 15:47:22 -0400 Subject: [PATCH 05/55] attempt to properly set a wake up timer that rides the line between speculating and future production; dont ack soft fails EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 37 ++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index f9481087e93..05df56a047b 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -156,7 +156,12 @@ class producer_plugin_impl { }); try { - return f(); + auto trace = f(); + if (trace->except) { + publish_success.cancel(); + channel.publish(std::pair(trace->except->dynamic_copy_exception(), data)); + } + return trace; } catch (const fc::exception& e) { publish_success.cancel(); channel.publish(std::pair(e.dynamic_copy_exception(), data)); @@ -571,6 +576,36 @@ void producer_plugin_impl::schedule_production_loop() { maybe_produce_block(); } }); + } else if (_pending_block_mode == pending_block_mode::speculating && !_producers.empty()){ + // if we have any producers then we should at least set a timer for our next available slot + chain::controller& chain = app().get_plugin().chain(); + const auto& hbs = chain.head_block_state(); + const auto& active_schedule = hbs->active_schedule; + const auto& hbt = hbs->header.timestamp; + uint32_t producer_index = hbt.slot % (active_schedule.producers.size() * config::producer_repetitions); + producer_index /= config::producer_repetitions; + + uint32_t producer_first_slot = hbt.slot - (hbt.slot % config::producer_repetitions); + + for (int idx = producer_index + 1; idx < producer_index + active_schedule.producers.size(); idx++) { + auto producer_name = active_schedule.producers.at(idx % active_schedule.producers.size()).producer_name; + if (_producers.find(producer_name) != _producers.end()) { + uint32_t my_next_slot = producer_first_slot + ((idx - producer_index) * config::producer_repetitions); + + // we should wake up 1 block prior to that so that we make our deadline + my_next_slot--; + + static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); + _timer.expires_at(epoch + boost::posix_time::microseconds(block_timestamp_type(my_next_slot).to_time_point().time_since_epoch().count())); + _timer.async_wait([&](const boost::system::error_code& ec) { + if (ec != boost::asio::error::operation_aborted) { + schedule_production_loop(); + } + }); + + break; + } + } } } From e8b323aa765bb395ab737e3545f2fb74dc761efb Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Thu, 17 May 2018 21:06:32 -0400 Subject: [PATCH 06/55] Fix #3187 - effecient detection of names with '.' - also exempt the eosio account from this restriction --- contracts/eosio.system/delegate_bandwidth.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/delegate_bandwidth.cpp b/contracts/eosio.system/delegate_bandwidth.cpp index 9e462b1522d..3287c7726ff 100644 --- a/contracts/eosio.system/delegate_bandwidth.cpp +++ b/contracts/eosio.system/delegate_bandwidth.cpp @@ -97,10 +97,14 @@ namespace eosiosystem { /* no need to parse authorites const authority& owner, const authority& active*/ ) { - auto name_str = eosio::name{newact}.to_string(); - eosio_assert( name_str.size() == 12 || creator == N(eosio), "account names must be 12 chars long" ); - eosio_assert( name_str.find_first_of('.') == std::string::npos || creator == N(eosio), "account names cannot contain '.' character"); + if( creator != _self ) { + auto tmp = newact; + for( uint32_t i = 0; i < 12; ++i ) { + if( tmp & 0x1f ) eosio_assert( false, "name may not contain '.'"); + tmp >>= 5; + } + } user_resources_table userres( _self, newact); From 7623573a67e1752f4b8cc622cc45d35a99659deb Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Fri, 18 May 2018 00:27:58 -0400 Subject: [PATCH 07/55] Implement Name Auction #3189 --- contracts/eosio.system/delegate_bandwidth.cpp | 38 -------- contracts/eosio.system/eosio.system.cpp | 86 +++++++++++++++++++ contracts/eosio.system/eosio.system.hpp | 21 ++++- contracts/eosio.system/producer_pay.cpp | 13 +++ contracts/eosiolib/types.hpp | 23 +++++ unittests/misc_tests.cpp | 49 +++++++++++ 6 files changed, 191 insertions(+), 39 deletions(-) diff --git a/contracts/eosio.system/delegate_bandwidth.cpp b/contracts/eosio.system/delegate_bandwidth.cpp index 3287c7726ff..c4e6bdaa7f3 100644 --- a/contracts/eosio.system/delegate_bandwidth.cpp +++ b/contracts/eosio.system/delegate_bandwidth.cpp @@ -80,44 +80,6 @@ namespace eosiosystem { typedef eosio::multi_index< N(refunds), refund_request> refunds_table; - /** - * Called after a new account is created. This code enforces resource-limits rules - * for new accounts as well as new account naming conventions. - * - * 1. accounts cannot contain '.' symbols which forces all acccounts to be 12 - * characters long without '.' until a future account auction process is implemented - * which prevents name squatting. - * - * 2. new accounts must stake a minimal number of tokens (as set in system parameters) - * therefore, this method will execute an inline buyram from receiver for newacnt in - * an amount equal to the current new account creation fee. - */ - void native::newaccount( account_name creator, - account_name newact - /* no need to parse authorites - const authority& owner, - const authority& active*/ ) { - - if( creator != _self ) { - auto tmp = newact; - for( uint32_t i = 0; i < 12; ++i ) { - if( tmp & 0x1f ) eosio_assert( false, "name may not contain '.'"); - tmp >>= 5; - } - } - - user_resources_table userres( _self, newact); - - userres.emplace( newact, [&]( auto& res ) { - res.owner = newact; - }); - - set_resource_limits( newact, - 0,// r->ram_bytes, - 0, 0 ); - // r->net_weight.amount, - // r->cpu_weight.amount ); - } /** * This action will buy an exact amount of ram and bill the payer the current market price. diff --git a/contracts/eosio.system/eosio.system.cpp b/contracts/eosio.system/eosio.system.cpp index 7ca481ceaca..668e164da8f 100644 --- a/contracts/eosio.system/eosio.system.cpp +++ b/contracts/eosio.system/eosio.system.cpp @@ -77,6 +77,91 @@ namespace eosiosystem { set_privileged( account, ispriv ); } + 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( !is_account( newname ), "account already exists" ); + eosio_assert( bid.symbol == asset().symbol, "asset must be system token" ); + eosio_assert( bid.amount > 0, "insufficient bid" ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {bidder,N(active)}, + { bidder, N(eosio), bid, std::string("bid name ")+(name{newname}).to_string() } ); + + name_bid_table bids(_self,_self); + auto current = bids.find( newname ); + if( current != bids.end() ) { + bids.emplace( bidder, [&]( auto& b ) { + b.newname = newname; + b.high_bidder = bidder; + b.high_bid = bid.amount; + b.last_bid_time = current_time(); + }); + } else { + eosio_assert( current->high_bid > 0, "this auction has already closed" ); + eosio_assert( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" ); + eosio_assert( current->high_bidder != bidder, "account is already high bidder" ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(eosio.code)}, + { N(eosio), current->high_bidder, asset(current->high_bid), + std::string("refund bid on name ")+(name{newname}).to_string() } ); + + bids.modify( current, bidder, [&]( auto& b ) { + b.high_bidder = bidder; + b.high_bid = bid.amount; + b.last_bid_time = current_time(); + }); + } + } + + /** + * Called after a new account is created. This code enforces resource-limits rules + * for new accounts as well as new account naming conventions. + * + * 1. accounts cannot contain '.' symbols which forces all acccounts to be 12 + * characters long without '.' until a future account auction process is implemented + * which prevents name squatting. + * + * 2. new accounts must stake a minimal number of tokens (as set in system parameters) + * therefore, this method will execute an inline buyram from receiver for newacnt in + * an amount equal to the current new account creation fee. + */ + void native::newaccount( account_name creator, + account_name newact + /* no need to parse authorites + const authority& owner, + const authority& active*/ ) { + + if( creator != _self ) { + auto tmp = newact; + bool has_dot = false; + for( uint32_t i = 0; i < 13; ++i ) { + has_dot |= (tmp >> 59); + tmp <<= 5; + } + auto suffix = eosio::name_suffix(newact); + if( has_dot ) { + if( suffix == newact ) { + name_bid_table bids(_self,_self); + auto current = bids.find( newact ); + eosio_assert( current != bids.end(), "no active bid for name" ); + eosio_assert( current->high_bidder == creator, "only high bidder can claim" ); + eosio_assert( current->high_bid < 0, "auction for name is not closed yet" ); + bids.erase( current ); + } else { + eosio_assert( creator == suffix, "only suffix may create this account" ); + } + } + } + + user_resources_table userres( _self, newact); + + userres.emplace( newact, [&]( auto& res ) { + res.owner = newact; + }); + + set_resource_limits( newact, 0, 0, 0 ); + } + } /// eosio.system @@ -93,5 +178,6 @@ EOSIO_ABI( eosiosystem::system_contract, (onblock) (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(postrecovery)(passrecovery)(vetorecovery)(onerror)(canceldelay) //this file + (bidname) (setpriv) ) diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp index 5f3f4887c06..42f8256cace 100644 --- a/contracts/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/eosio.system.hpp @@ -27,6 +27,23 @@ namespace eosiosystem { EOSLIB_SERIALIZE_DERIVED( eosio_parameters, eosio::blockchain_parameters, (max_ram_size) ) }; + struct name_bid { + account_name newname; + account_name high_bidder; + int64_t high_bid = 0; ///< negative high_bid == closed auction waiting to be claimed + uint64_t last_bid_time = 0; + + auto primary_key()const { return newname; } + uint64_t by_high_bid()const { return -high_bid; } + }; + + typedef eosio::multi_index< N(namebids), name_bid, + indexed_by > + > name_bid_table; + + + + struct eosio_global_state : eosio_parameters { uint64_t free_ram()const { return max_ram_size - total_ram_bytes_reserved; } @@ -42,12 +59,13 @@ namespace eosiosystem { int64_t total_activated_stake = 0; checksum160 last_producer_schedule_id; double total_producer_vote_weight = 0; /// the sum of all producer votes + block_timestamp last_name_close; // explicit serialization macro is not necessary, used here only to improve compilation time EOSLIB_SERIALIZE_DERIVED( eosio_global_state, eosio_parameters, (total_ram_bytes_reserved)(total_ram_stake) (last_producer_schedule_update) (last_pervote_bucket_fill) - (pervote_bucket)(perblock_bucket)(savings)(total_unpaid_blocks)(total_activated_stake)(last_producer_schedule_id)(total_producer_vote_weight) ) + (pervote_bucket)(perblock_bucket)(savings)(total_unpaid_blocks)(total_activated_stake)(last_producer_schedule_id)(total_producer_vote_weight)(last_name_close) ) }; struct producer_info { @@ -200,6 +218,7 @@ namespace eosiosystem { void setpriv( account_name account, uint8_t ispriv ); + void bidname( account_name bidder, account_name newname, asset bid ); private: void update_elected_producers( block_timestamp timestamp ); diff --git a/contracts/eosio.system/producer_pay.cpp b/contracts/eosio.system/producer_pay.cpp index 04831bce8d8..bfcf47186c7 100644 --- a/contracts/eosio.system/producer_pay.cpp +++ b/contracts/eosio.system/producer_pay.cpp @@ -46,6 +46,19 @@ namespace eosiosystem { /// only update block producers once every minute, block_timestamp is in half seconds if( timestamp.slot - _gstate.last_producer_schedule_update.slot > 120 ) { update_elected_producers( timestamp ); + + + if( (timestamp.slot - _gstate.last_name_close.slot) > (2*60*60*24ll)/*timeslots_per_day*/ ) { + name_bid_table bids(_self,_self); + auto idx = bids.get_index(); + auto highest = idx.begin(); + if( highest != idx.end() && highest->high_bid > 0 && highest->last_bid_time < (current_time() - useconds_per_day) ) { + _gstate.last_name_close = timestamp; + idx.modify( highest, 0, [&]( auto& b ){ + b.high_bid = -b.high_bid; + }); + } + } } } diff --git a/contracts/eosiolib/types.hpp b/contracts/eosiolib/types.hpp index 3ac1e2cdbe4..db79c767e37 100644 --- a/contracts/eosiolib/types.hpp +++ b/contracts/eosiolib/types.hpp @@ -66,6 +66,29 @@ namespace eosio { */ #define N(X) ::eosio::string_to_name(#X) + + static constexpr uint64_t name_suffix( uint64_t tmp ) { + uint64_t suffix = 0; + bool endsuffix = false; + uint32_t offset = 0; + for( uint32_t i = 0; i <= 12; ++i, ++offset ) { + auto p = tmp >> 59; + if( !p ) { + endsuffix = true; + } else { + if( !endsuffix ) { + suffix |= uint64_t(p) << (59-(5*offset)); + } + } + if( endsuffix && p ) { + endsuffix = false; + offset = 0; + suffix = uint64_t(p) << (59-(5*offset)); + } + tmp <<= 5; + } + return suffix; + } /** * @brief wraps a uint64_t to ensure it is only passed to methods that expect a Name * @details wraps a uint64_t to ensure it is only passed to methods that expect a Name and diff --git a/unittests/misc_tests.cpp b/unittests/misc_tests.cpp index a45e51b4beb..ebea90b8b69 100644 --- a/unittests/misc_tests.cpp +++ b/unittests/misc_tests.cpp @@ -532,6 +532,55 @@ BOOST_AUTO_TEST_CASE(alphabetic_sort) } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( suffix_test ) try { + uint64_t com = name( "com" ); + uint64_t order = com; + + uint64_t name_com = name("name.com"); + uint64_t name_com_au = name("name.com.au"); + + //std::string str(13,'.'); + + uint64_t tmp = com; + auto print = []( uint64_t tmp ) { + static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz"; + + uint64_t suffix = 0; + bool endsuffix = false; + uint32_t offset = 0; + for( uint32_t i = 0; i <= 12; ++i, ++offset ) { + auto p = tmp >> 59; + char c = charmap[p]; + + if( !p ) { + endsuffix = true; + } else { + if( !endsuffix ) { + suffix |= uint64_t(p) << (59-(5*offset)); + } + } + if( endsuffix && p ) { + endsuffix = false; + offset = 0; + suffix = uint64_t(p) << (59-(5*offset)); + } + std::cerr << c; + // str[12-i] = c; + tmp <<= 5; + } + std::cerr << " suffix: " << name(suffix) <<"\n"; + }; + + print( com ); + std::cerr <<"\n"; + print( name_com ); + print( name_com_au ); + + + + +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() } // namespace eosio From 889ec1bc4afbb85c190a04ce55ed9652d0ab937d Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Fri, 18 May 2018 11:38:59 -0400 Subject: [PATCH 08/55] clean up the producer speculative-to-producing delay math; account for watermarks; EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 102 ++++++++++++++------ 1 file changed, 75 insertions(+), 27 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 05df56a047b..771b8e8b6d1 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -80,6 +80,7 @@ class producer_plugin_impl { ,_transaction_ack_channel(app().get_channel()) {} + optional calculate_next_block_time(const account_name& producer_name) const; void schedule_production_loop(); void produce_block(); bool maybe_produce_block(); @@ -414,6 +415,59 @@ void producer_plugin::plugin_shutdown() { } } +optional producer_plugin_impl::calculate_next_block_time(const account_name& producer_name) const { + chain::controller& chain = app().get_plugin().chain(); + const auto& hbs = chain.head_block_state(); + const auto& active_schedule = hbs->active_schedule.producers; + const auto& hbt = hbs->header.timestamp; + + // determine if this producer is in the active schedule and if so, where + auto itr = std::find_if(active_schedule.begin(), active_schedule.end(), [&](const auto& asp){ return asp.producer_name == producer_name; }); + if (itr == active_schedule.end()) { + // this producer is not in the active producer set + return optional(); + } + + size_t producer_index = itr - active_schedule.begin(); + uint32_t minimum_offset = 1; // must at least be the "next" block + + // account for a watermark in the future which is disqualifying this producer for now + // this is conservative assuming no blocks are dropped. If blocks are dropped the watermark will + // disqualify this producer for longer but it is assumed they will wake up, determine that they + // are disqualified for longer due to skipped blocks and re-caculate their next block with better + // information then + auto current_watermark_itr = _producer_watermarks.find(producer_name); + if (current_watermark_itr != _producer_watermarks.end()) { + auto watermark = current_watermark_itr->second; + if (watermark > hbs->block_num) { + // if I have a watermark then I need to wait until after that watermark + minimum_offset = watermark - hbs->block_num + 1; + } + } + + // this producers next opportuity to produce is the next time its slot arrives after or at the calculated minimum + uint32_t minimum_slot = hbt.slot + minimum_offset; + size_t minimum_slot_producer_index = (minimum_slot % (active_schedule.size() * config::producer_repetitions)) / config::producer_repetitions; + if ( producer_index == minimum_slot_producer_index ) { + // this is the producer for the minimum slot, go with that + return block_timestamp_type(minimum_slot).to_time_point(); + } else { + // calculate how many rounds are between the minimum producer and the producer in question + size_t producer_distance = producer_index - minimum_slot_producer_index; + // check for unsigned underflow + if (producer_distance > producer_index) { + producer_distance += active_schedule.size(); + } + + // align the minimum slot to the first of its set of reps + uint32_t first_minimum_producer_slot = minimum_slot - (minimum_slot % config::producer_repetitions); + + // offset the aligned minimum to the *earliest* next set of slots for this producer + uint32_t next_block_slot = first_minimum_producer_slot + (producer_distance * config::producer_repetitions); + return block_timestamp_type(next_block_slot).to_time_point(); + } +} + producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { chain::controller& chain = app().get_plugin().chain(); const auto& hbs = chain.head_block_state(); @@ -578,36 +632,30 @@ void producer_plugin_impl::schedule_production_loop() { }); } else if (_pending_block_mode == pending_block_mode::speculating && !_producers.empty()){ // if we have any producers then we should at least set a timer for our next available slot - chain::controller& chain = app().get_plugin().chain(); - const auto& hbs = chain.head_block_state(); - const auto& active_schedule = hbs->active_schedule; - const auto& hbt = hbs->header.timestamp; - uint32_t producer_index = hbt.slot % (active_schedule.producers.size() * config::producer_repetitions); - producer_index /= config::producer_repetitions; - - uint32_t producer_first_slot = hbt.slot - (hbt.slot % config::producer_repetitions); - - for (int idx = producer_index + 1; idx < producer_index + active_schedule.producers.size(); idx++) { - auto producer_name = active_schedule.producers.at(idx % active_schedule.producers.size()).producer_name; - if (_producers.find(producer_name) != _producers.end()) { - uint32_t my_next_slot = producer_first_slot + ((idx - producer_index) * config::producer_repetitions); - - // we should wake up 1 block prior to that so that we make our deadline - my_next_slot--; - - static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); - _timer.expires_at(epoch + boost::posix_time::microseconds(block_timestamp_type(my_next_slot).to_time_point().time_since_epoch().count())); - _timer.async_wait([&](const boost::system::error_code& ec) { - if (ec != boost::asio::error::operation_aborted) { - schedule_production_loop(); - } - }); - - break; + optional wake_up_time; + for (const auto&p: _producers) { + auto next_producer_block_time = calculate_next_block_time(p); + if (next_producer_block_time) { + auto producer_wake_up_time = *next_producer_block_time - fc::microseconds(config::block_interval_us); + if (wake_up_time) { + // wake up with a full block interval to the deadline + wake_up_time = std::min(*wake_up_time, producer_wake_up_time); + } else { + wake_up_time = producer_wake_up_time; + } } } - } + if (wake_up_time) { + static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); + _timer.expires_at(epoch + boost::posix_time::microseconds(wake_up_time->time_since_epoch().count())); + _timer.async_wait([&](const boost::system::error_code& ec) { + if (ec != boost::asio::error::operation_aborted) { + schedule_production_loop(); + } + }); + } + } } bool producer_plugin_impl::maybe_produce_block() { From de54bb5e11b843b50ded0e475014f97779c53f16 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Fri, 18 May 2018 14:39:11 -0400 Subject: [PATCH 09/55] merge master, fix unit tests, and update system state abi --- contracts/eosio.system/eosio.system.abi | 3 ++- unittests/eosio.system_tests.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi index 691217a46d3..b5f1223f2fc 100644 --- a/contracts/eosio.system/eosio.system.abi +++ b/contracts/eosio.system/eosio.system.abi @@ -261,7 +261,8 @@ {"name":"total_unpaid_blocks", "type":"uint32"}, {"name":"total_activated_stake", "type":"int64"}, {"name":"last_producer_schedule_id", "type":"checksum160"}, - {"name":"total_producer_vote_weight", "type":"float64"} + {"name":"total_producer_vote_weight", "type":"float64"}, + {"name":"last_name_close", "type":"block_timestamp_type"} ] },{ "name": "producer_info", diff --git a/unittests/eosio.system_tests.cpp b/unittests/eosio.system_tests.cpp index a769f1f1dad..d8f3a9c9519 100644 --- a/unittests/eosio.system_tests.cpp +++ b/unittests/eosio.system_tests.cpp @@ -2578,7 +2578,7 @@ BOOST_FIXTURE_TEST_CASE( buyname, eosio_system_tester ) try { BOOST_REQUIRE_THROW( create_accounts_with_resources( { N(fail) }, N(dan) ), fc::exception ); // dan shouldn't be able to create fail bidname( "dan", "nofail", core_from_string( "1.0000" ) ); - BOOST_REQUIRE_EQUAL( "condition: assertion failed: must increase bid by 10%", bidname( "sam", "nofail", core_from_string( "1.0000" ) )); // didn't increase bid by 10% + BOOST_REQUIRE_EQUAL( "assertion failure with message: must increase bid by 10%", bidname( "sam", "nofail", core_from_string( "1.0000" ) )); // didn't increase bid by 10% BOOST_REQUIRE_EQUAL( success(), bidname( "sam", "nofail", core_from_string( "2.0000" ) )); // didn't increase bid by 10% produce_block( fc::days(1) ); produce_block(); From cb043624395c443fafe6d86b41c484b93de09911 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Fri, 18 May 2018 17:41:53 -0400 Subject: [PATCH 10/55] only treat block_time as a deadline if we are producing EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 32 ++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 771b8e8b6d1..228bb30e8b9 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -224,13 +224,19 @@ class producer_plugin_impl { while (true) { chain::controller& chain = app().get_plugin().chain(); auto block_time = chain.pending_block_state()->header.timestamp.to_time_point(); - auto max_deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); - auto deadline = std::min(block_time, max_deadline); + + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_pending_block_mode == pending_block_mode::producing && block_time < deadline) { + deadline_is_subjective = true; + deadline = block_time; + } + auto trace = chain.push_transaction(std::make_shared(*trx), deadline); // if we failed because the block was exhausted push the block out and try again if it succeeds if (trace->except) { - if (failure_is_subjective(*trace->except, deadline == block_time) ) { + if (failure_is_subjective(*trace->except, deadline_is_subjective) ) { if (_pending_block_mode == pending_block_mode::producing && maybe_produce_block()) { continue; } @@ -547,10 +553,16 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } try { - auto deadline = std::min(block_time, fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms)); + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_pending_block_mode == pending_block_mode::producing && block_time < deadline) { + deadline_is_subjective = true; + deadline = block_time; + } + auto trace = chain.push_transaction(trx, deadline); if (trace->except) { - if (failure_is_subjective(*trace->except, deadline == block_time)) { + if (failure_is_subjective(*trace->except, deadline_is_subjective)) { exhausted = true; } else { // this failed our configured maximum transaction time, we don't want to replay it @@ -578,10 +590,16 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } try { - auto deadline = std::min(block_time, fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms)); + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_pending_block_mode == pending_block_mode::producing && block_time < deadline) { + deadline_is_subjective = true; + deadline = block_time; + } + auto trace = chain.push_scheduled_transaction(trx, deadline); if (trace->except) { - if (failure_is_subjective(*trace->except, deadline == block_time)) { + if (failure_is_subjective(*trace->except, deadline_is_subjective)) { exhausted = true; } else { auto expiration = fc::time_point::now() + fc::seconds(chain.get_global_properties().configuration.deferred_trx_expiration_window); From 089d92b5f27375c7fbdaec8e362cf083ada604ef Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Fri, 18 May 2018 17:49:56 -0400 Subject: [PATCH 11/55] history_plugin: get accounts (#2876) and get servants (#3160) --- .../history_api_plugin/history_api_plugin.cpp | 4 +- plugins/history_plugin/history_plugin.cpp | 95 +++++++++++++++++++ .../include/eosio/history_plugin.hpp | 4 +- .../account_control_history_object.hpp | 0 .../public_key_history_object.hpp | 0 programs/cleos/httpc.hpp | 4 +- 6 files changed, 100 insertions(+), 7 deletions(-) rename plugins/{account_history_plugin/include/eosio/account_history_plugin => history_plugin/include/eosio/history_plugin}/account_control_history_object.hpp (100%) rename plugins/{account_history_plugin/include/eosio/account_history_plugin => history_plugin/include/eosio/history_plugin}/public_key_history_object.hpp (100%) diff --git a/plugins/history_api_plugin/history_api_plugin.cpp b/plugins/history_api_plugin/history_api_plugin.cpp index 9760c01bedb..2e99e37a5fc 100644 --- a/plugins/history_api_plugin/history_api_plugin.cpp +++ b/plugins/history_api_plugin/history_api_plugin.cpp @@ -49,8 +49,8 @@ void history_api_plugin::plugin_startup() { // CHAIN_RO_CALL(get_transaction), CHAIN_RO_CALL(get_actions), CHAIN_RO_CALL(get_transaction), -// CHAIN_RO_CALL(get_key_accounts), -// CHAIN_RO_CALL(get_controlled_accounts) + CHAIN_RO_CALL(get_key_accounts), + CHAIN_RO_CALL(get_controlled_accounts) }); } diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index cebd51d6882..be2ef63146a 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -74,6 +76,47 @@ CHAINBASE_SET_INDEX_TYPE(eosio::action_history_object, eosio::action_history_ind namespace eosio { + template + static void remove(chainbase::database& db, const account_name& account_name, const permission_name& permission) + { + const auto& idx = db.get_index(); + auto& mutable_idx = db.get_mutable_index(); + while(!idx.empty()) { + auto key = boost::make_tuple(account_name, permission); + const auto& itr = idx.lower_bound(key); + if (itr == idx.end()) + break; + + const auto& range_end = idx.upper_bound(key); + if (itr == range_end) + break; + + mutable_idx.remove(*itr); + } + } + + static void add(chainbase::database& db, const vector& keys, const account_name& name, const permission_name& permission) + { + for (auto pub_key_weight : keys ) { + db.create([&](public_key_history_object& obj) { + obj.public_key = pub_key_weight.key; + obj.name = name; + obj.permission = permission; + }); + } + } + + static void add(chainbase::database& db, const vector& controlling_accounts, const account_name& account_name, const permission_name& permission) + { + for (auto controlling_account : controlling_accounts ) { + db.create([&](account_control_history_object& obj) { + obj.controlled_account = account_name; + obj.controlled_permission = permission; + obj.controlling_account = controlling_account.permission.actor; + }); + } + } + class history_plugin_impl { public: std::set filter_on; @@ -123,6 +166,33 @@ namespace eosio { //idump((a.account)(a.action_sequence_num)(a.action_sequence_num)); } + void on_account_action( const action_trace& at ) { + auto& chain = chain_plug->chain(); + auto& db = chain.db(); + if( at.act.name == N(newaccount) ) + { + const auto create = at.act.data_as(); + add(db, create.owner.keys, create.name, N(owner)); + add(db, create.owner.accounts, create.name, N(owner)); + add(db, create.active.keys, create.name, N(active)); + add(db, create.active.accounts, create.name, N(active)); + } + else if( at.act.name == N(updateauth) ) + { + const auto update = at.act.data_as(); + remove(db, update.account, update.permission); + remove(db, update.account, update.permission); + add(db, update.auth.keys, update.account, update.permission); + add(db, update.auth.accounts, update.account, update.permission); + } + else if( at.act.name == N(deleteauth) ) + { + const auto del = at.act.data_as(); + remove(db, del.account, del.permission); + remove(db, del.account, del.permission); + } + } + void on_action_trace( const action_trace& at ) { if( filter( at ) ) { //idump((fc::json::to_pretty_string(at))); @@ -144,6 +214,9 @@ namespace eosio { for( auto a : aset ) { record_account_action( a, at ); } + + if( at.receipt.receiver == chain::config::system_account_name && is_filtered( at.receipt.receiver ) ) + on_account_action( at ); } for( const auto& iline : at.inline_traces ) { on_action_trace( iline ); @@ -186,6 +259,8 @@ namespace eosio { chain.db().add_index(); chain.db().add_index(); + chain.db().add_index(); + chain.db().add_index(); chain.applied_transaction.connect( [&]( const transaction_trace_ptr& p ){ my->on_applied_transaction(p); @@ -336,6 +411,26 @@ namespace eosio { return result; } + read_only::get_key_accounts_results read_only::get_key_accounts(const get_key_accounts_params& params) const { + std::set accounts; + const auto& db = history->chain_plug->chain().db(); + const auto& pub_key_idx = db.get_index(); + auto range = pub_key_idx.equal_range( params.public_key ); + for (auto obj = range.first; obj != range.second; ++obj) + accounts.insert(obj->name); + return {vector(accounts.begin(), accounts.end())}; + } + + read_only::get_controlled_accounts_results read_only::get_controlled_accounts(const get_controlled_accounts_params& params) const { + std::set accounts; + const auto& db = history->chain_plug->chain().db(); + const auto& account_control_idx = db.get_index(); + auto range = account_control_idx.equal_range( params.controlling_account ); + for (auto obj = range.first; obj != range.second; ++obj) + accounts.insert(obj->controlled_account); + return {vector(accounts.begin(), accounts.end())}; + } + } /// history_apis diff --git a/plugins/history_plugin/include/eosio/history_plugin.hpp b/plugins/history_plugin/include/eosio/history_plugin.hpp index cc84eecbc77..8751196b027 100644 --- a/plugins/history_plugin/include/eosio/history_plugin.hpp +++ b/plugins/history_plugin/include/eosio/history_plugin.hpp @@ -160,10 +160,8 @@ FC_REFLECT(eosio::history_apis::read_only::get_transaction_results, (transaction FC_REFLECT(eosio::history_apis::read_only::get_transactions_params, (account_name)(skip_seq)(num_seq) ) FC_REFLECT(eosio::history_apis::read_only::ordered_transaction_results, (seq_num)(transaction_id)(transaction) ) FC_REFLECT(eosio::history_apis::read_only::get_transactions_results, (transactions)(time_limit_exceeded_error) ) +*/ FC_REFLECT(eosio::history_apis::read_only::get_key_accounts_params, (public_key) ) FC_REFLECT(eosio::history_apis::read_only::get_key_accounts_results, (account_names) ) FC_REFLECT(eosio::history_apis::read_only::get_controlled_accounts_params, (controlling_account) ) FC_REFLECT(eosio::history_apis::read_only::get_controlled_accounts_results, (controlled_accounts) ) -*/ - - diff --git a/plugins/account_history_plugin/include/eosio/account_history_plugin/account_control_history_object.hpp b/plugins/history_plugin/include/eosio/history_plugin/account_control_history_object.hpp similarity index 100% rename from plugins/account_history_plugin/include/eosio/account_history_plugin/account_control_history_object.hpp rename to plugins/history_plugin/include/eosio/history_plugin/account_control_history_object.hpp diff --git a/plugins/account_history_plugin/include/eosio/account_history_plugin/public_key_history_object.hpp b/plugins/history_plugin/include/eosio/history_plugin/public_key_history_object.hpp similarity index 100% rename from plugins/account_history_plugin/include/eosio/account_history_plugin/public_key_history_object.hpp rename to plugins/history_plugin/include/eosio/history_plugin/public_key_history_object.hpp diff --git a/programs/cleos/httpc.hpp b/programs/cleos/httpc.hpp index f22243b8b92..4e889efcebe 100644 --- a/programs/cleos/httpc.hpp +++ b/programs/cleos/httpc.hpp @@ -37,11 +37,11 @@ namespace eosio { namespace client { namespace http { const string history_func_base = "/v1/history"; const string get_actions_func = history_func_base + "/get_actions"; const string get_transaction_func = history_func_base + "/get_transaction"; + const string get_key_accounts_func = history_func_base + "/get_key_accounts"; + const string get_controlled_accounts_func = history_func_base + "/get_controlled_accounts"; const string account_history_func_base = "/v1/account_history"; const string get_transactions_func = account_history_func_base + "/get_transactions"; - const string get_key_accounts_func = account_history_func_base + "/get_key_accounts"; - const string get_controlled_accounts_func = account_history_func_base + "/get_controlled_accounts"; const string net_func_base = "/v1/net"; const string net_connect = net_func_base + "/connect"; From 1efaeafa3b3a0dfcaf349def8c37caaf97b8f6da Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 21 May 2018 10:51:07 -0400 Subject: [PATCH 12/55] Prevent name auctions from closing until 14 days after min_stake_activated - #3209 --- contracts/eosio.system/eosio.system.abi | 1 + contracts/eosio.system/eosio.system.hpp | 4 +++- contracts/eosio.system/producer_pay.cpp | 31 ++++++++++++++----------- contracts/eosio.system/voting.cpp | 3 +++ 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi index b5f1223f2fc..6bdafa44071 100644 --- a/contracts/eosio.system/eosio.system.abi +++ b/contracts/eosio.system/eosio.system.abi @@ -260,6 +260,7 @@ {"name":"savings", "type":"int64"}, {"name":"total_unpaid_blocks", "type":"uint32"}, {"name":"total_activated_stake", "type":"int64"}, + {"name":"thresh_activated_stake_time", "type":"uint64"}, {"name":"last_producer_schedule_id", "type":"checksum160"}, {"name":"total_producer_vote_weight", "type":"float64"}, {"name":"last_name_close", "type":"block_timestamp_type"} diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp index 7174866a415..d8e410250e0 100644 --- a/contracts/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/eosio.system.hpp @@ -57,6 +57,7 @@ namespace eosiosystem { int64_t savings = 0; uint32_t total_unpaid_blocks = 0; /// all blocks which have been produced but not paid int64_t total_activated_stake = 0; + uint64_t thresh_activated_stake_time = 0; checksum160 last_producer_schedule_id; double total_producer_vote_weight = 0; /// the sum of all producer votes block_timestamp last_name_close; @@ -65,7 +66,8 @@ namespace eosiosystem { EOSLIB_SERIALIZE_DERIVED( eosio_global_state, eosio_parameters, (total_ram_bytes_reserved)(total_ram_stake) (last_producer_schedule_update) (last_pervote_bucket_fill) - (pervote_bucket)(perblock_bucket)(savings)(total_unpaid_blocks)(total_activated_stake)(last_producer_schedule_id)(total_producer_vote_weight)(last_name_close) ) + (pervote_bucket)(perblock_bucket)(savings)(total_unpaid_blocks)(total_activated_stake)(thresh_activated_stake_time) + (last_producer_schedule_id)(total_producer_vote_weight)(last_name_close) ) }; struct producer_info { diff --git a/contracts/eosio.system/producer_pay.cpp b/contracts/eosio.system/producer_pay.cpp index 96b9308f326..f06cee9568b 100644 --- a/contracts/eosio.system/producer_pay.cpp +++ b/contracts/eosio.system/producer_pay.cpp @@ -4,17 +4,17 @@ namespace eosiosystem { - const int64_t min_daily_tokens = 100; - const int64_t min_activated_stake = 150'000'000'0000; - const double continuous_rate = 0.04879; // 5% annual rate - const double perblock_rate = 0.0025; // 0.25% - const double standby_rate = 0.0075; // 0.75% - const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year - const uint32_t seconds_per_year = 52*7*24*3600; - const uint32_t blocks_per_day = 2 * 24 * 3600; - const uint32_t blocks_per_hour = 2 * 3600; - const uint64_t useconds_per_day = 24 * 3600 * uint64_t(1000000); - const uint64_t useconds_per_year = seconds_per_year*1000000ll; + const int64_t min_pervote_daily_pay = 100'0000; + const int64_t min_activated_stake = 150'000'000'0000; + const double continuous_rate = 0.04879; // 5% annual rate + const double perblock_rate = 0.0025; // 0.25% + const double standby_rate = 0.0075; // 0.75% + const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year + const uint32_t seconds_per_year = 52*7*24*3600; + const uint32_t blocks_per_day = 2 * 24 * 3600; + const uint32_t blocks_per_hour = 2 * 3600; + const uint64_t useconds_per_day = 24 * 3600 * uint64_t(1000000); + const uint64_t useconds_per_year = seconds_per_year*1000000ll; void system_contract::onblock( block_timestamp timestamp, account_name producer ) { @@ -49,12 +49,15 @@ namespace eosiosystem { print( "maybe update bids \n" ); - if( (timestamp.slot - _gstate.last_name_close.slot) > (2*60*60*24ll)/*timeslots_per_day*/ ) { + if( (timestamp.slot - _gstate.last_name_close.slot) > blocks_per_day ) { print( "update bids" ); name_bid_table bids(_self,_self); auto idx = bids.get_index(); auto highest = idx.begin(); - if( highest != idx.end() && highest->high_bid > 0 && highest->last_bid_time < (current_time() - useconds_per_day) ) { + if( highest != idx.end() && + highest->high_bid > 0 && + highest->last_bid_time < (current_time() - useconds_per_day) && + (current_time() - _gstate.thresh_activated_stake_time) > 14 * useconds_per_day ){ _gstate.last_name_close = timestamp; idx.modify( highest, 0, [&]( auto& b ){ b.high_bid = -b.high_bid; @@ -106,7 +109,7 @@ namespace eosiosystem { if( _gstate.total_producer_vote_weight > 0 ) { producer_per_vote_pay = int64_t((_gstate.pervote_bucket * prod.total_votes ) / _gstate.total_producer_vote_weight); } - if( producer_per_vote_pay < 100'0000 ) { + if( producer_per_vote_pay < min_pervote_daily_pay ) { producer_per_vote_pay = 0; } int64_t total_pay = producer_per_block_pay + producer_per_vote_pay; diff --git a/contracts/eosio.system/voting.cpp b/contracts/eosio.system/voting.cpp index 4b850c2dbad..feb40d55a62 100644 --- a/contracts/eosio.system/voting.cpp +++ b/contracts/eosio.system/voting.cpp @@ -167,6 +167,9 @@ namespace eosiosystem { */ if( voter->last_vote_weight <= 0.0 ) { _gstate.total_activated_stake += voter->staked; + if( _gstate.total_activated_stake >= min_activated_stake ) { + _gstate.thresh_activated_stake_time = current_time(); + } } auto new_vote_weight = stake2vote( voter->staked ); From ef5d7fcbbd8a9cd4d037ea17d6b9003ecfe3812b Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Mon, 21 May 2018 11:09:14 -0400 Subject: [PATCH 13/55] spec change: when speculating and exhuasting a block, drop pending transactions and continue EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 132 +++++++++++--------- 1 file changed, 76 insertions(+), 56 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 228bb30e8b9..fe853f461a2 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -234,10 +234,16 @@ class producer_plugin_impl { auto trace = chain.push_transaction(std::make_shared(*trx), deadline); - // if we failed because the block was exhausted push the block out and try again if it succeeds if (trace->except) { if (failure_is_subjective(*trace->except, deadline_is_subjective) ) { - if (_pending_block_mode == pending_block_mode::producing && maybe_produce_block()) { + // if we failed because the block was exhausted push the block out and try again if it succeeds + if (_pending_block_mode == pending_block_mode::producing ) { + if (maybe_produce_block()) { + continue; + } + } else if (_pending_block_mode == pending_block_mode::speculating) { + abort_block(); + schedule_production_loop(); continue; } @@ -545,72 +551,78 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } FC_LOG_AND_DROP(); if (chain.pending_block_state()) { - bool exhausted = false; - auto unapplied_trxs = chain.get_unapplied_transactions(); - for (const auto& trx : unapplied_trxs) { - if (exhausted) { - break; - } - - try { - auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); - bool deadline_is_subjective = false; - if (_pending_block_mode == pending_block_mode::producing && block_time < deadline) { - deadline_is_subjective = true; - deadline = block_time; + if (_pending_block_mode == pending_block_mode::producing) { + bool exhausted = false; + auto unapplied_trxs = chain.get_unapplied_transactions(); + for (const auto& trx : unapplied_trxs) { + if (exhausted) { + break; } - auto trace = chain.push_transaction(trx, deadline); - if (trace->except) { - if (failure_is_subjective(*trace->except, deadline_is_subjective)) { - exhausted = true; - } else { - // this failed our configured maximum transaction time, we don't want to replay it - chain.drop_unapplied_transaction(trx); + try { + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_pending_block_mode == pending_block_mode::producing && block_time < deadline) { + deadline_is_subjective = true; + deadline = block_time; } - } - } FC_LOG_AND_DROP(); - } - auto& blacklist_by_id = _blacklisted_transactions.get(); - auto& blacklist_by_expiry = _blacklisted_transactions.get(); - auto now = fc::time_point::now(); - while(!blacklist_by_expiry.empty() && blacklist_by_expiry.begin()->expiry <= now) { - blacklist_by_expiry.erase(blacklist_by_expiry.begin()); - } - - auto scheduled_trxs = chain.get_scheduled_transactions(); - for (const auto& trx : scheduled_trxs) { - if (exhausted) { - break; + auto trace = chain.push_transaction(trx, deadline); + if (trace->except) { + if (failure_is_subjective(*trace->except, deadline_is_subjective)) { + exhausted = true; + } else { + // this failed our configured maximum transaction time, we don't want to replay it + chain.drop_unapplied_transaction(trx); + } + } + } FC_LOG_AND_DROP(); } - if (blacklist_by_id.find(trx) != blacklist_by_id.end()) { - continue; + auto& blacklist_by_id = _blacklisted_transactions.get(); + auto& blacklist_by_expiry = _blacklisted_transactions.get(); + auto now = fc::time_point::now(); + while(!blacklist_by_expiry.empty() && blacklist_by_expiry.begin()->expiry <= now) { + blacklist_by_expiry.erase(blacklist_by_expiry.begin()); } - try { - auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); - bool deadline_is_subjective = false; - if (_pending_block_mode == pending_block_mode::producing && block_time < deadline) { - deadline_is_subjective = true; - deadline = block_time; + auto scheduled_trxs = chain.get_scheduled_transactions(); + for (const auto& trx : scheduled_trxs) { + if (exhausted) { + break; } - auto trace = chain.push_scheduled_transaction(trx, deadline); - if (trace->except) { - if (failure_is_subjective(*trace->except, deadline_is_subjective)) { - exhausted = true; - } else { - auto expiration = fc::time_point::now() + fc::seconds(chain.get_global_properties().configuration.deferred_trx_expiration_window); - // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist - _blacklisted_transactions.insert(blacklisted_transaction{trx, expiration}); - } + if (blacklist_by_id.find(trx) != blacklist_by_id.end()) { + continue; } - } FC_LOG_AND_DROP(); + + try { + auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); + bool deadline_is_subjective = false; + if (_pending_block_mode == pending_block_mode::producing && block_time < deadline) { + deadline_is_subjective = true; + deadline = block_time; + } + + auto trace = chain.push_scheduled_transaction(trx, deadline); + if (trace->except) { + if (failure_is_subjective(*trace->except, deadline_is_subjective)) { + exhausted = true; + } else { + auto expiration = fc::time_point::now() + fc::seconds(chain.get_global_properties().configuration.deferred_trx_expiration_window); + // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist + _blacklisted_transactions.insert(blacklisted_transaction{trx, expiration}); + } + } + } FC_LOG_AND_DROP(); + } + + if (exhausted) { + return start_block_result::exhausted; + } } - return exhausted ? start_block_result::exhausted : start_block_result::succeeded; + return start_block_result::succeeded; } return start_block_result::failed; @@ -638,14 +650,17 @@ void producer_plugin_impl::schedule_production_loop() { static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); chain::controller& chain = app().get_plugin().chain(); _timer.expires_at(epoch + boost::posix_time::microseconds(chain.pending_block_time().time_since_epoch().count())); + dlog("Scheduling Block Production on Normal Block #${num} for ${time}", ("num", chain.pending_block_state()->block_num)("time",chain.pending_block_time())); } else { // ship this block off immediately _timer.expires_from_now( boost::posix_time::microseconds( 0 )); + dlog("Scheduling Block Production on Exhausted Block #${num} immediately", ("num", chain.pending_block_state()->block_num)); } _timer.async_wait([&](const boost::system::error_code& ec) { if (ec != boost::asio::error::operation_aborted) { - maybe_produce_block(); + auto res = maybe_produce_block(); + dlog("Producing Block #${num} returned: ${res}", ("num", chain.pending_block_state()->block_num)("res", res) ); } }); } else if (_pending_block_mode == pending_block_mode::speculating && !_producers.empty()){ @@ -665,6 +680,7 @@ void producer_plugin_impl::schedule_production_loop() { } if (wake_up_time) { + dlog("Specualtive Block Created; Scheduling Speculative/Production Change at ", ("time", wake_up_time)); static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); _timer.expires_at(epoch + boost::posix_time::microseconds(wake_up_time->time_since_epoch().count())); _timer.async_wait([&](const boost::system::error_code& ec) { @@ -672,6 +688,10 @@ void producer_plugin_impl::schedule_production_loop() { schedule_production_loop(); } }); + } else { + dlog("Specualtive Block Created; Not Scheduling Speculative/Production, no local producers had valid wake up times"); + } else { + dlog("Specualtive Block Created"); } } } From fed5e6066ba1883c6ab0628836eff111616dc5f4 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Mon, 21 May 2018 11:13:31 -0400 Subject: [PATCH 14/55] fixes due to improper caffeination EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index fe853f461a2..96c20b64758 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -242,7 +242,7 @@ class producer_plugin_impl { continue; } } else if (_pending_block_mode == pending_block_mode::speculating) { - abort_block(); + chain.abort_block(); schedule_production_loop(); continue; } @@ -644,11 +644,12 @@ void producer_plugin_impl::schedule_production_loop() { } }); } else if (_pending_block_mode == pending_block_mode::producing) { + chain::controller& chain = app().get_plugin().chain(); + // we succeeded but block may be exhausted if (result == start_block_result::succeeded) { // ship this block off no later than its deadline static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); - chain::controller& chain = app().get_plugin().chain(); _timer.expires_at(epoch + boost::posix_time::microseconds(chain.pending_block_time().time_since_epoch().count())); dlog("Scheduling Block Production on Normal Block #${num} for ${time}", ("num", chain.pending_block_state()->block_num)("time",chain.pending_block_time())); } else { @@ -690,9 +691,9 @@ void producer_plugin_impl::schedule_production_loop() { }); } else { dlog("Specualtive Block Created; Not Scheduling Speculative/Production, no local producers had valid wake up times"); - } else { - dlog("Specualtive Block Created"); } + } else { + dlog("Specualtive Block Created"); } } From cd7d8ecefd80a14c448ceb8d7de47d2b15c2fa9f Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 21 May 2018 14:09:33 -0400 Subject: [PATCH 15/55] history_plugin: always record newaccount, updateauth, deleteauth --- plugins/history_plugin/history_plugin.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index be2ef63146a..5932401ef35 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -166,7 +166,7 @@ namespace eosio { //idump((a.account)(a.action_sequence_num)(a.action_sequence_num)); } - void on_account_action( const action_trace& at ) { + void on_system_action( const action_trace& at ) { auto& chain = chain_plug->chain(); auto& db = chain.db(); if( at.act.name == N(newaccount) ) @@ -214,10 +214,9 @@ namespace eosio { for( auto a : aset ) { record_account_action( a, at ); } - - if( at.receipt.receiver == chain::config::system_account_name && is_filtered( at.receipt.receiver ) ) - on_account_action( at ); } + if( at.receipt.receiver == chain::config::system_account_name ) + on_system_action( at ); for( const auto& iline : at.inline_traces ) { on_action_trace( iline ); } From 95d616ded0a0393076c34520a39780c90e33350b Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Mon, 21 May 2018 14:14:47 -0400 Subject: [PATCH 16/55] clean up a failed-production block; attempt to catch bad signing key errors at start_block instead of produce_block EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 42 ++++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 96c20b64758..300f31408e6 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -510,19 +510,19 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { _pending_block_mode = pending_block_mode::speculating; } else if( _producers.find(scheduled_producer.producer_name) == _producers.end()) { _pending_block_mode = pending_block_mode::speculating; - } else if (_pending_block_mode == pending_block_mode::producing) { - if (private_key_itr == _private_keys.end()) { - ilog("Not producing block because I don't have the private key for ${scheduled_key}", ("scheduled_key", scheduled_producer.block_signing_key)); - _pending_block_mode = pending_block_mode::speculating; - } - } else if (_pending_block_mode == pending_block_mode::producing) { + } else if (private_key_itr == _private_keys.end()) { + ilog("Not producing block because I don't have the private key for ${scheduled_key}", ("scheduled_key", scheduled_producer.block_signing_key)); + _pending_block_mode = pending_block_mode::speculating; + } + + if (_pending_block_mode == pending_block_mode::producing) { // determine if our watermark excludes us from producing at this point if (currrent_watermark_itr != _producer_watermarks.end()) { if (currrent_watermark_itr->second >= hbs->block_num + 1) { elog("Not producing block because \"${producer}\" signed a BFT confirmation OR block at a higher block number (${watermark}) than the current fork's head (${head_block_num})", - ("producer", scheduled_producer.producer_name) - ("watermark", currrent_watermark_itr->second) - ("head_block_num", hbs->block_num)); + ("producer", scheduled_producer.producer_name) + ("watermark", currrent_watermark_itr->second) + ("head_block_num", hbs->block_num)); _pending_block_mode = pending_block_mode::speculating; } } @@ -550,7 +550,14 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { chain.start_block(block_time, blocks_to_confirm); } FC_LOG_AND_DROP(); - if (chain.pending_block_state()) { + const auto& pbs = chain.pending_block_state(); + if (pbs) { + + if (_pending_block_mode == pending_block_mode::producing && pbs->block_signing_key != scheduled_producer.block_signing_key) { + elog("Block Signing Key is not expected value, reverting to speculative mode! [expected: \"${expected}\", actual: \"${actual\"", ("expected", scheduled_producer.block_signing_key)("actual", pbs->block_signing_key)); + _pending_block_mode = pending_block_mode::speculating; + } + if (_pending_block_mode == pending_block_mode::producing) { bool exhausted = false; auto unapplied_trxs = chain.get_unapplied_transactions(); @@ -698,23 +705,30 @@ void producer_plugin_impl::schedule_production_loop() { } bool producer_plugin_impl::maybe_produce_block() { - bool result = false; + auto reschedule = fc::make_scoped_exit([this]{ + schedule_production_loop(); + }); + try { produce_block(); - result = true; + return true; } FC_LOG_AND_DROP(); - schedule_production_loop(); - return result; + chain::controller& chain = app().get_plugin().chain(); + chain.abort_block(); + return false; } void producer_plugin_impl::produce_block() { + FC_ASSERT(_pending_block_mode == pending_block_mode::producing, "called produce_block while not actually producing"); + chain::controller& chain = app().get_plugin().chain(); const auto& pbs = chain.pending_block_state(); const auto& hbs = chain.head_block_state(); FC_ASSERT(pbs, "pending_block_state does not exist but it should, another plugin may have corrupted it"); auto private_key_itr = _private_keys.find( pbs->block_signing_key ); + FC_ASSERT(private_key_itr != _private_keys.end(), "Attempting to produce a block for which we don't have the private key"); //idump( (fc::time_point::now() - chain.pending_block_time()) ); chain.finalize_block(); From d69787cb387f0d6092254a33e9a9942975a09864 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Mon, 21 May 2018 14:27:51 -0400 Subject: [PATCH 17/55] take a page from net_plugin and create our own logger namespace for producer plugin EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 33 +++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 300f31408e6..b1096ce0d6b 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -35,6 +35,15 @@ using boost::multi_index_container; using std::string; using std::vector; +// HACK TO EXPOSE LOGGER MAP + +namespace fc { + extern std::unordered_map& get_logger_map(); +} + +const fc::string logger_name("producer_plugin"); +fc::logger _log; + namespace eosio { static appbase::abstract_plugin& _producer_plugin = app().register_plugin(); @@ -190,6 +199,7 @@ class producer_plugin_impl { }; void on_incoming_block(const signed_block_ptr& block) { + fc_dlog(_log, "received incoming block ${id}", ("id", block->id())); FC_ASSERT( block->timestamp < (fc::time_point::now() + fc::seconds(1)), "received a block from the future, ignoring it" ); @@ -220,6 +230,7 @@ class producer_plugin_impl { } transaction_trace_ptr on_incoming_transaction(const packed_transaction_ptr& trx) { + fc_dlog(_log, "received incoming transaction ${id}", ("id", trx->id())); return publish_results_of(trx, _transaction_ack_channel, [&]() -> transaction_trace_ptr { while (true) { chain::controller& chain = app().get_plugin().chain(); @@ -238,10 +249,14 @@ class producer_plugin_impl { if (failure_is_subjective(*trace->except, deadline_is_subjective) ) { // if we failed because the block was exhausted push the block out and try again if it succeeds if (_pending_block_mode == pending_block_mode::producing ) { + fc_dlog(_log, "flushing block under production"); + if (maybe_produce_block()) { continue; } } else if (_pending_block_mode == pending_block_mode::speculating) { + fc_dlog(_log, "dropping block under speculation"); + chain.abort_block(); schedule_production_loop(); continue; @@ -417,6 +432,11 @@ void producer_plugin::plugin_startup() my->schedule_production_loop(); ilog("producer plugin: plugin_startup() end"); + + if(fc::get_logger_map().find(logger_name) != fc::get_logger_map().end()) { + _log = fc::get_logger_map()[logger_name]; + } + } FC_CAPTURE_AND_RETHROW() } void producer_plugin::plugin_shutdown() { @@ -658,17 +678,17 @@ void producer_plugin_impl::schedule_production_loop() { // ship this block off no later than its deadline static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); _timer.expires_at(epoch + boost::posix_time::microseconds(chain.pending_block_time().time_since_epoch().count())); - dlog("Scheduling Block Production on Normal Block #${num} for ${time}", ("num", chain.pending_block_state()->block_num)("time",chain.pending_block_time())); + fc_dlog(_log, "Scheduling Block Production on Normal Block #${num} for ${time}", ("num", chain.pending_block_state()->block_num)("time",chain.pending_block_time())); } else { // ship this block off immediately _timer.expires_from_now( boost::posix_time::microseconds( 0 )); - dlog("Scheduling Block Production on Exhausted Block #${num} immediately", ("num", chain.pending_block_state()->block_num)); + fc_dlog(_log, "Scheduling Block Production on Exhausted Block #${num} immediately", ("num", chain.pending_block_state()->block_num)); } _timer.async_wait([&](const boost::system::error_code& ec) { if (ec != boost::asio::error::operation_aborted) { auto res = maybe_produce_block(); - dlog("Producing Block #${num} returned: ${res}", ("num", chain.pending_block_state()->block_num)("res", res) ); + fc_dlog(_log, "Producing Block #${num} returned: ${res}", ("num", chain.pending_block_state()->block_num)("res", res) ); } }); } else if (_pending_block_mode == pending_block_mode::speculating && !_producers.empty()){ @@ -688,7 +708,7 @@ void producer_plugin_impl::schedule_production_loop() { } if (wake_up_time) { - dlog("Specualtive Block Created; Scheduling Speculative/Production Change at ", ("time", wake_up_time)); + fc_dlog(_log, "Specualtive Block Created; Scheduling Speculative/Production Change at ", ("time", wake_up_time)); static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); _timer.expires_at(epoch + boost::posix_time::microseconds(wake_up_time->time_since_epoch().count())); _timer.async_wait([&](const boost::system::error_code& ec) { @@ -697,10 +717,10 @@ void producer_plugin_impl::schedule_production_loop() { } }); } else { - dlog("Specualtive Block Created; Not Scheduling Speculative/Production, no local producers had valid wake up times"); + fc_dlog(_log, "Specualtive Block Created; Not Scheduling Speculative/Production, no local producers had valid wake up times"); } } else { - dlog("Specualtive Block Created"); + fc_dlog(_log, "Specualtive Block Created"); } } @@ -714,6 +734,7 @@ bool producer_plugin_impl::maybe_produce_block() { return true; } FC_LOG_AND_DROP(); + fc_dlog(_log, "Aborting block due to produce_block error"); chain::controller& chain = app().get_plugin().chain(); chain.abort_block(); return false; From 42c065f800ea30ff5afd60365fd0e36316df8001 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 21 May 2018 16:25:26 -0400 Subject: [PATCH 18/55] eosio.token: limit memo size (#3244) --- contracts/eosio.token/eosio.token.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.token/eosio.token.cpp b/contracts/eosio.token/eosio.token.cpp index 552566fed8e..1541e47cab3 100644 --- a/contracts/eosio.token/eosio.token.cpp +++ b/contracts/eosio.token/eosio.token.cpp @@ -33,6 +33,7 @@ void token::issue( account_name to, asset quantity, string memo ) { auto sym = quantity.symbol; eosio_assert( sym.is_valid(), "invalid symbol name" ); + eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); auto sym_name = sym.name(); stats statstable( _self, sym_name ); @@ -61,7 +62,7 @@ void token::issue( account_name to, asset quantity, string memo ) void token::transfer( account_name from, account_name to, asset quantity, - string /*memo*/ ) + string memo ) { eosio_assert( from != to, "cannot transfer to self" ); require_auth( from ); @@ -76,6 +77,7 @@ void token::transfer( account_name from, eosio_assert( quantity.is_valid(), "invalid quantity" ); eosio_assert( quantity.amount > 0, "must transfer positive quantity" ); eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); + eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); sub_balance( from, quantity, st ); From ffa95f5126fb9de5f73145804839b2c975ae3fbb Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 21 May 2018 16:34:50 -0400 Subject: [PATCH 19/55] history plugin: agressive filters (#3244) --- plugins/history_plugin/history_plugin.cpp | 58 +++++++++++++++-------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index 5932401ef35..fd98707b4e8 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -7,6 +7,8 @@ #include +#include + namespace eosio { using namespace chain; @@ -117,31 +119,41 @@ namespace eosio { } } + struct filter_entry { + name receiver; + name action; + name actor; + + std::tuple key() const { + return {receiver, action, actor}; + } + + friend bool operator<( const filter_entry& a, const filter_entry& b ) { + return a.key() < b.key(); + } + }; + class history_plugin_impl { public: - std::set filter_on; + std::set filter_on; chain_plugin* chain_plug = nullptr; - bool is_filtered( const account_name& n ) { - return !filter_on.size() || filter_on.find(n) != filter_on.end(); - } bool filter( const action_trace& act ) { - if( filter_on.size() == 0 ) return true; - if( is_filtered( act.receipt.receiver ) ) return true; - for( const auto& a : act.act.authorization ) { - if( is_filtered( a.actor ) ) return true; - } + if( filter_on.find({ act.receipt.receiver, act.act.name, 0 }) != filter_on.end() ) + return true; + for( const auto& a : act.act.authorization ) + if( filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end() ) + return true; return false; } set account_set( const action_trace& act ) { set result; - if( is_filtered( act.receipt.receiver ) ) - result.insert( act.receipt.receiver ); - for( const auto& a : act.act.authorization ) { - if( is_filtered( a.actor ) ) result.insert( a.actor ); - } + result.insert( act.receipt.receiver ); + for( const auto& a : act.act.authorization ) + if( filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end() ) + result.insert( a.actor ); return result; } @@ -240,17 +252,23 @@ namespace eosio { void history_plugin::set_program_options(options_description& cli, options_description& cfg) { cfg.add_options() - ("filter_on_accounts,f", bpo::value>()->composing(), - "Track only transactions whose scopes involve the listed accounts. Default is to track all transactions.") + ("filter_on,f", bpo::value>()->composing(), + "Track actions which match receiver:action:actor. Actor may be blank to include all. Receiver and Action may not be blank.") ; } void history_plugin::plugin_initialize(const variables_map& options) { - if(options.count("filter_on_accounts")) + if( options.count("filter_on") ) { - auto foa = options.at("filter_on_accounts").as>(); - for(auto filter_account : foa) - my->filter_on.emplace(filter_account); + auto fo = options.at("filter_on").as>(); + for( auto& s : fo ) { + std::vector v; + boost::split(v, s, boost::is_any_of(":")); + EOS_ASSERT(v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter_on", ("s",s)); + filter_entry fe{ v[0], v[1], v[2] }; + EOS_ASSERT(fe.receiver.value && fe.action.value, fc::invalid_arg_exception, "Invalid value ${s} for --filter_on", ("s",s)); + my->filter_on.insert( fe ); + } } my->chain_plug = app().find_plugin(); From d0dd8bbcd026beca74d405d667e66bda042ed1e2 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 21 May 2018 16:57:21 -0400 Subject: [PATCH 20/55] Support older compiler --- plugins/history_plugin/history_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index fd98707b4e8..e7c6375e1c3 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -125,7 +125,7 @@ namespace eosio { name actor; std::tuple key() const { - return {receiver, action, actor}; + return std::make_tuple(receiver, action, actor); } friend bool operator<( const filter_entry& a, const filter_entry& b ) { From 1dc81edab97a57a3ccfc683b65eb1e06b08d2ab0 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Mon, 21 May 2018 17:18:26 -0400 Subject: [PATCH 21/55] fix log message --- plugins/producer_plugin/producer_plugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index b1096ce0d6b..83e2fe18ee1 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -656,6 +656,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } void producer_plugin_impl::schedule_production_loop() { + chain::controller& chain = app().get_plugin().chain(); _timer.cancel(); auto result = start_block(); @@ -671,7 +672,6 @@ void producer_plugin_impl::schedule_production_loop() { } }); } else if (_pending_block_mode == pending_block_mode::producing) { - chain::controller& chain = app().get_plugin().chain(); // we succeeded but block may be exhausted if (result == start_block_result::succeeded) { @@ -708,7 +708,7 @@ void producer_plugin_impl::schedule_production_loop() { } if (wake_up_time) { - fc_dlog(_log, "Specualtive Block Created; Scheduling Speculative/Production Change at ", ("time", wake_up_time)); + fc_dlog(_log, "Specualtive Block Created; Scheduling Speculative/Production Change at ${time}", ("time", wake_up_time)); static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); _timer.expires_at(epoch + boost::posix_time::microseconds(wake_up_time->time_since_epoch().count())); _timer.async_wait([&](const boost::system::error_code& ec) { From e35be613c68fe97b1f7b61ea771b39a831bb35c2 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Mon, 21 May 2018 17:51:18 -0400 Subject: [PATCH 22/55] handle wonky corner case with boost timers delivering un-aborted handlers after timer.cancel EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 28 +++++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 83e2fe18ee1..d314bac10d3 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -661,13 +661,25 @@ void producer_plugin_impl::schedule_production_loop() { auto result = start_block(); + /* + * HACK ALERT + * Boost timers can be in a state where a handler has not yet executed but is not abortable. + * As this method needs to mutate state handlers depend on for proper functioning to maintain + * invariants for other code (namely accepting incoming transactions in a nearly full block) + * the handlers capture a coorelation ID at the time they are set. When they are executed + * they must check that correlation_id against the global ordinal. If it does not match that + * implies that this method has been called with the handler in the state where it should be + * cancelled but wasn't able to be. + */ + static uint32_t _coorelation_id = 0; + if (result == start_block_result::failed) { elog("Failed to start a pending block, will try again later"); _timer.expires_from_now( boost::posix_time::microseconds( config::block_interval_us / 10 )); // we failed to start a block, so try again later? - _timer.async_wait([&](const boost::system::error_code& ec) { - if (ec != boost::asio::error::operation_aborted) { + _timer.async_wait([&,cid=_coorelation_id++](const boost::system::error_code& ec) { + if (ec != boost::asio::error::operation_aborted && cid == _coorelation_id) { schedule_production_loop(); } }); @@ -685,8 +697,8 @@ void producer_plugin_impl::schedule_production_loop() { fc_dlog(_log, "Scheduling Block Production on Exhausted Block #${num} immediately", ("num", chain.pending_block_state()->block_num)); } - _timer.async_wait([&](const boost::system::error_code& ec) { - if (ec != boost::asio::error::operation_aborted) { + _timer.async_wait([&,cid=_coorelation_id++](const boost::system::error_code& ec) { + if (ec != boost::asio::error::operation_aborted && cid == _coorelation_id) { auto res = maybe_produce_block(); fc_dlog(_log, "Producing Block #${num} returned: ${res}", ("num", chain.pending_block_state()->block_num)("res", res) ); } @@ -711,16 +723,16 @@ void producer_plugin_impl::schedule_production_loop() { fc_dlog(_log, "Specualtive Block Created; Scheduling Speculative/Production Change at ${time}", ("time", wake_up_time)); static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); _timer.expires_at(epoch + boost::posix_time::microseconds(wake_up_time->time_since_epoch().count())); - _timer.async_wait([&](const boost::system::error_code& ec) { - if (ec != boost::asio::error::operation_aborted) { + _timer.async_wait([&,cid=_coorelation_id++](const boost::system::error_code& ec) { + if (ec != boost::asio::error::operation_aborted && cid == _coorelation_id) { schedule_production_loop(); } }); } else { - fc_dlog(_log, "Specualtive Block Created; Not Scheduling Speculative/Production, no local producers had valid wake up times"); + fc_dlog(_log, "Speculative Block Created; Not Scheduling Speculative/Production, no local producers had valid wake up times"); } } else { - fc_dlog(_log, "Specualtive Block Created"); + fc_dlog(_log, "Speculative Block Created"); } } From 9e246c1446967d19f8f9d19bc979e5fcd5f8b6f0 Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Mon, 21 May 2018 18:09:29 -0400 Subject: [PATCH 23/55] system contract test cleanup: N(eosio) replaced with eosio::system_account_name #3213 --- unittests/eosio.system_tests.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/unittests/eosio.system_tests.cpp b/unittests/eosio.system_tests.cpp index 761b60eabe8..c94857caef6 100644 --- a/unittests/eosio.system_tests.cpp +++ b/unittests/eosio.system_tests.cpp @@ -69,16 +69,16 @@ class eosio_system_tester : public TESTER { produce_blocks(); - create_account_with_resources( N(alice1111111), N(eosio), core_from_string("1.0000"), false ); - create_account_with_resources( N(bob111111111), N(eosio), core_from_string("0.4500"), false ); - create_account_with_resources( N(carol1111111), N(eosio), core_from_string("1.0000"), false ); + create_account_with_resources( N(alice1111111), config::system_account_name, core_from_string("1.0000"), false ); + create_account_with_resources( N(bob111111111), config::system_account_name, core_from_string("0.4500"), false ); + create_account_with_resources( N(carol1111111), config::system_account_name, core_from_string("1.0000"), false ); BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance( "eosio" ) ); } - void create_accounts_with_resources( vector accounts, account_name creator = N(eosio) ) { + void create_accounts_with_resources( vector accounts, account_name creator = config::system_account_name ) { for( auto a : accounts ) { create_account_with_resources( a, creator ); } @@ -99,13 +99,13 @@ class eosio_system_tester : public TESTER { .active = authority( get_public_key( a, "active" ) ) }); - trx.actions.emplace_back( get_action( N(eosio), N(buyrambytes), vector{{creator,config::active_name}}, + trx.actions.emplace_back( get_action( config::system_account_name, N(buyrambytes), vector{{creator,config::active_name}}, mvo() ("payer", creator) ("receiver", a) ("bytes", 8000) ) ); - trx.actions.emplace_back( get_action( N(eosio), N(delegatebw), vector{{creator,config::active_name}}, + trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{{creator,config::active_name}}, mvo() ("from", creator) ("receiver", a) @@ -141,14 +141,14 @@ class eosio_system_tester : public TESTER { .active = authority( get_public_key( a, "active" ) ) }); - trx.actions.emplace_back( get_action( N(eosio), N(buyram), vector{{creator,config::active_name}}, + trx.actions.emplace_back( get_action( config::system_account_name, N(buyram), vector{{creator,config::active_name}}, mvo() ("payer", creator) ("receiver", a) ("quant", ramfunds) ) ); - trx.actions.emplace_back( get_action( N(eosio), N(delegatebw), vector{{creator,config::active_name}}, + trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{{creator,config::active_name}}, mvo() ("from", creator) ("receiver", a) @@ -164,7 +164,7 @@ class eosio_system_tester : public TESTER { } transaction_trace_ptr setup_producer_accounts( const std::vector& accounts ) { - account_name creator(N(eosio)); + account_name creator(config::system_account_name); signed_transaction trx; set_transaction_headers(trx); asset cpu = core_from_string("80.0000"); @@ -181,14 +181,14 @@ class eosio_system_tester : public TESTER { .active = authority( get_public_key( a, "active" ) ) }); - trx.actions.emplace_back( get_action( N(eosio), N(buyram), vector{ {creator, config::active_name} }, + trx.actions.emplace_back( get_action( config::system_account_name, N(buyram), vector{ {creator, config::active_name} }, mvo() ("payer", creator) ("receiver", a) ("quant", ram) ) ); - trx.actions.emplace_back( get_action( N(eosio), N(delegatebw), vector{ {creator, config::active_name} }, + trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{ {creator, config::active_name} }, mvo() ("from", creator) ("receiver", a) @@ -372,14 +372,14 @@ class eosio_system_tester : public TESTER { } fc::variant get_global_state() { - vector data = get_row_by_account( N(eosio), N(eosio), N(global), N(global) ); + vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global), N(global) ); if (data.empty()) std::cout << "\nData is empty\n" << std::endl; return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state", data ); } fc::variant get_refund_request( name account ) { - vector data = get_row_by_account( N(eosio), account, N(refunds), account ); + vector data = get_row_by_account( config::system_account_name, account, N(refunds), account ); return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "refund_request", data ); } @@ -884,7 +884,6 @@ BOOST_FIXTURE_TEST_CASE( stake_from_refund, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_from_string( "50.0000"), refund["cpu_amount"].as() ); //XXX auto request_time = refund["request_time"].as_int64(); - //std::cout << std::endl << std::endl << "Stake from refund" << std::endl; //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" ); @@ -1986,7 +1985,7 @@ BOOST_FIXTURE_TEST_CASE(producers_upgrade_system_contract, eosio_system_tester) //install multisig contract abi_serializer msig_abi_ser; { - create_account_with_resources( N(eosio.msig), N(eosio) ); + create_account_with_resources( N(eosio.msig), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), buyram( "eosio", "eosio.msig", core_from_string("5000.0000") ) ); produce_block(); From 97e5ad5e6c2a81919370c914ab75684db9366850 Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Mon, 21 May 2018 18:16:02 -0400 Subject: [PATCH 24/55] calling checktime from intrinsic_function_invoker, calling checktime from hashing functions at 1k boundaries #3255 --- libraries/chain/apply_context.cpp | 3 -- .../eosio/chain/webassembly/binaryen.hpp | 2 ++ libraries/chain/wasm_interface.cpp | 32 ++++++++++++++----- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index b59326b23b6..b5952793d72 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -287,7 +287,6 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a } trx_context.add_ram_usage( payer, (config::billable_size_v + trx_size) ); - trx_context.checktime(); } bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, account_name sender ) { @@ -297,7 +296,6 @@ bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, acc trx_context.add_ram_usage( gto->payer, -(config::billable_size_v + gto->packed_trx.size()) ); generated_transaction_idx.remove(*gto); } - trx_context.checktime(); return gto; } @@ -343,7 +341,6 @@ void apply_context::reset_console() { bytes apply_context::get_packed_transaction() { auto r = fc::raw::pack( static_cast(trx_context.trx) ); - trx_context.checktime(); return r; } diff --git a/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp b/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp index 0f38c66fae9..1b57804fcf9 100644 --- a/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/binaryen.hpp @@ -629,6 +629,7 @@ struct intrinsic_function_invoker { template static Ret wrapper(interpreter_interface* interface, Params... params, LiteralList&, int) { + class_from_wasm::value(interface->context).checktime(); return (class_from_wasm::value(interface->context).*Method)(params...); } @@ -644,6 +645,7 @@ struct intrinsic_function_invoker { template static void_type wrapper(interpreter_interface* interface, Params... params, LiteralList& args, int offset) { + class_from_wasm::value(interface->context).checktime(); (class_from_wasm::value(interface->context).*Method)(params...); return void_type(); } diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 2b9e4ae438b..d17df1921ed 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -72,6 +72,10 @@ class context_aware_api { context.used_context_free_api |= !context_free; } + void checktime() { + context.trx_context.checktime(); + } + protected: apply_context& context; @@ -720,40 +724,52 @@ class crypto_api : public context_aware_api { return pubds.tellp(); } + template auto encode(char* data, size_t datalen) { + Encoder e; + while ( datalen > 1024 ) { + e.write( data, 1024 ); + data += 1024; + datalen -= 1024; + context.trx_context.checktime(); + } + e.write( data, datalen ); + return e.result(); + } + void assert_sha256(array_ptr data, size_t datalen, const fc::sha256& hash_val) { - auto result = fc::sha256::hash( data, datalen ); + auto result = encode( data, datalen ); FC_ASSERT( result == hash_val, "hash mismatch" ); } void assert_sha1(array_ptr data, size_t datalen, const fc::sha1& hash_val) { - auto result = fc::sha1::hash( data, datalen ); + auto result = encode( data, datalen ); FC_ASSERT( result == hash_val, "hash mismatch" ); } void assert_sha512(array_ptr data, size_t datalen, const fc::sha512& hash_val) { - auto result = fc::sha512::hash( data, datalen ); + auto result = encode( data, datalen ); FC_ASSERT( result == hash_val, "hash mismatch" ); } void assert_ripemd160(array_ptr data, size_t datalen, const fc::ripemd160& hash_val) { - auto result = fc::ripemd160::hash( data, datalen ); + auto result = encode( data, datalen ); FC_ASSERT( result == hash_val, "hash mismatch" ); } void sha1(array_ptr data, size_t datalen, fc::sha1& hash_val) { - hash_val = fc::sha1::hash( data, datalen ); + hash_val = encode( data, datalen ); } void sha256(array_ptr data, size_t datalen, fc::sha256& hash_val) { - hash_val = fc::sha256::hash( data, datalen ); + hash_val = encode( data, datalen ); } void sha512(array_ptr data, size_t datalen, fc::sha512& hash_val) { - hash_val = fc::sha512::hash( data, datalen ); + hash_val = encode( data, datalen ); } void ripemd160(array_ptr data, size_t datalen, fc::ripemd160& hash_val) { - hash_val = fc::ripemd160::hash( data, datalen ); + hash_val = encode( data, datalen ); } }; From b05fc283a8d42c7891f26f546d226f76fa001812 Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Mon, 21 May 2018 18:44:55 -0400 Subject: [PATCH 25/55] checktime from instrinsics: magic number moved to config #3255 --- libraries/chain/include/eosio/chain/config.hpp | 2 ++ libraries/chain/wasm_interface.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 307175d56ac..bf545dc76ed 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -84,6 +84,8 @@ const static uint32_t overhead_per_row_per_index_ram_bytes = 32; ///< overh const static uint32_t overhead_per_account_ram_bytes = 2*1024; ///< overhead accounts for basic account storage and pre-pays features like account recovery const static uint32_t setcode_ram_bytes_multiplier = 10; ///< multiplier on contract size to account for multiple copies and cached compilation +const static uint32_t hashing_checktime_block_size = 1024; /// call checktime from hashing intrinsic once per this number of bytes + const static eosio::chain::wasm_interface::vm_type default_wasm_runtime = eosio::chain::wasm_interface::vm_type::binaryen; /** diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index d17df1921ed..d5710d96d6e 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -726,10 +726,11 @@ class crypto_api : public context_aware_api { template auto encode(char* data, size_t datalen) { Encoder e; - while ( datalen > 1024 ) { - e.write( data, 1024 ); - data += 1024; - datalen -= 1024; + const size_t bs = eosio::chain::config::hashing_checktime_block_size; + while ( datalen > bs ) { + e.write( data, bs ); + data += bs; + datalen -= bs; context.trx_context.checktime(); } e.write( data, datalen ); From 0e173fe7f272939fd666bb2760b9bdffe055edad Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 21 May 2018 19:44:03 -0400 Subject: [PATCH 26/55] Test multiple name auctions going in parallel - #3208 --- contracts/eosio.system/producer_pay.cpp | 11 +- unittests/eosio.system_tests.cpp | 164 ++++++++++++++++++++++-- 2 files changed, 160 insertions(+), 15 deletions(-) diff --git a/contracts/eosio.system/producer_pay.cpp b/contracts/eosio.system/producer_pay.cpp index f06cee9568b..1aea6e723bc 100644 --- a/contracts/eosio.system/producer_pay.cpp +++ b/contracts/eosio.system/producer_pay.cpp @@ -55,12 +55,13 @@ namespace eosiosystem { auto idx = bids.get_index(); auto highest = idx.begin(); if( highest != idx.end() && - highest->high_bid > 0 && + highest->high_bid > 0 && highest->last_bid_time < (current_time() - useconds_per_day) && - (current_time() - _gstate.thresh_activated_stake_time) > 14 * useconds_per_day ){ - _gstate.last_name_close = timestamp; - idx.modify( highest, 0, [&]( auto& b ){ - b.high_bid = -b.high_bid; + _gstate.thresh_activated_stake_time > 0 && + (current_time() - _gstate.thresh_activated_stake_time) > 14 * useconds_per_day ) { + _gstate.last_name_close = timestamp; + idx.modify( highest, 0, [&]( auto& b ){ + b.high_bid = -b.high_bid; }); } } diff --git a/unittests/eosio.system_tests.cpp b/unittests/eosio.system_tests.cpp index d8f3a9c9519..79949bdb8b9 100644 --- a/unittests/eosio.system_tests.cpp +++ b/unittests/eosio.system_tests.cpp @@ -315,7 +315,6 @@ class eosio_system_tester : public TESTER { } asset get_balance( const account_name& act ) { - vector data = get_row_by_account( N(eosio.token), act, N(accounts), symbol(CORE_SYMBOL).to_symbol_code().value ); return data.empty() ? asset(0, symbol(CORE_SYMBOL)) : token_abi_ser.binary_to_variant("account", data)["balance"].as(); } @@ -1735,7 +1734,6 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni const uint32_t prod_index = 2; const auto prod_name = producer_names[prod_index]; - const auto initial_global_state = get_global_state(); const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); @@ -1761,7 +1759,6 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni const uint64_t usecs_between_fills = claim_time - initial_claim_time; const int32_t secs_between_fills = static_cast(usecs_between_fills / 1000000); - const double expected_supply_growth = initial_supply.amount * double(usecs_between_fills) * cont_rate / usecs_per_year; BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.amount - initial_supply.amount ); BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); @@ -1798,7 +1795,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } - // wait to 23 hours which is not enough for producers to get deactivated + // wait for 23 hours which is not enough for producers to get deactivated // payment calculations don't change. By now, pervote_bucket has grown enough // that a producer's share is more than 100 tokens produce_block(fc::seconds(23 * 3600)); @@ -2563,17 +2560,22 @@ BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_teste //REQUIRE_EQUAL_OBJECTS(prod3_config, config); } FC_LOG_AND_RETHROW() + + BOOST_FIXTURE_TEST_CASE( buyname, eosio_system_tester ) try { create_accounts_with_resources( { N(dan), N(sam) } ); - transfer( "eosio", "dan", core_from_string( "10000.0000" ) ); - transfer( "eosio", "sam", core_from_string( "10000.0000" ) ); - stake_with_transfer( "eosio", "sam", core_from_string( "80000000.0000" ), core_from_string( "80000000.0000" ) ); + transfer( config::system_account_name, "dan", core_from_string( "10000.0000" ) ); + transfer( config::system_account_name, "sam", core_from_string( "10000.0000" ) ); + stake_with_transfer( config::system_account_name, "sam", core_from_string( "80000000.0000" ), core_from_string( "80000000.0000" ) ); - regproducer( N(eosio) ); + regproducer( config::system_account_name ); push_action( N(sam), N(voteproducer), mvo() ("voter", "sam") ("proxy", name(0).to_string() ) - ("producers", vector{ N(eosio) } ) ); + ("producers", vector{ config::system_account_name } ) ); + // wait 14 days after min required amount has been staked + produce_block( fc::days(14) ); + produce_block(); BOOST_REQUIRE_THROW( create_accounts_with_resources( { N(fail) }, N(dan) ), fc::exception ); // dan shouldn't be able to create fail @@ -2582,7 +2584,7 @@ BOOST_FIXTURE_TEST_CASE( buyname, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), bidname( "sam", "nofail", core_from_string( "2.0000" ) )); // didn't increase bid by 10% produce_block( fc::days(1) ); produce_block(); - + BOOST_REQUIRE_THROW( create_accounts_with_resources( { N(nofail) }, N(dan) ), fc::exception); // dan shoudn't be able to do this, sam won //wlog( "verify sam can create nofail" ); create_accounts_with_resources( { N(nofail) }, N(sam) ); // sam should be able to do this, he won the bid @@ -2594,4 +2596,146 @@ BOOST_FIXTURE_TEST_CASE( buyname, eosio_system_tester ) try { } 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"); + + std::vector accounts = { N(alice), N(bob), N(carl), N(david), N(eve) }; + create_accounts_with_resources( accounts ); + for ( const auto& a: accounts ) { + transfer( config::system_account_name, a, core_from_string( "10000.0000" ) ); + BOOST_REQUIRE_EQUAL( core_from_string( "10000.0000" ), get_balance(a) ); + } + create_accounts_with_resources( { N(producer) } ); + BOOST_REQUIRE_EQUAL( success(), regproducer( N(producer) ) ); + + produce_block(); + // stake but but not enough to go live + stake_with_transfer( config::system_account_name, "bob", core_from_string( "35000000.0000" ), core_from_string( "35000000.0000" ) ); + stake_with_transfer( config::system_account_name, "carl", core_from_string( "35000000.0000" ), core_from_string( "35000000.0000" ) ); + BOOST_REQUIRE_EQUAL( success(),push_action( N(bob), N(voteproducer), mvo() + ("voter", "bob") + ("proxy", name(0).to_string() ) + ("producers", vector{ N(producer) } ) + ) + ); + BOOST_REQUIRE_EQUAL( success(), push_action( N(carl), N(voteproducer), mvo() + ("voter", "carl") + ("proxy", name(0).to_string() ) + ("producers", vector{ N(producer) } ) + ) + ); + + // start bids + bidname( "bob", "prefa", core_from_string("1.0000") ); + BOOST_REQUIRE_EQUAL( core_from_string( "9999.0000" ), get_balance("bob") ); + bidname( "bob", "prefb", core_from_string("1.0000") ); + bidname( "bob", "prefc", core_from_string("1.0000") ); + BOOST_REQUIRE_EQUAL( core_from_string( "9997.0000" ), get_balance("bob") ); + + bidname( "carl", "prefd", core_from_string("1.0000") ); + bidname( "carl", "prefe", core_from_string("1.0000") ); + BOOST_REQUIRE_EQUAL( core_from_string( "9998.0000" ), get_balance("carl") ); + + BOOST_REQUIRE_EQUAL( error("assertion failure with message: account is already high bidder"), + bidname( "bob", "prefb", core_from_string("1.1001") ) ); + BOOST_REQUIRE_EQUAL( error("assertion failure with message: must increase bid by 10%"), + bidname( "alice", "prefb", core_from_string("1.0999") ) ); + BOOST_REQUIRE_EQUAL( core_from_string( "9997.0000" ), get_balance("bob") ); + BOOST_REQUIRE_EQUAL( core_from_string( "10000.0000" ), get_balance("alice") ); + + // alice outbids bob on prefb + { + BOOST_REQUIRE_EQUAL( success(), + bidname( "alice", "prefb", core_from_string("1.1001") ) ); + BOOST_REQUIRE_EQUAL( core_from_string( "9998.0000" ), get_balance("bob") ); + BOOST_REQUIRE_EQUAL( core_from_string( "9998.8999" ), get_balance("alice") ); + } + + // david outbids carl on prefd + { + BOOST_REQUIRE_EQUAL( core_from_string( "9998.0000" ), get_balance("carl") ); + BOOST_REQUIRE_EQUAL( core_from_string( "10000.0000" ), get_balance("david") ); + BOOST_REQUIRE_EQUAL( success(), + bidname( "david", "prefd", core_from_string("1.9900") ) ); + BOOST_REQUIRE_EQUAL( core_from_string( "9999.0000" ), get_balance("carl") ); + BOOST_REQUIRE_EQUAL( core_from_string( "9998.0100" ), get_balance("david") ); + } + + // eve outbids carl on prefe + { + BOOST_REQUIRE_EQUAL( success(), + bidname( "eve", "prefe", core_from_string("1.7200") ) ); + } + + produce_block( fc::days(14) ); + produce_block(); + + // highest bid is from david for prefd but not bids can be closed yet + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefd), N(david) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + + // stake enough to go above the 15% threshold + stake_with_transfer( config::system_account_name, "alice", core_from_string( "10000000.0000" ), core_from_string( "10000000.0000" ) ); + BOOST_REQUIRE_EQUAL(0, get_producer_info("producer")["unpaid_blocks"].as()); + BOOST_REQUIRE_EQUAL( success(), push_action( N(alice), N(voteproducer), mvo() + ("voter", "alice") + ("proxy", name(0).to_string() ) + ("producers", vector{ N(producer) } ) + ) + ); + + // need to wait for 14 days after going live + produce_blocks(10); + produce_block( fc::days(2) ); + produce_blocks( 10 ); + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefd), N(david) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + // it's been 14 days, auction for prefd has been closed + produce_block( fc::days(12) ); + create_account_with_resources( N(prefd), N(david) ); + produce_blocks(2); + produce_block( fc::hours(23) ); + // auctions for prefa, prefb, prefc, prefe haven't been closed + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefa), N(bob) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefb), N(alice) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefc), N(bob) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefe), N(eve) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + // changing highest bid pushes auction closing time by 24 hours + BOOST_REQUIRE_EQUAL( success(), + bidname( "eve", "prefb", core_from_string("2.1880") ) ); + + produce_block( fc::hours(22) ); + produce_blocks(2); + + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefb), N(eve) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + // but changing a bid that is not the highest does not push closing time + BOOST_REQUIRE_EQUAL( success(), + bidname( "carl", "prefe", core_from_string("2.0980") ) ); + produce_block( fc::hours(2) ); + produce_blocks(2); + // bid for prefb has closed, only highest bidder can claim + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefb), N(alice) ), + fc::exception, fc_assert_exception_message_is("only high bidder can claim") ); + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefb), N(carl) ), + fc::exception, fc_assert_exception_message_is("only high bidder can claim") ); + create_account_with_resources( N(prefb), N(eve) ); + + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefe), N(carl) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + produce_block(); + produce_block( fc::hours(24) ); + // by now bid for prefe has closed + create_account_with_resources( N(prefe), N(carl) ); + // but not others + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefa), N(bob) ), + fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From 7f795767c02ff5226834443e8020506d6c20b155 Mon Sep 17 00:00:00 2001 From: Phil Mesnier Date: Tue, 22 May 2018 03:57:55 -0500 Subject: [PATCH 27/55] #3017 fix syncing with a forked peer --- plugins/net_plugin/net_plugin.cpp | 125 +++++++++++++++--------------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 9146f59657f..5f509be878f 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -589,7 +589,6 @@ namespace eosio { uint32_t sync_last_requested_num; uint32_t sync_next_expected_num; uint32_t sync_req_span; - uint32_t last_repeated; connection_ptr source; stages state; @@ -601,18 +600,18 @@ namespace eosio { public: sync_manager(uint32_t span); void set_state(stages s); + bool sync_required(); + void send_handshakes(); bool is_active(connection_ptr conn); void reset_lib_num(connection_ptr conn); - bool sync_required(); void request_next_chunk(connection_ptr conn = connection_ptr() ); void start_sync(connection_ptr c, uint32_t target); - void send_handshakes(); void reassign_fetch(connection_ptr c, go_away_reason reason); void verify_catchup(connection_ptr c, uint32_t num, block_id_type id); - void recv_block(connection_ptr c, const block_id_type &blk_id, uint32_t blk_num, bool accepted); + void rejected_block(connection_ptr c, uint32_t blk_num); + void recv_block(connection_ptr c, const block_id_type &blk_id, uint32_t blk_num); void recv_handshake(connection_ptr c, const handshake_message& msg); void recv_notice(connection_ptr c, const notice_message& msg); - }; class dispatch_manager { @@ -1197,7 +1196,6 @@ namespace eosio { ,sync_last_requested_num( 0 ) ,sync_next_expected_num( 1 ) ,sync_req_span( req_span ) - ,last_repeated( 0 ) ,source() ,state(in_sync) { @@ -1256,58 +1254,66 @@ namespace eosio { void sync_manager::request_next_chunk( connection_ptr conn ) { uint32_t head_block = chain_plug->chain().head_block_num(); - if (head_block < sync_last_requested_num) { - fc_ilog (logger, "ignoring request, head is ${h} last req = ${r}", - ("h",head_block)("r",sync_last_requested_num)); + if (head_block < sync_last_requested_num && source && source->current()) { + fc_ilog (logger, "ignoring request, head is ${h} last req = ${r} source is ${p}", + ("h",head_block)("r",sync_last_requested_num)("p",source->peer_name())); return; } /* ---------- * next chunk provider selection criteria - * 1. a provider is supplied, use it. - * 2. we only have 1 peer so use that. - * 3. we have multiple peers, select the next available from the list + * a provider is supplied and able to be used, use it. + * otherwise select the next available from the list, round-robin style. */ if (conn && conn->current() ) { source = conn; } - else if (my_impl->connections.size() == 1) { - if (!source) { - source = *my_impl->connections.begin(); - } - if (!source->current()) { - source.reset(); - } - } else { - auto cptr = my_impl->connections.begin(); - auto cend = my_impl->connections.end(); - if (source) { - cptr = my_impl->connections.find(source); - cend = cptr; - if (cptr == my_impl->connections.end()) { - elog ("unable to find previous source connection in connections list"); - source.reset(); - cptr = my_impl->connections.begin(); - } else { - if (++cptr == my_impl->connections.end()) - cptr = my_impl->connections.begin(); + if (my_impl->connections.size() == 1) { + if (!source) { + source = *my_impl->connections.begin(); } } - while (cptr != cend) { - if ((*cptr)->current()) { - source = *cptr; - break; - } - else { - if (++cptr == my_impl->connections.end()) { + else { + // init to a linear array search + auto cptr = my_impl->connections.begin(); + auto cend = my_impl->connections.end(); + // do we remember the previous source? + if (source) { + //try to find it in the list + cptr = my_impl->connections.find(source); + cend = cptr; + if (cptr == my_impl->connections.end()) { + //not there - must have been closed! cend is now connections.end, so just flatten the ring. + source.reset(); cptr = my_impl->connections.begin(); + } else { + //was found - advance the start to the next. cend is the old source. + if (++cptr == my_impl->connections.end()) + cptr = my_impl->connections.begin(); } } + + //scan the list of peers looking for another able to provide sync blocks. + while (cptr != cend) { + //select the first one which is current and break out. + if ((*cptr)->current()) { + source = *cptr; + break; + } + else { + // advance the iterator in a round robin fashion. + if (++cptr == my_impl->connections.end()) { + cptr = my_impl->connections.begin(); + } + } + } + // no need to check the result, either source advanced or the whole list was checked and the old source is reused. } } + // verify there is an available source if (!source || !source->current() ) { elog("Unable to continue syncing at this time"); sync_known_lib_num = chain_plug->chain().last_irreversible_block_num(); @@ -1322,7 +1328,7 @@ namespace eosio { if( end > sync_known_lib_num ) end = sync_known_lib_num; if( end > 0 && end >= start ) { - fc_dlog(logger, "conn ${n} requesting range ${s} to ${e}, calling sync_wait", + fc_ilog(logger, "requesting range ${s} to ${e}, from ${n}", ("n",source->peer_name())("s",start)("e",end)); source->request_sync_blocks(start, end); sync_last_requested_num = end; @@ -1490,29 +1496,22 @@ namespace eosio { } } - void sync_manager::recv_block (connection_ptr c, const block_id_type &blk_id, uint32_t blk_num, bool accepted) { - fc_dlog(logger," got block ${bn} from ${p}",("bn",blk_num)("p",c->peer_name())); - if (!accepted) { - uint32_t head_num = chain_plug->chain().head_block_num(); - if (head_num != last_repeated) { - ilog ("block not accepted, try requesting one more time"); - last_repeated = head_num; - send_handshakes(); - } - else { - ilog ("second attempt to retrive block ${n} failed", - ("n", head_num + 1)); - last_repeated = 0; - sync_last_requested_num = 0; - my_impl->close(c); - } - return; + void sync_manager::rejected_block (connection_ptr c, uint32_t blk_num) { + if (state != in_sync ) { + fc_ilog (logger, "block ${bn} not accepted from ${p}",("bn",blk_num)("p",c->peer_name())); + sync_last_requested_num = 0; + source.reset(); + my_impl->close(c); + set_state(in_sync); + send_handshakes(); } - last_repeated = 0; + } + void sync_manager::recv_block (connection_ptr c, const block_id_type &blk_id, uint32_t blk_num) { + fc_dlog(logger," got block ${bn} from ${p}",("bn",blk_num)("p",c->peer_name())); if (state == lib_catchup) { if (blk_num != sync_next_expected_num) { fc_ilog (logger, "expected block ${ne} but got ${bn}",("ne",sync_next_expected_num)("bn",blk_num)); - c->close(); + my_impl->close(c); return; } sync_next_expected_num = blk_num + 1; @@ -2466,7 +2465,7 @@ namespace eosio { try { if( cc.fetch_block_by_id(blk_id)) { - sync_master->recv_block(c, blk_id, blk_num, true); + sync_master->recv_block(c, blk_id, blk_num); return; } } catch( ...) { @@ -2485,7 +2484,6 @@ namespace eosio { chain_plug->accept_block(sbp); //, sync_master->is_active(c)); reason = no_reason; } catch( const unlinkable_block_exception &ex) { - elog( "unlinkable_block_exception accept block #${n} syncing from ${p}",("n",blk_num)("p",c->peer_name())); reason = unlinkable; } catch( const block_validate_exception &ex) { elog( "block_validate_exception accept block #${n} syncing from ${p}",("n",blk_num)("p",c->peer_name())); @@ -2512,8 +2510,11 @@ namespace eosio { c->trx_state.modify( ctx, ubn ); } } + sync_master->recv_block(c, blk_id, blk_num); + } + else { + sync_master->rejected_block(c, blk_num); } - sync_master->recv_block(c, blk_id, blk_num, reason == no_reason); } void net_plugin_impl::start_conn_timer( ) { From e9525c424a71187581b80970803bc151f8887c82 Mon Sep 17 00:00:00 2001 From: John Williamson Date: Tue, 22 May 2018 23:44:03 +1000 Subject: [PATCH 28/55] fixed misspelling --- contracts/eosio.msig/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.msig/README.md b/contracts/eosio.msig/README.md index a1b839d553b..1d72791395e 100644 --- a/contracts/eosio.msig/README.md +++ b/contracts/eosio.msig/README.md @@ -13,7 +13,7 @@ Create a proposal Storage changes are billed to 'proposer' -Aprrove a proposal +Approve a proposal ## eosio.msig::approve proposer proposal_name level - **proposer** account proposing a transaction - **proposal_name** name of the proposal From 0fe62b578ef8690fd92c8a8dee3a4bd89939c8f7 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 22 May 2018 09:54:16 -0400 Subject: [PATCH 29/55] history plugin: support --filter-on * for tests --- plugins/history_plugin/history_plugin.cpp | 20 ++++++++++++++------ tests/testUtils.py | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index e7c6375e1c3..f3c0b9740bb 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -135,10 +135,13 @@ namespace eosio { class history_plugin_impl { public: + bool bypass_filter = false; std::set filter_on; chain_plugin* chain_plug = nullptr; bool filter( const action_trace& act ) { + if( bypass_filter ) + return true; if( filter_on.find({ act.receipt.receiver, act.act.name, 0 }) != filter_on.end() ) return true; for( const auto& a : act.act.authorization ) @@ -152,7 +155,7 @@ namespace eosio { result.insert( act.receipt.receiver ); for( const auto& a : act.act.authorization ) - if( filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end() ) + if( bypass_filter || filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end() ) result.insert( a.actor ); return result; } @@ -252,21 +255,26 @@ namespace eosio { void history_plugin::set_program_options(options_description& cli, options_description& cfg) { cfg.add_options() - ("filter_on,f", bpo::value>()->composing(), + ("filter-on,f", bpo::value>()->composing(), "Track actions which match receiver:action:actor. Actor may be blank to include all. Receiver and Action may not be blank.") ; } void history_plugin::plugin_initialize(const variables_map& options) { - if( options.count("filter_on") ) + if( options.count("filter-on") ) { - auto fo = options.at("filter_on").as>(); + auto fo = options.at("filter-on").as>(); for( auto& s : fo ) { + if( s == "*" ) { + my->bypass_filter = true; + wlog("--filter-on * enabled. This can fill shared_mem, causing nodeos to stop."); + break; + } std::vector v; boost::split(v, s, boost::is_any_of(":")); - EOS_ASSERT(v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter_on", ("s",s)); + EOS_ASSERT(v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s",s)); filter_entry fe{ v[0], v[1], v[2] }; - EOS_ASSERT(fe.receiver.value && fe.action.value, fc::invalid_arg_exception, "Invalid value ${s} for --filter_on", ("s",s)); + EOS_ASSERT(fe.receiver.value && fe.action.value, fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s",s)); my->filter_on.insert( fe ); } } diff --git a/tests/testUtils.py b/tests/testUtils.py index 47604a013cf..7655140a6d7 100755 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -1376,7 +1376,7 @@ def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", delay=1, only if self.staging: cmdArr.append("--nogen") - nodeosArgs="--max-transaction-time 5000" + nodeosArgs="--max-transaction-time 5000 --filter-on *" if not self.walletd: nodeosArgs += " --plugin eosio::wallet_api_plugin" if self.enableMongo: From 4c0fe744ce38d2be7d31547992b53886eef398e6 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 22 May 2018 10:49:01 -0400 Subject: [PATCH 30/55] Bypass name bidding when creating accounts in nodeos_run_test --- tests/nodeos_run_test.py | 13 +++++++------ unittests/eosio.system_tests.cpp | 5 ++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/nodeos_run_test.py b/tests/nodeos_run_test.py index 4dde085df98..f492bc98f5a 100755 --- a/tests/nodeos_run_test.py +++ b/tests/nodeos_run_test.py @@ -230,20 +230,21 @@ def cmdError(name, cmdCode=0, exitNow=False): Print("Validating accounts before user accounts creation") cluster.validateAccounts(None) - Print("Create new account %s via %s" % (testeraAccount.name, defproduceraAccount.name)) - transId=node.createInitializeAccount(testeraAccount, defproduceraAccount, stakedDeposit=0, waitForTransBlock=False) + # create accounts via eosio as otherwise a bid is needed + Print("Create new account %s via %s" % (testeraAccount.name, cluster.eosioAccount.name)) + transId=node.createInitializeAccount(testeraAccount, cluster.eosioAccount, stakedDeposit=0, waitForTransBlock=False) if transId is None: cmdError("%s create account" % (testeraAccount.name)) errorExit("Failed to create account %s" % (testeraAccount.name)) - Print("Create new account %s via %s" % (currencyAccount.name, defproducerbAccount.name)) - transId=node.createInitializeAccount(currencyAccount, defproducerbAccount, stakedDeposit=5000) + Print("Create new account %s via %s" % (currencyAccount.name, cluster.eosioAccount.name)) + transId=node.createInitializeAccount(currencyAccount, cluster.eosioAccount, stakedDeposit=5000) if transId is None: cmdError("%s create account" % (ClientName)) errorExit("Failed to create account %s" % (currencyAccount.name)) - Print("Create new account %s via %s" % (exchangeAccount.name, defproduceraAccount.name)) - transId=node.createInitializeAccount(exchangeAccount, defproduceraAccount, waitForTransBlock=True) + Print("Create new account %s via %s" % (exchangeAccount.name, cluster.eosioAccount.name)) + transId=node.createInitializeAccount(exchangeAccount, cluster.eosioAccount, waitForTransBlock=True) if transId is None: cmdError("%s create account" % (ClientName)) errorExit("Failed to create account %s" % (exchangeAccount.name)) diff --git a/unittests/eosio.system_tests.cpp b/unittests/eosio.system_tests.cpp index d06912d7f6f..c9541ea76aa 100644 --- a/unittests/eosio.system_tests.cpp +++ b/unittests/eosio.system_tests.cpp @@ -2368,6 +2368,9 @@ BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { fc::exception, fc_assert_exception_message_is( not_closed_message ) ); BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefe), N(eve) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); + // attemp to create account with no bid + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefg), N(alice) ), + fc::exception, fc_assert_exception_message_is( "no active bid for name" ) ); // changing highest bid pushes auction closing time by 24 hours BOOST_REQUIRE_EQUAL( success(), bidname( "eve", "prefb", core_from_string("2.1880") ) ); @@ -2398,7 +2401,7 @@ BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { // but not others BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefa), N(bob) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); - + } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() From 7f6cce307adfa391fa22fa4983667e95c51427c1 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 10:56:30 -0400 Subject: [PATCH 31/55] Add reflector_verifier_visitor for classes that wish to validate reflection serialization --- libraries/fc/include/fc/reflect/reflect.hpp | 46 +++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/libraries/fc/include/fc/reflect/reflect.hpp b/libraries/fc/include/fc/reflect/reflect.hpp index 1093db2e8a7..67114efe9b2 100644 --- a/libraries/fc/include/fc/reflect/reflect.hpp +++ b/libraries/fc/include/fc/reflect/reflect.hpp @@ -45,6 +45,21 @@ struct reflector{ * }; * @endcode * + * If reflection requires a verification (what a constructor might normally assert) then + * derive your Visitor from reflector_verifier_visitor and implement a reflector_verify() + * on your reflected type. + * + * @code + * template + * struct functor : reflector_verifier_visitor { + * functor(Class& _c) + * : fc::reflector_verifier_visitor(_c) {} + * + * template + * void operator()( const char* name )const; + * }; + * @endcode + * * If T is an enum then the functor has the following form: * @code * struct functor { @@ -65,6 +80,37 @@ struct reflector{ void throw_bad_enum_cast( int64_t i, const char* e ); void throw_bad_enum_cast( const char* k, const char* e ); + +template +struct reflector_verifier_visitor { + explicit reflector_verifier_visitor( Class& c ) + : obj(c) {} + + ~reflector_verifier_visitor() noexcept(false) { + verify( obj ); + } + + private: + + // int matches 0 if reflector_verify exists SFINAE + template + auto verify_imp(const T& t, int) -> decltype(t.reflector_verify(), void()) { + t.reflector_verify(); + } + + // if no reflector_verify method exists (SFINAE), 0 matches long + template + auto verify_imp(const T& t, long) -> decltype(t, void()) {} + + template + auto verify(const T& t) -> decltype(verify_imp(t, 0), void()) { + verify_imp(t, 0); + } + + protected: + Class& obj; +}; + } // namespace fc From d7d892a5a1b6d36f613ef7db76de272ecb50592b Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 10:58:31 -0400 Subject: [PATCH 32/55] Add usage of new reflector_verifier_visitor --- libraries/chain/include/eosio/chain/abi_serializer.hpp | 9 ++++----- libraries/fc/include/fc/io/raw.hpp | 8 ++++---- libraries/fc/include/fc/reflect/variant.hpp | 8 ++++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index eca88c5e05e..b5f7030366e 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -461,12 +461,12 @@ namespace impl { * @tparam Reslover - callable with the signature (const name& code_account) -> optional */ template - class abi_from_variant_visitor + class abi_from_variant_visitor : reflector_verifier_visitor { public: abi_from_variant_visitor( const variant_object& _vo, T& v, Resolver _resolver ) - :_vo(_vo) - ,_val(v) + : reflector_verifier_visitor(v) + ,_vo(_vo) ,_resolver(_resolver) {} @@ -482,12 +482,11 @@ namespace impl { { auto itr = _vo.find(name); if( itr != _vo.end() ) - abi_from_variant::extract( itr->value(), _val.*member, _resolver ); + abi_from_variant::extract( itr->value(), this->obj.*member, _resolver ); } private: const variant_object& _vo; - T& _val; Resolver _resolver; }; diff --git a/libraries/fc/include/fc/io/raw.hpp b/libraries/fc/include/fc/io/raw.hpp index 40a4a447c28..bec9ae709f7 100644 --- a/libraries/fc/include/fc/io/raw.hpp +++ b/libraries/fc/include/fc/io/raw.hpp @@ -350,17 +350,17 @@ namespace fc { }; template - struct unpack_object_visitor { + struct unpack_object_visitor : fc::reflector_verifier_visitor { unpack_object_visitor(Class& _c, Stream& _s) - :c(_c),s(_s){} + : fc::reflector_verifier_visitor(_c), s(_s){} template inline void operator()( const char* name )const { try { - fc::raw::unpack( s, c.*p ); + fc::raw::unpack( s, this->obj.*p ); } FC_RETHROW_EXCEPTIONS( warn, "Error unpacking field ${field}", ("field",name) ) } + private: - Class& c; Stream& s; }; diff --git a/libraries/fc/include/fc/reflect/variant.hpp b/libraries/fc/include/fc/reflect/variant.hpp index 31bbbdf18a2..95863d18448 100644 --- a/libraries/fc/include/fc/reflect/variant.hpp +++ b/libraries/fc/include/fc/reflect/variant.hpp @@ -39,22 +39,22 @@ namespace fc }; template - class from_variant_visitor + class from_variant_visitor : reflector_verifier_visitor { public: from_variant_visitor( const variant_object& _vo, T& v ) - :vo(_vo),val(v){} + :reflector_verifier_visitor(v) + ,vo(_vo){} template void operator()( const char* name )const { auto itr = vo.find(name); if( itr != vo.end() ) - from_variant( itr->value(), val.*member ); + from_variant( itr->value(), this->obj.*member ); } const variant_object& vo; - T& val; }; template From 66ca8d270cf0e46534dd53cb0b420b48ba611f29 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 22 May 2018 10:59:32 -0400 Subject: [PATCH 33/55] Fix for wrong bad_alloc --- plugins/chain_plugin/chain_plugin.cpp | 12 +++++++++--- programs/nodeos/main.cpp | 1 - 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 097fa6de024..b61ea884b8a 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -526,8 +526,10 @@ fc::variant read_only::get_block(const read_only::get_block_params& params) cons read_write::push_block_results read_write::push_block(const read_write::push_block_params& params) { try { db.push_block( std::make_shared(params) ); - } catch ( ... ) { + } catch ( boost::interprocess::bad_alloc& ) { raise(SIGUSR1); + } catch ( ... ) { + throw; } return read_write::push_block_results(); } @@ -547,8 +549,10 @@ read_write::push_transaction_results read_write::push_transaction(const read_wri pretty_output = db.to_variant_with_abi( *trx_trace_ptr );; //abi_serializer::to_variant(*trx_trace_ptr, pretty_output, resolver); id = trx_trace_ptr->id; - } catch ( ... ) { + } catch ( boost::interprocess::bad_alloc& ) { raise(SIGUSR1); + } catch ( ... ) { + throw; } return read_write::push_transaction_results{ id, pretty_output }; } @@ -566,8 +570,10 @@ read_write::push_transactions_results read_write::push_transactions(const read_w fc::mutable_variant_object( "error", e.to_detail_string() ) } ); } } - } catch ( ... ) { + } catch ( boost::interprocess::bad_alloc& ) { raise(SIGUSR1); + } catch ( ... ) { + throw; } return result; } diff --git a/programs/nodeos/main.cpp b/programs/nodeos/main.cpp index 9e726e59cfc..49aae0aae72 100644 --- a/programs/nodeos/main.cpp +++ b/programs/nodeos/main.cpp @@ -99,7 +99,6 @@ int main(int argc, char** argv) elog("${e}", ("e",e.to_detail_string())); } catch (const boost::interprocess::bad_alloc& e) { elog("bad alloc"); - //elog("${e}", ("e", boost::diagnostic_information(e))); return 3; } catch (const boost::exception& e) { elog("${e}", ("e",boost::diagnostic_information(e))); From 1cfb4365bc60fccd144a54a5f53188a329bd15d2 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 10:59:42 -0400 Subject: [PATCH 34/55] Add exception handling to to_string and to_detail_string --- libraries/fc/src/exception.cpp | 64 ++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/libraries/fc/src/exception.cpp b/libraries/fc/src/exception.cpp index 17cb19da65c..14b4a3be800 100644 --- a/libraries/fc/src/exception.cpp +++ b/libraries/fc/src/exception.cpp @@ -158,14 +158,32 @@ namespace fc string exception::to_detail_string( log_level ll )const { std::stringstream ss; - ss << variant(my->_code).as_string() <<" " << my->_name << ": " <_what<<"\n"; - for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ) - { - ss << itr->get_message() <<"\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; - ss << " " << json::to_string( itr->get_data() ) <<"\n"; - ss << " " << itr->get_context().to_string(); - ++itr; - if( itr != my->_elog.end() ) ss<<"\n"; + try { + try { + ss << variant( my->_code ).as_string(); + } catch( std::bad_alloc& ) { + throw; + } catch( ... ) { + ss << "<- exception in to_detail_string."; + } + ss << " " << my->_name << ": " << my->_what << "\n"; + for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ) { + try { + ss << itr->get_message() << "\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; + ss << " " << json::to_string( itr->get_data()) << "\n"; + ss << " " << itr->get_context().to_string(); + ++itr; + } catch( std::bad_alloc& ) { + throw; + } catch( ... ) { + ss << "<- exception in to_detail_string."; + } + if( itr != my->_elog.end()) ss << "\n"; + } + } catch( std::bad_alloc& ) { + throw; + } catch( ... ) { + ss << "<- exception in to_detail_string.\n"; } return ss.str(); } @@ -176,13 +194,31 @@ namespace fc string exception::to_string( log_level ll )const { std::stringstream ss; - ss << what() << " (" << variant(my->_code).as_string() <<")\n"; - for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr ) - { - ss << fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; - // ss << " " << itr->get_context().to_string() <<"\n"; + try { + ss << my->_what; + try { + ss << " (" << variant( my->_code ).as_string() << ")\n"; + } catch( std::bad_alloc& ) { + throw; + } catch( ... ) { + ss << "<- exception in to_string.\n"; + } + for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr ) { + try { + ss << fc::format_string( itr->get_format(), itr->get_data()) << "\n"; + // ss << " " << itr->get_context().to_string() <<"\n"; + } catch( std::bad_alloc& ) { + throw; + } catch( ... ) { + ss << "<- exception in to_string.\n"; + } + } + return ss.str(); + } catch( std::bad_alloc& ) { + throw; + } catch( ... ) { + ss << "<- exception in to_string.\n"; } - return ss.str(); } /** From 18946e0fea1f4b50caebdbeec6352600107e533e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 11:00:34 -0400 Subject: [PATCH 35/55] Add reflector_verify for FC_REFLECT of symbol --- libraries/chain/include/eosio/chain/symbol.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/symbol.hpp b/libraries/chain/include/eosio/chain/symbol.hpp index b7ca01900de..389d4103671 100644 --- a/libraries/chain/include/eosio/chain/symbol.hpp +++ b/libraries/chain/include/eosio/chain/symbol.hpp @@ -79,7 +79,7 @@ namespace eosio { auto prec_part = s.substr(0, comma_pos); uint8_t p = fc::to_int64(prec_part); string name_part = s.substr(comma_pos + 1); - FC_ASSERT( p <= max_precision, "precision should be <= 18"); + FC_ASSERT( p <= max_precision, "precision ${p} should be <= 18", ("p", p)); return symbol(string_to_symbol(p, name_part.c_str())); } FC_CAPTURE_LOG_AND_RETHROW((from)) } @@ -97,6 +97,7 @@ namespace eosio { uint8_t decimals() const { return m_value & 0xFF; } uint64_t precision() const { + FC_ASSERT( decimals() <= max_precision, "precision ${p} should be <= 18", ("p", decimals()) ); uint64_t p10 = 1; uint64_t p = decimals(); while( p > 0 ) { @@ -136,6 +137,11 @@ namespace eosio { return ds << s.to_string(); } + void reflector_verify()const { + FC_ASSERT( decimals() <= max_precision, "precision ${p} should be <= 18", ("p", decimals()) ); + FC_ASSERT( valid_name(name()), "invalid symbol: ${name}", ("name",name())); + } + private: uint64_t m_value; friend struct fc::reflector; From e97dfd85b1ecf71dd8b23ee10492e2e6d56a35db Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 11:02:00 -0400 Subject: [PATCH 36/55] Add common handle_exception method for handlers --- .../history_api_plugin/history_api_plugin.cpp | 10 +- plugins/http_plugin/CMakeLists.txt | 2 +- plugins/http_plugin/http_plugin.cpp | 123 +++++++++++++----- .../include/eosio/http_plugin/http_plugin.hpp | 3 + 4 files changed, 96 insertions(+), 42 deletions(-) diff --git a/plugins/history_api_plugin/history_api_plugin.cpp b/plugins/history_api_plugin/history_api_plugin.cpp index 9760c01bedb..8f5767aca00 100644 --- a/plugins/history_api_plugin/history_api_plugin.cpp +++ b/plugins/history_api_plugin/history_api_plugin.cpp @@ -26,14 +26,8 @@ void history_api_plugin::plugin_initialize(const variables_map&) {} if (body.empty()) body = "{}"; \ auto result = api_handle.call_name(fc::json::from_string(body).as()); \ cb(200, fc::json::to_string(result)); \ - } catch (fc::eof_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - cb(400, fc::json::to_string(results)); \ - elog("Unable to parse arguments: ${args}", ("args", body)); \ - } catch (fc::exception& e) { \ - error_results results{500, "Internal Service Error", e}; \ - cb(500, fc::json::to_string(results)); \ - elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ }} diff --git a/plugins/http_plugin/CMakeLists.txt b/plugins/http_plugin/CMakeLists.txt index 86cb41e8129..b12eb696067 100644 --- a/plugins/http_plugin/CMakeLists.txt +++ b/plugins/http_plugin/CMakeLists.txt @@ -3,5 +3,5 @@ add_library( http_plugin http_plugin.cpp ${HEADERS} ) -target_link_libraries( http_plugin appbase fc ) +target_link_libraries( http_plugin eosio_chain appbase fc ) target_include_directories( http_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/plugins/http_plugin/http_plugin.cpp b/plugins/http_plugin/http_plugin.cpp index a768fbd6cb1..6eb378a9eb0 100644 --- a/plugins/http_plugin/http_plugin.cpp +++ b/plugins/http_plugin/http_plugin.cpp @@ -3,6 +3,7 @@ * @copyright defined in eos/LICENSE.txt */ #include +#include #include #include @@ -129,51 +130,67 @@ namespace eosio { return ctx; } + template + static void handle_exception(typename websocketpp::server>::connection_ptr con) { + string err = "Internal Service error, http: "; + try { + con->set_status( websocketpp::http::status_code::internal_server_error ); + try { + throw; + } catch (const fc::exception& e) { + err += e.to_detail_string(); + elog( "${e}", ("e", err)); + error_results results{websocketpp::http::status_code::internal_server_error, + "Internal Service Error", e}; + con->set_body( fc::json::to_string( results )); + } catch (const std::exception& e) { + err += e.what(); + elog( "${e}", ("e", err)); + error_results results{websocketpp::http::status_code::internal_server_error, + "Internal Service Error", fc::exception( FC_LOG_MESSAGE( error, e.what()))}; + } catch (...) { + err += "Unknown Exception"; + error_results results{websocketpp::http::status_code::internal_server_error, + "Internal Service Error", + fc::exception( FC_LOG_MESSAGE( error, "Unknown Exception" ))}; + con->set_body( fc::json::to_string( results )); + } + } catch (...) { + con->set_body( R"xxx({"message": "Internal Server Error"})xxx" ); + std::cerr << "Exception attempting to handle exception: " << err << std::endl; + } + } + template void handle_http_request(typename websocketpp::server>::connection_ptr con) { try { - if (!access_control_allow_origin.empty()) { - con->append_header("Access-Control-Allow-Origin", access_control_allow_origin); + if( !access_control_allow_origin.empty()) { + con->append_header( "Access-Control-Allow-Origin", access_control_allow_origin ); } - if (!access_control_allow_headers.empty()) { - con->append_header("Access-Control-Allow-Headers", access_control_allow_headers); + if( !access_control_allow_headers.empty()) { + con->append_header( "Access-Control-Allow-Headers", access_control_allow_headers ); } - if (access_control_allow_credentials) { - con->append_header("Access-Control-Allow-Credentials", "true"); + if( access_control_allow_credentials ) { + con->append_header( "Access-Control-Allow-Credentials", "true" ); } - con->append_header("Content-type", "application/json"); + con->append_header( "Content-type", "application/json" ); auto body = con->get_request_body(); auto resource = con->get_uri()->get_resource(); - auto handler_itr = url_handlers.find(resource); - if(handler_itr != url_handlers.end()) { - handler_itr->second(resource, body, [con](auto code, auto&& body) { - con->set_body(std::move(body)); - con->set_status(websocketpp::http::status_code::value(code)); - }); + auto handler_itr = url_handlers.find( resource ); + if( handler_itr != url_handlers.end()) { + handler_itr->second( resource, body, [con]( auto code, auto&& body ) { + con->set_body( std::move( body )); + con->set_status( websocketpp::http::status_code::value( code )); + } ); } else { - wlog("404 - not found: ${ep}", ("ep",resource)); + wlog( "404 - not found: ${ep}", ("ep", resource)); error_results results{websocketpp::http::status_code::not_found, - "Not Found", fc::exception(FC_LOG_MESSAGE(error, "Unknown Endpoint"))}; - con->set_body(fc::json::to_string(results)); - con->set_status(websocketpp::http::status_code::not_found); + "Not Found", fc::exception( FC_LOG_MESSAGE( error, "Unknown Endpoint" ))}; + con->set_body( fc::json::to_string( results )); + con->set_status( websocketpp::http::status_code::not_found ); } - } catch( const fc::exception& e ) { - elog( "http: ${e}", ("e",e.to_detail_string())); - error_results results{websocketpp::http::status_code::internal_server_error, - "Internal Service Error", e}; - con->set_body(fc::json::to_string(results)); - con->set_status(websocketpp::http::status_code::internal_server_error); - } catch( const std::exception& e ) { - elog( "http: ${e}", ("e",e.what())); - error_results results{websocketpp::http::status_code::internal_server_error, - "Internal Service Error", fc::exception(FC_LOG_MESSAGE(error, e.what()))}; - con->set_body(fc::json::to_string(results)); - con->set_status(websocketpp::http::status_code::internal_server_error); } catch( ... ) { - error_results results{websocketpp::http::status_code::internal_server_error, - "Internal Service Error", fc::exception(FC_LOG_MESSAGE(error, "Unknown Exception"))}; - con->set_body(fc::json::to_string(results)); - con->set_status(websocketpp::http::status_code::internal_server_error); + handle_exception( con ); } } @@ -327,4 +344,44 @@ namespace eosio { my->url_handlers.insert(std::make_pair(url,handler)); }); } + + void http_plugin::handle_exception( const char *api_name, const char *call_name, const string& body, url_response_callback cb ) { + try { + try { + throw; + } catch (chain::unsatisfied_authorization& e) { + error_results results{401, "UnAuthorized", e}; + cb( 401, fc::json::to_string( results )); + } catch (chain::tx_duplicate& e) { + error_results results{409, "Conflict", e}; + cb( 409, fc::json::to_string( results )); + } catch (chain::transaction_exception& e) { + error_results results{400, "Bad Request", e}; + cb( 400, fc::json::to_string( results )); + } catch (fc::eof_exception& e) { + error_results results{400, "Bad Request", e}; + cb( 400, fc::json::to_string( results )); + elog( "Unable to parse arguments: ${args}", ("args", body)); + } catch (fc::exception& e) { + error_results results{500, "Internal Service Error", e}; + cb( 500, fc::json::to_string( results )); + elog( "FC Exception encountered while processing ${api}.${call}: ${e}", + ("api", api_name)( "call", call_name )( "e", e.to_detail_string())); + } catch (std::exception& e) { + error_results results{500, "Internal Service Error", fc::exception( FC_LOG_MESSAGE( error, e.what()))}; + cb( 500, fc::json::to_string( results )); + elog( "STD Exception encountered while processing ${api}.${call}: ${e}", + ("api", api_name)( "call", call_name )( "e", e.what())); + } catch (...) { + error_results results{500, "Internal Service Error", + fc::exception( FC_LOG_MESSAGE( error, "Unknown Exception" ))}; + cb( 500, fc::json::to_string( results )); + elog( "Unknown Exception encountered while processing ${api}.${call}", + ("api", api_name)( "call", call_name )); + } + } catch (...) { + std::cerr << "Exception attempting to handle exception for " << api_name << "." << call_name << std::endl; + } + } + } diff --git a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp index da2d5012474..0fa7e4c386d 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp @@ -73,6 +73,9 @@ namespace eosio { add_handler(call.first, call.second); } + // standard exception handling for api handlers + static void handle_exception( const char *api_name, const char *call_name, const string& body, url_response_callback cb ); + private: std::unique_ptr my; }; From 9b4b01fd9fa78bb83f8cf4c01b8588187993d0d8 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 11:03:16 -0400 Subject: [PATCH 37/55] Add usage of new common http exception handler --- .../account_history_api_plugin.cpp | 10 ++-------- plugins/chain_api_plugin/chain_api_plugin.cpp | 19 ++----------------- .../db_size_api_plugin/db_size_api_plugin.cpp | 10 ++-------- .../faucet_testnet_plugin.cpp | 10 ++-------- plugins/net_api_plugin/net_api_plugin.cpp | 10 ++-------- .../txn_test_gen_plugin.cpp | 10 ++-------- .../wallet_api_plugin/wallet_api_plugin.cpp | 10 ++-------- 7 files changed, 14 insertions(+), 65 deletions(-) diff --git a/plugins/account_history_api_plugin/account_history_api_plugin.cpp b/plugins/account_history_api_plugin/account_history_api_plugin.cpp index 2202adda3f2..d73298e7bb2 100644 --- a/plugins/account_history_api_plugin/account_history_api_plugin.cpp +++ b/plugins/account_history_api_plugin/account_history_api_plugin.cpp @@ -27,14 +27,8 @@ void account_history_api_plugin::plugin_initialize(const variables_map&) {} if (body.empty()) body = "{}"; \ auto result = api_handle.call_name(fc::json::from_string(body).as()); \ cb(200, fc::json::to_string(result)); \ - } catch (fc::eof_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - cb(400, fc::json::to_string(results)); \ - elog("Unable to parse arguments: ${args}", ("args", body)); \ - } catch (fc::exception& e) { \ - error_results results{500, "Internal Service Error", e}; \ - cb(500, fc::json::to_string(results)); \ - elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ }} diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index 92263ab9abf..004dc32c089 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -35,23 +35,8 @@ void chain_api_plugin::plugin_initialize(const variables_map&) {} if (body.empty()) body = "{}"; \ auto result = api_handle.call_name(fc::json::from_string(body).as()); \ cb(http_response_code, fc::json::to_string(result)); \ - } catch (chain::unsatisfied_authorization& e) { \ - error_results results{401, "UnAuthorized", e}; \ - cb(401, fc::json::to_string(results)); \ - } catch (chain::tx_duplicate& e) { \ - error_results results{409, "Conflict", e}; \ - cb(409, fc::json::to_string(results)); \ - } catch (chain::transaction_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - cb(400, fc::json::to_string(results)); \ - } catch (fc::eof_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - cb(400, fc::json::to_string(results)); \ - elog("Unable to parse arguments: ${args}", ("args", body)); \ - } catch (fc::exception& e) { \ - error_results results{500, "Internal Service Error", e}; \ - cb(500, fc::json::to_string(results)); \ - elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e.to_detail_string())); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ }} diff --git a/plugins/db_size_api_plugin/db_size_api_plugin.cpp b/plugins/db_size_api_plugin/db_size_api_plugin.cpp index 5ee0b1093a8..8dd5b50f48e 100644 --- a/plugins/db_size_api_plugin/db_size_api_plugin.cpp +++ b/plugins/db_size_api_plugin/db_size_api_plugin.cpp @@ -19,14 +19,8 @@ using namespace eosio; if (body.empty()) body = "{}"; \ INVOKE \ cb(http_response_code, fc::json::to_string(result)); \ - } catch (fc::eof_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - cb(400, fc::json::to_string(results)); \ - elog("Unable to parse arguments: ${args}", ("args", body)); \ - } catch (fc::exception& e) { \ - error_results results{500, "Internal Service Error", e}; \ - cb(500, fc::json::to_string(results)); \ - elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ }} diff --git a/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp b/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp index 76e6f9d8241..d53c2335415 100644 --- a/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp +++ b/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp @@ -62,14 +62,8 @@ using results_pair = std::pair; if (body.empty()) body = "{}"; \ const auto result = api_handle->invoke_cb(body); \ response_cb(result.first, fc::json::to_string(result.second)); \ - } catch (fc::eof_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - response_cb(400, fc::json::to_string(results)); \ - elog("Unable to parse arguments: ${args}", ("args", body)); \ - } catch (fc::exception& e) { \ - error_results results{500, "Internal Service Error", e}; \ - response_cb(500, fc::json::to_string(results)); \ - elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, response_cb); \ } \ }} diff --git a/plugins/net_api_plugin/net_api_plugin.cpp b/plugins/net_api_plugin/net_api_plugin.cpp index 54d3d25c104..ad4852a71cc 100644 --- a/plugins/net_api_plugin/net_api_plugin.cpp +++ b/plugins/net_api_plugin/net_api_plugin.cpp @@ -30,14 +30,8 @@ using namespace eosio; if (body.empty()) body = "{}"; \ INVOKE \ cb(http_response_code, fc::json::to_string(result)); \ - } catch (fc::eof_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - cb(400, fc::json::to_string(results)); \ - elog("Unable to parse arguments: ${args}", ("args", body)); \ - } catch (fc::exception& e) { \ - error_results results{500, "Internal Service Error", e}; \ - cb(500, fc::json::to_string(results)); \ - elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ }} 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 0d0f393483b..97c421dc9a0 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -45,14 +45,8 @@ using namespace eosio::chain; if (body.empty()) body = "{}"; \ INVOKE \ cb(http_response_code, fc::json::to_string(result)); \ - } catch (fc::eof_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - cb(400, fc::json::to_string(results)); \ - elog("Unable to parse arguments: ${args}", ("args", body)); \ - } catch (fc::exception& e) { \ - error_results results{500, "Internal Service Error", e}; \ - cb(500, fc::json::to_string(results)); \ - elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ }} diff --git a/plugins/wallet_api_plugin/wallet_api_plugin.cpp b/plugins/wallet_api_plugin/wallet_api_plugin.cpp index d08bcf5098c..d11faccb330 100644 --- a/plugins/wallet_api_plugin/wallet_api_plugin.cpp +++ b/plugins/wallet_api_plugin/wallet_api_plugin.cpp @@ -31,14 +31,8 @@ using namespace eosio; if (body.empty()) body = "{}"; \ INVOKE \ cb(http_response_code, fc::json::to_string(result)); \ - } catch (fc::eof_exception& e) { \ - error_results results{400, "Bad Request", e}; \ - cb(400, fc::json::to_string(results)); \ - elog("Unable to parse arguments: ${args}", ("args", body)); \ - } catch (fc::exception& e) { \ - error_results results{500, "Internal Service Error", e}; \ - cb(500, fc::json::to_string(results)); \ - elog("Exception encountered while processing ${call}: ${e}", ("call", #api_name "." #call_name)("e", e)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ }} From 8ee3ac0167fafeebc9ffbc0e4f0da64eececbaa9 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 22 May 2018 11:29:13 -0400 Subject: [PATCH 38/55] Added return codes --- programs/nodeos/main.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/programs/nodeos/main.cpp b/programs/nodeos/main.cpp index 49aae0aae72..d0ca35532e9 100644 --- a/programs/nodeos/main.cpp +++ b/programs/nodeos/main.cpp @@ -79,6 +79,13 @@ void initialize_logging() logging_conf_loop(); } +enum return_codes { + INITIALIZE_FAIL = -1, + SUCCESS = 0, + BAD_ALLOC = 1, + OTHER_FAIL = 2 +}; + int main(int argc, char** argv) { try { @@ -89,7 +96,7 @@ int main(int argc, char** argv) app().set_default_data_dir(root / "eosio/nodeos/data" ); app().set_default_config_dir(root / "eosio/nodeos/config" ); if(!app().initialize(argc, argv)) - return -1; + return INITIALIZE_FAIL; initialize_logging(); ilog("nodeos version ${ver}", ("ver", eosio::utilities::common::itoh(static_cast(app().version())))); ilog("eosio root is ${root}", ("root", root.string())); @@ -97,16 +104,20 @@ int main(int argc, char** argv) app().exec(); } catch (const fc::exception& e) { elog("${e}", ("e",e.to_detail_string())); + return OTHER_FAIL; } catch (const boost::interprocess::bad_alloc& e) { elog("bad alloc"); - return 3; + return BAD_ALLOC; } catch (const boost::exception& e) { elog("${e}", ("e",boost::diagnostic_information(e))); + return OTHER_FAIL; } catch (const std::exception& e) { elog("${e}", ("e",e.what())); + return OTHER_FAIL; } catch (...) { elog("unknown exception"); + return OTHER_FAIL; } - return 0; + return SUCCESS; } From 9d9d127df7b6aa9f69e1ce79c8b494b1b1bdc75b Mon Sep 17 00:00:00 2001 From: Phil Mesnier Date: Tue, 22 May 2018 12:11:38 -0500 Subject: [PATCH 39/55] fix for non-terminating loop condition --- plugins/net_plugin/net_plugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 5f509be878f..448b80ba798 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1290,8 +1290,9 @@ namespace eosio { cptr = my_impl->connections.begin(); } else { //was found - advance the start to the next. cend is the old source. - if (++cptr == my_impl->connections.end()) + if (++cptr == my_impl->connections.end() && cend != my_impl->connections.end() ) { cptr = my_impl->connections.begin(); + } } } From aafb9c202cf22d5c64ab929db08313a62df769be Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 14:31:50 -0400 Subject: [PATCH 40/55] Add reflector_verify for FC_REFLECT serialization verification --- libraries/chain/include/eosio/chain/asset.hpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/libraries/chain/include/eosio/chain/asset.hpp b/libraries/chain/include/eosio/chain/asset.hpp index db453048848..30f4faa14f6 100644 --- a/libraries/chain/include/eosio/chain/asset.hpp +++ b/libraries/chain/include/eosio/chain/asset.hpp @@ -27,9 +27,6 @@ struct asset EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" ); } - share_type amount; - symbol sym; - bool is_amount_within_range()const { return -max_amount <= amount && amount <= max_amount; } bool is_valid()const { return is_amount_within_range() && sym.valid(); } @@ -84,6 +81,17 @@ struct asset friend std::ostream& operator << (std::ostream& out, const asset& a) { return out << a.to_string(); } + friend struct fc::reflector; + + void reflector_verify()const { + EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" ); + EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" ); + } + +private: + share_type amount; + symbol sym; + }; struct extended_asset { From 92b2861a894aa872660a71126dd004c3ad661118 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 14:32:51 -0400 Subject: [PATCH 41/55] Move call of object reflector_verify from visitor destructor to explicit call in visit --- libraries/fc/include/fc/reflect/reflect.hpp | 27 ++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/libraries/fc/include/fc/reflect/reflect.hpp b/libraries/fc/include/fc/reflect/reflect.hpp index 67114efe9b2..9ee0f729c04 100644 --- a/libraries/fc/include/fc/reflect/reflect.hpp +++ b/libraries/fc/include/fc/reflect/reflect.hpp @@ -86,8 +86,8 @@ struct reflector_verifier_visitor { explicit reflector_verifier_visitor( Class& c ) : obj(c) {} - ~reflector_verifier_visitor() noexcept(false) { - verify( obj ); + void reflector_verify() { + reflect_verify( obj ); } private: @@ -103,7 +103,7 @@ struct reflector_verifier_visitor { auto verify_imp(const T& t, long) -> decltype(t, void()) {} template - auto verify(const T& t) -> decltype(verify_imp(t, 0), void()) { + auto reflect_verify(const T& t) -> decltype(verify_imp(t, 0), void()) { verify_imp(t, 0); } @@ -145,6 +145,7 @@ template\ static inline void visit( const Visitor& v ) { \ BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \ BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \ + verify( v ); \ } #define FC_REFLECT_DERIVED_IMPL_EXT( TYPE, INHERITS, MEMBERS ) \ @@ -252,6 +253,16 @@ template<> struct reflector {\ typedef TYPE type; \ typedef fc::true_type is_defined; \ typedef fc::false_type is_enum; \ + template \ + static auto verify_imp(const Visitor& v, int) -> decltype(v.reflector_verify(), void()) { \ + v.reflector_verify(); \ + } \ + template \ + static auto verify_imp(const Visitor& v, long) -> decltype(v, void()) {} \ + template \ + static auto verify(const Visitor& v) -> decltype(verify_imp(v, 0), void()) { \ + verify_imp(v, 0); \ + } \ enum member_count_enum { \ local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\ total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ @@ -265,6 +276,16 @@ template struct reflector {\ typedef TYPE type; \ typedef fc::true_type is_defined; \ typedef fc::false_type is_enum; \ + template \ + static auto verify_imp(const Visitor& v, int) -> decltype(v.reflector_verify(), void()) { \ + v.reflector_verify(); \ + } \ + template \ + static auto verify_imp(const Visitor& v, long) -> decltype(v, void()) {} \ + template \ + static auto verify(const Visitor& v) -> decltype(verify_imp(v, 0), void()) { \ + verify_imp(v, 0); \ + } \ enum member_count_enum { \ local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\ total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ From 08ade61eb1e5b66c292a4f5a4fea6efe80f3a8e4 Mon Sep 17 00:00:00 2001 From: Eric Stone Date: Tue, 22 May 2018 11:35:05 -0700 Subject: [PATCH 42/55] centos7 needs bzip2 not always default --- scripts/eosio_build_centos.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/eosio_build_centos.sh b/scripts/eosio_build_centos.sh index 02b8d16746b..eeeafc22cad 100644 --- a/scripts/eosio_build_centos.sh +++ b/scripts/eosio_build_centos.sh @@ -125,7 +125,7 @@ printf "\\n\\tYUM repository successfully updated.\\n\\n" - DEP_ARRAY=( git autoconf automake libtool ocaml.x86_64 doxygen graphviz-devel.x86_64 libicu-devel.x86_64 \ + DEP_ARRAY=( git autoconf automake bzip2 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="" @@ -708,4 +708,4 @@ mongodconf printf '\texport PATH=${HOME}/opt/mongodb/bin:$PATH\n' printf "\\tcd %s; make test\\n\\n" "${BUILD_DIR}" return 0 - } \ No newline at end of file + } From 096f1af78101dabaf4eb52748ab892368b75e61a Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 22 May 2018 14:37:25 -0400 Subject: [PATCH 43/55] One more account creation check --- unittests/eosio.system_tests.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/unittests/eosio.system_tests.cpp b/unittests/eosio.system_tests.cpp index c9541ea76aa..fa595f796d3 100644 --- a/unittests/eosio.system_tests.cpp +++ b/unittests/eosio.system_tests.cpp @@ -2398,7 +2398,13 @@ BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { produce_block( fc::hours(24) ); // by now bid for prefe has closed create_account_with_resources( N(prefe), N(carl) ); - // but not others + // prefe can now create *.prefe + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(xyz.prefe), N(carl) ), + fc::exception, fc_assert_exception_message_is("only suffix may create this account") ); + transfer( config::system_account_name, N(prefe), core_from_string("10000.0000") ); + create_account_with_resources( N(xyz.prefe), N(prefe) ); + + // other auctions haven't closed BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefa), N(bob) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); From 9ed1e9842e362b06171cbd79dc1761cd345bfbf7 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Tue, 22 May 2018 14:52:23 -0400 Subject: [PATCH 44/55] pre-increment the coorelation-id or this check will never pass. oops. EOSIO/eos#3161 --- plugins/producer_plugin/producer_plugin.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index d314bac10d3..e6ffbda971b 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -415,16 +415,22 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ void producer_plugin::plugin_startup() { try { + if(fc::get_logger_map().find(logger_name) != fc::get_logger_map().end()) { + _log = fc::get_logger_map()[logger_name]; + } + ilog("producer plugin: plugin_startup() begin"); chain::controller& chain = app().get_plugin().chain(); chain.accepted_block.connect( [this]( const auto& bsp ){ my->on_block( bsp ); } ); if (!my->_producers.empty()) { - ilog("Launching block production for ${n} producers.", ("n", my->_producers.size())); + ilog("Launching block production for ${n} producers at ${time}.", ("n", my->_producers.size())("time",fc::time_point::now())); + if (my->_production_enabled) { - if (chain.head_block_num() == 0) + if (chain.head_block_num() == 0) { new_chain_banner(chain); + } //_production_skip_flags |= eosio::chain::skip_undo_history_check; } } @@ -432,11 +438,6 @@ void producer_plugin::plugin_startup() my->schedule_production_loop(); ilog("producer plugin: plugin_startup() end"); - - if(fc::get_logger_map().find(logger_name) != fc::get_logger_map().end()) { - _log = fc::get_logger_map()[logger_name]; - } - } FC_CAPTURE_AND_RETHROW() } void producer_plugin::plugin_shutdown() { @@ -678,7 +679,7 @@ void producer_plugin_impl::schedule_production_loop() { _timer.expires_from_now( boost::posix_time::microseconds( config::block_interval_us / 10 )); // we failed to start a block, so try again later? - _timer.async_wait([&,cid=_coorelation_id++](const boost::system::error_code& ec) { + _timer.async_wait([&,cid=++_coorelation_id](const boost::system::error_code& ec) { if (ec != boost::asio::error::operation_aborted && cid == _coorelation_id) { schedule_production_loop(); } @@ -697,7 +698,7 @@ void producer_plugin_impl::schedule_production_loop() { fc_dlog(_log, "Scheduling Block Production on Exhausted Block #${num} immediately", ("num", chain.pending_block_state()->block_num)); } - _timer.async_wait([&,cid=_coorelation_id++](const boost::system::error_code& ec) { + _timer.async_wait([&,cid=++_coorelation_id](const boost::system::error_code& ec) { if (ec != boost::asio::error::operation_aborted && cid == _coorelation_id) { auto res = maybe_produce_block(); fc_dlog(_log, "Producing Block #${num} returned: ${res}", ("num", chain.pending_block_state()->block_num)("res", res) ); @@ -723,7 +724,7 @@ void producer_plugin_impl::schedule_production_loop() { fc_dlog(_log, "Specualtive Block Created; Scheduling Speculative/Production Change at ${time}", ("time", wake_up_time)); static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); _timer.expires_at(epoch + boost::posix_time::microseconds(wake_up_time->time_since_epoch().count())); - _timer.async_wait([&,cid=_coorelation_id++](const boost::system::error_code& ec) { + _timer.async_wait([&,cid=++_coorelation_id](const boost::system::error_code& ec) { if (ec != boost::asio::error::operation_aborted && cid == _coorelation_id) { schedule_production_loop(); } From 2c98697a98f46ddf8d4c71a2dd8f5498f02be9e5 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 15:07:35 -0400 Subject: [PATCH 45/55] Add get_amount() --- libraries/chain/include/eosio/chain/asset.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/chain/include/eosio/chain/asset.hpp b/libraries/chain/include/eosio/chain/asset.hpp index 30f4faa14f6..d4bce45df7e 100644 --- a/libraries/chain/include/eosio/chain/asset.hpp +++ b/libraries/chain/include/eosio/chain/asset.hpp @@ -36,6 +36,7 @@ struct asset string symbol_name()const; int64_t precision()const; const symbol& get_symbol() const { return sym; } + share_type get_amount()const { return amount; } static asset from_string(const string& from); string to_string()const; From 32a1efd0976ee5043098f516a7c77ba87a675072 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 15:08:45 -0400 Subject: [PATCH 46/55] Use new get_amount() of asset --- programs/cleos/main.cpp | 6 +-- unittests/bootseq_tests.cpp | 2 +- unittests/currency_tests.cpp | 14 +++--- unittests/eosio.system_tests.cpp | 78 ++++++++++++++++---------------- unittests/eosio.token_tests.cpp | 6 ++- unittests/misc_tests.cpp | 24 +++++----- 6 files changed, 66 insertions(+), 64 deletions(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index fda8327ad26..23f5e4388c4 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -576,7 +576,7 @@ authority parse_json_authority_or_key(const std::string& authorityJsonOrFile) { asset to_asset( const string& code, const string& s ) { static map cache; auto a = asset::from_string( s ); - eosio::chain::symbol_code sym = a.sym.to_symbol_code(); + eosio::chain::symbol_code sym = a.get_symbol().to_symbol_code(); auto it = cache.find( sym ); auto sym_str = a.symbol_name(); if ( it == cache.end() ) { @@ -588,7 +588,7 @@ asset to_asset( const string& code, const string& s ) { auto obj_it = obj.find( sym_str ); if (obj_it != obj.end()) { auto result = obj_it->value().as(); - auto p = cache.insert(make_pair( sym, result.max_supply.sym )); + auto p = cache.insert(make_pair( sym, result.max_supply.get_symbol() )); it = p.first; } else { FC_THROW("Symbol ${s} is not supported by token contract ${c}", ("s", sym_str)("c", code)); @@ -598,7 +598,7 @@ asset to_asset( const string& code, const string& s ) { if ( a.decimals() < expected_symbol.decimals() ) { auto factor = expected_symbol.precision() / a.precision(); auto a_old = a; - a = asset( a.amount * factor, expected_symbol ); + a = asset( a.get_amount() * factor, expected_symbol ); } else if ( a.decimals() > expected_symbol.decimals() ) { FC_THROW("Too many decimal digits in ${a}, only ${d} supported", ("a", a)("d", expected_symbol.decimals())); } // else precision matches diff --git a/unittests/bootseq_tests.cpp b/unittests/bootseq_tests.cpp index 786c641468b..7c140d21fc4 100644 --- a/unittests/bootseq_tests.cpp +++ b/unittests/bootseq_tests.cpp @@ -309,7 +309,7 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) { produce_min_num_of_blocks_to_spend_time_wo_inactive_prod(fc::seconds(30 * 24 * 3600)); // 30 days // Since the total activated stake is larger than 150,000,000, pool should be filled reward should be bigger than zero claim_rewards(N(runnerup1)); - BOOST_TEST(get_balance(N(runnerup1)).amount > 0); + BOOST_TEST(get_balance(N(runnerup1)).get_amount() > 0); const auto first_june_2018 = fc::seconds(1527811200); // 2018-06-01 const auto first_june_2028 = fc::seconds(1843430400); // 2028-06-01 diff --git a/unittests/currency_tests.cpp b/unittests/currency_tests.cpp index 6e46d8af238..eb5ba961376 100644 --- a/unittests/currency_tests.cpp +++ b/unittests/currency_tests.cpp @@ -329,7 +329,7 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try { // Missing decimal point, should create asset with 0 decimals { asset a = asset::from_string("10 CUR"); - BOOST_REQUIRE_EQUAL(a.amount, 10); + BOOST_REQUIRE_EQUAL(a.get_amount(), 10); BOOST_REQUIRE_EQUAL(a.precision(), 1); BOOST_REQUIRE_EQUAL(a.decimals(), 0); BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR"); @@ -356,7 +356,7 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try { // Multiple spaces { asset a = asset::from_string("1000000000.00000 CUR"); - BOOST_REQUIRE_EQUAL(a.amount, 100000000000000); + BOOST_REQUIRE_EQUAL(a.get_amount(), 100000000000000); BOOST_REQUIRE_EQUAL(a.decimals(), 5); BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR"); BOOST_REQUIRE_EQUAL(a.to_string(), "1000000000.00000 CUR"); @@ -365,7 +365,7 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try { // Valid asset { asset a = asset::from_string("1000000000.00000 CUR"); - BOOST_REQUIRE_EQUAL(a.amount, 100000000000000); + BOOST_REQUIRE_EQUAL(a.get_amount(), 100000000000000); BOOST_REQUIRE_EQUAL(a.decimals(), 5); BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR"); BOOST_REQUIRE_EQUAL(a.to_string(), "1000000000.00000 CUR"); @@ -374,7 +374,7 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try { // Negative asset { asset a = asset::from_string("-001000000.00010 CUR"); - BOOST_REQUIRE_EQUAL(a.amount, -100000000010); + BOOST_REQUIRE_EQUAL(a.get_amount(), -100000000010); BOOST_REQUIRE_EQUAL(a.decimals(), 5); BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR"); BOOST_REQUIRE_EQUAL(a.to_string(), "-1000000.00010 CUR"); @@ -383,7 +383,7 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try { // Negative asset below 1 { asset a = asset::from_string("-000000000.00100 CUR"); - BOOST_REQUIRE_EQUAL(a.amount, -100); + BOOST_REQUIRE_EQUAL(a.get_amount(), -100); BOOST_REQUIRE_EQUAL(a.decimals(), 5); BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR"); BOOST_REQUIRE_EQUAL(a.to_string(), "-0.00100 CUR"); @@ -392,7 +392,7 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try { // Negative asset below 1 { asset a = asset::from_string("-0.0001 PPP"); - BOOST_REQUIRE_EQUAL(a.amount, -1); + BOOST_REQUIRE_EQUAL(a.get_amount(), -1); BOOST_REQUIRE_EQUAL(a.decimals(), 4); BOOST_REQUIRE_EQUAL(a.symbol_name(), "PPP"); BOOST_REQUIRE_EQUAL(a.to_string(), "-0.0001 PPP"); @@ -575,7 +575,7 @@ BOOST_FIXTURE_TEST_CASE( test_input_quantity, currency_tester ) try { BOOST_CHECK_EQUAL(true, chain_has_transaction(trace->id)); BOOST_CHECK_EQUAL(asset::from_string( "100.0000 CUR"), get_balance(N(alice))); - BOOST_CHECK_EQUAL(1000000, get_balance(N(alice)).amount); + BOOST_CHECK_EQUAL(1000000, get_balance(N(alice)).get_amount()); } diff --git a/unittests/eosio.system_tests.cpp b/unittests/eosio.system_tests.cpp index 80b5d98c3e1..4edcd347852 100644 --- a/unittests/eosio.system_tests.cpp +++ b/unittests/eosio.system_tests.cpp @@ -353,7 +353,7 @@ class eosio_system_tester : public TESTER { double stake2votes( asset stake ) { auto now = control->pending_block_time().time_since_epoch().count() / 1000000; - return stake.amount * pow(2, int64_t((now - (config::block_timestamp_epoch / 1000)) / (86400 * 7))/ double(52) ); // 52 week periods (i.e. ~years) + return stake.get_amount() * pow(2, int64_t((now - (config::block_timestamp_epoch / 1000)) / (86400 * 7))/ double(52) ); // 52 week periods (i.e. ~years) } double stake2votes( const string& s ) { @@ -398,7 +398,7 @@ fc::mutable_variant_object voter( account_name acct ) { } fc::mutable_variant_object voter( account_name acct, const asset& vote_stake ) { - return voter( acct )( "staked", vote_stake.amount ); + return voter( acct )( "staked", vote_stake.get_amount() ); } fc::mutable_variant_object voter( account_name acct, int64_t vote_stake ) { @@ -410,7 +410,7 @@ fc::mutable_variant_object proxy( account_name acct ) { } inline uint64_t M( const string& eos_str ) { - return core_from_string( eos_str ).amount; + return core_from_string( eos_str ).get_amount(); } BOOST_AUTO_TEST_SUITE(eosio_system_tests) @@ -542,8 +542,8 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); total = get_total_stake( "alice1111111" ); - BOOST_REQUIRE_EQUAL( core_from_string("210.0000").amount, total["net_weight"].as().amount ); - BOOST_REQUIRE_EQUAL( core_from_string("110.0000").amount, total["cpu_weight"].as().amount ); + BOOST_REQUIRE_EQUAL( core_from_string("210.0000").get_amount(), total["net_weight"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( core_from_string("110.0000").get_amount(), total["cpu_weight"].as().get_amount() ); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000")), get_voter_info( "alice1111111" ) ); @@ -1480,22 +1480,22 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester, * boost::unit_test::t BOOST_REQUIRE_EQUAL(0, initial_perblock_bucket); BOOST_REQUIRE_EQUAL(0, initial_pervote_bucket); - BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.amount * double(secs_between_fills) * continuous_rate ) / secs_per_year ), - supply.amount - initial_supply.amount); - BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.amount * double(secs_between_fills) * (4. * continuous_rate/ 5.) / secs_per_year ) ), + BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.get_amount() * double(secs_between_fills) * continuous_rate ) / secs_per_year ), + supply.get_amount() - initial_supply.get_amount()); + BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.get_amount() * double(secs_between_fills) * (4. * continuous_rate/ 5.) / secs_per_year ) ), savings - initial_savings); - BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.amount * double(secs_between_fills) * (0.25 * continuous_rate/ 5.) / secs_per_year ) ), - balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.get_amount() * double(secs_between_fills) * (0.25 * continuous_rate/ 5.) / secs_per_year ) ), + balance.get_amount() - initial_balance.get_amount()); - int64_t from_perblock_bucket = int64_t( initial_supply.amount * double(secs_between_fills) * (0.25 * continuous_rate/ 5.) / secs_per_year ) ; - int64_t from_pervote_bucket = int64_t( initial_supply.amount * double(secs_between_fills) * (0.75 * continuous_rate/ 5.) / secs_per_year ) ; + int64_t from_perblock_bucket = int64_t( initial_supply.get_amount() * double(secs_between_fills) * (0.25 * continuous_rate/ 5.) / secs_per_year ) ; + int64_t from_pervote_bucket = int64_t( initial_supply.get_amount() * double(secs_between_fills) * (0.75 * continuous_rate/ 5.) / secs_per_year ) ; if (from_pervote_bucket >= 100 * 10000) { - BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(0, pervote_bucket); } else { - BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(from_pervote_bucket, pervote_bucket); } } @@ -1557,20 +1557,20 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester, * boost::unit_test::t BOOST_REQUIRE_EQUAL(claim_time, prod["last_claim_time"].as()); auto usecs_between_fills = claim_time - initial_claim_time; - BOOST_REQUIRE_EQUAL(int64_t( ( double(initial_supply.amount) * double(usecs_between_fills) * continuous_rate / usecs_per_year ) ), - supply.amount - initial_supply.amount); - BOOST_REQUIRE_EQUAL( (supply.amount - initial_supply.amount) - (supply.amount - initial_supply.amount) / 5, + BOOST_REQUIRE_EQUAL(int64_t( ( double(initial_supply.get_amount()) * double(usecs_between_fills) * continuous_rate / usecs_per_year ) ), + supply.get_amount() - initial_supply.get_amount()); + BOOST_REQUIRE_EQUAL( (supply.get_amount() - initial_supply.get_amount()) - (supply.get_amount() - initial_supply.get_amount()) / 5, savings - initial_savings); - int64_t to_producer = int64_t( (double(initial_supply.amount) * double(usecs_between_fills) * continuous_rate) / usecs_per_year ) / 5; + int64_t to_producer = int64_t( (double(initial_supply.get_amount()) * double(usecs_between_fills) * continuous_rate) / usecs_per_year ) / 5; int64_t to_perblock_bucket = to_producer / 4; int64_t to_pervote_bucket = to_producer - to_perblock_bucket; if (to_pervote_bucket + initial_pervote_bucket >= 100 * 10000) { - BOOST_REQUIRE_EQUAL(to_perblock_bucket + to_pervote_bucket + initial_pervote_bucket, balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(to_perblock_bucket + to_pervote_bucket + initial_pervote_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(0, pervote_bucket); } else { - BOOST_REQUIRE_EQUAL(to_perblock_bucket, balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(to_perblock_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(to_pervote_bucket + initial_pervote_bucket, pervote_bucket); } } @@ -1599,8 +1599,8 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester, * boost::unit_test::t const int64_t savings = get_global_state()["savings"].as(); // Amount issued per year is very close to the 5% inflation target. Small difference (500 tokens out of 50'000'000 issued) // is due to compounding every 8 hours in this test as opposed to theoretical continuous compounding - BOOST_REQUIRE(500 * 10000 > int64_t(double(initial_supply.amount) * double(0.05)) - (supply.amount - initial_supply.amount)); - BOOST_REQUIRE(500 * 10000 > int64_t(double(initial_supply.amount) * double(0.04)) - (savings - initial_savings)); + BOOST_REQUIRE(500 * 10000 > int64_t(double(initial_supply.get_amount()) * double(0.05)) - (supply.get_amount() - initial_supply.get_amount())); + BOOST_REQUIRE(500 * 10000 > int64_t(double(initial_supply.get_amount()) * double(0.04)) - (savings - initial_savings)); } } FC_LOG_AND_RETHROW() @@ -1757,12 +1757,12 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni const int32_t secs_between_fills = static_cast(usecs_between_fills / 1000000); - const double expected_supply_growth = initial_supply.amount * double(usecs_between_fills) * cont_rate / usecs_per_year; - BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.amount - initial_supply.amount ); + const double expected_supply_growth = initial_supply.get_amount() * double(usecs_between_fills) * cont_rate / usecs_per_year; + BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.get_amount() - initial_supply.get_amount() ); BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); - const int64_t expected_perblock_bucket = int64_t( initial_supply.amount * secs_between_fills * (0.25 * cont_rate/ 5.) / secs_per_year ) ; - const int64_t expected_pervote_bucket = int64_t( initial_supply.amount * secs_between_fills * (0.75 * cont_rate/ 5.) / secs_per_year ) ; + const int64_t expected_perblock_bucket = int64_t( initial_supply.get_amount() * secs_between_fills * (0.25 * cont_rate/ 5.) / secs_per_year ) ; + const int64_t expected_pervote_bucket = int64_t( initial_supply.get_amount() * secs_between_fills * (0.75 * cont_rate/ 5.) / secs_per_year ) ; const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks ; const int64_t from_pervote_bucket = int64_t( vote_shares[prod_index] * expected_pervote_bucket); @@ -1770,10 +1770,10 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni BOOST_REQUIRE( 1 >= abs(int32_t(initial_tot_unpaid_blocks - tot_unpaid_blocks) - int32_t(initial_unpaid_blocks - unpaid_blocks)) ); if (from_pervote_bucket >= 100 * 10000) { - BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(expected_pervote_bucket - from_pervote_bucket, pervote_bucket); } else { - BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(expected_pervote_bucket, pervote_bucket); } @@ -1788,7 +1788,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni const auto prod_name = producer_names[prod_index]; BOOST_REQUIRE_EQUAL(success(), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); - BOOST_REQUIRE_EQUAL(0, get_balance(prod_name).amount); + BOOST_REQUIRE_EQUAL(0, get_balance(prod_name).get_amount()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } @@ -1826,23 +1826,23 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni const uint64_t usecs_between_fills = claim_time - initial_claim_time; - const double expected_supply_growth = initial_supply.amount * double(usecs_between_fills) * cont_rate / usecs_per_year; - BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.amount - initial_supply.amount ); + const double expected_supply_growth = initial_supply.get_amount() * double(usecs_between_fills) * cont_rate / usecs_per_year; + BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.get_amount() - initial_supply.get_amount() ); BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); - const int64_t expected_perblock_bucket = int64_t( initial_supply.amount * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year ) + const int64_t expected_perblock_bucket = int64_t( initial_supply.get_amount() * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year ) + initial_perblock_bucket; - const int64_t expected_pervote_bucket = int64_t( initial_supply.amount * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year ) + const int64_t expected_pervote_bucket = int64_t( initial_supply.get_amount() * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year ) + initial_pervote_bucket; const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks ; const int64_t from_pervote_bucket = int64_t( vote_shares[prod_index] * expected_pervote_bucket); BOOST_REQUIRE( 1 >= abs(int32_t(initial_tot_unpaid_blocks - tot_unpaid_blocks) - int32_t(initial_unpaid_blocks - unpaid_blocks)) ); if (from_pervote_bucket >= 100 * 10000) { - BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(expected_pervote_bucket - from_pervote_bucket, pervote_bucket); } else { - BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.amount - initial_balance.amount); + BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(expected_pervote_bucket, pervote_bucket); } @@ -1857,7 +1857,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni const auto prod_name = producer_names[prod_index]; BOOST_REQUIRE_EQUAL(success(), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); - BOOST_REQUIRE(100 * 10000 <= get_balance(prod_name).amount); + BOOST_REQUIRE(100 * 10000 <= get_balance(prod_name).get_amount()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } @@ -2142,10 +2142,10 @@ BOOST_FIXTURE_TEST_CASE(producer_onblock_check, eosio_system_tester) try { BOOST_CHECK_EQUAL(0, get_global_state()["total_unpaid_blocks"].as()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("not enough has been staked for producers to claim rewards"), push_action(producer_names.front(), N(claimrewards), mvo()("owner", producer_names.front()))); - BOOST_REQUIRE_EQUAL(0, get_balance(producer_names.front()).amount); + BOOST_REQUIRE_EQUAL(0, get_balance(producer_names.front()).get_amount()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("not enough has been staked for producers to claim rewards"), push_action(producer_names.back(), N(claimrewards), mvo()("owner", producer_names.back()))); - BOOST_REQUIRE_EQUAL(0, get_balance(producer_names.back()).amount); + BOOST_REQUIRE_EQUAL(0, get_balance(producer_names.back()).get_amount()); } // stake across 15% boundary @@ -2187,7 +2187,7 @@ BOOST_FIXTURE_TEST_CASE(producer_onblock_check, eosio_system_tester) try { BOOST_REQUIRE_EQUAL(true, rest_didnt_produce); BOOST_REQUIRE_EQUAL(success(), push_action(producer_names.front(), N(claimrewards), mvo()("owner", producer_names.front()))); - BOOST_REQUIRE(0 < get_balance(producer_names.front()).amount); + BOOST_REQUIRE(0 < get_balance(producer_names.front()).get_amount()); } } FC_LOG_AND_RETHROW() diff --git a/unittests/eosio.token_tests.cpp b/unittests/eosio.token_tests.cpp index ea084bd0d07..692d7d1d634 100644 --- a/unittests/eosio.token_tests.cpp +++ b/unittests/eosio.token_tests.cpp @@ -149,7 +149,8 @@ BOOST_FIXTURE_TEST_CASE( create_max_supply, eosio_token_tester ) try { produce_blocks(1); asset max(10, symbol(SY(0, NKT))); - max.amount = 4611686018427387904; + share_type amount = 4611686018427387904; + memcpy(&max, &amount, sizeof(share_type)); // hack in an invalid amount BOOST_CHECK_EXCEPTION( create( N(alice), max) , asset_type_exception, [](const asset_type_exception& e) { return expect_assert_message(e, "magnitude of asset amount must be less than 2^62"); @@ -171,7 +172,8 @@ BOOST_FIXTURE_TEST_CASE( create_max_decimals, eosio_token_tester ) try { asset max(10, symbol(SY(0, NKT))); //1.0000000000000000000 => 0x8ac7230489e80000L - max.amount = 0x8ac7230489e80000L; + share_type amount = 0x8ac7230489e80000L; + memcpy(&max, &amount, sizeof(share_type)); // hack in an invalid amount BOOST_CHECK_EXCEPTION( create( N(alice), max) , asset_type_exception, [](const asset_type_exception& e) { return expect_assert_message(e, "magnitude of asset amount must be less than 2^62"); diff --git a/unittests/misc_tests.cpp b/unittests/misc_tests.cpp index 2635aeb32e0..4453adc9c60 100644 --- a/unittests/misc_tests.cpp +++ b/unittests/misc_tests.cpp @@ -59,23 +59,23 @@ BOOST_AUTO_TEST_CASE(asset_from_string_overflow) // precision = 19, magnitude < 2^61 BOOST_CHECK_EXCEPTION( asset::from_string("0.1000000000000000000 CUR") , assert_exception, [](const assert_exception& e) { - return expect_assert_message(e, "precision should be <= 18"); + return expect_assert_message(e, "precision 19 should be <= 18"); }); BOOST_CHECK_EXCEPTION( asset::from_string("-0.1000000000000000000 CUR") , assert_exception, [](const assert_exception& e) { - return expect_assert_message(e, "precision should be <= 18"); + return expect_assert_message(e, "precision 19 should be <= 18"); }); BOOST_CHECK_EXCEPTION( asset::from_string("1.0000000000000000000 CUR") , assert_exception, [](const assert_exception& e) { - return expect_assert_message(e, "precision should be <= 18"); + return expect_assert_message(e, "precision 19 should be <= 18"); }); BOOST_CHECK_EXCEPTION( asset::from_string("-1.0000000000000000000 CUR") , assert_exception, [](const assert_exception& e) { - return expect_assert_message(e, "precision should be <= 18"); + return expect_assert_message(e, "precision 19 should be <= 18"); }); // precision = 18, magnitude < 2^58 a = asset::from_string("0.100000000000000000 CUR"); - BOOST_CHECK_EQUAL(a.amount, 100000000000000000L); + BOOST_CHECK_EQUAL(a.get_amount(), 100000000000000000L); a = asset::from_string("-0.100000000000000000 CUR"); - BOOST_CHECK_EQUAL(a.amount, -100000000000000000L); + BOOST_CHECK_EQUAL(a.get_amount(), -100000000000000000L); // precision = 18, magnitude = 2^62 BOOST_CHECK_EXCEPTION( asset::from_string("4.611686018427387904 CUR") , asset_type_exception, [](const asset_type_exception& e) { @@ -93,9 +93,9 @@ BOOST_AUTO_TEST_CASE(asset_from_string_overflow) // precision = 18, magnitude = 2^62-1 a = asset::from_string("4.611686018427387903 CUR"); - BOOST_CHECK_EQUAL(a.amount, 4611686018427387903L); + BOOST_CHECK_EQUAL(a.get_amount(), 4611686018427387903L); a = asset::from_string("-4.611686018427387903 CUR"); - BOOST_CHECK_EQUAL(a.amount, -4611686018427387903L); + BOOST_CHECK_EQUAL(a.get_amount(), -4611686018427387903L); // precision = 0, magnitude = 2^62 BOOST_CHECK_EXCEPTION( asset::from_string("4611686018427387904 CUR") , asset_type_exception, [](const asset_type_exception& e) { @@ -107,9 +107,9 @@ BOOST_AUTO_TEST_CASE(asset_from_string_overflow) // precision = 0, magnitude = 2^62-1 a = asset::from_string("4611686018427387903 CUR"); - BOOST_CHECK_EQUAL(a.amount, 4611686018427387903L); + BOOST_CHECK_EQUAL(a.get_amount(), 4611686018427387903L); a = asset::from_string("-4611686018427387903 CUR"); - BOOST_CHECK_EQUAL(a.amount, -4611686018427387903L); + BOOST_CHECK_EQUAL(a.get_amount(), -4611686018427387903L); // precision = 18, magnitude = 2^65 BOOST_CHECK_EXCEPTION( asset::from_string("36.893488147419103232 CUR") , overflow_exception, [](const overflow_exception& e) { @@ -137,10 +137,10 @@ BOOST_AUTO_TEST_CASE(asset_from_string_overflow) // precision = 20, magnitude > 2^142 BOOST_CHECK_EXCEPTION( asset::from_string("100000000000000000000000.00000000000000000000 CUR") , assert_exception, [](const assert_exception& e) { - return expect_assert_message(e, "precision should be <= 18"); + return expect_assert_message(e, "precision 20 should be <= 18"); }); BOOST_CHECK_EXCEPTION( asset::from_string("-100000000000000000000000.00000000000000000000 CUR") , assert_exception, [](const assert_exception& e) { - return expect_assert_message(e, "precision should be <= 18"); + return expect_assert_message(e, "precision 20 should be <= 18"); }); } From c4efb45c6e4b6fb1330dc4b8bfe0e38fc37c822c Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Tue, 22 May 2018 16:00:35 -0400 Subject: [PATCH 47/55] add in a configuration/cli option for max-irreversible-block-age that will limit how old the LIB can be before the producer node voluntarily disables production. EOSIO/eos#3279 --- plugins/producer_plugin/producer_plugin.cpp | 26 +++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index a1ff941d8ed..ca0d5023a76 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -107,6 +107,8 @@ class producer_plugin_impl { pending_block_mode _pending_block_mode; int32_t _max_transaction_time_ms; + fc::microseconds _max_irreversible_block_age_us; + fc::microseconds _irreversible_block_age_us; time_point _last_signed_block_time; time_point _start_time = fc::time_point::now(); @@ -160,6 +162,11 @@ class producer_plugin_impl { } ) ); } + void on_irreversible_block( const signed_block_ptr& lib ) { + chain::controller& chain = app().get_plugin().chain(); + _irreversible_block_age_us = chain.head_block_time() - lib->timestamp.to_time_point(); + } + template auto publish_results_of(const Type &data, Channel& channel, F f) { auto publish_success = fc::make_scoped_exit([&, this](){ @@ -328,6 +335,8 @@ void producer_plugin::set_program_options( ("enable-stale-production,e", boost::program_options::bool_switch()->notifier([this](bool e){my->_production_enabled = e;}), "Enable block production, even if the chain is stale.") ("max-transaction-time", bpo::value()->default_value(30), "Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute before being considered invalid") + ("max-irreversible-block-age", bpo::value()->default_value( 30 * 60 ), + "Limits the maximum age (in seconds) of the DPOS Irreversible Block for a chain this node will produce blocks on") ("required-participation", boost::program_options::value() ->default_value(uint32_t(config::required_producer_participation/config::percent_1)) ->notifier([this](uint32_t e) { @@ -392,6 +401,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->_max_transaction_time_ms = options.at("max-transaction-time").as(); + my->_max_irreversible_block_age_us = fc::seconds(options.at("max-irreversible-block-age").as()); my->_incoming_block_subscription = app().get_channel().subscribe([this](const signed_block_ptr& block){ try { @@ -425,6 +435,15 @@ void producer_plugin::plugin_startup() chain::controller& chain = app().get_plugin().chain(); chain.accepted_block.connect( [this]( const auto& bsp ){ my->on_block( bsp ); } ); + chain.irreversible_block.connect( [this]( const auto& bsp ){ my->on_irreversible_block( bsp->block ); } ); + + const auto lib_num = chain.last_irreversible_block_num(); + const auto lib = chain.fetch_block_by_number(lib_num); + if (lib) { + my->on_irreversible_block(lib); + } else { + my->_irreversible_block_age_us = fc::seconds(0); + } if (!my->_producers.empty()) { ilog("Launching block production for ${n} producers at ${time}.", ("n", my->_producers.size())("time",fc::time_point::now())); @@ -534,7 +553,10 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } else if( _producers.find(scheduled_producer.producer_name) == _producers.end()) { _pending_block_mode = pending_block_mode::speculating; } else if (private_key_itr == _private_keys.end()) { - ilog("Not producing block because I don't have the private key for ${scheduled_key}", ("scheduled_key", scheduled_producer.block_signing_key)); + elog("Not producing block because I don't have the private key for ${scheduled_key}", ("scheduled_key", scheduled_producer.block_signing_key)); + _pending_block_mode = pending_block_mode::speculating; + } else if ( _irreversible_block_age_us >= _max_irreversible_block_age_us ) { + elog("Not producing block because the irreversible block is too old [age:${age}s, max:${max}s]", ("age", _irreversible_block_age_us.count() / 1'000'000)( "max", _max_irreversible_block_age_us.count() / 1'000'000 )); _pending_block_mode = pending_block_mode::speculating; } @@ -706,7 +728,7 @@ void producer_plugin_impl::schedule_production_loop() { fc_dlog(_log, "Producing Block #${num} returned: ${res}", ("num", chain.pending_block_state()->block_num)("res", res) ); } }); - } else if (_pending_block_mode == pending_block_mode::speculating && !_producers.empty()){ + } else if (_pending_block_mode == pending_block_mode::speculating && !_producers.empty() && _irreversible_block_age_us < _max_irreversible_block_age_us){ // if we have any producers then we should at least set a timer for our next available slot optional wake_up_time; for (const auto&p: _producers) { From 40c5a79c10586b41d3d48f854eaffee71ae078f7 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 16:03:04 -0400 Subject: [PATCH 48/55] Add static_assert protection around test hack --- unittests/eosio.token_tests.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unittests/eosio.token_tests.cpp b/unittests/eosio.token_tests.cpp index 692d7d1d634..b181ff85b4f 100644 --- a/unittests/eosio.token_tests.cpp +++ b/unittests/eosio.token_tests.cpp @@ -150,6 +150,8 @@ BOOST_FIXTURE_TEST_CASE( create_max_supply, eosio_token_tester ) try { asset max(10, symbol(SY(0, NKT))); share_type amount = 4611686018427387904; + static_assert(sizeof(share_type) <= sizeof(asset), "asset changed so test is no longer valid"); + static_assert(std::is_trivially_copyable::value, "asset is not trivially copyable"); memcpy(&max, &amount, sizeof(share_type)); // hack in an invalid amount BOOST_CHECK_EXCEPTION( create( N(alice), max) , asset_type_exception, [](const asset_type_exception& e) { @@ -173,6 +175,8 @@ BOOST_FIXTURE_TEST_CASE( create_max_decimals, eosio_token_tester ) try { asset max(10, symbol(SY(0, NKT))); //1.0000000000000000000 => 0x8ac7230489e80000L share_type amount = 0x8ac7230489e80000L; + static_assert(sizeof(share_type) <= sizeof(asset), "asset changed so test is no longer valid"); + static_assert(std::is_trivially_copyable::value, "asset is not trivially copyable"); memcpy(&max, &amount, sizeof(share_type)); // hack in an invalid amount BOOST_CHECK_EXCEPTION( create( N(alice), max) , asset_type_exception, [](const asset_type_exception& e) { From 4dbd8374a23774762f19ff43cefe023e806b2b2c Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Tue, 22 May 2018 15:43:07 -0500 Subject: [PATCH 49/55] Remove bad peer addresses from the connection list immediately. --- plugins/net_plugin/net_plugin.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 9146f59657f..b0dc2f0538b 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1940,6 +1940,14 @@ namespace eosio { if (colon == std::string::npos || colon == 0) { elog ("Invalid peer address. must be \"host:port\": ${p}", ("p",c->peer_addr)); + for ( auto itr : connections ) { + if((*itr).peer_addr == c->peer_addr) { + (*itr).reset(); + close(itr); + connections.erase(itr); + break; + } + } return; } From 27f6873a75154c22fe4ab518c6dd01905f29ffa3 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 16:57:58 -0400 Subject: [PATCH 50/55] Fix merge --- unittests/eosio_system_tester.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unittests/eosio_system_tester.hpp b/unittests/eosio_system_tester.hpp index 673af4a6f11..a145a54b285 100644 --- a/unittests/eosio_system_tester.hpp +++ b/unittests/eosio_system_tester.hpp @@ -368,7 +368,7 @@ class eosio_system_tester : public TESTER { double stake2votes( asset stake ) { auto now = control->pending_block_time().time_since_epoch().count() / 1000000; - return stake.amount * pow(2, int64_t((now - (config::block_timestamp_epoch / 1000)) / (86400 * 7))/ double(52) ); // 52 week periods (i.e. ~years) + return stake.get_amount() * pow(2, int64_t((now - (config::block_timestamp_epoch / 1000)) / (86400 * 7))/ double(52) ); // 52 week periods (i.e. ~years) } double stake2votes( const string& s ) { @@ -418,7 +418,7 @@ inline fc::mutable_variant_object voter( account_name acct ) { } inline fc::mutable_variant_object voter( account_name acct, const asset& vote_stake ) { - return voter( acct )( "staked", vote_stake.amount ); + return voter( acct )( "staked", vote_stake.get_amount() ); } inline fc::mutable_variant_object voter( account_name acct, int64_t vote_stake ) { @@ -430,7 +430,7 @@ inline fc::mutable_variant_object proxy( account_name acct ) { } inline uint64_t M( const string& eos_str ) { - return core_from_string( eos_str ).amount; + return core_from_string( eos_str ).get_amount(); } } From 3cf3f26c3ba156c6730598e27ac4362a26fd44b1 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Tue, 22 May 2018 17:15:18 -0400 Subject: [PATCH 51/55] Add the concept of persisted transactions to the producer plugin. persisted transactions are the transactions _directly submitted to that node_. They should only exist on RPC nodes that are accepting transactions from users. As such the expectation (from our smoke tests at least) is that said node will persist the state of the chain + that transaction until either the block-chain represents the side effects of the transaction OR the transaction expires. From the pov of the producer plugin, this means that even when speculating on a block the block should include these transactions. --- .../include/eosio/chain/plugin_interface.hpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 4 +- plugins/producer_plugin/producer_plugin.cpp | 75 +++++++++++++++---- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 858b92f6d48..970c6783391 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -45,7 +45,7 @@ namespace eosio { namespace chain { namespace plugin_interface { namespace methods { // synchronously push a block/trx to a single provider using block_sync = method_decl; - using transaction_sync = method_decl; + using transaction_sync = method_decl; } } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index d8a4666a370..8985b001723 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -284,7 +284,7 @@ void chain_plugin::accept_block(const signed_block_ptr& block ) { } chain::transaction_trace_ptr chain_plugin::accept_transaction(const packed_transaction& trx) { - return my->incoming_transaction_sync_method(std::make_shared(trx)); + return my->incoming_transaction_sync_method(std::make_shared(trx) , false); } bool chain_plugin::block_is_on_preferred_chain(const block_id_type& block_id) { @@ -544,7 +544,7 @@ read_write::push_transaction_results read_write::push_transaction(const read_wri abi_serializer::from_variant(params, *pretty_input, resolver); } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") - auto trx_trace_ptr = app().get_method()(pretty_input); + auto trx_trace_ptr = app().get_method()(pretty_input, true); pretty_output = db.to_variant_with_abi( *trx_trace_ptr );; //abi_serializer::to_variant(*trx_trace_ptr, pretty_output, resolver); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index a1ff941d8ed..30d851e1fd3 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -61,7 +61,7 @@ namespace { } } -struct blacklisted_transaction { +struct transaction_id_with_expiry { transaction_id_type trx_id; fc::time_point expiry; }; @@ -69,14 +69,16 @@ struct blacklisted_transaction { struct by_id; struct by_expiry; -using blacklisted_transaction_index = multi_index_container< - blacklisted_transaction, +using transaction_id_with_expiry_index = multi_index_container< + transaction_id_with_expiry, indexed_by< - hashed_unique, BOOST_MULTI_INDEX_MEMBER(blacklisted_transaction, transaction_id_type, trx_id)>, - ordered_non_unique, BOOST_MULTI_INDEX_MEMBER(blacklisted_transaction, fc::time_point, expiry)> + hashed_unique, BOOST_MULTI_INDEX_MEMBER(transaction_id_with_expiry, transaction_id_type, trx_id)>, + ordered_non_unique, BOOST_MULTI_INDEX_MEMBER(transaction_id_with_expiry, fc::time_point, expiry)> > >; + + enum class pending_block_mode { producing, speculating @@ -105,6 +107,7 @@ class producer_plugin_impl { boost::asio::deadline_timer _timer; std::map _producer_watermarks; pending_block_mode _pending_block_mode; + transaction_id_with_expiry_index _persistent_transactions; int32_t _max_transaction_time_ms; @@ -122,7 +125,7 @@ class producer_plugin_impl { incoming::methods::block_sync::method_type::handle _incoming_block_sync_provider; incoming::methods::transaction_sync::method_type::handle _incoming_transaction_sync_provider; - blacklisted_transaction_index _blacklisted_transactions; + transaction_id_with_expiry_index _blacklisted_transactions; void on_block( const block_state_ptr& bsp ) { if( bsp->header.timestamp <= _last_signed_block_time ) return; @@ -231,7 +234,7 @@ class producer_plugin_impl { } - transaction_trace_ptr on_incoming_transaction(const packed_transaction_ptr& trx) { + transaction_trace_ptr on_incoming_transaction(const packed_transaction_ptr& trx, bool persist_until_expired = false) { fc_dlog(_log, "received incoming transaction ${id}", ("id", trx->id())); return publish_results_of(trx, _transaction_ack_channel, [&]() -> transaction_trace_ptr { while (true) { @@ -270,6 +273,10 @@ class producer_plugin_impl { } else { trace->except->dynamic_rethrow_exception(); } + } else if (persist_until_expired) { + // if this trx didnt fail/soft-fail and the persist flag is set, store its ID so that we can + // ensure its applied to all future speculative blocks as well. + _persistent_transactions.insert(transaction_id_with_expiry{trx->id(), trx->expiration()}); } return trace; @@ -409,8 +416,8 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->on_incoming_block(block); }); - my->_incoming_transaction_sync_provider = app().get_method().register_provider([this](const packed_transaction_ptr& trx) -> transaction_trace_ptr { - return my->on_incoming_transaction(trx); + my->_incoming_transaction_sync_provider = app().get_method().register_provider([this](const packed_transaction_ptr& trx, bool persist_until_expired) -> transaction_trace_ptr { + return my->on_incoming_transaction(trx, persist_until_expired); }); } FC_LOG_AND_RETHROW() } @@ -581,14 +588,49 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { _pending_block_mode = pending_block_mode::speculating; } + // attempt to play persisted transactions first + bool exhausted = false; + auto unapplied_trxs = chain.get_unapplied_transactions(); + + // remove all persisted transactions that have now expired + auto& persisted_by_id = _persistent_transactions.get(); + auto& persisted_by_expiry = _persistent_transactions.get(); + while(!persisted_by_expiry.empty() && persisted_by_expiry.begin()->expiry <= pbs->header.timestamp.to_time_point()) { + persisted_by_expiry.erase(persisted_by_expiry.begin()); + } + + for (auto itr = unapplied_trxs.begin(); itr != unapplied_trxs.end(); ++itr) { + const auto& trx = *itr; + if(persisted_by_id.find(trx->id) != persisted_by_id.end()) { + // this is a persisted transaction, push it into the block (even if we are speculating) with + // no deadline as it has already passed the subjective deadlines once and we want to represent + // the state of the chain including this transaction + try { + chain.push_transaction(trx, fc::time_point::maximum()); + } FC_LOG_AND_DROP(); + + // remove it from further consideration as it is applied + *itr = nullptr; + } + } + if (_pending_block_mode == pending_block_mode::producing) { - bool exhausted = false; - auto unapplied_trxs = chain.get_unapplied_transactions(); for (const auto& trx : unapplied_trxs) { if (exhausted) { break; } + if (!trx ) { + // nulled in the loop above, skip it + continue; + } + + if (trx->packed_trx.expiration() > pbs->header.timestamp.to_time_point()) { + // expired, drop it + chain.drop_unapplied_transaction(trx); + continue; + } + try { auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); bool deadline_is_subjective = false; @@ -641,18 +683,19 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } else { auto expiration = fc::time_point::now() + fc::seconds(chain.get_global_properties().configuration.deferred_trx_expiration_window); // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist - _blacklisted_transactions.insert(blacklisted_transaction{trx, expiration}); + _blacklisted_transactions.insert(transaction_id_with_expiry{trx, expiration}); } } } FC_LOG_AND_DROP(); } - if (exhausted) { - return start_block_result::exhausted; - } } - return start_block_result::succeeded; + if (exhausted) { + return start_block_result::exhausted; + } else { + return start_block_result::succeeded; + } } return start_block_result::failed; From e7d58f7c6888cb7a341cf05c6fb6b2bccb75ea0c Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Tue, 22 May 2018 19:11:48 -0400 Subject: [PATCH 52/55] checktime from instrinsics: checktime interval increased to 10Kbytes #3255 --- libraries/chain/include/eosio/chain/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index bf545dc76ed..e5551996ff2 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -84,7 +84,7 @@ const static uint32_t overhead_per_row_per_index_ram_bytes = 32; ///< overh const static uint32_t overhead_per_account_ram_bytes = 2*1024; ///< overhead accounts for basic account storage and pre-pays features like account recovery const static uint32_t setcode_ram_bytes_multiplier = 10; ///< multiplier on contract size to account for multiple copies and cached compilation -const static uint32_t hashing_checktime_block_size = 1024; /// call checktime from hashing intrinsic once per this number of bytes +const static uint32_t hashing_checktime_block_size = 10*1024; /// call checktime from hashing intrinsic once per this number of bytes const static eosio::chain::wasm_interface::vm_type default_wasm_runtime = eosio::chain::wasm_interface::vm_type::binaryen; From de364baeeea5038520de2ea3a1c8448d82d930c3 Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Tue, 22 May 2018 19:33:37 -0400 Subject: [PATCH 53/55] system contract test cleanup: N(eosio) replaced with eosio::system_account_name #3213 --- unittests/eosio_system_tester.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/unittests/eosio_system_tester.hpp b/unittests/eosio_system_tester.hpp index a145a54b285..f5853934692 100644 --- a/unittests/eosio_system_tester.hpp +++ b/unittests/eosio_system_tester.hpp @@ -76,16 +76,16 @@ class eosio_system_tester : public TESTER { produce_blocks(); - create_account_with_resources( N(alice1111111), N(eosio), core_from_string("1.0000"), false ); - create_account_with_resources( N(bob111111111), N(eosio), core_from_string("0.4500"), false ); - create_account_with_resources( N(carol1111111), N(eosio), core_from_string("1.0000"), false ); + create_account_with_resources( N(alice1111111), config::system_account_name, core_from_string("1.0000"), false ); + create_account_with_resources( N(bob111111111), config::system_account_name, core_from_string("0.4500"), false ); + create_account_with_resources( N(carol1111111), config::system_account_name, core_from_string("1.0000"), false ); BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance( "eosio" ) ); } - void create_accounts_with_resources( vector accounts, account_name creator = N(eosio) ) { + void create_accounts_with_resources( vector accounts, account_name creator = config::system_account_name ) { for( auto a : accounts ) { create_account_with_resources( a, creator ); } @@ -106,13 +106,13 @@ class eosio_system_tester : public TESTER { .active = authority( get_public_key( a, "active" ) ) }); - trx.actions.emplace_back( get_action( N(eosio), N(buyrambytes), vector{{creator,config::active_name}}, + trx.actions.emplace_back( get_action( config::system_account_name, N(buyrambytes), vector{{creator,config::active_name}}, mvo() ("payer", creator) ("receiver", a) ("bytes", ram_bytes) ) ); - trx.actions.emplace_back( get_action( N(eosio), N(delegatebw), vector{{creator,config::active_name}}, + trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{{creator,config::active_name}}, mvo() ("from", creator) ("receiver", a) @@ -148,14 +148,14 @@ class eosio_system_tester : public TESTER { .active = authority( get_public_key( a, "active" ) ) }); - trx.actions.emplace_back( get_action( N(eosio), N(buyram), vector{{creator,config::active_name}}, + trx.actions.emplace_back( get_action( config::system_account_name, N(buyram), vector{{creator,config::active_name}}, mvo() ("payer", creator) ("receiver", a) ("quant", ramfunds) ) ); - trx.actions.emplace_back( get_action( N(eosio), N(delegatebw), vector{{creator,config::active_name}}, + trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{{creator,config::active_name}}, mvo() ("from", creator) ("receiver", a) @@ -171,7 +171,7 @@ class eosio_system_tester : public TESTER { } transaction_trace_ptr setup_producer_accounts( const std::vector& accounts ) { - account_name creator(N(eosio)); + account_name creator(config::system_account_name); signed_transaction trx; set_transaction_headers(trx); asset cpu = core_from_string("80.0000"); @@ -188,14 +188,14 @@ class eosio_system_tester : public TESTER { .active = authority( get_public_key( a, "active" ) ) }); - trx.actions.emplace_back( get_action( N(eosio), N(buyram), vector{ {creator, config::active_name} }, + trx.actions.emplace_back( get_action( config::system_account_name, N(buyram), vector{ {creator, config::active_name} }, mvo() ("payer", creator) ("receiver", a) ("quant", ram) ) ); - trx.actions.emplace_back( get_action( N(eosio), N(delegatebw), vector{ {creator, config::active_name} }, + trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{ {creator, config::active_name} }, mvo() ("from", creator) ("receiver", a) @@ -387,14 +387,14 @@ class eosio_system_tester : public TESTER { } fc::variant get_global_state() { - vector data = get_row_by_account( N(eosio), N(eosio), N(global), N(global) ); + vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global), N(global) ); if (data.empty()) std::cout << "\nData is empty\n" << std::endl; return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state", data ); } fc::variant get_refund_request( name account ) { - vector data = get_row_by_account( N(eosio), account, N(refunds), account ); + vector data = get_row_by_account( config::system_account_name, account, N(refunds), account ); return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "refund_request", data ); } From 8ee9181df4aadb8a17e28cd2bf2e48c4c1e5e32b Mon Sep 17 00:00:00 2001 From: enumivo Date: Wed, 23 May 2018 08:55:20 +0800 Subject: [PATCH 54/55] corrections --- .../account_control_history_object.hpp | 56 ------------------- .../public_key_history_object.hpp | 55 ------------------ .../account_control_history_object.hpp | 0 .../public_key_history_object.hpp | 0 4 files changed, 111 deletions(-) delete mode 100644 plugins/account_history_plugin/include/enumivo/account_history_plugin/account_control_history_object.hpp delete mode 100644 plugins/account_history_plugin/include/enumivo/account_history_plugin/public_key_history_object.hpp rename plugins/history_plugin/include/{eosio => enumivo}/history_plugin/account_control_history_object.hpp (100%) rename plugins/history_plugin/include/{eosio => enumivo}/history_plugin/public_key_history_object.hpp (100%) diff --git a/plugins/account_history_plugin/include/enumivo/account_history_plugin/account_control_history_object.hpp b/plugins/account_history_plugin/include/enumivo/account_history_plugin/account_control_history_object.hpp deleted file mode 100644 index 827c1bfcb1e..00000000000 --- a/plugins/account_history_plugin/include/enumivo/account_history_plugin/account_control_history_object.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file - * @copyright defined in enumivo/LICENSE.txt - */ -#pragma once - -#include -#include - -namespace enumivo { -using chain::account_name; -using chain::permission_name; -using chain::shared_vector; -using chain::transaction_id_type; -using namespace boost::multi_index; - -class account_control_history_object : public chainbase::object { - OBJECT_CTOR(account_control_history_object) - - id_type id; - account_name controlled_account; - permission_name controlled_permission; - account_name controlling_account; -}; - -struct by_id; -struct by_controlling; -struct by_controlled_authority; -using account_control_history_multi_index = chainbase::shared_multi_index_container< - account_control_history_object, - indexed_by< - ordered_unique, BOOST_MULTI_INDEX_MEMBER(account_control_history_object, account_control_history_object::id_type, id)>, - ordered_unique, - composite_key< account_control_history_object, - member, - member - > - >, - ordered_unique, - composite_key< account_control_history_object, - member, - member, - member - > - > - > ->; - -typedef chainbase::generic_index account_control_history_index; - -} - -CHAINBASE_SET_INDEX_TYPE( enumivo::account_control_history_object, enumivo::account_control_history_multi_index ) - -FC_REFLECT( enumivo::account_control_history_object, (controlled_account)(controlled_permission)(controlling_account) ) - diff --git a/plugins/account_history_plugin/include/enumivo/account_history_plugin/public_key_history_object.hpp b/plugins/account_history_plugin/include/enumivo/account_history_plugin/public_key_history_object.hpp deleted file mode 100644 index 8b830f21f98..00000000000 --- a/plugins/account_history_plugin/include/enumivo/account_history_plugin/public_key_history_object.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file - * @copyright defined in enumivo/LICENSE.txt - */ -#pragma once - -#include -#include - -namespace enumivo { -using chain::account_name; -using chain::public_key_type; -using chain::permission_name; -using namespace boost::multi_index; - -class public_key_history_object : public chainbase::object { - OBJECT_CTOR(public_key_history_object) - - id_type id; - public_key_type public_key; - account_name name; - permission_name permission; -}; - -struct by_id; -struct by_pub_key; -struct by_account_permission; -using public_key_history_multi_index = chainbase::shared_multi_index_container< - public_key_history_object, - indexed_by< - ordered_unique, BOOST_MULTI_INDEX_MEMBER(public_key_history_object, public_key_history_object::id_type, id)>, - ordered_unique, - composite_key< public_key_history_object, - member, - member - > - >, - ordered_unique, - composite_key< public_key_history_object, - member, - member, - member - > - > - > ->; - -typedef chainbase::generic_index public_key_history_index; - -} - -CHAINBASE_SET_INDEX_TYPE( enumivo::public_key_history_object, enumivo::public_key_history_multi_index ) - -FC_REFLECT( enumivo::public_key_history_object, (public_key)(name)(permission) ) - diff --git a/plugins/history_plugin/include/eosio/history_plugin/account_control_history_object.hpp b/plugins/history_plugin/include/enumivo/history_plugin/account_control_history_object.hpp similarity index 100% rename from plugins/history_plugin/include/eosio/history_plugin/account_control_history_object.hpp rename to plugins/history_plugin/include/enumivo/history_plugin/account_control_history_object.hpp diff --git a/plugins/history_plugin/include/eosio/history_plugin/public_key_history_object.hpp b/plugins/history_plugin/include/enumivo/history_plugin/public_key_history_object.hpp similarity index 100% rename from plugins/history_plugin/include/eosio/history_plugin/public_key_history_object.hpp rename to plugins/history_plugin/include/enumivo/history_plugin/public_key_history_object.hpp From de9cc8fa81202fbda6756d00e9548d3ef6935f57 Mon Sep 17 00:00:00 2001 From: enumivo Date: Wed, 23 May 2018 09:01:03 +0800 Subject: [PATCH 55/55] corrections --- Docker/Dockerfile | 22 ++++++++--------- Docker/builder/Dockerfile | 2 +- Docker/dev/Dockerfile | 24 +++++++++---------- Doxyfile | 2 +- debian/postinst | 10 ++++---- .../chain/include/enumivo/chain/asset.hpp | 4 ++-- libraries/chain/wasm_interface.cpp | 2 +- plugins/history_plugin/history_plugin.cpp | 6 ++--- .../account_control_history_object.hpp | 10 ++++---- .../public_key_history_object.hpp | 8 +++---- plugins/http_plugin/CMakeLists.txt | 2 +- tests/enunode_run_test.py | 14 +++++------ unittests/enumivo.system_tests.cpp | 6 ++--- unittests/enumivo_system_tester.hpp | 2 +- 14 files changed, 57 insertions(+), 57 deletions(-) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index bd39a9a06e2..c5f2878f984 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -1,24 +1,24 @@ -FROM eosio/builder as builder +FROM enumivo/builder as builder ARG branch=master RUN git clone -b $branch https://github.com/enumivo/enumivo.git --recursive \ - && cd eos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ + && cd enumivo && echo "$branch:$(git rev-parse HEAD)" > /etc/enumivo-version \ && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DSecp256k1_ROOT_DIR=/usr/local -DBUILD_MONGO_DB_PLUGIN=true \ - && cmake --build /tmp/build --target install && rm /tmp/build/bin/eosiocpp + && cmake --build /tmp/build --target install && rm /tmp/build/bin/enumivocpp FROM ubuntu:18.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/lib/* /usr/local/lib/ -COPY --from=builder /tmp/build/bin /opt/eosio/bin +COPY --from=builder /tmp/build/bin /opt/enumivo/bin COPY --from=builder /tmp/build/contracts /contracts -COPY --from=builder /eos/Docker/config.ini / -COPY --from=builder /etc/eosio-version /etc -COPY --from=builder /eos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh -ENV ENUMIVO_ROOT=/opt/eosio -RUN chmod +x /opt/eosio/bin/nodeosd.sh +COPY --from=builder /enumivo/Docker/config.ini / +COPY --from=builder /etc/enumivo-version /etc +COPY --from=builder /enumivo/Docker/enunoded.sh /opt/enumivo/bin/enunoded.sh +ENV ENUMIVO_ROOT=/opt/enumivo +RUN chmod +x /opt/enumivo/bin/enunoded.sh ENV LD_LIBRARY_PATH /usr/local/lib -VOLUME /opt/eosio/bin/data-dir -ENV PATH /opt/eosio/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +VOLUME /opt/enumivo/bin/data-dir +ENV PATH /opt/enumivo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/Docker/builder/Dockerfile b/Docker/builder/Dockerfile index 6e8ca3b8e4a..e220890000a 100644 --- a/Docker/builder/Dockerfile +++ b/Docker/builder/Dockerfile @@ -1,7 +1,7 @@ FROM ubuntu:16.04 LABEL author="xiaobo " maintainer="Xiaobo Huang-Ming Huang " version="0.1.1" \ - description="This is a base image for building eosio/eos" + description="This is a base image for building enumivo/enumivo" RUN echo 'APT::Install-Recommends 0;' >> /etc/apt/apt.conf.d/01norecommends \ && echo 'APT::Install-Suggests 0;' >> /etc/apt/apt.conf.d/01norecommends \ diff --git a/Docker/dev/Dockerfile b/Docker/dev/Dockerfile index 82f200ee1f0..6faf26eb165 100644 --- a/Docker/dev/Dockerfile +++ b/Docker/dev/Dockerfile @@ -1,17 +1,17 @@ -FROM eosio/builder +FROM enumivo/builder ARG branch=master -RUN git clone -b $branch https://github.com/EOSIO/eos.git --recursive \ - && cd eos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ - && cmake -H. -B"/opt/eosio" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ - -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/opt/eosio -DSecp256k1_ROOT_DIR=/usr/local -DBUILD_MONGO_DB_PLUGIN=true \ - && cmake --build /opt/eosio --target install \ - && mv /eos/Docker/config.ini / && mv /opt/eosio/contracts /contracts && mv /eos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh \ - && rm -rf /eos +RUN git clone -b $branch https://github.com/enumivo/enumivo.git --recursive \ + && cd enumivo && echo "$branch:$(git rev-parse HEAD)" > /etc/enumivo-version \ + && cmake -H. -B"/opt/enumivo" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/opt/enumivo -DSecp256k1_ROOT_DIR=/usr/local -DBUILD_MONGO_DB_PLUGIN=true \ + && cmake --build /opt/enumivo --target install \ + && mv /enumivo/Docker/config.ini / && mv /opt/enumivo/contracts /contracts && mv /enumivo/Docker/enunoded.sh /opt/enumivo/bin/enunoded.sh \ + && rm -rf /enumivo RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl && rm -rf /var/lib/apt/lists/* -ENV EOSIO_ROOT=/opt/eosio -RUN chmod +x /opt/eosio/bin/nodeosd.sh +ENV ENUMIVO_ROOT=/opt/enumivo +RUN chmod +x /opt/enumivo/bin/enunoded.sh ENV LD_LIBRARY_PATH /usr/local/lib -VOLUME /opt/eosio/bin/data-dir -ENV PATH /opt/eosio/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +VOLUME /opt/enumivo/bin/data-dir +ENV PATH /opt/enumivo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/Doxyfile b/Doxyfile index 557e5f823ea..3c957a127bf 100644 --- a/Doxyfile +++ b/Doxyfile @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "Eos" +PROJECT_NAME = "Enumivo" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version diff --git a/debian/postinst b/debian/postinst index 42123695c90..c587a03b053 100755 --- a/debian/postinst +++ b/debian/postinst @@ -1,5 +1,5 @@ #!/bin/sh -# postinst script for eosio +# postinst script for enumivo # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. @@ -8,8 +8,8 @@ set -e -PACKAGE="eosio" -USER="eosio" +PACKAGE="enumivo" +USER="enumivo" GROUP=${USER} # summary of how this script can be called: @@ -40,8 +40,8 @@ case "$1" in chown ${USER}:${GROUP} /var/lib/${PACKAGE} chown ${USER}:${GROUP} /etc/${PACKAGE} chown ${USER}:${GROUP} /etc/${PACKAGE}/node_00 - chown ${USER} /usr/bin/nodeos - chmod u+s /usr/bin/nodeos + chown ${USER} /usr/bin/enunode + chmod u+s /usr/bin/enunode ;; abort-upgrade|abort-remove|abort-deconfigure) diff --git a/libraries/chain/include/enumivo/chain/asset.hpp b/libraries/chain/include/enumivo/chain/asset.hpp index 851c6119d8c..2c3329e7667 100644 --- a/libraries/chain/include/enumivo/chain/asset.hpp +++ b/libraries/chain/include/enumivo/chain/asset.hpp @@ -85,8 +85,8 @@ struct asset friend struct fc::reflector; void reflector_verify()const { - EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" ); - EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" ); + ENU_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" ); + ENU_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" ); } private: diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 348830496c2..7e7c7ffdba7 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -726,7 +726,7 @@ class crypto_api : public context_aware_api { template auto encode(char* data, size_t datalen) { Encoder e; - const size_t bs = eosio::chain::config::hashing_checktime_block_size; + const size_t bs = enumivo::chain::config::hashing_checktime_block_size; while ( datalen > bs ) { e.write( data, bs ); data += bs; diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index 68dd657072c..ae94c8f9adb 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -267,14 +267,14 @@ namespace enumivo { for( auto& s : fo ) { if( s == "*" ) { my->bypass_filter = true; - wlog("--filter-on * enabled. This can fill shared_mem, causing nodeos to stop."); + wlog("--filter-on * enabled. This can fill shared_mem, causing enunode to stop."); break; } std::vector v; boost::split(v, s, boost::is_any_of(":")); - EOS_ASSERT(v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s",s)); + ENU_ASSERT(v.size() == 3, fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s",s)); filter_entry fe{ v[0], v[1], v[2] }; - EOS_ASSERT(fe.receiver.value && fe.action.value, fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s",s)); + ENU_ASSERT(fe.receiver.value && fe.action.value, fc::invalid_arg_exception, "Invalid value ${s} for --filter-on", ("s",s)); my->filter_on.insert( fe ); } } diff --git a/plugins/history_plugin/include/enumivo/history_plugin/account_control_history_object.hpp b/plugins/history_plugin/include/enumivo/history_plugin/account_control_history_object.hpp index 55aec70abe5..827c1bfcb1e 100644 --- a/plugins/history_plugin/include/enumivo/history_plugin/account_control_history_object.hpp +++ b/plugins/history_plugin/include/enumivo/history_plugin/account_control_history_object.hpp @@ -1,13 +1,13 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in enumivo/LICENSE.txt */ #pragma once #include -#include +#include -namespace eosio { +namespace enumivo { using chain::account_name; using chain::permission_name; using chain::shared_vector; @@ -50,7 +50,7 @@ typedef chainbase::generic_index account_co } -CHAINBASE_SET_INDEX_TYPE( eosio::account_control_history_object, eosio::account_control_history_multi_index ) +CHAINBASE_SET_INDEX_TYPE( enumivo::account_control_history_object, enumivo::account_control_history_multi_index ) -FC_REFLECT( eosio::account_control_history_object, (controlled_account)(controlled_permission)(controlling_account) ) +FC_REFLECT( enumivo::account_control_history_object, (controlled_account)(controlled_permission)(controlling_account) ) diff --git a/plugins/history_plugin/include/enumivo/history_plugin/public_key_history_object.hpp b/plugins/history_plugin/include/enumivo/history_plugin/public_key_history_object.hpp index 996aff7c04b..8b830f21f98 100644 --- a/plugins/history_plugin/include/enumivo/history_plugin/public_key_history_object.hpp +++ b/plugins/history_plugin/include/enumivo/history_plugin/public_key_history_object.hpp @@ -1,13 +1,13 @@ /** * @file - * @copyright defined in eos/LICENSE.txt + * @copyright defined in enumivo/LICENSE.txt */ #pragma once #include #include -namespace eosio { +namespace enumivo { using chain::account_name; using chain::public_key_type; using chain::permission_name; @@ -49,7 +49,7 @@ typedef chainbase::generic_index public_key_hist } -CHAINBASE_SET_INDEX_TYPE( eosio::public_key_history_object, eosio::public_key_history_multi_index ) +CHAINBASE_SET_INDEX_TYPE( enumivo::public_key_history_object, enumivo::public_key_history_multi_index ) -FC_REFLECT( eosio::public_key_history_object, (public_key)(name)(permission) ) +FC_REFLECT( enumivo::public_key_history_object, (public_key)(name)(permission) ) diff --git a/plugins/http_plugin/CMakeLists.txt b/plugins/http_plugin/CMakeLists.txt index 1a213142066..e71b4b7aa41 100644 --- a/plugins/http_plugin/CMakeLists.txt +++ b/plugins/http_plugin/CMakeLists.txt @@ -3,5 +3,5 @@ add_library( http_plugin http_plugin.cpp ${HEADERS} ) -target_link_libraries( http_plugin eosio_chain appbase fc ) +target_link_libraries( http_plugin enumivo_chain appbase fc ) target_include_directories( http_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/tests/enunode_run_test.py b/tests/enunode_run_test.py index eefddb6e771..d216101b62f 100755 --- a/tests/enunode_run_test.py +++ b/tests/enunode_run_test.py @@ -230,21 +230,21 @@ def cmdError(name, cmdCode=0, exitNow=False): Print("Validating accounts before user accounts creation") cluster.validateAccounts(None) - # create accounts via eosio as otherwise a bid is needed - Print("Create new account %s via %s" % (testeraAccount.name, cluster.eosioAccount.name)) - transId=node.createInitializeAccount(testeraAccount, cluster.eosioAccount, stakedDeposit=0, waitForTransBlock=False) + # create accounts via enumivo as otherwise a bid is needed + Print("Create new account %s via %s" % (testeraAccount.name, cluster.enumivoAccount.name)) + transId=node.createInitializeAccount(testeraAccount, cluster.enumivoAccount, stakedDeposit=0, waitForTransBlock=False) if transId is None: cmdError("%s create account" % (testeraAccount.name)) errorExit("Failed to create account %s" % (testeraAccount.name)) - Print("Create new account %s via %s" % (currencyAccount.name, cluster.eosioAccount.name)) - transId=node.createInitializeAccount(currencyAccount, cluster.eosioAccount, stakedDeposit=5000) + Print("Create new account %s via %s" % (currencyAccount.name, cluster.enumivoAccount.name)) + transId=node.createInitializeAccount(currencyAccount, cluster.enumivoAccount, stakedDeposit=5000) if transId is None: cmdError("%s create account" % (ClientName)) errorExit("Failed to create account %s" % (currencyAccount.name)) - Print("Create new account %s via %s" % (exchangeAccount.name, cluster.eosioAccount.name)) - transId=node.createInitializeAccount(exchangeAccount, cluster.eosioAccount, waitForTransBlock=True) + Print("Create new account %s via %s" % (exchangeAccount.name, cluster.enumivoAccount.name)) + transId=node.createInitializeAccount(exchangeAccount, cluster.enumivoAccount, waitForTransBlock=True) if transId is None: cmdError("%s create account" % (ClientName)) errorExit("Failed to create account %s" % (exchangeAccount.name)) diff --git a/unittests/enumivo.system_tests.cpp b/unittests/enumivo.system_tests.cpp index 0f7034ca44e..1d5e5a09295 100644 --- a/unittests/enumivo.system_tests.cpp +++ b/unittests/enumivo.system_tests.cpp @@ -2225,7 +2225,7 @@ BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, enumivo_system_tes } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE( buyname, eosio_system_tester ) try { +BOOST_FIXTURE_TEST_CASE( buyname, enumivo_system_tester ) try { create_accounts_with_resources( { N(dan), N(sam) } ); transfer( config::system_account_name, "dan", core_from_string( "10000.0000" ) ); transfer( config::system_account_name, "sam", core_from_string( "10000.0000" ) ); @@ -2252,14 +2252,14 @@ BOOST_FIXTURE_TEST_CASE( buyname, eosio_system_tester ) try { //wlog( "verify sam can create nofail" ); create_accounts_with_resources( { N(nofail) }, N(sam) ); // sam should be able to do this, he won the bid //wlog( "verify nofail can create test.nofail" ); - transfer( "eosio", "nofail", core_from_string( "1000.0000" ) ); + transfer( "enumivo", "nofail", core_from_string( "1000.0000" ) ); create_accounts_with_resources( { N(test.nofail) }, N(nofail) ); // only nofail can create test.nofail //wlog( "verify dan cannot create test.fail" ); BOOST_REQUIRE_THROW( create_accounts_with_resources( { N(test.fail) }, N(dan) ), fc::exception ); // dan shouldn't be able to do this } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { +BOOST_FIXTURE_TEST_CASE( multiple_namebids, enumivo_system_tester ) try { const std::string not_closed_message("auction for name is not closed yet"); diff --git a/unittests/enumivo_system_tester.hpp b/unittests/enumivo_system_tester.hpp index 64e04abd0b6..9681ca1a050 100644 --- a/unittests/enumivo_system_tester.hpp +++ b/unittests/enumivo_system_tester.hpp @@ -429,7 +429,7 @@ inline fc::mutable_variant_object proxy( account_name acct ) { return voter( acct )( "is_proxy", 1 ); } -inline uint64_t M( const string& eos_str ) { +inline uint64_t M( const string& enu_str ) { return core_from_string( enu_str ).get_amount(); }