Skip to content

Commit

Permalink
[Pruning] Accept pruned-related blocks in blocks processing & rollback (
Browse files Browse the repository at this point in the history
#2974)

* [Pruning] Accept pruned-related blocks in blocks processing & rollback

* Fix open block pruned source rollback & add test (Guilherme review)
* Add state block comment
* Fix processing open/receive blocks with pruned source after rollback
* Use C++17 [[maybe_unused]]
  • Loading branch information
SergiySW committed Oct 3, 2020
1 parent 8462acb commit 27c1365
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 29 deletions.
174 changes: 173 additions & 1 deletion nano/core_test/ledger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3420,6 +3420,18 @@ TEST (ledger, pruning_action)
ASSERT_TRUE (store->pruned_exists (transaction, send1.hash ()));
ASSERT_TRUE (store->block_exists (transaction, genesis.hash ()));
ASSERT_TRUE (store->block_exists (transaction, send2.hash ()));
// Receiving pruned block
nano::state_block receive1 (nano::genesis_account, send2.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, send1.hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (send2.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_TRUE (store->block_exists (transaction, receive1.hash ()));
auto receive1_stored (store->block_get (transaction, receive1.hash ()));
ASSERT_NE (nullptr, receive1_stored);
ASSERT_EQ (receive1, *receive1_stored);
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
ASSERT_EQ (4, receive1_stored->sideband ().height);
ASSERT_FALSE (receive1_stored->sideband ().details.is_send);
ASSERT_TRUE (receive1_stored->sideband ().details.is_receive);
ASSERT_FALSE (receive1_stored->sideband ().details.is_epoch);
// Middle block pruning
ASSERT_TRUE (store->block_exists (transaction, send2.hash ()));
ASSERT_EQ (1, ledger.pruning_action (transaction, send2.hash (), 1));
Expand Down Expand Up @@ -3467,6 +3479,166 @@ TEST (ledger, pruning_large_chain)
ASSERT_EQ (1, store->block_count (transaction)); // Genesis
}

TEST (ledger, pruning_source_rollback)
{
nano::logger_mt logger;
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
nano::stat stats;
nano::ledger ledger (*store, stats);
ledger.pruning = true;
nano::genesis genesis;
auto transaction (store->tx_begin_write ());
store->initialize (transaction, genesis, ledger.cache);
nano::work_pool pool (std::numeric_limits<unsigned>::max ());
nano::state_block epoch1 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount, ledger.epoch_link (nano::epoch::epoch_1), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (genesis.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch1).code);
nano::state_block send1 (nano::genesis_account, epoch1.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, nano::genesis_account, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (epoch1.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
ASSERT_TRUE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
nano::state_block send2 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio * 2, nano::genesis_account, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (send1.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send2).code);
ASSERT_TRUE (store->block_exists (transaction, send2.hash ()));
// Pruning action
ASSERT_EQ (2, ledger.pruning_action (transaction, send1.hash (), 1));
ASSERT_FALSE (store->block_exists (transaction, send1.hash ()));
ASSERT_TRUE (store->pruned_exists (transaction, send1.hash ()));
ASSERT_FALSE (store->block_exists (transaction, epoch1.hash ()));
ASSERT_TRUE (store->pruned_exists (transaction, epoch1.hash ()));
ASSERT_TRUE (store->block_exists (transaction, genesis.hash ()));
nano::pending_info info;
ASSERT_FALSE (store->pending_get (transaction, nano::pending_key (nano::genesis_account, send1.hash ()), info));
ASSERT_EQ (nano::genesis_account, info.source);
ASSERT_EQ (nano::Gxrb_ratio, info.amount.number ());
ASSERT_EQ (nano::epoch::epoch_1, info.epoch);
// Receiving pruned block
nano::state_block receive1 (nano::genesis_account, send2.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, send1.hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (send2.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
ASSERT_EQ (2, ledger.cache.pruned_count);
ASSERT_EQ (5, ledger.cache.block_count);
// Rollback receive block
ASSERT_FALSE (ledger.rollback (transaction, receive1.hash ()));
nano::pending_info info2;
ASSERT_FALSE (store->pending_get (transaction, nano::pending_key (nano::genesis_account, send1.hash ()), info2));
ASSERT_NE (nano::genesis_account, info2.source); // Tradeoff to not store pruned blocks accounts
ASSERT_EQ (nano::Gxrb_ratio, info2.amount.number ());
ASSERT_EQ (nano::epoch::epoch_1, info2.epoch);
// Process receive block again
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
ASSERT_EQ (2, ledger.cache.pruned_count);
ASSERT_EQ (5, ledger.cache.block_count);
}

TEST (ledger, pruning_source_rollback_legacy)
{
nano::logger_mt logger;
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
nano::stat stats;
nano::ledger ledger (*store, stats);
ledger.pruning = true;
nano::genesis genesis;
auto transaction (store->tx_begin_write ());
store->initialize (transaction, genesis, ledger.cache);
nano::work_pool pool (std::numeric_limits<unsigned>::max ());
nano::send_block send1 (genesis.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (genesis.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
ASSERT_TRUE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
nano::keypair key1;
nano::send_block send2 (send1.hash (), key1.pub, nano::genesis_amount - 2 * nano::Gxrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (send1.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send2).code);
ASSERT_TRUE (store->block_exists (transaction, send2.hash ()));
ASSERT_TRUE (store->pending_exists (transaction, nano::pending_key (key1.pub, send2.hash ())));
nano::send_block send3 (send2.hash (), nano::genesis_account, nano::genesis_amount - 3 * nano::Gxrb_ratio, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (send2.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send3).code);
ASSERT_TRUE (store->block_exists (transaction, send3.hash ()));
ASSERT_TRUE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send3.hash ())));
// Pruning action
ASSERT_EQ (2, ledger.pruning_action (transaction, send2.hash (), 1));
ASSERT_FALSE (store->block_exists (transaction, send2.hash ()));
ASSERT_TRUE (store->pruned_exists (transaction, send2.hash ()));
ASSERT_FALSE (store->block_exists (transaction, send1.hash ()));
ASSERT_TRUE (store->pruned_exists (transaction, send1.hash ()));
ASSERT_TRUE (store->block_exists (transaction, genesis.hash ()));
nano::pending_info info1;
ASSERT_FALSE (store->pending_get (transaction, nano::pending_key (nano::genesis_account, send1.hash ()), info1));
ASSERT_EQ (nano::genesis_account, info1.source);
ASSERT_EQ (nano::Gxrb_ratio, info1.amount.number ());
ASSERT_EQ (nano::epoch::epoch_0, info1.epoch);
nano::pending_info info2;
ASSERT_FALSE (store->pending_get (transaction, nano::pending_key (key1.pub, send2.hash ()), info2));
ASSERT_EQ (nano::genesis_account, info2.source);
ASSERT_EQ (nano::Gxrb_ratio, info2.amount.number ());
ASSERT_EQ (nano::epoch::epoch_0, info2.epoch);
// Receiving pruned block
nano::receive_block receive1 (send3.hash (), send1.hash (), nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (send3.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
ASSERT_EQ (2, ledger.cache.pruned_count);
ASSERT_EQ (5, ledger.cache.block_count);
// Rollback receive block
ASSERT_FALSE (ledger.rollback (transaction, receive1.hash ()));
nano::pending_info info3;
ASSERT_FALSE (store->pending_get (transaction, nano::pending_key (nano::genesis_account, send1.hash ()), info3));
ASSERT_NE (nano::genesis_account, info3.source); // Tradeoff to not store pruned blocks accounts
ASSERT_EQ (nano::Gxrb_ratio, info3.amount.number ());
ASSERT_EQ (nano::epoch::epoch_0, info3.epoch);
// Process receive block again
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
ASSERT_EQ (2, ledger.cache.pruned_count);
ASSERT_EQ (5, ledger.cache.block_count);
// Receiving pruned block (open)
nano::open_block open1 (send2.hash (), nano::genesis_account, key1.pub, key1.prv, key1.pub, *pool.generate (key1.pub));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, open1).code);
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (key1.pub, send2.hash ())));
ASSERT_EQ (2, ledger.cache.pruned_count);
ASSERT_EQ (6, ledger.cache.block_count);
// Rollback open block
ASSERT_FALSE (ledger.rollback (transaction, open1.hash ()));
nano::pending_info info4;
ASSERT_FALSE (store->pending_get (transaction, nano::pending_key (key1.pub, send2.hash ()), info4));
ASSERT_NE (nano::genesis_account, info4.source); // Tradeoff to not store pruned blocks accounts
ASSERT_EQ (nano::Gxrb_ratio, info4.amount.number ());
ASSERT_EQ (nano::epoch::epoch_0, info4.epoch);
// Process open block again
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, open1).code);
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (key1.pub, send2.hash ())));
ASSERT_EQ (2, ledger.cache.pruned_count);
ASSERT_EQ (6, ledger.cache.block_count);
}

TEST (ledger, pruning_process_error)
{
nano::logger_mt logger;
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
nano::stat stats;
nano::ledger ledger (*store, stats);
ledger.pruning = true;
nano::genesis genesis;
auto transaction (store->tx_begin_write ());
store->initialize (transaction, genesis, ledger.cache);
nano::work_pool pool (std::numeric_limits<unsigned>::max ());
nano::state_block send1 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, nano::genesis_account, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (genesis.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
ASSERT_EQ (0, ledger.cache.pruned_count);
ASSERT_EQ (2, ledger.cache.block_count);
// Pruning action for latest block (not valid action)
ASSERT_EQ (1, ledger.pruning_action (transaction, send1.hash (), 1));
ASSERT_FALSE (store->block_exists (transaction, send1.hash ()));
ASSERT_TRUE (store->pruned_exists (transaction, send1.hash ()));
// Attempt to process pruned block again
ASSERT_EQ (nano::process_result::old, ledger.process (transaction, send1).code);
// Attept to process new block after pruned
nano::state_block send2 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio * 2, nano::genesis_account, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *pool.generate (send1.hash ()));
ASSERT_EQ (nano::process_result::gap_previous, ledger.process (transaction, send2).code);
ASSERT_EQ (1, ledger.cache.pruned_count);
ASSERT_EQ (2, ledger.cache.block_count);
}

TEST (ledger, pruning_legacy_blocks)
{
nano::logger_mt logger;
Expand Down Expand Up @@ -3598,4 +3770,4 @@ TEST (ledger, hash_root_random)
done = (root_hash.first == send2.hash ()) && (root_hash.second == send2.root ().as_block_hash ());
ASSERT_LE (iteration, 1000);
}
}
}
Loading

0 comments on commit 27c1365

Please sign in to comment.