Attach sideband to block (#2596)

* Move epoch from secure to nano_lib

* Attach sideband to block and always (de)serialize along with it

Using the sideband is only valid for blocks that were processed with code `progress`, otherwise they may not be set (important examples: old, fork).

* Make sideband optional to ensure usage correctness

* Interim

* Use new nano::optional_ptr to hold the sideband

* Adjust some tests to ensure two nodes don't simultaneously process the same block object

* Update comment
This commit is contained in:
Guilherme Lawless 2020-03-02 22:10:54 +00:00 committed by GitHub
commit 62fc659143
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 705 additions and 687 deletions

View file

@ -90,7 +90,6 @@ TEST (block_store, block_details_serialization)
TEST (block_store, sideband_serialization)
{
nano::block_sideband sideband1;
sideband1.type = nano::block_type::receive;
sideband1.account = 1;
sideband1.balance = 2;
sideband1.height = 3;
@ -99,12 +98,11 @@ TEST (block_store, sideband_serialization)
std::vector<uint8_t> vector;
{
nano::vectorstream stream1 (vector);
sideband1.serialize (stream1);
sideband1.serialize (stream1, nano::block_type::receive);
}
nano::bufferstream stream2 (vector.data (), vector.size ());
nano::block_sideband sideband2;
sideband2.type = nano::block_type::receive;
ASSERT_FALSE (sideband2.deserialize (stream2));
ASSERT_FALSE (sideband2.deserialize (stream2, nano::block_type::receive));
ASSERT_EQ (sideband1.account, sideband2.account);
ASSERT_EQ (sideband1.balance, sideband2.balance);
ASSERT_EQ (sideband1.height, sideband2.height);
@ -118,13 +116,13 @@ TEST (block_store, add_item)
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
nano::open_block block (0, 1, 0, nano::keypair ().prv, 0, 0);
block.sideband_set ({});
auto hash1 (block.hash ());
auto transaction (store->tx_begin_write ());
auto latest1 (store->block_get (transaction, hash1));
ASSERT_EQ (nullptr, latest1);
ASSERT_FALSE (store->block_exists (transaction, hash1));
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, hash1, block, sideband);
store->block_put (transaction, hash1, block);
auto latest2 (store->block_get (transaction, hash1));
ASSERT_NE (nullptr, latest2);
ASSERT_EQ (block, *latest2);
@ -141,20 +139,30 @@ TEST (block_store, clear_successor)
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
nano::open_block block1 (0, 1, 0, nano::keypair ().prv, 0, 0);
block1.sideband_set ({});
auto transaction (store->tx_begin_write ());
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, block1.hash (), block1, sideband);
store->block_put (transaction, block1.hash (), block1);
nano::open_block block2 (0, 2, 0, nano::keypair ().prv, 0, 0);
store->block_put (transaction, block2.hash (), block2, sideband);
ASSERT_NE (nullptr, store->block_get (transaction, block1.hash (), &sideband));
ASSERT_EQ (0, sideband.successor.number ());
sideband.successor = block2.hash ();
store->block_put (transaction, block1.hash (), block1, sideband);
ASSERT_NE (nullptr, store->block_get (transaction, block1.hash (), &sideband));
ASSERT_EQ (block2.hash (), sideband.successor);
block2.sideband_set ({});
store->block_put (transaction, block2.hash (), block2);
auto block2_store (store->block_get (transaction, block1.hash ()));
ASSERT_NE (nullptr, block2_store);
ASSERT_EQ (0, block2_store->sideband ().successor.number ());
auto modified_sideband = block2_store->sideband ();
modified_sideband.successor = block2.hash ();
block1.sideband_set (modified_sideband);
store->block_put (transaction, block1.hash (), block1);
{
auto block1_store (store->block_get (transaction, block1.hash ()));
ASSERT_NE (nullptr, block1_store);
ASSERT_EQ (block2.hash (), block1_store->sideband ().successor);
}
store->block_successor_clear (transaction, block1.hash ());
ASSERT_NE (nullptr, store->block_get (transaction, block1.hash (), &sideband));
ASSERT_EQ (0, sideband.successor.number ());
{
auto block1_store (store->block_get (transaction, block1.hash ()));
ASSERT_NE (nullptr, block1_store);
ASSERT_EQ (0, block1_store->sideband ().successor.number ());
}
}
TEST (block_store, add_nonempty_block)
@ -164,13 +172,13 @@ TEST (block_store, add_nonempty_block)
ASSERT_TRUE (!store->init_error ());
nano::keypair key1;
nano::open_block block (0, 1, 0, nano::keypair ().prv, 0, 0);
block.sideband_set ({});
auto hash1 (block.hash ());
block.signature = nano::sign_message (key1.prv, key1.pub, hash1);
auto transaction (store->tx_begin_write ());
auto latest1 (store->block_get (transaction, hash1));
ASSERT_EQ (nullptr, latest1);
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, hash1, block, sideband);
store->block_put (transaction, hash1, block);
auto latest2 (store->block_get (transaction, hash1));
ASSERT_NE (nullptr, latest2);
ASSERT_EQ (block, *latest2);
@ -183,21 +191,21 @@ TEST (block_store, add_two_items)
ASSERT_TRUE (!store->init_error ());
nano::keypair key1;
nano::open_block block (0, 1, 1, nano::keypair ().prv, 0, 0);
block.sideband_set ({});
auto hash1 (block.hash ());
block.signature = nano::sign_message (key1.prv, key1.pub, hash1);
auto transaction (store->tx_begin_write ());
auto latest1 (store->block_get (transaction, hash1));
ASSERT_EQ (nullptr, latest1);
nano::open_block block2 (0, 1, 3, nano::keypair ().prv, 0, 0);
block2.sideband_set ({});
block2.hashables.account = 3;
auto hash2 (block2.hash ());
block2.signature = nano::sign_message (key1.prv, key1.pub, hash2);
auto latest2 (store->block_get (transaction, hash2));
ASSERT_EQ (nullptr, latest2);
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, hash1, block, sideband);
nano::block_sideband sideband2 (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, hash2, block2, sideband2);
store->block_put (transaction, hash1, block);
store->block_put (transaction, hash2, block2);
auto latest3 (store->block_get (transaction, hash1));
ASSERT_NE (nullptr, latest3);
ASSERT_EQ (block, *latest3);
@ -215,15 +223,15 @@ TEST (block_store, add_receive)
nano::keypair key1;
nano::keypair key2;
nano::open_block block1 (0, 1, 0, nano::keypair ().prv, 0, 0);
block1.sideband_set ({});
auto transaction (store->tx_begin_write ());
nano::block_sideband sideband1 (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, block1.hash (), block1, sideband1);
store->block_put (transaction, block1.hash (), block1);
nano::receive_block block (block1.hash (), 1, nano::keypair ().prv, 2, 3);
block.sideband_set ({});
nano::block_hash hash1 (block.hash ());
auto latest1 (store->block_get (transaction, hash1));
ASSERT_EQ (nullptr, latest1);
nano::block_sideband sideband (nano::block_type::receive, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, hash1, block, sideband);
store->block_put (transaction, hash1, block);
auto latest2 (store->block_get (transaction, hash1));
ASSERT_NE (nullptr, latest2);
ASSERT_EQ (block, *latest2);
@ -463,9 +471,9 @@ TEST (block_store, one_block)
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
nano::open_block block1 (0, 1, 0, nano::keypair ().prv, 0, 0);
block1.sideband_set ({});
auto transaction (store->tx_begin_write ());
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, block1.hash (), block1, sideband);
store->block_put (transaction, block1.hash (), block1);
ASSERT_TRUE (store->block_exists (transaction, block1.hash ()));
}
@ -560,19 +568,19 @@ TEST (block_store, two_block)
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
nano::open_block block1 (0, 1, 1, nano::keypair ().prv, 0, 0);
block1.sideband_set ({});
block1.hashables.account = 1;
std::vector<nano::block_hash> hashes;
std::vector<nano::open_block> blocks;
hashes.push_back (block1.hash ());
blocks.push_back (block1);
auto transaction (store->tx_begin_write ());
nano::block_sideband sideband1 (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, hashes[0], block1, sideband1);
store->block_put (transaction, hashes[0], block1);
nano::open_block block2 (0, 1, 2, nano::keypair ().prv, 0, 0);
block2.sideband_set ({});
hashes.push_back (block2.hash ());
blocks.push_back (block2);
nano::block_sideband sideband2 (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, hashes[1], block2, sideband2);
store->block_put (transaction, hashes[1], block2);
ASSERT_TRUE (store->block_exists (transaction, block1.hash ()));
ASSERT_TRUE (store->block_exists (transaction, block2.hash ()));
}
@ -755,12 +763,12 @@ TEST (block_store, block_replace)
auto store = nano::make_store (logger, nano::unique_path ());
ASSERT_TRUE (!store->init_error ());
nano::send_block send1 (0, 0, 0, nano::keypair ().prv, 0, 1);
send1.sideband_set ({});
nano::send_block send2 (0, 0, 0, nano::keypair ().prv, 0, 2);
send2.sideband_set ({});
auto transaction (store->tx_begin_write ());
nano::block_sideband sideband1 (nano::block_type::send, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, 0, send1, sideband1);
nano::block_sideband sideband2 (nano::block_type::send, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, 0, send2, sideband2);
store->block_put (transaction, 0, send1);
store->block_put (transaction, 0, send2);
auto block3 (store->block_get (transaction, 0));
ASSERT_NE (nullptr, block3);
ASSERT_EQ (2, block3->block_work ());
@ -775,9 +783,9 @@ TEST (block_store, block_count)
auto transaction (store->tx_begin_write ());
ASSERT_EQ (0, store->block_count (transaction).sum ());
nano::open_block block (0, 1, 0, nano::keypair ().prv, 0, 0);
block.sideband_set ({});
auto hash1 (block.hash ());
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, hash1, block, sideband);
store->block_put (transaction, hash1, block);
}
auto transaction (store->tx_begin_read ());
ASSERT_EQ (1, store->block_count (transaction).sum ());
@ -1172,13 +1180,13 @@ TEST (block_store, state_block)
nano::genesis genesis;
nano::keypair key1;
nano::state_block block1 (1, genesis.hash (), 3, 4, 6, key1.prv, key1.pub, 7);
block1.sideband_set ({});
{
nano::ledger_cache ledger_cache;
auto transaction (store->tx_begin_write ());
store->initialize (transaction, genesis, ledger_cache);
ASSERT_EQ (nano::block_type::state, block1.type ());
nano::block_sideband sideband1 (nano::block_type::state, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (transaction, block1.hash (), block1, sideband1);
store->block_put (transaction, block1.hash (), block1);
ASSERT_TRUE (store->block_exists (transaction, block1.hash ()));
auto block2 (store->block_get (transaction, block1.hash ()));
ASSERT_NE (nullptr, block2);
@ -1209,10 +1217,9 @@ TEST (mdb_block_store, upgrade_sideband_genesis)
nano::ledger_cache ledger_cache;
store.initialize (transaction, genesis, ledger_cache);
modify_account_info_to_v13 (store, transaction, nano::genesis_account, nano::genesis_hash);
nano::block_sideband sideband;
auto genesis_block (store.block_get (transaction, genesis.hash (), &sideband));
auto genesis_block (store.block_get (transaction, genesis.hash ()));
ASSERT_NE (nullptr, genesis_block);
ASSERT_EQ (1, sideband.height);
ASSERT_EQ (1, genesis_block->sideband ().height);
ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "state_v1", MDB_CREATE, &store.state_blocks_v1));
write_sideband_v12 (store, transaction, *genesis_block, 0, store.open_blocks);
nano::block_sideband_v14 sideband1;
@ -1226,10 +1233,9 @@ TEST (mdb_block_store, upgrade_sideband_genesis)
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_read ());
ASSERT_TRUE (store.full_sideband (transaction));
nano::block_sideband sideband;
auto genesis_block (store.block_get (transaction, genesis.hash (), &sideband));
auto genesis_block (store.block_get (transaction, genesis.hash ()));
ASSERT_NE (nullptr, genesis_block);
ASSERT_EQ (1, sideband.height);
ASSERT_EQ (1, genesis_block->sideband ().height);
}
TEST (mdb_block_store, upgrade_sideband_two_blocks)
@ -1265,14 +1271,12 @@ TEST (mdb_block_store, upgrade_sideband_two_blocks)
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_read ());
ASSERT_TRUE (store.full_sideband (transaction));
nano::block_sideband sideband;
auto genesis_block (store.block_get (transaction, genesis.hash (), &sideband));
auto genesis_block (store.block_get (transaction, genesis.hash ()));
ASSERT_NE (nullptr, genesis_block);
ASSERT_EQ (1, sideband.height);
nano::block_sideband sideband2;
auto block2 (store.block_get (transaction, hash2, &sideband2));
ASSERT_EQ (1, genesis_block->sideband ().height);
auto block2 (store.block_get (transaction, hash2));
ASSERT_NE (nullptr, block2);
ASSERT_EQ (2, sideband2.height);
ASSERT_EQ (2, block2->sideband ().height);
}
TEST (mdb_block_store, upgrade_sideband_two_accounts)
@ -1314,18 +1318,15 @@ TEST (mdb_block_store, upgrade_sideband_two_accounts)
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_read ());
ASSERT_TRUE (store.full_sideband (transaction));
nano::block_sideband sideband;
auto genesis_block (store.block_get (transaction, genesis.hash (), &sideband));
auto genesis_block (store.block_get (transaction, genesis.hash ()));
ASSERT_NE (nullptr, genesis_block);
ASSERT_EQ (1, sideband.height);
nano::block_sideband sideband2;
auto block2 (store.block_get (transaction, hash2, &sideband2));
ASSERT_EQ (1, genesis_block->sideband ().height);
auto block2 (store.block_get (transaction, hash2));
ASSERT_NE (nullptr, block2);
ASSERT_EQ (2, sideband2.height);
nano::block_sideband sideband3;
auto block3 (store.block_get (transaction, hash3, &sideband3));
ASSERT_EQ (2, block2->sideband ().height);
auto block3 (store.block_get (transaction, hash3));
ASSERT_NE (nullptr, block3);
ASSERT_EQ (1, sideband3.height);
ASSERT_EQ (1, block3->sideband ().height);
}
TEST (mdb_block_store, insert_after_legacy)
@ -1406,9 +1407,8 @@ TEST (mdb_block_store, upgrade_sideband_epoch)
auto transaction (store.tx_begin_write ());
ASSERT_TRUE (store.full_sideband (transaction));
ASSERT_EQ (nano::epoch::epoch_1, store.block_version (transaction, hash2));
nano::block_sideband sideband;
auto block1 (store.block_get (transaction, hash2, &sideband));
ASSERT_NE (0, sideband.height);
auto block1 (store.block_get (transaction, hash2));
ASSERT_NE (0, block1->sideband ().height);
nano::state_block block2 (nano::test_genesis_key.pub, hash2, nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (hash2));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, block2).code);
ASSERT_EQ (nano::epoch::epoch_1, store.block_version (transaction, block2.hash ()));
@ -1452,42 +1452,30 @@ TEST (mdb_block_store, sideband_height)
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state_receive).code);
nano::open_block open (state_send3.hash (), nano::test_genesis_key.pub, key3.pub, key3.prv, key3.pub, *pool.generate (key3.pub));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, open).code);
nano::block_sideband sideband1;
auto block1 (store.block_get (transaction, genesis.hash (), &sideband1));
ASSERT_EQ (sideband1.height, 1);
nano::block_sideband sideband2;
auto block2 (store.block_get (transaction, send.hash (), &sideband2));
ASSERT_EQ (sideband2.height, 2);
nano::block_sideband sideband3;
auto block3 (store.block_get (transaction, receive.hash (), &sideband3));
ASSERT_EQ (sideband3.height, 3);
nano::block_sideband sideband4;
auto block4 (store.block_get (transaction, change.hash (), &sideband4));
ASSERT_EQ (sideband4.height, 4);
nano::block_sideband sideband5;
auto block5 (store.block_get (transaction, state_send1.hash (), &sideband5));
ASSERT_EQ (sideband5.height, 5);
nano::block_sideband sideband6;
auto block6 (store.block_get (transaction, state_send2.hash (), &sideband6));
ASSERT_EQ (sideband6.height, 6);
nano::block_sideband sideband7;
auto block7 (store.block_get (transaction, state_send3.hash (), &sideband7));
ASSERT_EQ (sideband7.height, 7);
nano::block_sideband sideband8;
auto block8 (store.block_get (transaction, state_open.hash (), &sideband8));
ASSERT_EQ (sideband8.height, 1);
nano::block_sideband sideband9;
auto block9 (store.block_get (transaction, epoch.hash (), &sideband9));
ASSERT_EQ (sideband9.height, 2);
nano::block_sideband sideband10;
auto block10 (store.block_get (transaction, epoch_open.hash (), &sideband10));
ASSERT_EQ (sideband10.height, 1);
nano::block_sideband sideband11;
auto block11 (store.block_get (transaction, state_receive.hash (), &sideband11));
ASSERT_EQ (sideband11.height, 2);
nano::block_sideband sideband12;
auto block12 (store.block_get (transaction, open.hash (), &sideband12));
ASSERT_EQ (sideband12.height, 1);
auto block1 (store.block_get (transaction, genesis.hash ()));
ASSERT_EQ (block1->sideband ().height, 1);
auto block2 (store.block_get (transaction, send.hash ()));
ASSERT_EQ (block2->sideband ().height, 2);
auto block3 (store.block_get (transaction, receive.hash ()));
ASSERT_EQ (block3->sideband ().height, 3);
auto block4 (store.block_get (transaction, change.hash ()));
ASSERT_EQ (block4->sideband ().height, 4);
auto block5 (store.block_get (transaction, state_send1.hash ()));
ASSERT_EQ (block5->sideband ().height, 5);
auto block6 (store.block_get (transaction, state_send2.hash ()));
ASSERT_EQ (block6->sideband ().height, 6);
auto block7 (store.block_get (transaction, state_send3.hash ()));
ASSERT_EQ (block7->sideband ().height, 7);
auto block8 (store.block_get (transaction, state_open.hash ()));
ASSERT_EQ (block8->sideband ().height, 1);
auto block9 (store.block_get (transaction, epoch.hash ()));
ASSERT_EQ (block9->sideband ().height, 2);
auto block10 (store.block_get (transaction, epoch_open.hash ()));
ASSERT_EQ (block10->sideband ().height, 1);
auto block11 (store.block_get (transaction, state_receive.hash ()));
ASSERT_EQ (block11->sideband ().height, 2);
auto block12 (store.block_get (transaction, open.hash ()));
ASSERT_EQ (block12->sideband ().height, 1);
}
TEST (block_store, peers)
@ -1751,14 +1739,12 @@ TEST (mdb_block_store, upgrade_v14_v15)
ASSERT_NE (error_get_state_v1, MDB_SUCCESS);
// Check that the epochs are set correctly for the sideband, accounts and pending entries
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_send.hash (), &sideband);
auto block = store.block_get (transaction, state_send.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
block = store.block_get (transaction, send.hash (), &sideband);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
block = store.block_get (transaction, send.hash ());
ASSERT_NE (block, nullptr);
nano::block_sideband sideband1;
ASSERT_EQ (sideband1.details.epoch, nano::epoch::epoch_0);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_0);
ASSERT_EQ (info.epoch (), nano::epoch::epoch_1);
nano::pending_info pending_info;
store.pending_get (transaction, nano::pending_key (nano::test_genesis_key.pub, send.hash ()), pending_info);
@ -1818,7 +1804,7 @@ TEST (mdb_block_store, upgrade_v16_v17)
nano::state_block block2 (nano::test_genesis_key.pub, block1.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio - 1, nano::test_genesis_key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (block1.hash ()));
nano::state_block block3 (nano::test_genesis_key.pub, block2.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio - 2, nano::test_genesis_key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (block2.hash ()));
auto code = [block1, block2, block3](auto confirmation_height, nano::block_hash const & expected_cemented_frontier) {
auto code = [&block1, &block2, &block3](auto confirmation_height, nano::block_hash const & expected_cemented_frontier) {
auto path (nano::unique_path ());
nano::mdb_val value;
{
@ -1937,124 +1923,112 @@ TEST (mdb_block_store, upgrade_v17_v18)
// Check that sidebands are correctly populated
{
// Non-state unaffected
nano::block_sideband sideband;
auto block = store.block_get (transaction, send_zero.hash (), &sideband);
auto block = store.block_get (transaction, send_zero.hash ());
ASSERT_NE (block, nullptr);
// All defaults
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_0);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_0);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_FALSE (block->sideband ().details.is_send);
ASSERT_FALSE (block->sideband ().details.is_receive);
}
{
// State receive from old zero send
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_receive_zero.hash (), &sideband);
auto block = store.block_get (transaction, state_receive_zero.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_0);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_TRUE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_0);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_FALSE (block->sideband ().details.is_send);
ASSERT_TRUE (block->sideband ().details.is_receive);
}
{
// Epoch
nano::block_sideband sideband;
auto block = store.block_get (transaction, epoch.hash (), &sideband);
auto block = store.block_get (transaction, epoch.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
ASSERT_TRUE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
ASSERT_TRUE (block->sideband ().details.is_epoch);
ASSERT_FALSE (block->sideband ().details.is_send);
ASSERT_FALSE (block->sideband ().details.is_receive);
}
{
// State send
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_send.hash (), &sideband);
auto block = store.block_get (transaction, state_send.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_TRUE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_TRUE (block->sideband ().details.is_send);
ASSERT_FALSE (block->sideband ().details.is_receive);
}
{
// State receive
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_receive.hash (), &sideband);
auto block = store.block_get (transaction, state_receive.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_TRUE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_FALSE (block->sideband ().details.is_send);
ASSERT_TRUE (block->sideband ().details.is_receive);
}
{
// State change
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_change.hash (), &sideband);
auto block = store.block_get (transaction, state_change.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_FALSE (block->sideband ().details.is_send);
ASSERT_FALSE (block->sideband ().details.is_receive);
}
{
// State send + change
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_send_change.hash (), &sideband);
auto block = store.block_get (transaction, state_send_change.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_TRUE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_TRUE (block->sideband ().details.is_send);
ASSERT_FALSE (block->sideband ().details.is_receive);
}
{
// Epoch on unopened account
nano::block_sideband sideband;
auto block = store.block_get (transaction, epoch_first.hash (), &sideband);
auto block = store.block_get (transaction, epoch_first.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_2);
ASSERT_TRUE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_2);
ASSERT_TRUE (block->sideband ().details.is_epoch);
ASSERT_FALSE (block->sideband ().details.is_send);
ASSERT_FALSE (block->sideband ().details.is_receive);
}
{
// State open following epoch
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_receive2.hash (), &sideband);
auto block = store.block_get (transaction, state_receive2.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_2);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_TRUE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_2);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_FALSE (block->sideband ().details.is_send);
ASSERT_TRUE (block->sideband ().details.is_receive);
}
{
// Another state send
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_send2.hash (), &sideband);
auto block = store.block_get (transaction, state_send2.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_TRUE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_TRUE (block->sideband ().details.is_send);
ASSERT_FALSE (block->sideband ().details.is_receive);
}
{
// State open
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_open.hash (), &sideband);
auto block = store.block_get (transaction, state_open.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_TRUE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_FALSE (block->sideband ().details.is_send);
ASSERT_TRUE (block->sideband ().details.is_receive);
}
{
// State send to an epoch link
nano::block_sideband sideband;
auto block = store.block_get (transaction, state_send_epoch_link.hash (), &sideband);
auto block = store.block_get (transaction, state_send_epoch_link.hash ());
ASSERT_NE (block, nullptr);
ASSERT_EQ (sideband.details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_TRUE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_EQ (block->sideband ().details.epoch, nano::epoch::epoch_1);
ASSERT_FALSE (block->sideband ().details.is_epoch);
ASSERT_TRUE (block->sideband ().details.is_send);
ASSERT_FALSE (block->sideband ().details.is_receive);
}
// Version should be correct
ASSERT_LT (17, store.version_get (transaction));
@ -2166,8 +2140,8 @@ TEST (mdb_block_store, upgrade_confirmation_height_many)
{
nano::account account (i);
nano::open_block open (1, nano::genesis_account, 3, nullptr);
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store.block_put (transaction, open.hash (), open, sideband);
open.sideband_set ({});
store.block_put (transaction, open.hash (), open);
nano::account_info_v13 account_info_v13 (open.hash (), open.hash (), open.hash (), 3, 4, 1, nano::epoch::epoch_0);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v0, nano::mdb_val (account), nano::mdb_val (account_info_v13), 0));
ASSERT_EQ (status, 0);
@ -2224,6 +2198,7 @@ TEST (block_store, reset_renew_existing_transaction)
nano::keypair key1;
nano::open_block block (0, 1, 1, nano::keypair ().prv, 0, 0);
block.sideband_set ({});
auto hash1 (block.hash ());
auto read_transaction = store->tx_begin_read ();
@ -2237,8 +2212,7 @@ TEST (block_store, reset_renew_existing_transaction)
// Write the block
{
auto write_transaction (store->tx_begin_write ());
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store->block_put (write_transaction, hash1, block, sideband);
store->block_put (write_transaction, hash1, block);
}
read_transaction.renew ();
@ -2297,11 +2271,10 @@ void write_sideband_v12 (nano::mdb_store & store_a, nano::transaction & transact
void write_sideband_v14 (nano::mdb_store & store_a, nano::transaction & transaction_a, nano::block const & block_a, MDB_dbi db_a)
{
nano::block_sideband sideband;
auto block = store_a.block_get (transaction_a, block_a.hash (), &sideband);
auto block = store_a.block_get (transaction_a, block_a.hash ());
ASSERT_NE (block, nullptr);
nano::block_sideband_v14 sideband_v14 (sideband.type, sideband.account, sideband.successor, sideband.balance, sideband.timestamp, sideband.height);
nano::block_sideband_v14 sideband_v14 (block->type (), block->sideband ().account, block->sideband ().successor, block->sideband ().balance, block->sideband ().timestamp, block->sideband ().height);
std::vector<uint8_t> data;
{
nano::vectorstream stream (data);
@ -2310,23 +2283,22 @@ void write_sideband_v14 (nano::mdb_store & store_a, nano::transaction & transact
}
MDB_val val{ data.size (), data.data () };
ASSERT_FALSE (mdb_put (store_a.env.tx (transaction_a), sideband.details.epoch == nano::epoch::epoch_0 ? store_a.state_blocks_v0 : store_a.state_blocks_v1, nano::mdb_val (block_a.hash ()), &val, 0));
ASSERT_FALSE (mdb_put (store_a.env.tx (transaction_a), block->sideband ().details.epoch == nano::epoch::epoch_0 ? store_a.state_blocks_v0 : store_a.state_blocks_v1, nano::mdb_val (block_a.hash ()), &val, 0));
}
void write_sideband_v15 (nano::mdb_store & store_a, nano::transaction & transaction_a, nano::block const & block_a)
{
nano::block_sideband sideband;
auto block = store_a.block_get (transaction_a, block_a.hash (), &sideband);
auto block = store_a.block_get (transaction_a, block_a.hash ());
ASSERT_NE (block, nullptr);
ASSERT_LE (sideband.details.epoch, nano::epoch::max);
ASSERT_LE (block->sideband ().details.epoch, nano::epoch::max);
// Simulated by writing 0 on every of the most significant bits, leaving out epoch only, as if pre-upgrade
nano::block_sideband sideband_v15 (sideband.type, sideband.account, sideband.successor, sideband.balance, sideband.timestamp, sideband.height, sideband.details.epoch, false, false, false);
nano::block_sideband sideband_v15 (block->sideband ().account, block->sideband ().successor, block->sideband ().balance, block->sideband ().timestamp, block->sideband ().height, block->sideband ().details.epoch, false, false, false);
std::vector<uint8_t> data;
{
nano::vectorstream stream (data);
block_a.serialize (stream);
sideband_v15.serialize (stream);
sideband_v15.serialize (stream, block_a.type ());
}
MDB_val val{ data.size (), data.data () };

View file

@ -1,5 +1,5 @@
#include <nano/lib/epoch.hpp>
#include <nano/secure/common.hpp>
#include <nano/secure/epoch.hpp>
#include <gtest/gtest.h>

View file

@ -71,6 +71,21 @@ TEST (system, system_genesis)
}
}
TEST (ledger, process_modifies_sideband)
{
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);
nano::genesis genesis;
store->initialize (store->tx_begin_write (), 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::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (store->tx_begin_write (), send1).code);
ASSERT_EQ (send1.sideband ().timestamp, store->block_get (store->tx_begin_read (), send1.hash ())->sideband ().timestamp);
}
// Create a send block and publish it.
TEST (ledger, process_send)
{
@ -92,6 +107,8 @@ TEST (ledger, process_send)
ASSERT_EQ (1, info1.block_count);
// This was a valid block, it should progress.
auto return1 (ledger.process (transaction, send));
ASSERT_EQ (nano::test_genesis_key.pub, send.sideband ().account);
ASSERT_EQ (2, send.sideband ().height);
ASSERT_EQ (nano::genesis_amount - 50, ledger.amount (transaction, hash1));
ASSERT_TRUE (store->frontier_get (transaction, info1.head).is_zero ());
ASSERT_EQ (nano::test_genesis_key.pub, store->frontier_get (transaction, hash1));
@ -113,6 +130,10 @@ TEST (ledger, process_send)
nano::block_hash hash2 (open.hash ());
// This was a valid block, it should progress.
auto return2 (ledger.process (transaction, open));
ASSERT_EQ (nano::process_result::progress, return2.code);
ASSERT_EQ (key2.pub, open.sideband ().account);
ASSERT_EQ (nano::genesis_amount - 50, open.sideband ().balance.number ());
ASSERT_EQ (1, open.sideband ().height);
ASSERT_EQ (nano::genesis_amount - 50, ledger.amount (transaction, hash2));
ASSERT_EQ (nano::process_result::progress, return2.code);
ASSERT_EQ (key2.pub, return2.account);
@ -190,6 +211,9 @@ TEST (ledger, process_receive)
auto return1 (ledger.process (transaction, open));
ASSERT_EQ (nano::process_result::progress, return1.code);
ASSERT_EQ (key2.pub, return1.account);
ASSERT_EQ (key2.pub, open.sideband ().account);
ASSERT_EQ (nano::genesis_amount - 50, open.sideband ().balance.number ());
ASSERT_EQ (1, open.sideband ().height);
ASSERT_EQ (nano::genesis_amount - 50, return1.amount.number ());
ASSERT_EQ (nano::genesis_amount - 50, ledger.weight (key3.pub));
nano::send_block send2 (hash1, key2.pub, 25, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (hash1));
@ -199,6 +223,9 @@ TEST (ledger, process_receive)
auto hash4 (receive.hash ());
ASSERT_EQ (key2.pub, store->frontier_get (transaction, hash2));
auto return2 (ledger.process (transaction, receive));
ASSERT_EQ (key2.pub, receive.sideband ().account);
ASSERT_EQ (nano::genesis_amount - 25, receive.sideband ().balance.number ());
ASSERT_EQ (2, receive.sideband ().height);
ASSERT_EQ (25, ledger.amount (transaction, hash4));
ASSERT_TRUE (store->frontier_get (transaction, hash2).is_zero ());
ASSERT_EQ (key2.pub, store->frontier_get (transaction, hash4));
@ -1680,22 +1707,21 @@ TEST (ledger, state_send_receive)
nano::state_block send1 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, nano::genesis_account, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
ASSERT_TRUE (store->block_exists (transaction, send1.hash ()));
nano::block_sideband sideband;
auto send2 (store->block_get (transaction, send1.hash (), &sideband));
auto send2 (store->block_get (transaction, send1.hash ()));
ASSERT_NE (nullptr, send2);
ASSERT_EQ (send1, *send2);
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, ledger.balance (transaction, send1.hash ()));
ASSERT_EQ (nano::Gxrb_ratio, ledger.amount (transaction, send1.hash ()));
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, ledger.weight (nano::genesis_account));
ASSERT_TRUE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
ASSERT_TRUE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_EQ (2, send2->sideband ().height);
ASSERT_TRUE (send2->sideband ().details.is_send);
ASSERT_FALSE (send2->sideband ().details.is_receive);
ASSERT_FALSE (send2->sideband ().details.is_epoch);
nano::state_block receive1 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount, send1.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send1.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_TRUE (store->block_exists (transaction, receive1.hash ()));
nano::block_sideband sideband2;
auto receive2 (store->block_get (transaction, receive1.hash (), &sideband2));
auto receive2 (store->block_get (transaction, receive1.hash ()));
ASSERT_NE (nullptr, receive2);
ASSERT_EQ (receive1, *receive2);
ASSERT_EQ (nano::genesis_amount, ledger.balance (transaction, receive1.hash ()));
@ -1703,9 +1729,10 @@ TEST (ledger, state_send_receive)
ASSERT_EQ (nano::genesis_amount, ledger.weight (nano::genesis_account));
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (nano::genesis_account, send1.hash ())));
ASSERT_EQ (store->account_count (transaction), ledger.cache.account_count);
ASSERT_FALSE (sideband2.details.is_send);
ASSERT_TRUE (sideband2.details.is_receive);
ASSERT_FALSE (sideband2.details.is_epoch);
ASSERT_EQ (3, receive2->sideband ().height);
ASSERT_FALSE (receive2->sideband ().details.is_send);
ASSERT_TRUE (receive2->sideband ().details.is_receive);
ASSERT_FALSE (receive2->sideband ().details.is_epoch);
}
TEST (ledger, state_receive)
@ -1731,16 +1758,16 @@ TEST (ledger, state_receive)
nano::state_block receive1 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount, send1.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send1.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_TRUE (store->block_exists (transaction, receive1.hash ()));
nano::block_sideband sideband;
auto receive2 (store->block_get (transaction, receive1.hash (), &sideband));
auto receive2 (store->block_get (transaction, receive1.hash ()));
ASSERT_NE (nullptr, receive2);
ASSERT_EQ (receive1, *receive2);
ASSERT_EQ (nano::genesis_amount, ledger.balance (transaction, receive1.hash ()));
ASSERT_EQ (nano::Gxrb_ratio, ledger.amount (transaction, receive1.hash ()));
ASSERT_EQ (nano::genesis_amount, ledger.weight (nano::genesis_account));
ASSERT_FALSE (sideband.details.is_send);
ASSERT_TRUE (sideband.details.is_receive);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_EQ (3, receive2->sideband ().height);
ASSERT_FALSE (receive2->sideband ().details.is_send);
ASSERT_TRUE (receive2->sideband ().details.is_receive);
ASSERT_FALSE (receive2->sideband ().details.is_epoch);
}
TEST (ledger, state_rep_change)
@ -1758,17 +1785,17 @@ TEST (ledger, state_rep_change)
nano::state_block change1 (nano::genesis_account, genesis.hash (), rep.pub, nano::genesis_amount, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, change1).code);
ASSERT_TRUE (store->block_exists (transaction, change1.hash ()));
nano::block_sideband sideband;
auto change2 (store->block_get (transaction, change1.hash (), &sideband));
auto change2 (store->block_get (transaction, change1.hash ()));
ASSERT_NE (nullptr, change2);
ASSERT_EQ (change1, *change2);
ASSERT_EQ (nano::genesis_amount, ledger.balance (transaction, change1.hash ()));
ASSERT_EQ (0, ledger.amount (transaction, change1.hash ()));
ASSERT_EQ (0, ledger.weight (nano::genesis_account));
ASSERT_EQ (nano::genesis_amount, ledger.weight (rep.pub));
ASSERT_FALSE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_EQ (2, change2->sideband ().height);
ASSERT_FALSE (change2->sideband ().details.is_send);
ASSERT_FALSE (change2->sideband ().details.is_receive);
ASSERT_FALSE (change2->sideband ().details.is_epoch);
}
TEST (ledger, state_open)
@ -1797,17 +1824,17 @@ TEST (ledger, state_open)
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, open1).code);
ASSERT_FALSE (store->pending_exists (transaction, nano::pending_key (destination.pub, send1.hash ())));
ASSERT_TRUE (store->block_exists (transaction, open1.hash ()));
nano::block_sideband sideband;
auto open2 (store->block_get (transaction, open1.hash (), &sideband));
auto open2 (store->block_get (transaction, open1.hash ()));
ASSERT_NE (nullptr, open2);
ASSERT_EQ (open1, *open2);
ASSERT_EQ (nano::Gxrb_ratio, ledger.balance (transaction, open1.hash ()));
ASSERT_EQ (nano::Gxrb_ratio, ledger.amount (transaction, open1.hash ()));
ASSERT_EQ (nano::genesis_amount, ledger.weight (nano::genesis_account));
ASSERT_EQ (ledger.cache.account_count, store->account_count (transaction));
ASSERT_FALSE (sideband.details.is_send);
ASSERT_TRUE (sideband.details.is_receive);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_EQ (1, open2->sideband ().height);
ASSERT_FALSE (open2->sideband ().details.is_send);
ASSERT_TRUE (open2->sideband ().details.is_receive);
ASSERT_FALSE (open2->sideband ().details.is_epoch);
}
// Make sure old block types can't be inserted after a state block.
@ -2050,17 +2077,17 @@ TEST (ledger, state_send_change)
nano::state_block send1 (nano::genesis_account, genesis.hash (), rep.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::genesis_account, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
ASSERT_TRUE (store->block_exists (transaction, send1.hash ()));
nano::block_sideband sideband;
auto send2 (store->block_get (transaction, send1.hash (), &sideband));
auto send2 (store->block_get (transaction, send1.hash ()));
ASSERT_NE (nullptr, send2);
ASSERT_EQ (send1, *send2);
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, ledger.balance (transaction, send1.hash ()));
ASSERT_EQ (nano::Gxrb_ratio, ledger.amount (transaction, send1.hash ()));
ASSERT_EQ (0, ledger.weight (nano::genesis_account));
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, ledger.weight (rep.pub));
ASSERT_TRUE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_EQ (2, send2->sideband ().height);
ASSERT_TRUE (send2->sideband ().details.is_send);
ASSERT_FALSE (send2->sideband ().details.is_receive);
ASSERT_FALSE (send2->sideband ().details.is_epoch);
}
TEST (ledger, state_receive_change)
@ -2087,17 +2114,17 @@ TEST (ledger, state_receive_change)
nano::state_block receive1 (nano::genesis_account, send1.hash (), rep.pub, nano::genesis_amount, send1.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send1.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code);
ASSERT_TRUE (store->block_exists (transaction, receive1.hash ()));
nano::block_sideband sideband2;
auto receive2 (store->block_get (transaction, receive1.hash (), &sideband2));
auto receive2 (store->block_get (transaction, receive1.hash ()));
ASSERT_NE (nullptr, receive2);
ASSERT_EQ (receive1, *receive2);
ASSERT_EQ (nano::genesis_amount, ledger.balance (transaction, receive1.hash ()));
ASSERT_EQ (nano::Gxrb_ratio, ledger.amount (transaction, receive1.hash ()));
ASSERT_EQ (0, ledger.weight (nano::genesis_account));
ASSERT_EQ (nano::genesis_amount, ledger.weight (rep.pub));
ASSERT_FALSE (sideband2.details.is_send);
ASSERT_TRUE (sideband2.details.is_receive);
ASSERT_FALSE (sideband2.details.is_epoch);
ASSERT_EQ (3, receive2->sideband ().height);
ASSERT_FALSE (receive2->sideband ().details.is_send);
ASSERT_TRUE (receive2->sideband ().details.is_receive);
ASSERT_FALSE (receive2->sideband ().details.is_epoch);
}
TEST (ledger, state_open_old)
@ -2341,13 +2368,9 @@ TEST (ledger, epoch_blocks_v1_general)
nano::keypair destination;
nano::state_block epoch1 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount, ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch1).code);
{
nano::block_sideband sideband;
(void)ledger.store.block_get (transaction, epoch1.hash (), &sideband);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_TRUE (sideband.details.is_epoch);
}
ASSERT_FALSE (epoch1.sideband ().details.is_send);
ASSERT_FALSE (epoch1.sideband ().details.is_receive);
ASSERT_TRUE (epoch1.sideband ().details.is_epoch);
nano::state_block epoch2 (nano::genesis_account, epoch1.hash (), nano::genesis_account, nano::genesis_amount, ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch1.hash ()));
ASSERT_EQ (nano::process_result::block_position, ledger.process (transaction, epoch2).code);
nano::account_info genesis_info;
@ -2359,37 +2382,25 @@ TEST (ledger, epoch_blocks_v1_general)
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch1).code);
ASSERT_FALSE (ledger.store.account_get (transaction, nano::genesis_account, genesis_info));
ASSERT_EQ (genesis_info.epoch (), nano::epoch::epoch_1);
{
nano::block_sideband sideband;
(void)ledger.store.block_get (transaction, epoch1.hash (), &sideband);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_TRUE (sideband.details.is_epoch);
}
ASSERT_FALSE (epoch1.sideband ().details.is_send);
ASSERT_FALSE (epoch1.sideband ().details.is_receive);
ASSERT_TRUE (epoch1.sideband ().details.is_epoch);
nano::change_block change1 (epoch1.hash (), nano::genesis_account, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch1.hash ()));
ASSERT_EQ (nano::process_result::block_position, ledger.process (transaction, change1).code);
nano::state_block send1 (nano::genesis_account, epoch1.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, destination.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch1.hash ()));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code);
{
nano::block_sideband sideband;
(void)ledger.store.block_get (transaction, send1.hash (), &sideband);
ASSERT_TRUE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_FALSE (sideband.details.is_epoch);
}
ASSERT_TRUE (send1.sideband ().details.is_send);
ASSERT_FALSE (send1.sideband ().details.is_receive);
ASSERT_FALSE (send1.sideband ().details.is_epoch);
nano::open_block open1 (send1.hash (), nano::genesis_account, destination.pub, destination.prv, destination.pub, *pool.generate (destination.pub));
ASSERT_EQ (nano::process_result::unreceivable, ledger.process (transaction, open1).code);
nano::state_block epoch3 (destination.pub, 0, nano::genesis_account, 0, ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (destination.pub));
ASSERT_EQ (nano::process_result::representative_mismatch, ledger.process (transaction, epoch3).code);
nano::state_block epoch4 (destination.pub, 0, 0, 0, ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (destination.pub));
ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch4).code);
{
nano::block_sideband sideband;
(void)ledger.store.block_get (transaction, epoch4.hash (), &sideband);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_receive);
ASSERT_TRUE (sideband.details.is_epoch);
}
ASSERT_FALSE (epoch4.sideband ().details.is_send);
ASSERT_FALSE (epoch4.sideband ().details.is_receive);
ASSERT_TRUE (epoch4.sideband ().details.is_epoch);
nano::receive_block receive1 (epoch4.hash (), send1.hash (), destination.prv, destination.pub, *pool.generate (epoch4.hash ()));
ASSERT_EQ (nano::process_result::block_position, ledger.process (transaction, receive1).code);
nano::state_block receive2 (destination.pub, epoch4.hash (), destination.pub, nano::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, *pool.generate (epoch4.hash ()));
@ -2399,13 +2410,9 @@ TEST (ledger, epoch_blocks_v1_general)
ASSERT_EQ (nano::Gxrb_ratio, ledger.amount (transaction, receive2.hash ()));
ASSERT_EQ (nano::genesis_amount - nano::Gxrb_ratio, ledger.weight (nano::genesis_account));
ASSERT_EQ (nano::Gxrb_ratio, ledger.weight (destination.pub));
{
nano::block_sideband sideband;
(void)ledger.store.block_get (transaction, receive2.hash (), &sideband);
ASSERT_FALSE (sideband.details.is_send);
ASSERT_TRUE (sideband.details.is_receive);
ASSERT_FALSE (sideband.details.is_epoch);
}
ASSERT_FALSE (receive2.sideband ().details.is_send);
ASSERT_TRUE (receive2.sideband ().details.is_receive);
ASSERT_FALSE (receive2.sideband ().details.is_epoch);
}
TEST (ledger, epoch_blocks_v2_general)
@ -2804,12 +2811,12 @@ TEST (ledger, unchecked_epoch_invalid)
nano::account_info info;
ASSERT_FALSE (node1.store.account_get (transaction, destination.pub, info));
ASSERT_NE (info.epoch (), nano::epoch::epoch_1);
nano::block_sideband sideband;
ASSERT_NE (nullptr, node1.store.block_get (transaction, epoch2->hash (), &sideband));
ASSERT_EQ (nano::epoch::epoch_0, sideband.details.epoch);
ASSERT_TRUE (sideband.details.is_send);
ASSERT_FALSE (sideband.details.is_epoch);
ASSERT_FALSE (sideband.details.is_receive);
auto epoch2_store (node1.store.block_get (transaction, epoch2->hash ()));
ASSERT_NE (nullptr, epoch2_store);
ASSERT_EQ (nano::epoch::epoch_0, epoch2_store->sideband ().details.epoch);
ASSERT_TRUE (epoch2_store->sideband ().details.is_send);
ASSERT_FALSE (epoch2_store->sideband ().details.is_epoch);
ASSERT_FALSE (epoch2_store->sideband ().details.is_receive);
}
}

View file

@ -1506,8 +1506,10 @@ TEST (node, fork_open_flip)
nano::keypair rep1;
nano::keypair rep2;
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key1.pub, nano::genesis_amount - 1, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ())));
// A copy is necessary to avoid data races during ledger processing, which sets the sideband
auto send1_copy (std::make_shared<nano::send_block> (*send1));
node1.process_active (send1);
node2.process_active (send1);
node2.process_active (send1_copy);
// We should be keeping this block
auto open1 (std::make_shared<nano::open_block> (send1->hash (), rep1.pub, key1.pub, key1.prv, key1.pub, *system.work.generate (key1.pub)));
// This block should be evicted
@ -1741,9 +1743,6 @@ TEST (node, broadcast_elected)
nano::keypair rep_big;
nano::keypair rep_small;
nano::keypair rep_other;
//std::cerr << "Big: " << rep_big.pub.to_account () << std::endl;
//std::cerr << "Small: " << rep_small.pub.to_account () << std::endl;
//std::cerr << "Other: " << rep_other.pub.to_account () << std::endl;
{
auto transaction0 (node0->store.tx_begin_write ());
auto transaction1 (node1->store.tx_begin_write ());
@ -1784,14 +1783,14 @@ TEST (node, broadcast_elected)
system.wallet (2)->insert_adhoc (rep_other.prv);
auto fork0 (std::make_shared<nano::send_block> (node2->latest (nano::test_genesis_key.pub), rep_small.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node0->work_generate_blocking (*fork0);
// A copy is necessary to avoid data races during ledger processing, which sets the sideband
auto fork0_copy (std::make_shared<nano::send_block> (*fork0));
node0->process_active (fork0);
node1->process_active (fork0);
node1->process_active (fork0_copy);
auto fork1 (std::make_shared<nano::send_block> (node2->latest (nano::test_genesis_key.pub), rep_big.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node0->work_generate_blocking (*fork1);
system.wallet (2)->insert_adhoc (rep_small.prv);
node2->process_active (fork1);
//std::cerr << "fork0: " << fork_hash.to_string () << std::endl;
//std::cerr << "fork1: " << fork1.hash ().to_string () << std::endl;
system.deadline_set (10s);
while (!node0->ledger.block_exists (fork0->hash ()) || !node1->ledger.block_exists (fork0->hash ()))
{
@ -2486,15 +2485,17 @@ TEST (node, block_confirm)
nano::keypair key;
system.wallet (1)->insert_adhoc (nano::test_genesis_key.prv);
auto send1 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *node1.work_generate_blocking (genesis.hash ())));
// A copy is necessary to avoid data races during ledger processing, which sets the sideband
auto send1_copy (std::make_shared<nano::state_block> (*send1));
node1.block_processor.add (send1, nano::seconds_since_epoch ());
node2.block_processor.add (send1, nano::seconds_since_epoch ());
node2.block_processor.add (send1_copy, nano::seconds_since_epoch ());
system.deadline_set (std::chrono::seconds (5));
while (!node1.ledger.block_exists (send1->hash ()) || !node2.ledger.block_exists (send1->hash ()))
while (!node1.ledger.block_exists (send1->hash ()) || !node2.ledger.block_exists (send1_copy->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_TRUE (node1.ledger.block_exists (send1->hash ()));
ASSERT_TRUE (node2.ledger.block_exists (send1->hash ()));
ASSERT_TRUE (node2.ledger.block_exists (send1_copy->hash ()));
auto send2 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send1->hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio * 2, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *node1.work_generate_blocking (send1->hash ())));
{
auto transaction (node1.store.tx_begin_write ());

View file

@ -11,14 +11,14 @@ TEST (versioning, account_info_v1)
auto file (nano::unique_path ());
nano::account account (1);
nano::open_block open (1, 2, 3, nullptr);
open.sideband_set ({});
nano::account_info_v1 v1 (open.hash (), open.hash (), 3, 4);
{
nano::logger_mt logger;
nano::mdb_store store (logger, file);
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_write ());
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store.block_put (transaction, open.hash (), open, sideband);
store.block_put (transaction, open.hash (), open);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v0, nano::mdb_val (account), nano::mdb_val (sizeof (v1), &v1), 0));
ASSERT_EQ (0, status);
store.version_put (transaction, 1);
@ -47,14 +47,14 @@ TEST (versioning, account_info_v5)
auto file (nano::unique_path ());
nano::account account (1);
nano::open_block open (1, 2, 3, nullptr);
open.sideband_set ({});
nano::account_info_v5 v5 (open.hash (), open.hash (), open.hash (), 3, 4);
{
nano::logger_mt logger;
nano::mdb_store store (logger, file);
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_write ());
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store.block_put (transaction, open.hash (), open, sideband);
store.block_put (transaction, open.hash (), open);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v0, nano::mdb_val (account), nano::mdb_val (sizeof (v5), &v5), 0));
ASSERT_EQ (0, status);
store.version_put (transaction, 5);
@ -83,14 +83,14 @@ TEST (versioning, account_info_v13)
auto file (nano::unique_path ());
nano::account account (1);
nano::open_block open (1, 2, 3, nullptr);
open.sideband_set ({});
nano::account_info_v13 v13 (open.hash (), open.hash (), open.hash (), 3, 4, 10, nano::epoch::epoch_0);
{
nano::logger_mt logger;
nano::mdb_store store (logger, file);
ASSERT_FALSE (store.init_error ());
auto transaction (store.tx_begin_write ());
nano::block_sideband sideband (nano::block_type::open, 0, 0, 0, 0, 0, nano::epoch::epoch_0, false, false, false);
store.block_put (transaction, open.hash (), open, sideband);
store.block_put (transaction, open.hash (), open);
auto status (mdb_put (store.env.tx (transaction), store.accounts_v0, nano::mdb_val (account), nano::mdb_val (v13), 0));
ASSERT_EQ (0, status);
store.version_put (transaction, 13);

View file

@ -25,6 +25,8 @@ add_library (nano_lib
configbase.hpp
diagnosticsconfig.hpp
diagnosticsconfig.cpp
epoch.hpp
epoch.cpp
errors.hpp
errors.cpp
ipc.hpp

View file

@ -9,6 +9,8 @@
#include <boost/endian/conversion.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <bitset>
/** Compare blocks, first by type, then content. This is an optimization over dynamic_cast, which is very slow on some platforms. */
namespace
{
@ -136,6 +138,17 @@ nano::block_hash nano::block::full_hash () const
return result;
}
nano::block_sideband const & nano::block::sideband () const
{
debug_assert (sideband_m.is_initialized ());
return *sideband_m;
}
void nano::block::sideband_set (nano::block_sideband const & sideband_a)
{
sideband_m = sideband_a;
}
nano::account const & nano::block::representative () const
{
static nano::account rep{ 0 };
@ -176,6 +189,11 @@ void nano::send_block::visit (nano::block_visitor & visitor_a) const
visitor_a.send_block (*this);
}
void nano::send_block::visit (nano::mutable_block_visitor & visitor_a)
{
visitor_a.send_block (*this);
}
void nano::send_block::hash (blake2b_state & hash_a) const
{
hashables.hash (hash_a);
@ -660,6 +678,11 @@ void nano::open_block::visit (nano::block_visitor & visitor_a) const
visitor_a.open_block (*this);
}
void nano::open_block::visit (nano::mutable_block_visitor & visitor_a)
{
visitor_a.open_block (*this);
}
nano::block_type nano::open_block::type () const
{
return nano::block_type::open;
@ -896,6 +919,11 @@ void nano::change_block::visit (nano::block_visitor & visitor_a) const
visitor_a.change_block (*this);
}
void nano::change_block::visit (nano::mutable_block_visitor & visitor_a)
{
visitor_a.change_block (*this);
}
nano::block_type nano::change_block::type () const
{
return nano::block_type::change;
@ -1203,6 +1231,11 @@ void nano::state_block::visit (nano::block_visitor & visitor_a) const
visitor_a.state_block (*this);
}
void nano::state_block::visit (nano::mutable_block_visitor & visitor_a)
{
visitor_a.state_block (*this);
}
nano::block_type nano::state_block::type () const
{
return nano::block_type::state;
@ -1364,6 +1397,11 @@ void nano::receive_block::visit (nano::block_visitor & visitor_a) const
visitor_a.receive_block (*this);
}
void nano::receive_block::visit (nano::mutable_block_visitor & visitor_a)
{
visitor_a.receive_block (*this);
}
bool nano::receive_block::operator== (nano::receive_block const & other_a) const
{
auto result (hashables.previous == other_a.hashables.previous && hashables.source == other_a.hashables.source && work == other_a.work && signature == other_a.signature);
@ -1608,6 +1646,157 @@ void nano::receive_hashables::hash (blake2b_state & hash_a) const
blake2b_update (&hash_a, source.bytes.data (), sizeof (source.bytes));
}
nano::block_details::block_details (nano::epoch const epoch_a, bool const is_send_a, bool const is_receive_a, bool const is_epoch_a) :
epoch (epoch_a), is_send (is_send_a), is_receive (is_receive_a), is_epoch (is_epoch_a)
{
}
constexpr size_t nano::block_details::size ()
{
return 1;
}
bool nano::block_details::operator== (nano::block_details const & other_a) const
{
return epoch == other_a.epoch && is_send == other_a.is_send && is_receive == other_a.is_receive && is_epoch == other_a.is_epoch;
}
uint8_t nano::block_details::packed () const
{
std::bitset<8> result (static_cast<uint8_t> (epoch));
result.set (7, is_send);
result.set (6, is_receive);
result.set (5, is_epoch);
return static_cast<uint8_t> (result.to_ulong ());
}
void nano::block_details::unpack (uint8_t details_a)
{
constexpr std::bitset<8> epoch_mask{ 0b00011111 };
auto as_bitset = static_cast<std::bitset<8>> (details_a);
is_send = as_bitset.test (7);
is_receive = as_bitset.test (6);
is_epoch = as_bitset.test (5);
epoch = static_cast<nano::epoch> ((as_bitset & epoch_mask).to_ulong ());
}
void nano::block_details::serialize (nano::stream & stream_a) const
{
nano::write (stream_a, packed ());
}
bool nano::block_details::deserialize (nano::stream & stream_a)
{
bool result (false);
try
{
uint8_t packed{ 0 };
nano::read (stream_a, packed);
unpack (packed);
}
catch (std::runtime_error &)
{
result = true;
}
return result;
}
nano::block_sideband::block_sideband (nano::account const & account_a, nano::block_hash const & successor_a, nano::amount const & balance_a, uint64_t height_a, uint64_t timestamp_a, nano::epoch epoch_a, bool is_send, bool is_receive, bool is_epoch) :
successor (successor_a),
account (account_a),
balance (balance_a),
height (height_a),
timestamp (timestamp_a),
details (epoch_a, is_send, is_receive, is_epoch)
{
}
size_t nano::block_sideband::size (nano::block_type type_a)
{
size_t result (0);
result += sizeof (successor);
if (type_a != nano::block_type::state && type_a != nano::block_type::open)
{
result += sizeof (account);
}
if (type_a != nano::block_type::open)
{
result += sizeof (height);
}
if (type_a == nano::block_type::receive || type_a == nano::block_type::change || type_a == nano::block_type::open)
{
result += sizeof (balance);
}
result += sizeof (timestamp);
if (type_a == nano::block_type::state)
{
static_assert (sizeof (nano::epoch) == nano::block_details::size (), "block_details is larger than the epoch enum");
result += nano::block_details::size ();
}
return result;
}
void nano::block_sideband::serialize (nano::stream & stream_a, nano::block_type type_a) const
{
nano::write (stream_a, successor.bytes);
if (type_a != nano::block_type::state && type_a != nano::block_type::open)
{
nano::write (stream_a, account.bytes);
}
if (type_a != nano::block_type::open)
{
nano::write (stream_a, boost::endian::native_to_big (height));
}
if (type_a == nano::block_type::receive || type_a == nano::block_type::change || type_a == nano::block_type::open)
{
nano::write (stream_a, balance.bytes);
}
nano::write (stream_a, boost::endian::native_to_big (timestamp));
if (type_a == nano::block_type::state)
{
details.serialize (stream_a);
}
}
bool nano::block_sideband::deserialize (nano::stream & stream_a, nano::block_type type_a)
{
bool result (false);
try
{
nano::read (stream_a, successor.bytes);
if (type_a != nano::block_type::state && type_a != nano::block_type::open)
{
nano::read (stream_a, account.bytes);
}
if (type_a != nano::block_type::open)
{
nano::read (stream_a, height);
boost::endian::big_to_native_inplace (height);
}
else
{
height = 1;
}
if (type_a == nano::block_type::receive || type_a == nano::block_type::change || type_a == nano::block_type::open)
{
nano::read (stream_a, balance.bytes);
}
nano::read (stream_a, timestamp);
boost::endian::big_to_native_inplace (timestamp);
if (type_a == nano::block_type::state)
{
result = details.deserialize (stream_a);
}
}
catch (std::runtime_error &)
{
result = true;
}
return result;
}
std::shared_ptr<nano::block> nano::block_uniquer::unique (std::shared_ptr<nano::block> block_a)
{
auto result (block_a);

View file

@ -1,8 +1,10 @@
#pragma once
#include <nano/crypto/blake2/blake2.h>
#include <nano/lib/epoch.hpp>
#include <nano/lib/errors.hpp>
#include <nano/lib/numbers.hpp>
#include <nano/lib/optional_ptr.hpp>
#include <nano/lib/stream.hpp>
#include <nano/lib/utility.hpp>
#include <nano/lib/work.hpp>
@ -14,6 +16,7 @@
namespace nano
{
class block_visitor;
class mutable_block_visitor;
enum class block_type : uint8_t
{
invalid = 0,
@ -24,6 +27,43 @@ enum class block_type : uint8_t
change = 5,
state = 6
};
class block_details
{
static_assert (std::is_same<std::underlying_type<nano::epoch>::type, uint8_t> (), "Epoch enum is not the proper type");
static_assert (static_cast<uint8_t> (nano::epoch::max) < (1 << 5), "Epoch max is too large for the sideband");
public:
block_details () = default;
block_details (nano::epoch const epoch_a, bool const is_send_a, bool const is_receive_a, bool const is_epoch_a);
static constexpr size_t size ();
bool operator== (block_details const & other_a) const;
void serialize (nano::stream &) const;
bool deserialize (nano::stream &);
nano::epoch epoch{ nano::epoch::epoch_0 };
bool is_send{ false };
bool is_receive{ false };
bool is_epoch{ false };
private:
uint8_t packed () const;
void unpack (uint8_t);
};
class block_sideband final
{
public:
block_sideband () = default;
block_sideband (nano::account const &, nano::block_hash const &, nano::amount const &, uint64_t, uint64_t, nano::epoch, bool is_send, bool is_receive, bool is_epoch);
void serialize (nano::stream &, nano::block_type) const;
bool deserialize (nano::stream &, nano::block_type);
static size_t size (nano::block_type);
nano::block_hash successor{ 0 };
nano::account account{ 0 };
nano::amount balance{ 0 };
uint64_t height{ 0 };
uint64_t timestamp{ 0 };
nano::block_details details;
};
class block
{
public:
@ -31,6 +71,8 @@ public:
nano::block_hash const & hash () const;
// Return a digest of hashables and non-hashables in this block.
nano::block_hash full_hash () const;
nano::block_sideband const & sideband () const;
void sideband_set (nano::block_sideband const &);
std::string to_json () const;
virtual void hash (blake2b_state &) const = 0;
virtual uint64_t block_work () const = 0;
@ -52,6 +94,7 @@ public:
virtual void serialize_json (std::string &, bool = false) const = 0;
virtual void serialize_json (boost::property_tree::ptree &) const = 0;
virtual void visit (nano::block_visitor &) const = 0;
virtual void visit (nano::mutable_block_visitor &) = 0;
virtual bool operator== (nano::block const &) const = 0;
virtual nano::block_type type () const = 0;
virtual nano::signature const & block_signature () const = 0;
@ -66,6 +109,12 @@ public:
protected:
mutable nano::block_hash cached_hash{ 0 };
/**
* Contextual details about a block, some fields may or may not be set depending on block type.
* This field is set via sideband_set in ledger processing or deserializing blocks from the database.
* Otherwise it may be null (for example, an old block or fork).
*/
nano::optional_ptr<nano::block_sideband> sideband_m;
private:
nano::block_hash generate_hash () const;
@ -104,6 +153,7 @@ public:
void serialize_json (boost::property_tree::ptree &) const override;
bool deserialize_json (boost::property_tree::ptree const &);
void visit (nano::block_visitor &) const override;
void visit (nano::mutable_block_visitor &) override;
nano::block_type type () const override;
nano::signature const & block_signature () const override;
void signature_set (nano::signature const &) override;
@ -148,6 +198,7 @@ public:
void serialize_json (boost::property_tree::ptree &) const override;
bool deserialize_json (boost::property_tree::ptree const &);
void visit (nano::block_visitor &) const override;
void visit (nano::mutable_block_visitor &) override;
nano::block_type type () const override;
nano::signature const & block_signature () const override;
void signature_set (nano::signature const &) override;
@ -196,6 +247,7 @@ public:
void serialize_json (boost::property_tree::ptree &) const override;
bool deserialize_json (boost::property_tree::ptree const &);
void visit (nano::block_visitor &) const override;
void visit (nano::mutable_block_visitor &) override;
nano::block_type type () const override;
nano::signature const & block_signature () const override;
void signature_set (nano::signature const &) override;
@ -240,6 +292,7 @@ public:
void serialize_json (boost::property_tree::ptree &) const override;
bool deserialize_json (boost::property_tree::ptree const &);
void visit (nano::block_visitor &) const override;
void visit (nano::mutable_block_visitor &) override;
nano::block_type type () const override;
nano::signature const & block_signature () const override;
void signature_set (nano::signature const &) override;
@ -300,6 +353,7 @@ public:
void serialize_json (boost::property_tree::ptree &) const override;
bool deserialize_json (boost::property_tree::ptree const &);
void visit (nano::block_visitor &) const override;
void visit (nano::mutable_block_visitor &) override;
nano::block_type type () const override;
nano::signature const & block_signature () const override;
void signature_set (nano::signature const &) override;
@ -321,6 +375,16 @@ public:
virtual void state_block (nano::state_block const &) = 0;
virtual ~block_visitor () = default;
};
class mutable_block_visitor
{
public:
virtual void send_block (nano::send_block &) = 0;
virtual void receive_block (nano::receive_block &) = 0;
virtual void open_block (nano::open_block &) = 0;
virtual void change_block (nano::change_block &) = 0;
virtual void state_block (nano::state_block &) = 0;
virtual ~mutable_block_visitor () = default;
};
/**
* This class serves to find and return unique variants of a block in order to minimize memory usage
*/

View file

@ -1,5 +1,5 @@
#include <nano/lib/epoch.hpp>
#include <nano/lib/utility.hpp>
#include <nano/secure/epoch.hpp>
nano::link const & nano::epochs::link (nano::epoch epoch_a) const
{

View file

@ -995,14 +995,14 @@ int main (int argc, char * const * argv)
auto hash (info.open_block);
nano::block_hash calculated_hash (0);
nano::block_sideband sideband;
auto block (node.node->store.block_get (transaction, hash, &sideband)); // Block data
auto block (node.node->store.block_get (transaction, hash)); // Block data
uint64_t height (0);
uint64_t previous_timestamp (0);
nano::account calculated_representative (0);
while (!hash.is_zero () && block != nullptr)
{
++block_count;
auto const & sideband (block->sideband ());
// Check for state & open blocks if account field is correct
if (block->type () == nano::block_type::open || block->type () == nano::block_type::state)
{
@ -1125,7 +1125,7 @@ int main (int argc, char * const * argv)
// Retrieving block data
if (!hash.is_zero ())
{
block = node.node->store.block_get (transaction, hash, &sideband);
block = node.node->store.block_get (transaction, hash);
}
}
// Check if required block exists

View file

@ -24,8 +24,8 @@ thread ([this]() {
})
{
// Register a callback which will get called after a block is cemented
confirmation_height_processor.add_cemented_observer ([this](nano::block_w_sideband const & callback_data_a) {
this->block_cemented_callback (callback_data_a.block, callback_data_a.sideband);
confirmation_height_processor.add_cemented_observer ([this](std::shared_ptr<nano::block> callback_block_a) {
this->block_cemented_callback (callback_block_a);
});
// Register a callback which will get called after a batch of blocks is written and observer calls finished
@ -119,7 +119,7 @@ void nano::active_transactions::search_frontiers (nano::transaction const & tran
}
}
void nano::active_transactions::block_cemented_callback (std::shared_ptr<nano::block> const & block_a, nano::block_sideband const & sideband_a)
void nano::active_transactions::block_cemented_callback (std::shared_ptr<nano::block> const & block_a)
{
auto transaction = node.store.tx_begin_read ();
@ -142,7 +142,7 @@ void nano::active_transactions::block_cemented_callback (std::shared_ptr<nano::b
nano::uint128_t amount (0);
bool is_state_send (false);
nano::account pending_account (0);
node.process_confirmed_data (transaction, block_a, block_a->hash (), sideband_a, account, amount, is_state_send, pending_account);
node.process_confirmed_data (transaction, block_a, block_a->hash (), account, amount, is_state_send, pending_account);
node.observers.blocks.notify (nano::election_status{ block_a, 0, std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now ().time_since_epoch ()), std::chrono::duration_values<std::chrono::milliseconds>::zero (), 0, 1, 0, nano::election_status_type::inactive_confirmation_height }, account, amount, is_state_send);
}
else
@ -167,7 +167,7 @@ void nano::active_transactions::block_cemented_callback (std::shared_ptr<nano::b
nano::uint128_t amount (0);
bool is_state_send (false);
nano::account pending_account (0);
node.process_confirmed_data (transaction, block_a, hash, sideband_a, account, amount, is_state_send, pending_account);
node.process_confirmed_data (transaction, block_a, hash, account, amount, is_state_send, pending_account);
election->status.type = *election_status_type;
election->status.confirmation_request_count = election->confirmation_request_count;
node.observers.blocks.notify (election->status, account, amount, is_state_send);

View file

@ -112,7 +112,7 @@ public:
void stop ();
bool publish (std::shared_ptr<nano::block> block_a);
boost::optional<nano::election_status_type> confirm_block (nano::transaction const &, std::shared_ptr<nano::block>);
void block_cemented_callback (std::shared_ptr<nano::block> const & block_a, nano::block_sideband const & sideband_a);
void block_cemented_callback (std::shared_ptr<nano::block> const & block_a);
void block_already_cemented_callback (nano::block_hash const &);
// clang-format off
boost::multi_index_container<nano::conflict_info,

View file

@ -8,7 +8,7 @@
#include <numeric>
nano::confirmation_height_bounded::confirmation_height_bounded (nano::ledger & ledger_a, nano::write_database_queue & write_database_queue_a, std::chrono::milliseconds batch_separate_pending_min_time_a, nano::logger_mt & logger_a, std::atomic<bool> & stopped_a, nano::block_hash const & original_hash_a, std::function<void(std::vector<nano::block_w_sideband> const &)> const & notify_observers_callback_a, std::function<void(nano::block_hash const &)> const & notify_block_already_cemented_observers_callback_a, std::function<uint64_t ()> const & awaiting_processing_size_callback_a) :
nano::confirmation_height_bounded::confirmation_height_bounded (nano::ledger & ledger_a, nano::write_database_queue & write_database_queue_a, std::chrono::milliseconds batch_separate_pending_min_time_a, nano::logger_mt & logger_a, std::atomic<bool> & stopped_a, nano::block_hash const & original_hash_a, std::function<void(std::vector<std::shared_ptr<nano::block>> const &)> const & notify_observers_callback_a, std::function<void(nano::block_hash const &)> const & notify_block_already_cemented_observers_callback_a, std::function<uint64_t ()> const & awaiting_processing_size_callback_a) :
ledger (ledger_a),
write_database_queue (write_database_queue_a),
batch_separate_pending_min_time (batch_separate_pending_min_time_a),
@ -67,13 +67,12 @@ void nano::confirmation_height_bounded::process ()
current = hash_to_process.top;
auto top_level_hash = current;
nano::block_sideband sideband;
auto block = ledger.store.block_get (transaction, current, &sideband);
auto block = ledger.store.block_get (transaction, current);
debug_assert (block != nullptr);
nano::account account (block->account ());
if (account.is_zero ())
{
account = sideband.account;
account = block->sideband ().account;
}
// Checks if we have encountered this account before but not commited changes yet, if so then update the cached confirmation height
@ -90,13 +89,13 @@ void nano::confirmation_height_bounded::process ()
(void)error;
debug_assert (!error);
// This block was added to the confirmation height processor but is already confirmed
if (first_iter && confirmation_height_info.height >= sideband.height && current == original_hash)
if (first_iter && confirmation_height_info.height >= block->sideband ().height && current == original_hash)
{
notify_block_already_cemented_observers_callback (original_hash);
}
}
auto block_height = sideband.height;
auto block_height = block->sideband ().height;
bool already_cemented = confirmation_height_info.height >= block_height;
// If we are not already at the bottom of the account chain (1 above cemented frontier) then find it
@ -199,14 +198,14 @@ void nano::confirmation_height_bounded::process ()
nano::block_hash nano::confirmation_height_bounded::get_least_unconfirmed_hash_from_top_level (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::account const & account_a, nano::confirmation_height_info const & confirmation_height_info_a, uint64_t & block_height_a)
{
nano::block_hash least_unconfirmed_hash = hash_a;
nano::block_sideband sideband;
if (confirmation_height_info_a.height != 0)
{
if (block_height_a > confirmation_height_info_a.height)
{
release_assert (ledger.store.block_get (transaction_a, confirmation_height_info_a.frontier, &sideband) != nullptr);
least_unconfirmed_hash = sideband.successor;
block_height_a = sideband.height + 1;
auto block (ledger.store.block_get (transaction_a, confirmation_height_info_a.frontier));
release_assert (block != nullptr);
least_unconfirmed_hash = block->sideband ().successor;
block_height_a = block->sideband ().height + 1;
}
}
else
@ -225,14 +224,13 @@ bool nano::confirmation_height_bounded::iterate (nano::read_transaction const &
bool reached_target = false;
bool hit_receive = false;
auto hash = bottom_hash_a;
nano::block_sideband sideband;
uint64_t num_blocks = 0;
while (!hash.is_zero () && !reached_target && !stopped)
{
// Keep iterating upwards until we either reach the desired block or the second receive.
// Once a receive is cemented, we can cement all blocks above it until the next receive, so store those details for later.
++num_blocks;
auto block = ledger.store.block_get (transaction_a, hash, &sideband);
auto block = ledger.store.block_get (transaction_a, hash);
auto source (block->source ());
if (source.is_zero ())
{
@ -243,6 +241,7 @@ bool nano::confirmation_height_bounded::iterate (nano::read_transaction const &
{
hit_receive = true;
reached_target = true;
auto const & sideband (block->sideband ());
auto next = !sideband.successor.is_zero () && sideband.successor != top_level_hash_a ? boost::optional<nano::block_hash> (sideband.successor) : boost::none;
receive_source_pairs_a.push_back ({ receive_chain_details{ account_a, sideband.height, hash, top_level_hash_a, next, bottom_height_a, bottom_hash_a }, source });
// Store a checkpoint every max_items so that we can always traverse a long number of accounts to genesis
@ -261,7 +260,7 @@ bool nano::confirmation_height_bounded::iterate (nano::read_transaction const &
}
else
{
hash = sideband.successor;
hash = block->sideband ().successor;
}
}
@ -337,7 +336,7 @@ bool nano::confirmation_height_bounded::cement_blocks ()
{
// Will contain all blocks that have been cemented (bounded by batch_write_size)
// and will get run through the cemented observer callback
std::vector<block_w_sideband> cemented_blocks;
std::vector<std::shared_ptr<nano::block>> cemented_blocks;
{
// This only writes to the confirmation_height table and is the only place to do so in a single process
auto transaction (ledger.store.tx_begin_write ({}, { nano::tables::confirmation_height }));
@ -354,9 +353,9 @@ bool nano::confirmation_height_bounded::cement_blocks ()
// Extra debug checks
nano::confirmation_height_info confirmation_height_info;
debug_assert (!ledger.store.confirmation_height_get (transaction, account, confirmation_height_info));
nano::block_sideband sideband;
debug_assert (ledger.store.block_get (transaction, confirmed_frontier, &sideband));
debug_assert (sideband.height == confirmation_height_info.height + num_blocks_cemented);
auto block (ledger.store.block_get (transaction, confirmed_frontier));
debug_assert (block != nullptr);
debug_assert (block->sideband ().height == confirmation_height_info.height + num_blocks_cemented);
#endif
ledger.store.confirmation_height_put (transaction, account, nano::confirmation_height_info{ confirmation_height, confirmed_frontier });
ledger.cache.cemented_count += num_blocks_cemented;
@ -370,7 +369,6 @@ bool nano::confirmation_height_bounded::cement_blocks ()
// Some blocks need to be cemented at least
if (pending.top_height > confirmation_height_info.height)
{
nano::block_sideband sideband;
// The highest hash which will be cemented
nano::block_hash new_cemented_frontier;
uint64_t num_blocks_confirmed = 0;
@ -385,8 +383,8 @@ bool nano::confirmation_height_bounded::cement_blocks ()
}
else
{
auto block = ledger.store.block_get (transaction, confirmation_height_info.frontier, &sideband);
new_cemented_frontier = sideband.successor;
auto block = ledger.store.block_get (transaction, confirmation_height_info.frontier);
new_cemented_frontier = block->sideband ().successor;
num_blocks_confirmed = pending.top_height - confirmation_height_info.height;
start_height = confirmation_height_info.height + 1;
}
@ -394,7 +392,7 @@ bool nano::confirmation_height_bounded::cement_blocks ()
auto total_blocks_cemented = 0;
auto num_blocks_iterated = 0;
auto block = ledger.store.block_get (transaction, new_cemented_frontier, &sideband);
auto block = ledger.store.block_get (transaction, new_cemented_frontier);
// Cementing starts from the bottom of the chain and works upwards. This is because chains can have effectively
// an infinite number of send/change blocks in a row. We don't want to hold the write transaction open for too long.
@ -409,7 +407,7 @@ bool nano::confirmation_height_bounded::cement_blocks ()
return true;
}
cemented_blocks.emplace_back (block, sideband);
cemented_blocks.emplace_back (block);
// We have likely hit a long chain, flush these callbacks and continue
if (cemented_blocks.size () == confirmation_height::batch_write_size)
@ -427,8 +425,8 @@ bool nano::confirmation_height_bounded::cement_blocks ()
auto last_iteration = (num_blocks_confirmed - num_blocks_iterated) == 1;
if (!last_iteration)
{
new_cemented_frontier = sideband.successor;
block = ledger.store.block_get (transaction, new_cemented_frontier, &sideband);
new_cemented_frontier = block->sideband ().successor;
block = ledger.store.block_get (transaction, new_cemented_frontier);
}
else
{

View file

@ -15,7 +15,7 @@ class write_database_queue;
class confirmation_height_bounded final
{
public:
confirmation_height_bounded (nano::ledger &, nano::write_database_queue &, std::chrono::milliseconds, nano::logger_mt &, std::atomic<bool> &, nano::block_hash const &, std::function<void(std::vector<nano::block_w_sideband> const &)> const &, std::function<void(nano::block_hash const &)> const &, std::function<uint64_t ()> const &);
confirmation_height_bounded (nano::ledger &, nano::write_database_queue &, std::chrono::milliseconds, nano::logger_mt &, std::atomic<bool> &, nano::block_hash const &, std::function<void(std::vector<std::shared_ptr<nano::block>> const &)> const &, std::function<void(nano::block_hash const &)> const &, std::function<uint64_t ()> const &);
bool pending_empty () const;
void prepare_new ();
void process ();
@ -114,7 +114,7 @@ private:
nano::logger_mt & logger;
std::atomic<bool> & stopped;
nano::block_hash const & original_hash;
std::function<void(std::vector<block_w_sideband> const &)> notify_observers_callback;
std::function<void(std::vector<std::shared_ptr<nano::block>> const &)> notify_observers_callback;
std::function<void(nano::block_hash const &)> notify_block_already_cemented_observers_callback;
std::function<uint64_t ()> awaiting_processing_size_callback;

View file

@ -165,7 +165,7 @@ void nano::confirmation_height_processor::set_next_hash ()
}
// Not thread-safe, only call before this processor has begun cementing
void nano::confirmation_height_processor::add_cemented_observer (std::function<void(block_w_sideband)> const & callback_a)
void nano::confirmation_height_processor::add_cemented_observer (std::function<void(std::shared_ptr<nano::block>)> const & callback_a)
{
cemented_observers.push_back (callback_a);
}
@ -176,7 +176,7 @@ void nano::confirmation_height_processor::add_block_already_cemented_observer (s
block_already_cemented_observers.push_back (callback_a);
}
void nano::confirmation_height_processor::notify_observers (std::vector<nano::block_w_sideband> const & cemented_blocks)
void nano::confirmation_height_processor::notify_observers (std::vector<std::shared_ptr<nano::block>> const & cemented_blocks)
{
for (auto const & block_callback_data : cemented_blocks)
{

View file

@ -35,7 +35,7 @@ public:
bool is_processing_block (nano::block_hash const &);
nano::block_hash current ();
void add_cemented_observer (std::function<void(block_w_sideband)> const &);
void add_cemented_observer (std::function<void(std::shared_ptr<nano::block>)> const &);
void add_block_already_cemented_observer (std::function<void(nano::block_hash const &)> const &);
private:
@ -51,7 +51,7 @@ private:
nano::condition_variable condition;
std::atomic<bool> stopped{ false };
std::vector<std::function<void(nano::block_w_sideband)>> cemented_observers;
std::vector<std::function<void(std::shared_ptr<nano::block>)>> cemented_observers;
std::vector<std::function<void(nano::block_hash const &)>> block_already_cemented_observers;
nano::ledger & ledger;
@ -61,7 +61,7 @@ private:
std::thread thread;
void set_next_hash ();
void notify_observers (std::vector<nano::block_w_sideband> const &);
void notify_observers (std::vector<std::shared_ptr<nano::block>> const &);
void notify_observers (nano::block_hash const &);
friend std::unique_ptr<container_info_component> collect_container_info (confirmation_height_processor &, const std::string &);

View file

@ -5,7 +5,7 @@
#include <numeric>
nano::confirmation_height_unbounded::confirmation_height_unbounded (nano::ledger & ledger_a, nano::write_database_queue & write_database_queue_a, std::chrono::milliseconds batch_separate_pending_min_time_a, nano::logger_mt & logger_a, std::atomic<bool> & stopped_a, nano::block_hash const & original_hash_a, std::function<void(std::vector<nano::block_w_sideband> const &)> const & notify_observers_callback_a, std::function<void(nano::block_hash const &)> const & notify_block_already_cemented_observers_callback_a, std::function<uint64_t ()> const & awaiting_processing_size_callback_a) :
nano::confirmation_height_unbounded::confirmation_height_unbounded (nano::ledger & ledger_a, nano::write_database_queue & write_database_queue_a, std::chrono::milliseconds batch_separate_pending_min_time_a, nano::logger_mt & logger_a, std::atomic<bool> & stopped_a, nano::block_hash const & original_hash_a, std::function<void(std::vector<std::shared_ptr<nano::block>> const &)> const & notify_observers_callback_a, std::function<void(nano::block_hash const &)> const & notify_block_already_cemented_observers_callback_a, std::function<uint64_t ()> const & awaiting_processing_size_callback_a) :
ledger (ledger_a),
write_database_queue (write_database_queue_a),
batch_separate_pending_min_time (batch_separate_pending_min_time_a),
@ -49,16 +49,14 @@ void nano::confirmation_height_unbounded::process ()
}
}
std::shared_ptr<nano::block> block;
nano::block_sideband sideband;
get_block_and_sideband (current, read_transaction, block, sideband);
auto block (get_block_and_sideband (current, read_transaction));
nano::account account (block->account ());
if (account.is_zero ())
{
account = sideband.account;
account = block->sideband ().account;
}
auto block_height = sideband.height;
auto block_height = block->sideband ().height;
uint64_t confirmation_height = 0;
auto account_it = confirmed_iterated_pairs.find (account);
if (account_it != confirmed_iterated_pairs.cend ())
@ -164,10 +162,7 @@ void nano::confirmation_height_unbounded::collect_unconfirmed_receive_and_source
bool hit_receive = false;
while ((num_to_confirm > 0) && !hash.is_zero () && !stopped)
{
std::shared_ptr<nano::block> block;
nano::block_sideband sideband;
get_block_and_sideband (hash, transaction_a, block, sideband);
auto block (get_block_and_sideband (hash, transaction_a));
if (block)
{
auto source (block->source ());
@ -330,11 +325,10 @@ bool nano::confirmation_height_unbounded::cement_blocks ()
{
#ifndef NDEBUG
// Do more thorough checking in Debug mode, indicates programming error.
nano::block_sideband sideband;
auto block = ledger.store.block_get (transaction, pending.hash, &sideband);
auto block = ledger.store.block_get (transaction, pending.hash);
static nano::network_constants network_constants;
debug_assert (network_constants.is_test_network () || block != nullptr);
debug_assert (network_constants.is_test_network () || sideband.height == pending.height);
debug_assert (network_constants.is_test_network () || block->sideband ().height == pending.height);
if (!block)
{
@ -355,7 +349,7 @@ bool nano::confirmation_height_unbounded::cement_blocks ()
// Reverse it so that the callbacks start from the lowest newly cemented block and move upwards
std::reverse (pending.block_callback_data.begin (), pending.block_callback_data.end ());
std::vector<nano::block_w_sideband> callback_data;
std::vector<std::shared_ptr<nano::block>> callback_data;
callback_data.reserve (pending.block_callback_data.size ());
std::transform (pending.block_callback_data.begin (), pending.block_callback_data.end (), std::back_inserter (callback_data), [& block_cache = block_cache](auto const & hash_a) {
debug_assert (block_cache.find (hash_a) != block_cache.end ());
@ -373,19 +367,19 @@ bool nano::confirmation_height_unbounded::cement_blocks ()
return false;
}
void nano::confirmation_height_unbounded::get_block_and_sideband (nano::block_hash const & hash_a, nano::transaction const & transaction_a, std::shared_ptr<nano::block> & block_a, nano::block_sideband & sideband_a)
std::shared_ptr<nano::block> nano::confirmation_height_unbounded::get_block_and_sideband (nano::block_hash const & hash_a, nano::transaction const & transaction_a)
{
auto block_cache_it = block_cache.find (hash_a);
if (block_cache_it != block_cache.cend ())
{
block_a = block_cache_it->second.block;
sideband_a = block_cache_it->second.sideband;
return block_cache_it->second;
}
else
{
block_a = ledger.store.block_get (transaction_a, hash_a, &sideband_a);
block_cache.emplace (std::piecewise_construct, std::forward_as_tuple (hash_a), std::forward_as_tuple (block_a, sideband_a));
auto block (ledger.store.block_get (transaction_a, hash_a));
block_cache.emplace (hash_a, block);
++block_cache_size;
return block;
}
}

View file

@ -16,7 +16,7 @@ class write_database_queue;
class confirmation_height_unbounded final
{
public:
confirmation_height_unbounded (nano::ledger &, nano::write_database_queue &, std::chrono::milliseconds, nano::logger_mt &, std::atomic<bool> &, nano::block_hash const &, std::function<void(std::vector<nano::block_w_sideband> const &)> const &, std::function<void(nano::block_hash const &)> const &, std::function<uint64_t ()> const &);
confirmation_height_unbounded (nano::ledger &, nano::write_database_queue &, std::chrono::milliseconds, nano::logger_mt &, std::atomic<bool> &, nano::block_hash const &, std::function<void(std::vector<std::shared_ptr<nano::block>> const &)> const &, std::function<void(nano::block_hash const &)> const &, std::function<uint64_t ()> const &);
bool pending_empty () const;
void prepare_new ();
void process ();
@ -55,9 +55,9 @@ private:
std::unordered_map<account, confirmed_iterated_pair> confirmed_iterated_pairs;
std::atomic<uint64_t> confirmed_iterated_pairs_size{ 0 };
std::unordered_map<nano::block_hash, block_w_sideband> block_cache;
std::unordered_map<nano::block_hash, std::shared_ptr<nano::block>> block_cache;
std::atomic<uint64_t> block_cache_size{ 0 };
void get_block_and_sideband (nano::block_hash const &, nano::transaction const &, std::shared_ptr<nano::block> &, nano::block_sideband &);
std::shared_ptr<nano::block> get_block_and_sideband (nano::block_hash const &, nano::transaction const &);
std::deque<conf_height_details> pending_writes;
std::atomic<uint64_t> pending_writes_size{ 0 };
std::vector<nano::block_hash> orig_block_callback_data;
@ -90,7 +90,7 @@ private:
nano::logger_mt & logger;
std::atomic<bool> & stopped;
nano::block_hash const & original_hash;
std::function<void(std::vector<nano::block_w_sideband> const &)> notify_observers_callback;
std::function<void(std::vector<std::shared_ptr<nano::block>> const &)> notify_observers_callback;
std::function<void(nano::block_hash const &)> notify_block_already_cemented_observers_callback;
std::function<uint64_t ()> awaiting_processing_size_callback;

View file

@ -970,19 +970,18 @@ void nano::json_handler::block_info ()
auto hash (hash_impl ());
if (!ec)
{
nano::block_sideband sideband;
auto transaction (node.store.tx_begin_read ());
auto block (node.store.block_get (transaction, hash, &sideband));
auto block (node.store.block_get (transaction, hash));
if (block != nullptr)
{
nano::account account (block->account ().is_zero () ? sideband.account : block->account ());
nano::account account (block->account ().is_zero () ? block->sideband ().account : block->account ());
response_l.put ("block_account", account.to_account ());
auto amount (node.ledger.amount (transaction, hash));
response_l.put ("amount", amount.convert_to<std::string> ());
auto balance (node.ledger.balance (transaction, hash));
response_l.put ("balance", balance.convert_to<std::string> ());
response_l.put ("height", std::to_string (sideband.height));
response_l.put ("local_timestamp", std::to_string (sideband.timestamp));
response_l.put ("height", std::to_string (block->sideband ().height));
response_l.put ("local_timestamp", std::to_string (block->sideband ().timestamp));
auto confirmed (node.ledger.block_confirmed (transaction, hash));
response_l.put ("confirmed", confirmed);
@ -1121,19 +1120,18 @@ void nano::json_handler::blocks_info ()
nano::block_hash hash;
if (!hash.decode_hex (hash_text))
{
nano::block_sideband sideband;
auto block (node.store.block_get (transaction, hash, &sideband));
auto block (node.store.block_get (transaction, hash));
if (block != nullptr)
{
boost::property_tree::ptree entry;
nano::account account (block->account ().is_zero () ? sideband.account : block->account ());
nano::account account (block->account ().is_zero () ? block->sideband ().account : block->account ());
entry.put ("block_account", account.to_account ());
auto amount (node.ledger.amount (transaction, hash));
entry.put ("amount", amount.convert_to<std::string> ());
auto balance (node.ledger.balance (transaction, hash));
entry.put ("balance", balance.convert_to<std::string> ());
entry.put ("height", std::to_string (sideband.height));
entry.put ("local_timestamp", std::to_string (sideband.timestamp));
entry.put ("height", std::to_string (block->sideband ().height));
entry.put ("local_timestamp", std::to_string (block->sideband ().timestamp));
auto confirmed (node.ledger.block_confirmed (transaction, hash));
entry.put ("confirmed", confirmed);
@ -2557,8 +2555,7 @@ void nano::json_handler::account_history ()
boost::property_tree::ptree history;
bool output_raw (request.get_optional<bool> ("raw") == true);
response_l.put ("account", account.to_account ());
nano::block_sideband sideband;
auto block (node.store.block_get (transaction, hash, &sideband));
auto block (node.store.block_get (transaction, hash));
while (block != nullptr && count > 0)
{
if (offset > 0)
@ -2572,8 +2569,8 @@ void nano::json_handler::account_history ()
block->visit (visitor);
if (!entry.empty ())
{
entry.put ("local_timestamp", std::to_string (sideband.timestamp));
entry.put ("height", std::to_string (sideband.height));
entry.put ("local_timestamp", std::to_string (block->sideband ().timestamp));
entry.put ("height", std::to_string (block->sideband ().height));
entry.put ("hash", hash.to_string ());
if (output_raw)
{
@ -2585,7 +2582,7 @@ void nano::json_handler::account_history ()
}
}
hash = reverse ? node.store.block_successor (transaction, hash) : block->previous ();
block = node.store.block_get (transaction, hash, &sideband);
block = node.store.block_get (transaction, hash);
}
response_l.add_child ("history", history);
if (!hash.is_zero ())
@ -4589,9 +4586,8 @@ void nano::json_handler::wallet_history ()
auto hash (info.head);
while (timestamp >= modified_since && !hash.is_zero ())
{
nano::block_sideband sideband;
auto block (node.store.block_get (block_transaction, hash, &sideband));
timestamp = sideband.timestamp;
auto block (node.store.block_get (block_transaction, hash));
timestamp = block->sideband ().timestamp;
if (block != nullptr && timestamp >= modified_since)
{
boost::property_tree::ptree entry;

View file

@ -507,7 +507,7 @@ void nano::mdb_store::upgrade_v12_to_v13 (nano::write_transaction & transaction_
}
nano::mdb_val value{ vector.size (), (void *)vector.data () };
MDB_dbi database = is_state_block_v1 ? state_blocks_v1 : table_to_dbi (block_database (sideband.type));
MDB_dbi database = is_state_block_v1 ? state_blocks_v1 : table_to_dbi (block_database (block->type ()));
auto status = mdb_put (env.tx (transaction_a), database, nano::mdb_val (hash), value, 0);
release_assert (success (status));
@ -628,14 +628,14 @@ void nano::mdb_store::upgrade_v14_to_v15 (nano::write_transaction & transaction_
nano::state_block_w_sideband_v14 state_block_w_sideband_v14 (i_state->second);
auto & sideband_v14 = state_block_w_sideband_v14.sideband;
nano::block_sideband sideband (sideband_v14.type, sideband_v14.account, sideband_v14.successor, sideband_v14.balance, sideband_v14.height, sideband_v14.timestamp, i_state.from_first_database ? nano::epoch::epoch_0 : nano::epoch::epoch_1, false, false, false);
nano::block_sideband sideband (sideband_v14.account, sideband_v14.successor, sideband_v14.balance, sideband_v14.height, sideband_v14.timestamp, i_state.from_first_database ? nano::epoch::epoch_0 : nano::epoch::epoch_1, false, false, false);
// Write these out
std::vector<uint8_t> data;
{
nano::vectorstream stream (data);
state_block_w_sideband_v14.state_block->serialize (stream);
sideband.serialize (stream);
sideband.serialize (stream, sideband_v14.type);
}
nano::mdb_val value{ data.size (), (void *)data.data () };
@ -732,27 +732,25 @@ void nano::mdb_store::upgrade_v16_to_v17 (nano::write_transaction const & transa
if (account_info_i->second.block_count / 2 >= confirmation_height)
{
// The confirmation height of the account is closer to the bottom of the chain, so start there and work up
nano::block_sideband sideband;
auto block = block_get (transaction_a, account_info.open_block, &sideband);
auto block = block_get (transaction_a, account_info.open_block);
debug_assert (block);
auto height = 1;
while (height != confirmation_height)
{
block = block_get (transaction_a, sideband.successor, &sideband);
block = block_get (transaction_a, block->sideband ().successor);
debug_assert (block);
++height;
}
debug_assert (sideband.height == confirmation_height);
debug_assert (block->sideband ().height == confirmation_height);
confirmation_height_infos.emplace_back (account, confirmation_height_info{ confirmation_height, block->hash () });
}
else
{
// The confirmation height of the account is closer to the top of the chain so start there and work down
nano::block_sideband sideband;
auto block = block_get (transaction_a, account_info.head, &sideband);
auto height = sideband.height;
auto block = block_get (transaction_a, account_info.head);
auto height = block->sideband ().height;
while (height != confirmation_height)
{
block = block_get (transaction_a, block->previous ());
@ -820,13 +818,13 @@ void nano::mdb_store::upgrade_v17_to_v18 (nano::write_transaction const & transa
is_receive = true;
}
nano::block_sideband new_sideband (sideband.type, sideband.account, sideband.successor, sideband.balance, sideband.height, sideband.timestamp, sideband.details.epoch, is_send, is_receive, is_epoch);
nano::block_sideband new_sideband (sideband.account, sideband.successor, sideband.balance, sideband.height, sideband.timestamp, sideband.details.epoch, is_send, is_receive, is_epoch);
// Write these out
std::vector<uint8_t> data;
{
nano::vectorstream stream (data);
block->serialize (stream);
new_sideband.serialize (stream);
new_sideband.serialize (stream, block->type ());
}
nano::mdb_val value{ data.size (), (void *)data.data () };
auto s = mdb_cursor_put (state_i.cursor, state_i->first, value, MDB_CURRENT);

View file

@ -616,7 +616,7 @@ void nano::node::process_active (std::shared_ptr<nano::block> incoming)
block_processor.add (incoming, nano::seconds_since_epoch ());
}
nano::process_return nano::node::process (nano::block const & block_a)
nano::process_return nano::node::process (nano::block & block_a)
{
auto transaction (store.tx_begin_write ({ tables::accounts, tables::cached_counts, tables::change_blocks, tables::frontiers, tables::open_blocks, tables::pending, tables::receive_blocks, tables::representation, tables::send_blocks, tables::state_blocks }, { tables::confirmation_height }));
auto result (ledger.process (transaction, block_a));
@ -1225,18 +1225,18 @@ void nano::node::receive_confirmed (nano::transaction const & transaction_a, std
block_a->visit (visitor);
}
void nano::node::process_confirmed_data (nano::transaction const & transaction_a, std::shared_ptr<nano::block> block_a, nano::block_hash const & hash_a, nano::block_sideband const & sideband_a, nano::account & account_a, nano::uint128_t & amount_a, bool & is_state_send_a, nano::account & pending_account_a)
void nano::node::process_confirmed_data (nano::transaction const & transaction_a, std::shared_ptr<nano::block> block_a, nano::block_hash const & hash_a, nano::account & account_a, nano::uint128_t & amount_a, bool & is_state_send_a, nano::account & pending_account_a)
{
// Faster account calculation
account_a = block_a->account ();
if (account_a.is_zero ())
{
account_a = sideband_a.account;
account_a = block_a->sideband ().account;
}
// Faster amount calculation
auto previous (block_a->previous ());
auto previous_balance (ledger.balance (transaction_a, previous));
auto block_balance (store.block_balance_calculated (block_a, sideband_a));
auto block_balance (store.block_balance_calculated (block_a));
if (hash_a != ledger.network_params.ledger.genesis_account)
{
amount_a = block_balance > previous_balance ? block_balance - previous_balance : previous_balance - block_balance;

View file

@ -103,10 +103,10 @@ public:
std::shared_ptr<nano::node> shared ();
int store_version ();
void receive_confirmed (nano::transaction const &, std::shared_ptr<nano::block>, nano::block_hash const &);
void process_confirmed_data (nano::transaction const &, std::shared_ptr<nano::block>, nano::block_hash const &, nano::block_sideband const &, nano::account &, nano::uint128_t &, bool &, nano::account &);
void process_confirmed_data (nano::transaction const &, std::shared_ptr<nano::block>, nano::block_hash const &, nano::account &, nano::uint128_t &, bool &, nano::account &);
void process_confirmed (nano::election_status const &, std::shared_ptr<nano::election> const &, uint8_t = 0);
void process_active (std::shared_ptr<nano::block>);
nano::process_return process (nano::block const &);
nano::process_return process (nano::block &);
nano::process_return process_local (std::shared_ptr<nano::block>, bool const = false);
void keepalive_preconfigured (std::vector<std::string> const &);
nano::block_hash latest (nano::account const &);

View file

@ -41,8 +41,6 @@ add_library (secure
buffer.hpp
common.hpp
common.cpp
epoch.hpp
epoch.cpp
ledger.hpp
ledger.cpp
network_filter.hpp

View file

@ -1,162 +1,6 @@
#include <nano/lib/threading.hpp>
#include <nano/secure/blockstore.hpp>
#include <boost/endian/conversion.hpp>
#include <bitset>
nano::block_details::block_details (nano::epoch const epoch_a, bool const is_send_a, bool const is_receive_a, bool const is_epoch_a) :
epoch (epoch_a), is_send (is_send_a), is_receive (is_receive_a), is_epoch (is_epoch_a)
{
}
constexpr size_t nano::block_details::size ()
{
return 1;
}
bool nano::block_details::operator== (nano::block_details const & other_a) const
{
return epoch == other_a.epoch && is_send == other_a.is_send && is_receive == other_a.is_receive && is_epoch == other_a.is_epoch;
}
uint8_t nano::block_details::packed () const
{
std::bitset<8> result (static_cast<uint8_t> (epoch));
result.set (7, is_send);
result.set (6, is_receive);
result.set (5, is_epoch);
return static_cast<uint8_t> (result.to_ulong ());
}
void nano::block_details::unpack (uint8_t details_a)
{
constexpr std::bitset<8> epoch_mask{ 0b00011111 };
auto as_bitset = static_cast<std::bitset<8>> (details_a);
is_send = as_bitset.test (7);
is_receive = as_bitset.test (6);
is_epoch = as_bitset.test (5);
epoch = static_cast<nano::epoch> ((as_bitset & epoch_mask).to_ulong ());
}
void nano::block_details::serialize (nano::stream & stream_a) const
{
nano::write (stream_a, packed ());
}
bool nano::block_details::deserialize (nano::stream & stream_a)
{
bool result (false);
try
{
uint8_t packed{ 0 };
nano::read (stream_a, packed);
unpack (packed);
}
catch (std::runtime_error &)
{
result = true;
}
return result;
}
nano::block_sideband::block_sideband (nano::block_type type_a, nano::account const & account_a, nano::block_hash const & successor_a, nano::amount const & balance_a, uint64_t height_a, uint64_t timestamp_a, nano::epoch epoch_a, bool is_send, bool is_receive, bool is_epoch) :
type (type_a),
successor (successor_a),
account (account_a),
balance (balance_a),
height (height_a),
timestamp (timestamp_a),
details (epoch_a, is_send, is_receive, is_epoch)
{
}
size_t nano::block_sideband::size (nano::block_type type_a)
{
size_t result (0);
result += sizeof (successor);
if (type_a != nano::block_type::state && type_a != nano::block_type::open)
{
result += sizeof (account);
}
if (type_a != nano::block_type::open)
{
result += sizeof (height);
}
if (type_a == nano::block_type::receive || type_a == nano::block_type::change || type_a == nano::block_type::open)
{
result += sizeof (balance);
}
result += sizeof (timestamp);
if (type_a == nano::block_type::state)
{
static_assert (sizeof (nano::epoch) == nano::block_details::size (), "block_details is larger than the epoch enum");
result += nano::block_details::size ();
}
return result;
}
void nano::block_sideband::serialize (nano::stream & stream_a) const
{
nano::write (stream_a, successor.bytes);
if (type != nano::block_type::state && type != nano::block_type::open)
{
nano::write (stream_a, account.bytes);
}
if (type != nano::block_type::open)
{
nano::write (stream_a, boost::endian::native_to_big (height));
}
if (type == nano::block_type::receive || type == nano::block_type::change || type == nano::block_type::open)
{
nano::write (stream_a, balance.bytes);
}
nano::write (stream_a, boost::endian::native_to_big (timestamp));
if (type == nano::block_type::state)
{
details.serialize (stream_a);
}
}
bool nano::block_sideband::deserialize (nano::stream & stream_a)
{
bool result (false);
try
{
nano::read (stream_a, successor.bytes);
if (type != nano::block_type::state && type != nano::block_type::open)
{
nano::read (stream_a, account.bytes);
}
if (type != nano::block_type::open)
{
nano::read (stream_a, height);
boost::endian::big_to_native_inplace (height);
}
else
{
height = 1;
}
if (type == nano::block_type::receive || type == nano::block_type::change || type == nano::block_type::open)
{
nano::read (stream_a, balance.bytes);
}
nano::read (stream_a, timestamp);
boost::endian::big_to_native_inplace (timestamp);
if (type == nano::block_type::state)
{
result = details.deserialize (stream_a);
}
}
catch (std::runtime_error &)
{
result = true;
}
return result;
}
nano::summation_visitor::summation_visitor (nano::transaction const & transaction_a, nano::block_store const & store_a, bool is_v14_upgrade_a) :
transaction (transaction_a),
store (store_a),
@ -397,7 +241,7 @@ nano::uint128_t nano::summation_visitor::compute_balance (nano::block_hash const
std::shared_ptr<nano::block> nano::summation_visitor::block_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const
{
return is_v14_upgrade ? store.block_get_v14 (transaction, hash_a) : store.block_get (transaction, hash_a);
return is_v14_upgrade ? store.block_get_v14 (transaction, hash_a) : store.block_get_no_sideband (transaction, hash_a);
}
nano::representative_visitor::representative_visitor (nano::transaction const & transaction_a, nano::block_store & store_a) :

View file

@ -16,45 +16,6 @@
namespace nano
{
class block_details
{
static_assert (std::is_same<std::underlying_type<nano::epoch>::type, uint8_t> (), "Epoch enum is not the proper type");
static_assert (static_cast<uint8_t> (nano::epoch::max) < (1 << 5), "Epoch max is too large for the sideband");
public:
block_details () = default;
block_details (nano::epoch const epoch_a, bool const is_send_a, bool const is_receive_a, bool const is_epoch_a);
static constexpr size_t size ();
bool operator== (block_details const & other_a) const;
void serialize (nano::stream &) const;
bool deserialize (nano::stream &);
nano::epoch epoch{ nano::epoch::epoch_0 };
bool is_send{ false };
bool is_receive{ false };
bool is_epoch{ false };
private:
uint8_t packed () const;
void unpack (uint8_t);
};
class block_sideband final
{
public:
block_sideband () = default;
block_sideband (nano::block_type, nano::account const &, nano::block_hash const &, nano::amount const &, uint64_t, uint64_t, nano::epoch, bool is_send, bool is_receive, bool is_epoch);
void serialize (nano::stream &) const;
bool deserialize (nano::stream &);
static size_t size (nano::block_type);
nano::block_type type{ nano::block_type::invalid };
nano::block_hash successor{ 0 };
nano::account account{ 0 };
nano::amount balance{ 0 };
uint64_t height{ 0 };
uint64_t timestamp{ 0 };
nano::block_details details;
};
// Move to versioning with a specific version if required for a future upgrade
class state_block_w_sideband
{
@ -311,14 +272,25 @@ public:
return result;
}
private:
// Common usage for versioning
template <typename T, typename = std::enable_if<std::is_same<T, state_block_w_sideband>::value || std::is_same<T, state_block_w_sideband_v14>::value>>
T as () const
explicit operator state_block_w_sideband () const
{
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (data ()), size ());
auto error (false);
T block_w_sideband;
nano::state_block_w_sideband block_w_sideband;
block_w_sideband.state_block = std::make_shared<nano::state_block> (error, stream);
debug_assert (!error);
error = block_w_sideband.sideband.deserialize (stream, nano::block_type::state);
debug_assert (!error);
return block_w_sideband;
}
explicit operator state_block_w_sideband_v14 () const
{
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (data ()), size ());
auto error (false);
nano::state_block_w_sideband_v14 block_w_sideband;
block_w_sideband.state_block = std::make_shared<nano::state_block> (error, stream);
debug_assert (!error);
@ -329,17 +301,6 @@ private:
return block_w_sideband;
}
public:
explicit operator state_block_w_sideband () const
{
return as<state_block_w_sideband> ();
}
explicit operator state_block_w_sideband_v14 () const
{
return as<state_block_w_sideband_v14> ();
}
explicit operator nano::no_value () const
{
return no_value::dummy;
@ -441,19 +402,6 @@ private:
class transaction;
class block_store;
class block_w_sideband final
{
public:
block_w_sideband (std::shared_ptr<nano::block> const & block_a, nano::block_sideband const & sideband_a) :
block (block_a),
sideband (sideband_a)
{
}
std::shared_ptr<nano::block> block;
nano::block_sideband sideband;
};
/**
* Summation visitor for blocks, supporting amount and balance computations. These
* computations are mutually dependant. The natural solution is to use mutual recursion
@ -714,10 +662,11 @@ class block_store
public:
virtual ~block_store () = default;
virtual void initialize (nano::write_transaction const &, nano::genesis const &, nano::ledger_cache &) = 0;
virtual void block_put (nano::write_transaction const &, nano::block_hash const &, nano::block const &, nano::block_sideband const &) = 0;
virtual void block_put (nano::write_transaction const &, nano::block_hash const &, nano::block const &) = 0;
virtual nano::block_hash block_successor (nano::transaction const &, nano::block_hash const &) const = 0;
virtual void block_successor_clear (nano::write_transaction const &, nano::block_hash const &) = 0;
virtual std::shared_ptr<nano::block> block_get (nano::transaction const &, nano::block_hash const &, nano::block_sideband * = nullptr) const = 0;
virtual std::shared_ptr<nano::block> block_get (nano::transaction const &, nano::block_hash const &) const = 0;
virtual std::shared_ptr<nano::block> block_get_no_sideband (nano::transaction const &, nano::block_hash const &) const = 0;
virtual std::shared_ptr<nano::block> block_get_v14 (nano::transaction const &, nano::block_hash const &, nano::block_sideband_v14 * = nullptr, bool * = nullptr) const = 0;
virtual std::shared_ptr<nano::block> block_random (nano::transaction const &) = 0;
virtual void block_del (nano::write_transaction const &, nano::block_hash const &, nano::block_type) = 0;
@ -753,7 +702,7 @@ public:
virtual bool block_info_get (nano::transaction const &, nano::block_hash const &, nano::block_info &) const = 0;
virtual nano::uint128_t block_balance (nano::transaction const &, nano::block_hash const &) = 0;
virtual nano::uint128_t block_balance_calculated (std::shared_ptr<nano::block>, nano::block_sideband const &) const = 0;
virtual nano::uint128_t block_balance_calculated (std::shared_ptr<nano::block> const &) const = 0;
virtual nano::epoch block_version (nano::transaction const &, nano::block_hash const &) = 0;
virtual void unchecked_clear (nano::write_transaction const &) = 0;

View file

@ -31,8 +31,8 @@ public:
{
auto hash_l (genesis_a.hash ());
debug_assert (latest_begin (transaction_a) == latest_end ());
nano::block_sideband sideband (nano::block_type::open, network_params.ledger.genesis_account, 0, network_params.ledger.genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false);
block_put (transaction_a, hash_l, *genesis_a.open, sideband);
genesis_a.open->sideband_set (nano::block_sideband (network_params.ledger.genesis_account, 0, network_params.ledger.genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false));
block_put (transaction_a, hash_l, *genesis_a.open);
++ledger_cache_a.block_count;
confirmation_height_put (transaction_a, network_params.ledger.genesis_account, nano::confirmation_height_info{ 1, genesis_a.hash () });
++ledger_cache_a.cemented_count;
@ -44,9 +44,8 @@ public:
nano::uint128_t block_balance (nano::transaction const & transaction_a, nano::block_hash const & hash_a) override
{
nano::block_sideband sideband;
auto block (block_get (transaction_a, hash_a, &sideband));
nano::uint128_t result (block_balance_calculated (block, sideband));
auto block (block_get (transaction_a, hash_a));
nano::uint128_t result (block_balance_calculated (block));
return result;
}
@ -97,15 +96,14 @@ public:
return result;
}
void block_put (nano::write_transaction const & transaction_a, nano::block_hash const & hash_a, nano::block const & block_a, nano::block_sideband const & sideband_a) override
void block_put (nano::write_transaction const & transaction_a, nano::block_hash const & hash_a, nano::block const & block_a) override
{
debug_assert (block_a.type () == sideband_a.type);
debug_assert (sideband_a.successor.is_zero () || block_exists (transaction_a, sideband_a.successor));
debug_assert (block_a.sideband ().successor.is_zero () || block_exists (transaction_a, block_a.sideband ().successor));
std::vector<uint8_t> vector;
{
nano::vectorstream stream (vector);
block_a.serialize (stream);
sideband_a.serialize (stream);
block_a.sideband ().serialize (stream, block_a.type ());
}
block_raw_put (transaction_a, vector, block_a.type (), hash_a);
nano::block_predecessor_set<Val, Derived_Store> predecessor (transaction_a, *this);
@ -116,13 +114,12 @@ public:
// Converts a block hash to a block height
uint64_t block_account_height (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const override
{
nano::block_sideband sideband;
auto block = block_get (transaction_a, hash_a, &sideband);
auto block = block_get (transaction_a, hash_a);
debug_assert (block != nullptr);
return sideband.height;
return block->sideband ().height;
}
std::shared_ptr<nano::block> block_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a, nano::block_sideband * sideband_a = nullptr) const override
std::shared_ptr<nano::block> block_get (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const override
{
nano::block_type type;
auto value (block_raw_get (transaction_a, hash_a, type));
@ -132,25 +129,37 @@ public:
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.data ()), value.size ());
result = nano::deserialize_block (stream, type);
debug_assert (result != nullptr);
if (sideband_a)
nano::block_sideband sideband;
if (full_sideband (transaction_a) || entry_has_sideband (value.size (), type))
{
sideband_a->type = type;
if (full_sideband (transaction_a) || entry_has_sideband (value.size (), type))
{
auto error (sideband_a->deserialize (stream));
(void)error;
debug_assert (!error);
}
else
{
// Reconstruct sideband data for block.
sideband_a->account = block_account_computed (transaction_a, hash_a);
sideband_a->balance = block_balance_computed (transaction_a, hash_a);
sideband_a->successor = block_successor (transaction_a, hash_a);
sideband_a->height = 0;
sideband_a->timestamp = 0;
}
auto error (sideband.deserialize (stream, type));
(void)error;
debug_assert (!error);
}
else
{
// Reconstruct sideband data for block.
sideband.account = block_account_computed (transaction_a, hash_a);
sideband.balance = block_balance_computed (transaction_a, hash_a);
sideband.successor = block_successor (transaction_a, hash_a);
sideband.height = 0;
sideband.timestamp = 0;
}
result->sideband_set (sideband);
}
return result;
}
std::shared_ptr<nano::block> block_get_no_sideband (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const override
{
nano::block_type type;
auto value (block_raw_get (transaction_a, hash_a, type));
std::shared_ptr<nano::block> result;
if (value.size () != 0)
{
nano::bufferstream stream (reinterpret_cast<uint8_t const *> (value.data ()), value.size ());
result = nano::deserialize_block (stream, type);
debug_assert (result != nullptr);
}
return result;
}
@ -186,18 +195,17 @@ public:
nano::account block_account (nano::transaction const & transaction_a, nano::block_hash const & hash_a) const override
{
nano::block_sideband sideband;
auto block (block_get (transaction_a, hash_a, &sideband));
auto block (block_get (transaction_a, hash_a));
nano::account result (block->account ());
if (result.is_zero ())
{
result = sideband.account;
result = block->sideband ().account;
}
debug_assert (!result.is_zero ());
return result;
}
nano::uint128_t block_balance_calculated (std::shared_ptr<nano::block> block_a, nano::block_sideband const & sideband_a) const override
nano::uint128_t block_balance_calculated (std::shared_ptr<nano::block> const & block_a) const override
{
nano::uint128_t result;
switch (block_a->type ())
@ -205,7 +213,7 @@ public:
case nano::block_type::open:
case nano::block_type::receive:
case nano::block_type::change:
result = sideband_a.balance.number ();
result = block_a->sideband ().balance.number ();
break;
case nano::block_type::send:
result = boost::polymorphic_downcast<nano::send_block *> (block_a.get ())->hashables.balance.number ();
@ -407,11 +415,10 @@ public:
nano::epoch block_version (nano::transaction const & transaction_a, nano::block_hash const & hash_a) override
{
nano::db_val<Val> value;
nano::block_sideband sideband;
auto block = block_get (transaction_a, hash_a, &sideband);
if (sideband.type == nano::block_type::state)
auto block = block_get (transaction_a, hash_a);
if (block && block->type () == nano::block_type::state)
{
return sideband.details.epoch;
return block->sideband ().details.epoch;
}
return nano::epoch::epoch_0;
@ -842,7 +849,7 @@ protected:
auto hash (hash_a);
while (result.is_zero ())
{
auto block (block_get (transaction_a, hash));
auto block (block_get_no_sideband (transaction_a, hash));
debug_assert (block);
result = block->account ();
if (result.is_zero ())

View file

@ -4,10 +4,10 @@
#include <nano/lib/blockbuilders.hpp>
#include <nano/lib/blocks.hpp>
#include <nano/lib/config.hpp>
#include <nano/lib/epoch.hpp>
#include <nano/lib/numbers.hpp>
#include <nano/lib/rep_weights.hpp>
#include <nano/lib/utility.hpp>
#include <nano/secure/epoch.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/optional/optional.hpp>

View file

@ -172,18 +172,18 @@ public:
bool error{ false };
};
class ledger_processor : public nano::block_visitor
class ledger_processor : public nano::mutable_block_visitor
{
public:
ledger_processor (nano::ledger &, nano::write_transaction const &, nano::signature_verification = nano::signature_verification::unknown);
virtual ~ledger_processor () = default;
void send_block (nano::send_block const &) override;
void receive_block (nano::receive_block const &) override;
void open_block (nano::open_block const &) override;
void change_block (nano::change_block const &) override;
void state_block (nano::state_block const &) override;
void state_block_impl (nano::state_block const &);
void epoch_block_impl (nano::state_block const &);
void send_block (nano::send_block &) override;
void receive_block (nano::receive_block &) override;
void open_block (nano::open_block &) override;
void change_block (nano::change_block &) override;
void state_block (nano::state_block &) override;
void state_block_impl (nano::state_block &);
void epoch_block_impl (nano::state_block &);
nano::ledger & ledger;
nano::write_transaction const & transaction;
nano::signature_verification verification;
@ -230,7 +230,7 @@ bool ledger_processor::validate_epoch_block (nano::state_block const & block_a)
return (block_a.hashables.balance == prev_balance);
}
void ledger_processor::state_block (nano::state_block const & block_a)
void ledger_processor::state_block (nano::state_block & block_a)
{
result.code = nano::process_result::progress;
auto is_epoch_block = false;
@ -253,7 +253,7 @@ void ledger_processor::state_block (nano::state_block const & block_a)
}
}
void ledger_processor::state_block_impl (nano::state_block const & block_a)
void ledger_processor::state_block_impl (nano::state_block & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, block_a.type (), hash));
@ -334,9 +334,8 @@ void ledger_processor::state_block_impl (nano::state_block const & block_a)
if (result.code == nano::process_result::progress)
{
ledger.stats.inc (nano::stat::type::ledger, nano::stat::detail::state_block);
result.state_is_send = is_send;
nano::block_sideband sideband (nano::block_type::state, block_a.hashables.account /* unused */, 0, 0 /* unused */, info.block_count + 1, nano::seconds_since_epoch (), epoch, is_send, is_receive, false);
ledger.store.block_put (transaction, hash, block_a, sideband);
block_a.sideband_set (nano::block_sideband (block_a.hashables.account /* unused */, 0, 0 /* unused */, info.block_count + 1, nano::seconds_since_epoch (), epoch, is_send, is_receive, false));
ledger.store.block_put (transaction, hash, block_a);
if (!info.head.is_zero ())
{
@ -371,7 +370,7 @@ void ledger_processor::state_block_impl (nano::state_block const & block_a)
}
}
void ledger_processor::epoch_block_impl (nano::state_block const & block_a)
void ledger_processor::epoch_block_impl (nano::state_block & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, block_a.type (), hash));
@ -423,8 +422,8 @@ void ledger_processor::epoch_block_impl (nano::state_block const & block_a)
ledger.stats.inc (nano::stat::type::ledger, nano::stat::detail::epoch_block);
result.account = block_a.hashables.account;
result.amount = 0;
nano::block_sideband sideband (nano::block_type::state, block_a.hashables.account /* unused */, 0, 0 /* unused */, info.block_count + 1, nano::seconds_since_epoch (), epoch, false, false, true);
ledger.store.block_put (transaction, hash, block_a, sideband);
block_a.sideband_set (nano::block_sideband (block_a.hashables.account /* unused */, 0, 0 /* unused */, info.block_count + 1, nano::seconds_since_epoch (), epoch, false, false, true));
ledger.store.block_put (transaction, hash, block_a);
nano::account_info new_info (hash, block_a.representative (), info.open_block.is_zero () ? hash : info.open_block, info.balance, nano::seconds_since_epoch (), info.block_count + 1, epoch);
ledger.change_latest (transaction, block_a.hashables.account, info, new_info);
if (!ledger.store.frontier_get (transaction, info.head).is_zero ())
@ -439,7 +438,7 @@ void ledger_processor::epoch_block_impl (nano::state_block const & block_a)
}
}
void ledger_processor::change_block (nano::change_block const & block_a)
void ledger_processor::change_block (nano::change_block & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, block_a.type (), hash));
@ -471,8 +470,8 @@ void ledger_processor::change_block (nano::change_block const & block_a)
{
debug_assert (!validate_message (account, hash, block_a.signature));
result.verified = nano::signature_verification::valid;
nano::block_sideband sideband (nano::block_type::change, account, 0, info.balance, info.block_count + 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false);
ledger.store.block_put (transaction, hash, block_a, sideband);
block_a.sideband_set (nano::block_sideband (account, 0, info.balance, info.block_count + 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false /* unused */, false /* unused */, false /* unused */));
ledger.store.block_put (transaction, hash, block_a);
auto balance (ledger.balance (transaction, block_a.hashables.previous));
ledger.cache.rep_weights.representation_add (block_a.representative (), balance);
ledger.cache.rep_weights.representation_add (info.representative, 0 - balance);
@ -490,7 +489,7 @@ void ledger_processor::change_block (nano::change_block const & block_a)
}
}
void ledger_processor::send_block (nano::send_block const & block_a)
void ledger_processor::send_block (nano::send_block & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, block_a.type (), hash));
@ -527,8 +526,8 @@ void ledger_processor::send_block (nano::send_block const & block_a)
{
auto amount (info.balance.number () - block_a.hashables.balance.number ());
ledger.cache.rep_weights.representation_add (info.representative, 0 - amount);
nano::block_sideband sideband (nano::block_type::send, account, 0, block_a.hashables.balance /* unused */, info.block_count + 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false /* unused */, false /* unused */, false /* unused */);
ledger.store.block_put (transaction, hash, block_a, sideband);
block_a.sideband_set (nano::block_sideband (account, 0, block_a.hashables.balance /* unused */, info.block_count + 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false /* unused */, false /* unused */, false /* unused */));
ledger.store.block_put (transaction, hash, block_a);
nano::account_info new_info (hash, info.representative, info.open_block, block_a.hashables.balance, nano::seconds_since_epoch (), info.block_count + 1, nano::epoch::epoch_0);
ledger.change_latest (transaction, account, info, new_info);
ledger.store.pending_put (transaction, nano::pending_key (block_a.hashables.destination, hash), { account, amount, nano::epoch::epoch_0 });
@ -546,7 +545,7 @@ void ledger_processor::send_block (nano::send_block const & block_a)
}
}
void ledger_processor::receive_block (nano::receive_block const & block_a)
void ledger_processor::receive_block (nano::receive_block & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, block_a.type (), hash));
@ -595,8 +594,8 @@ void ledger_processor::receive_block (nano::receive_block const & block_a)
(void)error;
debug_assert (!error);
ledger.store.pending_del (transaction, key);
nano::block_sideband sideband (nano::block_type::receive, account, 0, new_balance, info.block_count + 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false /* unused */, false /* unused */, false /* unused */);
ledger.store.block_put (transaction, hash, block_a, sideband);
block_a.sideband_set (nano::block_sideband (account, 0, new_balance, info.block_count + 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false /* unused */, false /* unused */, false /* unused */));
ledger.store.block_put (transaction, hash, block_a);
nano::account_info new_info (hash, info.representative, info.open_block, new_balance, nano::seconds_since_epoch (), info.block_count + 1, nano::epoch::epoch_0);
ledger.change_latest (transaction, account, info, new_info);
ledger.cache.rep_weights.representation_add (info.representative, pending.amount.number ());
@ -620,7 +619,7 @@ void ledger_processor::receive_block (nano::receive_block const & block_a)
}
}
void ledger_processor::open_block (nano::open_block const & block_a)
void ledger_processor::open_block (nano::open_block & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, block_a.type (), hash));
@ -659,8 +658,8 @@ void ledger_processor::open_block (nano::open_block const & block_a)
(void)error;
debug_assert (!error);
ledger.store.pending_del (transaction, key);
nano::block_sideband sideband (nano::block_type::open, block_a.hashables.account, 0, pending.amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false /* unused */, false /* unused */, false /* unused */);
ledger.store.block_put (transaction, hash, block_a, sideband);
block_a.sideband_set (nano::block_sideband (block_a.hashables.account, 0, pending.amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false /* unused */, false /* unused */, false /* unused */));
ledger.store.block_put (transaction, hash, block_a);
nano::account_info new_info (hash, block_a.representative (), hash, pending.amount.number (), nano::seconds_since_epoch (), 1, nano::epoch::epoch_0);
ledger.change_latest (transaction, block_a.hashables.account, info, new_info);
ledger.cache.rep_weights.representation_add (block_a.representative (), pending.amount.number ());
@ -752,7 +751,7 @@ nano::uint128_t nano::ledger::account_pending (nano::transaction const & transac
return result;
}
nano::process_return nano::ledger::process (nano::write_transaction const & transaction_a, nano::block const & block_a, nano::signature_verification verification)
nano::process_return nano::ledger::process (nano::write_transaction const & transaction_a, nano::block & block_a, nano::signature_verification verification)
{
debug_assert (!nano::work_validate (block_a));
ledger_processor processor (*this, transaction_a, verification);

View file

@ -38,7 +38,7 @@ public:
bool is_send (nano::transaction const &, nano::state_block const &) const;
nano::account const & block_destination (nano::transaction const &, nano::block const &);
nano::block_hash block_source (nano::transaction const &, nano::block const &);
nano::process_return process (nano::write_transaction const &, nano::block const &, nano::signature_verification = nano::signature_verification::unknown);
nano::process_return process (nano::write_transaction const &, nano::block &, nano::signature_verification = nano::signature_verification::unknown);
bool rollback (nano::write_transaction const &, nano::block_hash const &, std::vector<std::shared_ptr<nano::block>> &);
bool rollback (nano::write_transaction const &, nano::block_hash const &);
void change_latest (nano::write_transaction const &, nano::account const &, nano::account_info const &, nano::account_info const &);