Skip to content

Commit

Permalink
Merge branch 'develop' into GRPH-75
Browse files Browse the repository at this point in the history
  • Loading branch information
oxarbitrage committed Sep 18, 2019
2 parents d911b3d + ca4a02d commit bada09d
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 40 deletions.
19 changes: 14 additions & 5 deletions libraries/chain/db_block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,15 @@ bool database::_push_block(const signed_block& new_block)

// pop blocks until we hit the forked block
while( head_block_id() != branches.second.back()->data.previous )
{
ilog( "popping block #${n} ${id}", ("n",head_block_num())("id",head_block_id()) );
pop_block();
}

// push all blocks on the new fork
for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr )
{
ilog( "pushing blocks from fork ${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->data.id()) );
ilog( "pushing block from fork #${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->id) );
optional<fc::exception> except;
try {
undo_database::session session = _undo_db.start_undo_session();
Expand All @@ -235,21 +238,27 @@ bool database::_push_block(const signed_block& new_block)
// remove the rest of branches.first from the fork_db, those blocks are invalid
while( ritr != branches.first.rend() )
{
_fork_db.remove( (*ritr)->data.id() );
ilog( "removing block from fork_db #${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->id) );
_fork_db.remove( (*ritr)->id );
++ritr;
}
_fork_db.set_head( branches.second.front() );

// pop all blocks from the bad fork
while( head_block_id() != branches.second.back()->data.previous )
{
ilog( "popping block #${n} ${id}", ("n",head_block_num())("id",head_block_id()) );
pop_block();
}

ilog( "Switching back to fork: ${id}", ("id",branches.second.front()->data.id()) );
// restore all blocks from the good fork
for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr )
for( auto ritr2 = branches.second.rbegin(); ritr2 != branches.second.rend(); ++ritr2 )
{
ilog( "pushing block #${n} ${id}", ("n",(*ritr2)->data.block_num())("id",(*ritr2)->id) );
auto session = _undo_db.start_undo_session();
apply_block( (*ritr)->data, skip );
_block_id_to_block.store( new_block.id(), (*ritr)->data );
apply_block( (*ritr2)->data, skip );
_block_id_to_block.store( (*ritr2)->id, (*ritr2)->data );
session.commit();
}
throw *except;
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/graphene/chain/proposal_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class proposal_object : public abstract_object<proposal_object>
std::string fail_reason;

bool is_authorized_to_execute(database& db) const;

};

/**
Expand Down
7 changes: 4 additions & 3 deletions tests/tests/authority_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,9 +521,10 @@ BOOST_AUTO_TEST_CASE( committee_authority )
// Should throw because the transaction is now in review.
GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception);

// generate_blocks(prop.expiration_time);
// fails
// BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 100000);
generate_blocks(prop.expiration_time);
BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 100000);
// proposal deleted
BOOST_CHECK_THROW( db.get<proposal_object>(prop.id), fc::exception );
} FC_LOG_AND_RETHROW() }

BOOST_FIXTURE_TEST_CASE( fired_committee_members, database_fixture )
Expand Down
119 changes: 87 additions & 32 deletions tests/tests/block_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,51 +247,106 @@ BOOST_AUTO_TEST_CASE( fork_blocks )
BOOST_CHECK( db1.get_chain_id() == db2.get_chain_id() );

auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
for( uint32_t i = 0; i < 10; ++i )

BOOST_TEST_MESSAGE( "Adding blocks 1 through 10" );
for( uint32_t i = 1; i <= 10; ++i )
{
auto b = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1), init_account_priv_key, database::skip_nothing);
try {
PUSH_BLOCK( db2, b );
} FC_CAPTURE_AND_RETHROW( ("db2") );
}
for( uint32_t i = 10; i < 13; ++i )
{
auto b = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1), init_account_priv_key, database::skip_nothing);
}
string db1_tip = db1.head_block_id().str();
uint32_t next_slot = 3;
for( uint32_t i = 13; i < 16; ++i )

for( uint32_t j = 0; j <= 4; j += 4 )
{
auto b = db2.generate_block(db2.get_slot_time(next_slot), db2.get_scheduled_witness(next_slot), init_account_priv_key, database::skip_nothing);
next_slot = 1;
// notify both databases of the new block.
// only db2 should switch to the new fork, db1 should not
PUSH_BLOCK( db1, b );
// add blocks 11 through 13 to db1 only
BOOST_TEST_MESSAGE( "Adding 3 blocks to db1 only" );
for( uint32_t i = 11 + j; i <= 13 + j; ++i )
{
BOOST_TEST_MESSAGE( i );
auto b = db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1), init_account_priv_key, database::skip_nothing);
}
string db1_tip = db1.head_block_id().str();

// add different blocks 11 through 13 to db2 only
BOOST_TEST_MESSAGE( "Add 3 different blocks to db2 only" );
uint32_t next_slot = 3;
for( uint32_t i = 11 + j; i <= 13 + j; ++i )
{
BOOST_TEST_MESSAGE( i );
auto b = db2.generate_block(db2.get_slot_time(next_slot), db2.get_scheduled_witness(next_slot), init_account_priv_key, database::skip_nothing);
next_slot = 1;
// notify both databases of the new block.
// only db2 should switch to the new fork, db1 should not
PUSH_BLOCK( db1, b );
BOOST_CHECK_EQUAL(db1.head_block_id().str(), db1_tip);
BOOST_CHECK_EQUAL(db2.head_block_id().str(), b.id().str());
}

//The two databases are on distinct forks now, but at the same height.
BOOST_CHECK_EQUAL(db1.head_block_num(), 13u + j);
BOOST_CHECK_EQUAL(db2.head_block_num(), 13u + j);
BOOST_CHECK( db1.head_block_id() != db2.head_block_id() );

//Make a block on db2, make it invalid, then
//pass it to db1 and assert that db1 doesn't switch to the new fork.
signed_block good_block;
{
auto b = db2.generate_block(db2.get_slot_time(1), db2.get_scheduled_witness(1), init_account_priv_key, database::skip_nothing);
good_block = b;
b.transactions.emplace_back(signed_transaction());
b.transactions.back().operations.emplace_back(transfer_operation());
b.sign( init_account_priv_key );
BOOST_CHECK_EQUAL(b.block_num(), 14u + j);
GRAPHENE_CHECK_THROW(PUSH_BLOCK( db1, b ), fc::exception);

// At this point, `fetch_block_by_number` will fetch block from fork_db,
// so unable to reproduce the issue which is fixed in PR #938
// https://github.com/bitshares/bitshares-core/pull/938
fc::optional<signed_block> previous_block = db1.fetch_block_by_number(1);
BOOST_CHECK ( previous_block.valid() );
uint32_t db1_blocks = db1.head_block_num();
for( uint32_t curr_block_num = 2; curr_block_num <= db1_blocks; ++curr_block_num )
{
fc::optional<signed_block> curr_block = db1.fetch_block_by_number( curr_block_num );
BOOST_CHECK( curr_block.valid() );
BOOST_CHECK_EQUAL( curr_block->previous.str(), previous_block->id().str() );
previous_block = curr_block;
}
}
BOOST_CHECK_EQUAL(db1.head_block_num(), 13u + j);
BOOST_CHECK_EQUAL(db1.head_block_id().str(), db1_tip);
BOOST_CHECK_EQUAL(db2.head_block_id().str(), b.id().str());

if( j == 0 )
{
// assert that db1 switches to new fork with good block
BOOST_CHECK_EQUAL(db2.head_block_num(), 14u + j);
PUSH_BLOCK( db1, good_block );
BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());
}
}

//The two databases are on distinct forks now, but at the same height. Make a block on db2, make it invalid, then
//pass it to db1 and assert that db1 doesn't switch to the new fork.
signed_block good_block;
BOOST_CHECK_EQUAL(db1.head_block_num(), 13);
BOOST_CHECK_EQUAL(db2.head_block_num(), 13);
// generate more blocks to push the forked blocks out of fork_db
BOOST_TEST_MESSAGE( "Adding more blocks to db1, push the forked blocks out of fork_db" );
for( uint32_t i = 1; i <= 50; ++i )
{
auto b = db2.generate_block(db2.get_slot_time(1), db2.get_scheduled_witness(1), init_account_priv_key, database::skip_nothing);
good_block = b;
b.transactions.emplace_back(signed_transaction());
b.transactions.back().operations.emplace_back(transfer_operation());
b.sign( init_account_priv_key );
BOOST_CHECK_EQUAL(b.block_num(), 14);
GRAPHENE_CHECK_THROW(PUSH_BLOCK( db1, b ), fc::exception);
db1.generate_block(db1.get_slot_time(1), db1.get_scheduled_witness(1), init_account_priv_key, database::skip_nothing);
}
BOOST_CHECK_EQUAL(db1.head_block_num(), 13);
BOOST_CHECK_EQUAL(db1.head_block_id().str(), db1_tip);

// assert that db1 switches to new fork with good block
BOOST_CHECK_EQUAL(db2.head_block_num(), 14);
PUSH_BLOCK( db1, good_block );
BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());
{
// PR #938 make sure db is in a good state https://github.com/bitshares/bitshares-core/pull/938
BOOST_TEST_MESSAGE( "Checking whether all blocks on disk are good" );
fc::optional<signed_block> previous_block = db1.fetch_block_by_number(1);
BOOST_CHECK ( previous_block.valid() );
uint32_t db1_blocks = db1.head_block_num();
for( uint32_t curr_block_num = 2; curr_block_num <= db1_blocks; ++curr_block_num )
{
fc::optional<signed_block> curr_block = db1.fetch_block_by_number( curr_block_num );
BOOST_CHECK( curr_block.valid() );
BOOST_CHECK_EQUAL( curr_block->previous.str(), previous_block->id().str() );
previous_block = curr_block;
}
}
} catch (fc::exception& e) {
edump((e.to_detail_string()));
throw;
Expand Down

0 comments on commit bada09d

Please sign in to comment.