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

async push transaction api

......@@ -294,7 +294,9 @@ struct controller_impl {
if( add_to_fork_db ) {
pending->_pending_block_state->validated = true;
head = fork_db.add( pending->_pending_block_state );
auto new_bsp = fork_db.add( pending->_pending_block_state );
head = fork_db.head();
FC_ASSERT( new_bsp == head, "committed block did not become the new head in fork database" );
}
pending->push();
......@@ -466,6 +468,7 @@ struct controller_impl {
pending = db.start_undo_session(true);
pending->_pending_block_state = std::make_shared<block_state>( *head, when );
pending->_pending_block_state->in_current_chain = true;
try {
auto onbtrx = std::make_shared<transaction_metadata>( get_on_block_transaction() );
......@@ -522,22 +525,28 @@ struct controller_impl {
try {
abort_block();
apply_block( b );
fork_db.mark_in_current_chain( new_head, true );
fork_db.set_validity( new_head, true );
head = new_head;
} catch ( const fc::exception& e ) {
fork_db.set_validity( new_head, false );
fork_db.set_validity( new_head, false ); // Removes new_head from fork_db index, so no need to mark it as not in the current chain.
throw;
}
} else {
} else if( new_head->id != head->id ) {
auto branches = fork_db.fetch_branch_from( new_head->id, head->id );
while( head_block_id() != branches.second.back()->header.previous )
for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
fork_db.mark_in_current_chain( *itr , false );
pop_block();
}
FC_ASSERT( head_block_id() == branches.second.back()->header.previous,
"loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
optional<fc::exception> except;
try {
apply_block( (*ritr)->block );
fork_db.mark_in_current_chain( *ritr, true );
}
catch (const fc::exception& e) { except = e; }
if (except) {
......@@ -549,12 +558,17 @@ struct controller_impl {
}
// pop all blocks from the bad fork
while( head_block_id() != branches.second.back()->header.previous )
for( auto itr = (ritr + 1).base(); itr != branches.second.end(); ++itr ) {
fork_db.mark_in_current_chain( *itr , false );
pop_block();
}
FC_ASSERT( head_block_id() == branches.second.back()->header.previous,
"loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
// re-apply good blocks
for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
apply_block( (*ritr)->block );
fork_db.mark_in_current_chain( *ritr, true );
}
throw *except;
} // end if exception
......@@ -646,18 +660,6 @@ struct controller_impl {
});
}
/**
* This method only works for blocks within the TAPOS range, (last 65K blocks). It
* will return block_id_type() for older blocks.
*/
block_id_type get_block_id_for_num( uint32_t block_num ) {
auto sid = block_num & 0xffff;
auto id = db.get<block_summary_object,by_id>(sid).block_id;
auto num = block_header::num_from_id( id );
if( num == block_num ) return id;
return block_id_type();
}
void clear_expired_transactions() {
//Look for expired transactions in the deduplication list, and remove them.
auto& transaction_idx = db.get_mutable_index<transaction_multi_index>();
......@@ -851,9 +853,8 @@ void controller::log_irreversible_blocks() {
if( lib > 1 ) {
while( log_head && log_head->block_num() < lib ) {
auto lhead = log_head->block_num();
auto blk_id = my->get_block_id_for_num( lhead + 1 );
auto blk = my->fork_db.get_block( blk_id );
FC_ASSERT( blk, "unable to find block state", ("id",blk_id));
auto blk = my->fork_db.get_block_in_current_chain_by_num( lhead + 1 );
FC_ASSERT( blk, "unable to find block state", ("block_num",lhead+1));
irreversible_block( blk );
my->blog.append( *blk->block );
my->fork_db.prune( blk );
......@@ -873,8 +874,7 @@ signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const {
optional<signed_block> b = my->blog.read_block_by_num(block_num);
if( b ) return std::make_shared<signed_block>( move(*b) );
auto blk_id = my->get_block_id_for_num( block_num );
auto blk_state = my->fork_db.get_block( blk_id );
auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
if( blk_state ) return blk_state->block;
return signed_block_ptr();
}
......
......@@ -22,11 +22,17 @@ namespace eosio { namespace chain {
block_state_ptr,
indexed_by<
hashed_unique< tag<by_block_id>, member<block_header_state, block_id_type, &block_header_state::id>, std::hash<block_id_type>>,
hashed_non_unique< tag<by_prev>, const_mem_fun<block_header_state,
const block_id_type&, &block_header_state::prev>,
hashed_non_unique< tag<by_prev>, const_mem_fun<block_header_state,
const block_id_type&, &block_header_state::prev>,
std::hash<block_id_type>>,
ordered_non_unique< tag<by_block_num>, member<block_header_state,uint32_t,&block_header_state::block_num>>,
ordered_non_unique< tag<by_lib_block_num>,
ordered_non_unique< tag<by_block_num>,
composite_key< block_state,
member<block_header_state,uint32_t,&block_header_state::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_last_irreversible_blocknum>,
member<block_header_state,uint32_t,&block_header_state::block_num>
......@@ -135,7 +141,7 @@ namespace eosio { namespace chain {
auto first_branch = get_block(first);
auto second_branch = get_block(second);
while( first_branch->block_num> second_branch->block_num )
while( first_branch->block_num > second_branch->block_num )
{
result.first.push_back(first_branch);
first_branch = get_block( first_branch->header.previous );
......@@ -187,34 +193,54 @@ namespace eosio { namespace chain {
void fork_database::set_validity( const block_state_ptr& h, bool valid ) {
if( !valid ) {
remove( h->id );
remove( h->id );
} else {
/// remove older than irreversible and mark block as valid
h->validated = true;
}
}
void fork_database::mark_in_current_chain( const block_state_ptr& h, bool in_current_chain ) {
if( h->in_current_chain == in_current_chain )
return;
auto& by_id_idx = my->index.get<by_block_id>();
auto itr = by_id_idx.find( h->id );
FC_ASSERT( itr != by_id_idx.end(), "could not find block in fork database" );
by_id_idx.modify( itr, [&]( auto& bsp ) { // Need to modify this way rather than directly so that Boost MultiIndex can re-sort
bsp->in_current_chain = in_current_chain;
});
}
void fork_database::prune( const block_state_ptr& h ) {
auto num = h->block_num;
auto itr = my->index.find( h->id );
if( itr != my->index.end() )
my->index.erase(itr);
auto& numidx = my->index.get<by_block_num>();
auto nitr = numidx.find( num );
if( nitr != numidx.end() ) {
for( auto nitr = numidx.lower_bound( num ); nitr != numidx.end() && (*nitr)->block_num == num; ++nitr ) {
remove( (*nitr)->id );
}
}
block_state_ptr fork_database::get_block(const block_id_type& id)const {
auto itr = my->index.find( id );
if( itr != my->index.end() )
if( itr != my->index.end() )
return *itr;
return block_state_ptr();
}
block_state_ptr fork_database::get_block_in_current_chain_by_num( uint32_t n )const {
const auto& numidx = my->index.get<by_block_num>();
auto nitr = numidx.lower_bound( n );
FC_ASSERT( nitr != numidx.end() && (*nitr)->block_num == n,
"could not find block in fork database with block number ${block_num}", ("block_num", n) );
FC_ASSERT( (*nitr)->in_current_chain == true,
"block (with block number ${block_num}) found in fork database is not in the current chain", ("block_num", n) );
return *nitr;
}
} } /// eosio::chain
......@@ -20,6 +20,7 @@ namespace eosio { namespace chain {
/// weak_ptr prev_block_state....
signed_block_ptr block;
bool validated = false;
bool in_current_chain = false;
/// this data is redundant with the data stored in block, but facilitates
/// recapturing transactions when we pop a block
......
#pragma once
#pragma once
#include <eosio/chain/block_state.hpp>
#include <boost/signals2/signal.hpp>
......@@ -17,7 +17,7 @@ namespace eosio { namespace chain {
* As new blocks are received, they are pushed into the fork database. The fork
* database tracks the longest chain and the last irreversible block number. All
* blocks older than the last irreversible block are freed after emitting the
* irreversible signal.
* irreversible signal.
*/
class fork_database {
public:
......@@ -26,6 +26,7 @@ namespace eosio { namespace chain {
~fork_database();
block_state_ptr get_block(const block_id_type& id)const;
block_state_ptr get_block_in_current_chain_by_num( uint32_t n )const;
// vector<block_state_ptr> get_blocks_by_number(uint32_t n)const;
/**
......@@ -34,11 +35,11 @@ namespace eosio { namespace chain {
void set( block_state_ptr s );
/** this method will attempt to append the block to an exsting
* block_state and will return a pointer to the head block or
* block_state and will return a pointer to the new block state or
* throw on error.
*/
block_state_ptr add( signed_block_ptr b );
block_state_ptr add( block_state_ptr next_block );
block_state_ptr add( signed_block_ptr b );
block_state_ptr add( block_state_ptr next_block );
void remove( const block_id_type& id );
const block_state_ptr& head()const;
......@@ -56,6 +57,7 @@ namespace eosio { namespace chain {
* than the LIB are pruned after emitting irreversible signal.
*/
void set_validity( const block_state_ptr& h, bool valid );
void mark_in_current_chain( const block_state_ptr& h, bool in_current_chain );
void prune( const block_state_ptr& h );
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册