未验证 提交 b247021c 编写于 作者: W wanderingbort 提交者: GitHub

Merge pull request #2745 from wanderingbort/feature/add-confirms-to-producer-plugin

add DPOS confirmations to producer plugin
......@@ -114,7 +114,9 @@ namespace eosio { namespace chain {
/// grow the confirmed count
static_assert(std::numeric_limits<uint8_t>::max() >= (config::max_producers * 2 / 3) + 1, "8bit confirmations may not be able to hold all of the needed confirmations");
auto num_active_producers = result.active_schedule.producers.size();
// This uses the previous block active_schedule because thats the "schedule" that signs and therefore confirms _this_ block
auto num_active_producers = active_schedule.producers.size();
uint32_t required_confs = (uint32_t)(num_active_producers * 2 / 3) + 1;
if( confirm_count.size() < config::maximum_tracked_dpos_confirmations ) {
......
......@@ -21,7 +21,8 @@ namespace block_production_condition {
no_private_key = 4,
low_participation = 5,
lag = 6,
exception_producing_block = 7
exception_producing_block = 7,
fork_below_watermark = 8,
};
}
......
......@@ -45,6 +45,7 @@ class producer_plugin_impl {
std::map<chain::public_key_type, chain::private_key_type> _private_keys;
std::set<chain::account_name> _producers;
boost::asio::deadline_timer _timer;
std::map<chain::account_name, uint32_t> _producer_watermarks;
int32_t _max_deferred_transaction_time_ms;
......@@ -271,8 +272,25 @@ void producer_plugin_impl::schedule_production_loop() {
chain::controller& chain = app().get_plugin<chain_plugin>().chain();
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<uint16_t>(std::numeric_limits<uint16_t>::max(), (uint16_t)(hbs->block_num - watermark));
}
}
chain.abort_block();
chain.start_block(block_time);
chain.start_block(block_time, blocks_to_confirm);
} FC_LOG_AND_DROP();
if (chain.pending_block_state()) {
......@@ -338,10 +356,10 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
auto producer = db.head_block_producer();
auto pending = db.head_block_state();
wlog("\r${p} generated block ${id}... #${n} @ ${t} with ${count} trxs, lib: ${lib}",
wlog("\r${p} generated block ${id}... #${n} @ ${t} with ${count} trxs, 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())(capture) );
("count",pending->block->transactions.size())("lib",db.last_irreversible_block_num())("confs", pending->header.confirmed)(capture) );
break;
}
case block_production_condition::not_synced:
......@@ -365,6 +383,9 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
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;
}
}
schedule_production_loop();
......@@ -373,7 +394,7 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
block_production_condition::block_production_condition_enum producer_plugin_impl::maybe_produce_block(fc::mutable_variant_object& capture) {
chain::controller& chain = app().get_plugin<chain_plugin>().chain();
const auto& hbs = *chain.head_block_state();
block_state_ptr hbs = chain.head_block_state();
fc::time_point now = fc::time_point::now();
/*
......@@ -384,7 +405,7 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
// If the next block production opportunity is in the present or future, we're synced.
if( !_production_enabled )
{
if( hbs.header.timestamp.next().to_time_point() >= now )
if( hbs->header.timestamp.next().to_time_point() >= now )
_production_enabled = true;
else
return block_production_condition::not_synced;
......@@ -402,7 +423,7 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
//
assert( now > chain.head_block_time() );
const auto& scheduled_producer = hbs.get_scheduled_producer( pending_block_timestamp );
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() )
{
......@@ -418,7 +439,7 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
return block_production_condition::no_private_key;
}
/*uint32_t prate = hbs.producer_participation_rate();
/*uint32_t prate = hbs->producer_participation_rate();
if( prate < _required_producer_participation )
{
capture("pct", uint32_t(prate / config::percent_1));
......@@ -431,6 +452,15 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
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();
chain.sign_block( [&]( const digest_type& d ) { return private_key_itr->second.sign(d); } );
......@@ -438,6 +468,25 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
auto hbt = chain.head_block_time();
//idump((fc::time_point::now() - hbt));
block_state_ptr new_bs = chain.head_block_state();
// for newly installed producers we can set their watermarks to the block they became
if (hbs->active_schedule.version != new_bs->active_schedule.version) {
flat_set<account_name> new_producers;
new_producers.reserve(new_bs->active_schedule.producers.size());
for( const auto& p: new_bs->active_schedule.producers) {
if (_producers.count(p.producer_name) > 0)
new_producers.insert(p.producer_name);
}
for( const auto& p: hbs->active_schedule.producers) {
new_producers.erase(p.producer_name);
}
for (const auto& new_producer: new_producers) {
_producer_watermarks[new_producer] = chain.head_block_num();
}
}
_producer_watermarks[scheduled_producer.producer_name] = chain.head_block_num();
return block_production_condition::produced;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册