Skip to content

Commit

Permalink
Merge pull request #1034 from AntelopeIO/GH-239-future-block
Browse files Browse the repository at this point in the history
Do not reject future blocks on speculative nodes
  • Loading branch information
heifner authored Nov 15, 2024
2 parents 07d65b8 + 9f3c603 commit 9afe8c3
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 16 deletions.
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ namespace eosio::chain {
void replace_account_keys( name account, name permission, const public_key_type& key );

void set_producer_node(bool is_producer_node);
bool is_producer_node()const;
bool is_producer_node()const; // thread safe, set at program initialization

void set_db_read_only_mode();
void unset_db_read_only_mode();
Expand Down
6 changes: 4 additions & 2 deletions plugins/net_plugin/net_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3716,8 +3716,10 @@ namespace eosio {
bool unlinkable = false;
sync_manager::closing_mode close_mode = sync_manager::closing_mode::immediately;
try {
EOS_ASSERT(ptr->timestamp < (fc::time_point::now() + fc::seconds(7)), block_from_the_future,
"received a block from the future, rejecting it: ${id}", ("id", id));
if (cc.is_producer_node()) {
EOS_ASSERT(ptr->timestamp < (fc::time_point::now() + fc::seconds(7)), block_from_the_future,
"received a block from the future, rejecting it: ${id}", ("id", id));
}
// this will return empty optional<block_handle> if block is not linkable
controller::accepted_block_result abh = cc.accept_block( id, ptr );
best_head = abh.is_new_best_head;
Expand Down
32 changes: 19 additions & 13 deletions plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,10 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
return _implicit_pause_vote_tracker.check_pause_status(fc::time_point::now()).should_pause();
}

bool is_configured_producer() const {
return !_producers.empty();
}

void on_accepted_block(const signed_block_ptr& block, const block_id_type& id) {
auto& chain = chain_plug->chain();
auto before = _unapplied_transactions.size();
Expand Down Expand Up @@ -1312,7 +1316,7 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia

chain::controller& chain = chain_plug->chain();

chain.set_producer_node(!_producers.empty());
chain.set_producer_node(is_configured_producer());

if (options.count("signature-provider")) {
const std::vector<std::string> key_spec_pairs = options["signature-provider"].as<std::vector<std::string>>();
Expand Down Expand Up @@ -1421,7 +1425,7 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia

if (options.count("read-only-threads")) {
_ro_thread_pool_size = options.at("read-only-threads").as<uint32_t>();
} else if (_producers.empty()) {
} else if (!is_configured_producer()) {
// appbase initialization order is non-deterministic outside listed APPBASE_PLUGIN_REQUIRES plugins.
// To avoid setting up a dependency of producer_plugin on chain_api_plugin, search for the plugin in options instead.
if (options.count("plugin")) {
Expand All @@ -1434,7 +1438,7 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia
}
}
}
EOS_ASSERT(producer_plugin::test_mode_ || _ro_thread_pool_size == 0 || _producers.empty(), plugin_config_exception,
EOS_ASSERT(producer_plugin::test_mode_ || _ro_thread_pool_size == 0 || !is_configured_producer(), plugin_config_exception,
"read-only-threads not allowed on producer node");

// only initialize other read-only options when read-only thread pool is enabled
Expand Down Expand Up @@ -1528,16 +1532,16 @@ void producer_plugin_impl::plugin_startup() {
dlog("producer plugin: plugin_startup() begin");

chain::controller& chain = chain_plug->chain();
EOS_ASSERT(_producers.empty() || chain.get_read_mode() != chain::db_read_mode::IRREVERSIBLE, plugin_config_exception,
EOS_ASSERT(!is_configured_producer() || chain.get_read_mode() != chain::db_read_mode::IRREVERSIBLE, plugin_config_exception,
"node cannot have any producer-name configured because block production is impossible when read_mode is \"irreversible\"");

EOS_ASSERT(_finalizer_keys.empty() || chain.get_read_mode() != chain::db_read_mode::IRREVERSIBLE, plugin_config_exception,
"node cannot have any finalizers configured because finalization is impossible when read_mode is \"irreversible\"");

EOS_ASSERT(_producers.empty() || chain.get_validation_mode() == chain::validation_mode::FULL, plugin_config_exception,
EOS_ASSERT(!is_configured_producer() || chain.get_validation_mode() == chain::validation_mode::FULL, plugin_config_exception,
"node cannot have any producer-name configured because block production is not safe when validation_mode is not \"full\"");

EOS_ASSERT(_producers.empty() || chain_plug->accept_transactions(), plugin_config_exception,
EOS_ASSERT(!is_configured_producer() || chain_plug->accept_transactions(), plugin_config_exception,
"node cannot have any producer-name configured because no block production is possible with no [api|p2p]-accepted-transactions");

chain.set_node_finalizer_keys(_finalizer_keys);
Expand All @@ -1564,7 +1568,7 @@ void producer_plugin_impl::plugin_startup() {
}
}));

if (!_producers.empty()) { // track votes if producer to verify votes are being processed
if (is_configured_producer()) { // track votes if producer to verify votes are being processed
auto on_vote_signal = [this]( const vote_signal_params& vote_signal ) {
const auto& [connection_id, status, msg, active_auth, pending_auth] = vote_signal;
try {
Expand All @@ -1583,7 +1587,7 @@ void producer_plugin_impl::plugin_startup() {
_irreversible_block_time = fc::time_point::maximum();
}

if (!_producers.empty()) {
if (is_configured_producer()) {
ilog("Launching block production for ${n} producers at ${time}.", ("n", _producers.size())("time", fc::time_point::now()));

if (_production_enabled) {
Expand Down Expand Up @@ -1963,8 +1967,10 @@ producer_plugin::get_unapplied_transactions_result producer_plugin::get_unapplie

block_timestamp_type producer_plugin_impl::calculate_pending_block_time() const {
const chain::controller& chain = chain_plug->chain();
const fc::time_point now = fc::time_point::now();
const fc::time_point base = std::max<fc::time_point>(now, chain.head().block_time());
// on speculative nodes, always use next block time. On producers, honor current clock time
const fc::time_point base = is_configured_producer()
? std::max<fc::time_point>(fc::time_point::now(), chain.head().block_time())
: chain.head().block_time();
return block_timestamp_type(base).next();
}

Expand All @@ -1973,7 +1979,7 @@ bool producer_plugin_impl::should_interrupt_start_block(const fc::time_point& de
return deadline <= fc::time_point::now();
}
// if we can produce then honor deadline so production starts on time
return (!_producers.empty() && deadline <= fc::time_point::now()) || (_received_block >= pending_block_num);
return (is_configured_producer() && deadline <= fc::time_point::now()) || (_received_block >= pending_block_num);
}

producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
Expand Down Expand Up @@ -2744,7 +2750,7 @@ void producer_plugin_impl::schedule_production_loop() {
}
}));
} else if (result == start_block_result::waiting_for_block) {
if (!_producers.empty() && !production_disabled_by_policy()) {
if (is_configured_producer() && !production_disabled_by_policy()) {
chain::controller& chain = chain_plug->chain();
fc_dlog(_log, "Waiting till another block is received and scheduling Speculative/Production Change");
auto wake_time = block_timing_util::calculate_producer_wake_up_time(_produce_block_cpu_effort, chain.head().block_num(), calculate_pending_block_time(),
Expand All @@ -2762,7 +2768,7 @@ void producer_plugin_impl::schedule_production_loop() {
} else if (in_producing_mode()) {
schedule_maybe_produce_block(result == start_block_result::exhausted);

} else if (in_speculating_mode() && !_producers.empty() && !production_disabled_by_policy()) {
} else if (in_speculating_mode() && is_configured_producer() && !production_disabled_by_policy()) {
chain::controller& chain = chain_plug->chain();
fc_dlog(_log, "Speculative Block Created; Scheduling Speculative/Production Change");
EOS_ASSERT(chain.is_building_block(), missing_pending_block_state, "speculating without pending_block_state");
Expand Down

0 comments on commit 9afe8c3

Please sign in to comment.