提交 fedded39 编写于 作者: D Daniel Larimer

Progress on #2192 fork database

上级 c10bf78f
......@@ -28,19 +28,26 @@ namespace eosio { namespace chain {
return result;
}
public_key_type signed_block_header::signee()const
public_key_type signed_block_header::signee( const digest_type& schedule_digest )const
{
return fc::crypto::public_key(producer_signature, digest(), true/*enforce canonical*/);
return fc::crypto::public_key(producer_signature, signed_digest( schedule_digest ), true/*enforce canonical*/);
}
void signed_block_header::sign(const private_key_type& signer)
digest_type signed_block_header::signed_digest( const digest_type& schedule_digest )const {
schedule_digest::encoder enc;
fc::raw::pack( enc, schedule_digest );
fc::raw::pack( enc, digest() );
return enc.result();
}
void signed_block_header::sign(const private_key_type& signer, const fc::sha256& schedule_digest )
{
producer_signature = signer.sign(digest());
producer_signature = signer.sign( signed_digest( schedule_digest ) );
}
bool signed_block_header::validate_signee(const public_key_type& expected_signee)const
bool signed_block_header::validate_signee(const public_key_type& expected_signee, const fc::sha256& schedule_digest )const
{
return signee() == expected_signee;
return signee( schedule_digest ) == expected_signee;
}
} }
......@@ -35,23 +35,83 @@ void fork_database::start_block(signed_block b)
* Pushes the block into the fork database and caches it if it doesn't link
*
*/
shared_ptr<fork_item> fork_database::push_block(const signed_block& b, const producer_schedule_type& sch )
shared_ptr<fork_item> fork_database::push_block( const signed_block& b )
{
auto item = std::make_shared<fork_item>(b);
try {
_push_block(item, sch);
}
catch ( const unlinkable_block_exception& e )
{
auto item = push_block_header( b );
item->data = std::make_shared<signed_block>(b);
return item;
shared_ptr<fork_item> fork_database::push_block_header( const signed_block_header& b ) { try {
const auto& by_id_idx = _index.get<by_block_id>();
auto existing = by_id_idx.find( b.id() );
if( existing != by_id_idx.end() ) return *existing;
auto previous = by_id_idx.find( b.previous );
if( previous == by_id_idx.end() ) {
wlog( "Pushing block to fork database that failed to link: ${id}, ${num}", ("id",b.id())("num",b.block_num()) );
wlog( "Head: ${num}, ${id}", ("num",_head->data.block_num())("id",_head->data.id()) );
throw;
_unlinked_index.insert( item );
EOS_ASSERT(itr != index.end(), unlinkable_block_exception, "block does not link to known chain");
}
FC_ASSERT( !previous->invalid, unlinkable_block_exception, "unable to link to a known invalid block" );
auto next = std::make_shared<fork_item>( *previous );
next->confirmations.clear();
next->data.reset();
next->previous = previous;
next->header = b;
next->id = b.id();
next->invalid = false;
next->num = previous->num + 1;
next->last_block_per_producer[b.producer] = next->num;
FC_ASSERT( b.timestamp > previous->header.timestamp, "block must advance time" );
// next->last_irreversible_block = next->calculate_last_irr
if( next->last_irreversible_block >= next->pending_schedule_block )
next->active_schedule = std::move(next->pending_schedule );
if( b.new_producers ) {
FC_ASSERT( !next->pending_schedule, "there is already an unconfirmed pending schedule" );
next->pending_schedule = std::make_shared<producer_schedule_type>( *b.new_producers );
}
FC_ASSERT( b.schedule_version == next->active_schedule->version, "wrong schedule version provided" );
auto schedule_hash = fc::sha256::hash( *next->active_schedule );
auto signee = b.signee( schedule_digest );
auto num_producers = next->active_schedule->producers.size();
vector<uint32_t> ibb;
flat_map<account_name, uint32_t> new_block_per_producer;
ibb.reserve( num_producers );
size_t offset = EOS_PERCENT(ibb.size(), config::percent_100- config::irreversible_threshold_percent);
for( const auto& item : next->active_schedule->producers ) {
ibb.push_back( last_block_per_producer[item.producer_name] );
new_block_per_producer[item.producer_name] = ibb.back();
}
next->last_block_per_producer = move(new_block_per_producer);
std::nth_element( ibb.begin(), ibb.begin() + offset, ibb.end() );
next->last_irreversible_block = ibb[offset];
auto index = b.timestamp.slot % (num_producers * config::producer_repetitions);
index /= config::producer_repetitions;
auto prod = next->active_schedule->producers[index];
FC_ASSERT( prod.producer_name == b.producer, "unexpected producer specified" );
FC_ASSERT( prod.block_signing_key == signee, "block not signed by expected key" );
_push_block( next );
return _head;
}
} FC_CAPTURE_AND_RETHROW( (b) ) }
void fork_database::_push_block(const item_ptr& item, const producer_schedule_type& sch)
void fork_database::_push_block(const item_ptr& item )
{
if( _head ) // make sure the block is within the range that we are caching
{
......@@ -67,10 +127,6 @@ void fork_database::_push_block(const item_ptr& item, const producer_schedule_t
EOS_ASSERT(itr != index.end(), unlinkable_block_exception, "block does not link to known chain");
FC_ASSERT(!(*itr)->invalid);
if( (*itr)->schedule && *(*itr)->schedule == sch )
item->schedule = (*itr)->schedule;
else
item->schedule = std::make_shared<producer_schedule_type>( sch );
item->prev = *itr;
}
......@@ -82,13 +138,12 @@ void fork_database::_push_block(const item_ptr& item, const producer_schedule_t
if (delta > 1)
wlog("Number of missed blocks: ${num}", ("num", delta-1));
_head = item;
uint32_t min_num = _head->num - std::min( _max_size, _head->num );
uint32_t min_num = _head->last_irreversible_block - 1; //_head->num - std::min( _max_size, _head->num );
// ilog( "min block in fork DB ${n}, max_size: ${m}", ("n",min_num)("m",_max_size) );
auto& num_idx = _index.get<block_num>();
while( num_idx.size() && (*num_idx.begin())->num < min_num )
num_idx.erase( num_idx.begin() );
_unlinked_index.get<block_num>().erase(_head->num - _max_size);
}
}
......
......@@ -46,9 +46,10 @@ namespace eosio { namespace chain {
struct signed_block_header : public block_header
{
block_id_type id() const;
public_key_type signee() const;
void sign(const private_key_type& signer);
bool validate_signee(const public_key_type& expected_signee) const;
public_key_type signee( const digest_type& schedule_digest ) const;
void sign(const private_key_type& signer, const digest_type& schedule_digest );
bool validate_signee(const public_key_type& expected_signee, const digest_type& schedule_digest ) const;
digest_type signed_digest( const digest_type& schedule_digest )const;
signature_type producer_signature;
};
......
......@@ -28,18 +28,26 @@ namespace eosio { namespace chain {
return (schedule->producers.size() * 2) / 3 < confirmations.size();
}
weak_ptr< fork_item > prev;
shared_ptr< producer_schedule_type > schedule;
uint32_t num; // initialized in ctor
weak_ptr< fork_item > prev;
shared_ptr< producer_schedule_type > active_schedule;
shared_ptr< producer_schedule_type > pending_schedule;
uint32_t pending_schedule_block;
uint32_t last_irreversible_block = 0;
vector<uint32_t,account_name> last_block_per_producer;
uint32_t num; // initialized in ctor
/**
* Used to flag a block as invalid and prevent other blocks from
* building on top of it.
*/
bool invalid = false;
block_id_type id;
signed_block data;
block_header header;
shared_ptr<signed_block> data;
vector<producer_confirmation> confirmations;
};
typedef shared_ptr<fork_item> item_ptr;
......@@ -79,7 +87,9 @@ namespace eosio { namespace chain {
/**
* @return the new head block ( the longest fork )
*/
shared_ptr<fork_item> push_block(const signed_block& b, const producer_schedule_type& s = producer_schedule_type() );
shared_ptr<fork_item> push_block( const signed_block& b );
shared_ptr<fork_item> push_block_header( const signed_block_header& b );
shared_ptr<fork_item> head()const { return _head; }
void pop_block();
......@@ -90,15 +100,15 @@ namespace eosio { namespace chain {
pair< branch_type, branch_type > fetch_branch_from(block_id_type first,
block_id_type second)const;
struct block_id;
struct block_num;
struct by_block_id;
struct by_block_num;
struct by_previous;
typedef multi_index_container<
item_ptr,
indexed_by<
hashed_unique<tag<block_id>, member<fork_item, block_id_type, &fork_item::id>, std::hash<block_id_type>>,
hashed_unique<tag<by_block_id>, member<fork_item, block_id_type, &fork_item::id>, std::hash<block_id_type>>,
hashed_non_unique<tag<by_previous>, const_mem_fun<fork_item, block_id_type, &fork_item::previous_id>, std::hash<block_id_type>>,
ordered_non_unique<tag<block_num>, member<fork_item,uint32_t,&fork_item::num>>
ordered_non_unique<tag<by_block_num>, member<fork_item,uint32_t,&fork_item::num>>
>
> fork_multi_index_type;
......@@ -110,7 +120,6 @@ namespace eosio { namespace chain {
uint32_t _max_size = 1024;
fork_multi_index_type _unlinked_index;
fork_multi_index_type _index;
shared_ptr<fork_item> _head;
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册