Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #6588 from EOSIO/refactor-block-header-state
Browse files Browse the repository at this point in the history
Refactor block_header_state
  • Loading branch information
arhag authored Jan 28, 2019
2 parents 859c02e + be795a8 commit 7436f60
Show file tree
Hide file tree
Showing 20 changed files with 744 additions and 618 deletions.
2 changes: 1 addition & 1 deletion libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void apply_context::exec_one( action_trace& trace )
r.act_digest = digest_type::hash(act);

trace.trx_id = trx_context.id;
trace.block_num = control.pending_block_state()->block_num;
trace.block_num = control.head_block_num() + 1;
trace.block_time = control.pending_block_time();
trace.producer_block_id = control.pending_producer_block_id();
trace.act = act;
Expand Down
399 changes: 211 additions & 188 deletions libraries/chain/block_header_state.cpp

Large diffs are not rendered by default.

34 changes: 25 additions & 9 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,33 @@

namespace eosio { namespace chain {

block_state::block_state( const block_header_state& prev, block_timestamp_type when )
:block_header_state( prev.generate_next( when ) ),
block( std::make_shared<signed_block>() )
{
static_cast<block_header&>(*block) = header;
}
block_state::block_state( const block_header_state& prev,
signed_block_ptr b,
bool skip_validate_signee
)
:block_header_state( prev.next( *b, skip_validate_signee ) )
,block( std::move(b) )
{}

block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee )
:block_header_state( prev.next( *b, skip_validate_signee )), block( move(b) )
{ }
block_state::block_state( pending_block_header_state&& cur,
signed_block_ptr&& b,
vector<transaction_metadata_ptr>&& trx_metas,
const std::function<signature_type(const digest_type&)>& signer
)
:block_header_state( std::move(cur).finish_next( *b, signer ) )
,block( std::move(b) )
,trxs( std::move(trx_metas) )
{}


block_state::block_state( pending_block_header_state&& cur,
const signed_block_ptr& b,
vector<transaction_metadata_ptr>&& trx_metas,
bool skip_validate_signee
)
:block_header_state( std::move(cur).finish_next( *b, skip_validate_signee ) )
,block( b )
,trxs( std::move(trx_metas) )
{}

} } /// eosio::chain
495 changes: 310 additions & 185 deletions libraries/chain/controller.cpp

Large diffs are not rendered by default.

73 changes: 7 additions & 66 deletions libraries/chain/fork_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,17 @@ namespace eosio { namespace chain {
ordered_non_unique< tag<by_prev>, const_mem_fun<block_header_state, const block_id_type&, &block_header_state::prev> >,
ordered_non_unique< tag<by_block_num>,
composite_key< block_state,
member<block_header_state,uint32_t,&block_header_state::block_num>,
member<detail::block_header_state_common,uint32_t,&detail::block_header_state_common::block_num>,
member<block_state,bool,&block_state::in_current_chain>
>,
composite_key_compare< std::less<uint32_t>, std::greater<bool> >
>,
ordered_non_unique< tag<by_lib_block_num>,
composite_key< block_header_state,
member<block_header_state,uint32_t,&block_header_state::dpos_irreversible_blocknum>,
member<block_header_state,uint32_t,&block_header_state::bft_irreversible_blocknum>,
member<block_header_state,uint32_t,&block_header_state::block_num>
member<detail::block_header_state_common,uint32_t,&detail::block_header_state_common::dpos_irreversible_blocknum>,
member<detail::block_header_state_common,uint32_t,&detail::block_header_state_common::block_num>
>,
composite_key_compare< std::greater<uint32_t>, std::greater<uint32_t>, std::greater<uint32_t> >
composite_key_compare< std::greater<uint32_t>, std::greater<uint32_t> >
>
>
> fork_multi_index_type;
Expand Down Expand Up @@ -110,7 +109,7 @@ namespace eosio { namespace chain {

void fork_database::set( block_state_ptr s ) {
auto result = my->index.insert( s );
EOS_ASSERT( s->id == s->header.id(), fork_database_exception,
EOS_ASSERT( s->id == s->header.id(), fork_database_exception,
"block state id (${id}) is different from block state header id (${hid})", ("id", string(s->id))("hid", string(s->header.id())) );

//FC_ASSERT( s->block_num == s->header.block_num() );
Expand Down Expand Up @@ -196,8 +195,8 @@ namespace eosio { namespace chain {
result.second.push_back(second_branch);
first_branch = get_block( first_branch->header.previous );
second_branch = get_block( second_branch->header.previous );
EOS_ASSERT( first_branch && second_branch, fork_db_block_not_found,
"either block ${fid} or ${sid} does not exist",
EOS_ASSERT( first_branch && second_branch, fork_db_block_not_found,
"either block ${fid} or ${sid} does not exist",
("fid", string(first_branch->header.previous))("sid", string(second_branch->header.previous)) );
}

Expand Down Expand Up @@ -297,62 +296,4 @@ namespace eosio { namespace chain {
return *nitr;
}

void fork_database::add( const header_confirmation& c ) {
auto b = get_block( c.block_id );
EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",c.block_id));
b->add_confirmation( c );

if( b->bft_irreversible_blocknum < b->block_num &&
b->confirmations.size() >= ((b->active_schedule.producers.size() * 2) / 3 + 1) ) {
set_bft_irreversible( c.block_id );
}
}

/**
* This method will set this block as being BFT irreversible and will update
* all blocks which build off of it to have the same bft_irb if their existing
* bft irb is less than this block num.
*
* This will require a search over all forks
*/
void fork_database::set_bft_irreversible( block_id_type id ) {
auto& idx = my->index.get<by_block_id>();
auto itr = idx.find(id);
uint32_t block_num = (*itr)->block_num;
idx.modify( itr, [&]( auto& bsp ) {
bsp->bft_irreversible_blocknum = bsp->block_num;
});

/** to prevent stack-overflow, we perform a bredth-first traversal of the
* fork database. At each stage we iterate over the leafs from the prior stage
* and find all nodes that link their previous. If we update the bft lib then we
* add it to a queue for the next layer. This lambda takes one layer and returns
* all block ids that need to be iterated over for next layer.
*/
auto update = [&]( const vector<block_id_type>& in ) {
vector<block_id_type> updated;

for( const auto& i : in ) {
auto& pidx = my->index.get<by_prev>();
auto pitr = pidx.lower_bound( i );
auto epitr = pidx.upper_bound( i );
while( pitr != epitr ) {
pidx.modify( pitr, [&]( auto& bsp ) {
if( bsp->bft_irreversible_blocknum < block_num ) {
bsp->bft_irreversible_blocknum = block_num;
updated.push_back( bsp->id );
}
});
++pitr;
}
}
return updated;
};

vector<block_id_type> queue{id};
while( queue.size() ) {
queue = update( queue );
}
}

} } /// eosio::chain
17 changes: 6 additions & 11 deletions libraries/chain/include/eosio/chain/block_header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ namespace eosio { namespace chain {
account_name producer;

/**
* By signing this block this producer is confirming blocks [block_num() - confirmed, blocknum())
* By signing this block this producer is confirming blocks [block_num() - confirmed, blocknum())
* as being the best blocks for that range and that he has not signed any other
* statements that would contradict.
* statements that would contradict.
*
* No producer should sign a block with overlapping ranges or it is proof of byzantine
* behavior. When producing a block a producer is always confirming at least the block he
* is building off of. A producer cannot confirm "this" block, only prior blocks.
*/
uint16_t confirmed = 1;
uint16_t confirmed = 1;

block_id_type previous;

Expand All @@ -35,6 +35,8 @@ namespace eosio { namespace chain {
extensions_type header_extensions;


block_header() = default;

digest_type digest()const;
block_id_type id() const;
uint32_t block_num() const { return num_from_id(previous) + 1; }
Expand All @@ -47,18 +49,11 @@ namespace eosio { namespace chain {
signature_type producer_signature;
};

struct header_confirmation {
block_id_type block_id;
account_name producer;
signature_type producer_signature;
};

} } /// namespace eosio::chain

FC_REFLECT(eosio::chain::block_header,
FC_REFLECT(eosio::chain::block_header,
(timestamp)(producer)(confirmed)(previous)
(transaction_mroot)(action_mroot)
(schedule_version)(new_producers)(header_extensions))

FC_REFLECT_DERIVED(eosio::chain::signed_block_header, (eosio::chain::block_header), (producer_signature))
FC_REFLECT(eosio::chain::header_confirmation, (block_id)(producer)(producer_signature) )
143 changes: 93 additions & 50 deletions libraries/chain/include/eosio/chain/block_header_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,106 @@

namespace eosio { namespace chain {

struct block_header_state;

namespace detail {
struct block_header_state_common {
uint32_t block_num = 0;
uint32_t dpos_proposed_irreversible_blocknum = 0;
uint32_t dpos_irreversible_blocknum = 0;
producer_schedule_type active_schedule;
incremental_merkle blockroot_merkle;
flat_map<account_name,uint32_t> producer_to_last_produced;
flat_map<account_name,uint32_t> producer_to_last_implied_irb;
public_key_type block_signing_key;
vector<uint8_t> confirm_count;
};

struct schedule_info {
uint32_t schedule_lib_num = 0; /// last irr block num
digest_type schedule_hash;
producer_schedule_type schedule;
};
}

struct pending_block_header_state : public detail::block_header_state_common {
detail::schedule_info prev_pending_schedule;
bool was_pending_promoted = false;
block_id_type previous;
account_name producer;
block_timestamp_type timestamp;
uint32_t active_schedule_version = 0;
uint16_t confirmed = 1;

signed_block_header make_block_header( const checksum256_type& transaction_mroot,
const checksum256_type& action_mroot,
optional<producer_schedule_type>&& new_producers )const;

block_header_state finish_next( const signed_block_header& h, bool skip_validate_signee = false )&&;

block_header_state finish_next( signed_block_header& h,
const std::function<signature_type(const digest_type&)>& signer )&&;

protected:
block_header_state _finish_next( const signed_block_header& h )&&;
};


/**
* @struct block_header_state
* @brief defines the minimum state necessary to validate transaction headers
*/
struct block_header_state {
block_id_type id;
uint32_t block_num = 0;
signed_block_header header;
uint32_t dpos_proposed_irreversible_blocknum = 0;
uint32_t dpos_irreversible_blocknum = 0;
uint32_t bft_irreversible_blocknum = 0;
uint32_t pending_schedule_lib_num = 0; /// last irr block num
digest_type pending_schedule_hash;
producer_schedule_type pending_schedule;
producer_schedule_type active_schedule;
incremental_merkle blockroot_merkle;
flat_map<account_name,uint32_t> producer_to_last_produced;
flat_map<account_name,uint32_t> producer_to_last_implied_irb;
public_key_type block_signing_key;
vector<uint8_t> confirm_count;
vector<header_confirmation> confirmations;

block_header_state next( const signed_block_header& h, bool trust = false )const;
block_header_state generate_next( block_timestamp_type when )const;

void set_new_producers( producer_schedule_type next_pending );
void set_confirmed( uint16_t num_prev_blocks );
void add_confirmation( const header_confirmation& c );
bool maybe_promote_pending();


bool has_pending_producers()const { return pending_schedule.producers.size(); }
uint32_t calc_dpos_last_irreversible()const;
bool is_active_producer( account_name n )const;

/*
block_timestamp_type get_slot_time( uint32_t slot_num )const;
uint32_t get_slot_at_time( block_timestamp_type t )const;
producer_key get_scheduled_producer( uint32_t slot_num )const;
uint32_t producer_participation_rate()const;
*/

producer_key get_scheduled_producer( block_timestamp_type t )const;
const block_id_type& prev()const { return header.previous; }
digest_type sig_digest()const;
void sign( const std::function<signature_type(const digest_type&)>& signer );
public_key_type signee()const;
void verify_signee(const public_key_type& signee)const;
struct block_header_state : public detail::block_header_state_common {
block_id_type id;
signed_block_header header;
detail::schedule_info pending_schedule;

block_header_state() = default;

block_header_state( detail::block_header_state_common&& base )
:detail::block_header_state_common( std::move(base) )
{}

pending_block_header_state next( block_timestamp_type when, uint16_t num_prev_blocks_to_confirm )const;

block_header_state next( const signed_block_header& h, bool skip_validate_signee = false )const;

bool has_pending_producers()const { return pending_schedule.schedule.producers.size(); }
uint32_t calc_dpos_last_irreversible( account_name producer_of_next_block )const;
bool is_active_producer( account_name n )const;

producer_key get_scheduled_producer( block_timestamp_type t )const;
const block_id_type& prev()const { return header.previous; }
digest_type sig_digest()const;
void sign( const std::function<signature_type(const digest_type&)>& signer );
public_key_type signee()const;
void verify_signee(const public_key_type& signee)const;
};



} } /// namespace eosio::chain

FC_REFLECT( eosio::chain::block_header_state,
(id)(block_num)(header)(dpos_proposed_irreversible_blocknum)(dpos_irreversible_blocknum)(bft_irreversible_blocknum)
(pending_schedule_lib_num)(pending_schedule_hash)
(pending_schedule)(active_schedule)(blockroot_merkle)
(producer_to_last_produced)(producer_to_last_implied_irb)(block_signing_key)
(confirm_count)(confirmations) )
FC_REFLECT( eosio::chain::detail::block_header_state_common,
(block_num)
(dpos_proposed_irreversible_blocknum)
(dpos_irreversible_blocknum)
(active_schedule)
(blockroot_merkle)
(producer_to_last_produced)
(producer_to_last_implied_irb)
(block_signing_key)
(confirm_count)
)

FC_REFLECT( eosio::chain::detail::schedule_info,
(schedule_lib_num)
(schedule_hash)
(schedule)
)

FC_REFLECT_DERIVED( eosio::chain::block_header_state, (eosio::chain::detail::block_header_state_common),
(id)
(header)
(pending_schedule)
)
20 changes: 17 additions & 3 deletions libraries/chain/include/eosio/chain/block_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,23 @@
namespace eosio { namespace chain {

struct block_state : public block_header_state {
explicit block_state( const block_header_state& cur ):block_header_state(cur){}
block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee );
block_state( const block_header_state& prev, block_timestamp_type when );
block_state( const block_header_state& prev,
signed_block_ptr b,
bool skip_validate_signee
);

block_state( pending_block_header_state&& cur,
signed_block_ptr&& b, // unsigned block
vector<transaction_metadata_ptr>&& trx_metas,
const std::function<signature_type(const digest_type&)>& signer
);

block_state( pending_block_header_state&& cur,
const signed_block_ptr& b, // signed block
vector<transaction_metadata_ptr>&& trx_metas,
bool skip_validate_signee
);

block_state() = default;

/// weak_ptr prev_block_state....
Expand Down
Loading

0 comments on commit 7436f60

Please sign in to comment.