Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not reject future blocks on speculative nodes #1034

Merged
merged 3 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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