From b795fd1cba992c365ff17e8b066b33560eeae431 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Mon, 10 Aug 2020 14:54:16 +0300 Subject: [PATCH] Add source block epoch to sideband information (#2873) * Add source block epoch to sideband information With v18->v19 DB upgrade To prevent rollback issues for pruned ledger in future versions. * Fix build error & warnings * Clang formatting * Move source epoch out of block details & more tests * Remove unused header --- nano/core_test/active_transactions.cpp | 2 +- nano/core_test/block_store.cpp | 36 +++++++-- nano/core_test/election.cpp | 2 +- nano/core_test/ledger.cpp | 43 ++++++++++ nano/core_test/vote_processor.cpp | 4 +- nano/core_test/wallet.cpp | 8 ++ nano/lib/blocks.cpp | 21 ++--- nano/lib/blocks.hpp | 10 ++- nano/nano_node/entry.cpp | 8 ++ nano/node/lmdb/lmdb.cpp | 43 +++++++--- nano/secure/blockstore.hpp | 2 +- nano/secure/blockstore_partial.hpp | 3 +- nano/secure/ledger.cpp | 19 ++--- nano/secure/versioning.cpp | 105 +++++++++++++++++++++++++ nano/secure/versioning.hpp | 16 ++++ 15 files changed, 277 insertions(+), 45 deletions(-) diff --git a/nano/core_test/active_transactions.cpp b/nano/core_test/active_transactions.cpp index 9a4d49883..a9ed1adce 100644 --- a/nano/core_test/active_transactions.cpp +++ b/nano/core_test/active_transactions.cpp @@ -909,7 +909,7 @@ TEST (active_transactions, dropped_cleanup) nano::genesis genesis; auto block = genesis.open; - block->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false)); + block->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false, nano::epoch::epoch_0)); // Add to network filter to ensure proper cleanup after the election is dropped std::vector block_bytes; diff --git a/nano/core_test/block_store.cpp b/nano/core_test/block_store.cpp index 52726c35a..4cc134b46 100644 --- a/nano/core_test/block_store.cpp +++ b/nano/core_test/block_store.cpp @@ -1623,10 +1623,13 @@ TEST (mdb_block_store, upgrade_v18_v19) auto path (nano::unique_path ()); nano::keypair key1; nano::work_pool pool (std::numeric_limits::max ()); + nano::network_params network_params; nano::send_block send (nano::genesis_hash, nano::test_genesis_key.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (nano::genesis_hash)); nano::receive_block receive (send.hash (), send.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send.hash ())); nano::change_block change (receive.hash (), 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (receive.hash ())); - nano::state_block state (nano::test_genesis_key.pub, change.hash (), 0, nano::genesis_amount - nano::Gxrb_ratio, key1.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (change.hash ())); + nano::state_block state_epoch (nano::test_genesis_key.pub, change.hash (), 0, nano::genesis_amount, network_params.ledger.epochs.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (change.hash ())); + nano::state_block state_send (nano::test_genesis_key.pub, state_epoch.hash (), 0, nano::genesis_amount - nano::Gxrb_ratio, key1.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (state_epoch.hash ())); + nano::state_block state_open (key1.pub, 0, 0, nano::Gxrb_ratio, state_send.hash (), key1.prv, key1.pub, *pool.generate (key1.pub)); { nano::genesis genesis; @@ -1640,7 +1643,9 @@ TEST (mdb_block_store, upgrade_v18_v19) ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send).code); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive).code); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, change).code); - ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state).code); + ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state_epoch).code); + ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state_send).code); + ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state_open).code); // These tables need to be re-opened and populated so that an upgrade can be done auto txn = store.env.tx (transaction); @@ -1655,7 +1660,9 @@ TEST (mdb_block_store, upgrade_v18_v19) write_block_w_sideband_v18 (store, store.send_blocks, transaction, send); write_block_w_sideband_v18 (store, store.receive_blocks, transaction, receive); write_block_w_sideband_v18 (store, store.change_blocks, transaction, change); - write_block_w_sideband_v18 (store, store.state_blocks, transaction, state); + write_block_w_sideband_v18 (store, store.state_blocks, transaction, state_epoch); + write_block_w_sideband_v18 (store, store.state_blocks, transaction, state_send); + write_block_w_sideband_v18 (store, store.state_blocks, transaction, state_open); store.version_put (transaction, 18); } @@ -1678,9 +1685,22 @@ TEST (mdb_block_store, upgrade_v18_v19) ASSERT_TRUE (store.block_get (transaction, receive.hash ())); ASSERT_TRUE (store.block_get (transaction, change.hash ())); ASSERT_TRUE (store.block_get (transaction, nano::genesis_hash)); - ASSERT_TRUE (store.block_get (transaction, state.hash ())); + auto state_epoch_disk (store.block_get (transaction, state_epoch.hash ())); + ASSERT_NE (nullptr, state_epoch_disk); + ASSERT_EQ (nano::epoch::epoch_1, state_epoch_disk->sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, state_epoch_disk->sideband ().source_epoch); // Not used for epoch state blocks + ASSERT_TRUE (store.block_get (transaction, state_send.hash ())); + auto state_send_disk (store.block_get (transaction, state_send.hash ())); + ASSERT_NE (nullptr, state_send_disk); + ASSERT_EQ (nano::epoch::epoch_1, state_send_disk->sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, state_send_disk->sideband ().source_epoch); // Not used for send state blocks + ASSERT_TRUE (store.block_get (transaction, state_open.hash ())); + auto state_open_disk (store.block_get (transaction, state_open.hash ())); + ASSERT_NE (nullptr, state_open_disk); + ASSERT_EQ (nano::epoch::epoch_1, state_open_disk->sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_1, state_open_disk->sideband ().source_epoch); - ASSERT_EQ (5, store.count (transaction, store.blocks)); + ASSERT_EQ (7, store.count (transaction, store.blocks)); // Version should be correct ASSERT_LT (18, store.version_get (transaction)); @@ -1879,7 +1899,7 @@ void write_sideband_v15 (nano::mdb_store & store_a, nano::transaction & transact 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 (block->sideband ().account, block->sideband ().successor, block->sideband ().balance, block->sideband ().timestamp, block->sideband ().height, block->sideband ().details.epoch, false, false, false); + nano::block_sideband_v18 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 data; { nano::vectorstream stream (data); @@ -1895,12 +1915,14 @@ void write_block_w_sideband_v18 (nano::mdb_store & store_a, MDB_dbi database, na { auto block = store_a.block_get (transaction_a, block_a.hash ()); ASSERT_NE (block, nullptr); + auto new_sideband (block->sideband ()); + nano::block_sideband_v18 sideband_v18 (new_sideband.account, new_sideband.successor, new_sideband.balance, new_sideband.height, new_sideband.timestamp, new_sideband.details.epoch, new_sideband.details.is_send, new_sideband.details.is_receive, new_sideband.details.is_epoch); std::vector data; { nano::vectorstream stream (data); block->serialize (stream); - block->sideband ().serialize (stream, block->type ()); + sideband_v18.serialize (stream, block->type ()); } MDB_val val{ data.size (), data.data () }; diff --git a/nano/core_test/election.cpp b/nano/core_test/election.cpp index e47e79461..0479117fd 100644 --- a/nano/core_test/election.cpp +++ b/nano/core_test/election.cpp @@ -9,7 +9,7 @@ TEST (election, construction) nano::system system (1); nano::genesis genesis; auto & node = *system.nodes[0]; - genesis.open->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false)); + genesis.open->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false, nano::epoch::epoch_0)); auto election = node.active.insert (genesis.open).election; ASSERT_TRUE (election->idle ()); election->transition_active (); diff --git a/nano/core_test/ledger.cpp b/nano/core_test/ledger.cpp index cc5127f37..0df1fe69a 100644 --- a/nano/core_test/ledger.cpp +++ b/nano/core_test/ledger.cpp @@ -2369,6 +2369,8 @@ TEST (ledger, epoch_blocks_v1_general) ASSERT_FALSE (epoch1.sideband ().details.is_send); ASSERT_FALSE (epoch1.sideband ().details.is_receive); ASSERT_TRUE (epoch1.sideband ().details.is_epoch); + ASSERT_EQ (nano::epoch::epoch_1, epoch1.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch1.sideband ().source_epoch); // Not used for epoch blocks 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; @@ -2383,6 +2385,8 @@ TEST (ledger, epoch_blocks_v1_general) ASSERT_FALSE (epoch1.sideband ().details.is_send); ASSERT_FALSE (epoch1.sideband ().details.is_receive); ASSERT_TRUE (epoch1.sideband ().details.is_epoch); + ASSERT_EQ (nano::epoch::epoch_1, epoch1.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch1.sideband ().source_epoch); // Not used for epoch blocks 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 ())); @@ -2390,6 +2394,8 @@ TEST (ledger, epoch_blocks_v1_general) ASSERT_TRUE (send1.sideband ().details.is_send); ASSERT_FALSE (send1.sideband ().details.is_receive); ASSERT_FALSE (send1.sideband ().details.is_epoch); + ASSERT_EQ (nano::epoch::epoch_1, send1.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, send1.sideband ().source_epoch); // Not used for send blocks 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)); @@ -2399,10 +2405,14 @@ TEST (ledger, epoch_blocks_v1_general) ASSERT_FALSE (epoch4.sideband ().details.is_send); ASSERT_FALSE (epoch4.sideband ().details.is_receive); ASSERT_TRUE (epoch4.sideband ().details.is_epoch); + ASSERT_EQ (nano::epoch::epoch_1, epoch4.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch4.sideband ().source_epoch); // Not used for epoch blocks 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 ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive2).code); + ASSERT_EQ (nano::epoch::epoch_1, receive2.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_1, receive2.sideband ().source_epoch); ASSERT_EQ (0, ledger.balance (transaction, epoch4.hash ())); ASSERT_EQ (nano::Gxrb_ratio, ledger.balance (transaction, receive2.hash ())); ASSERT_EQ (nano::Gxrb_ratio, ledger.amount (transaction, receive2.hash ())); @@ -2431,8 +2441,12 @@ TEST (ledger, epoch_blocks_v2_general) // Set it to the first epoch and it should now succeed epoch1 = nano::state_block (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, epoch1.work); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch1).code); + ASSERT_EQ (nano::epoch::epoch_1, epoch1.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch1.sideband ().source_epoch); // Not used for epoch blocks nano::state_block epoch2 (nano::genesis_account, epoch1.hash (), nano::genesis_account, nano::genesis_amount, ledger.epoch_link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch1.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch2).code); + ASSERT_EQ (nano::epoch::epoch_2, epoch2.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch2.sideband ().source_epoch); // Not used for epoch blocks nano::state_block epoch3 (nano::genesis_account, epoch2.hash (), nano::genesis_account, nano::genesis_amount, ledger.epoch_link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch2.hash ())); ASSERT_EQ (nano::process_result::block_position, ledger.process (transaction, epoch3).code); nano::account_info genesis_info; @@ -2448,18 +2462,26 @@ TEST (ledger, epoch_blocks_v2_general) 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); + ASSERT_EQ (nano::epoch::epoch_1, send1.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, send1.sideband ().source_epoch); // Not used for send blocks 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 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); + ASSERT_EQ (nano::epoch::epoch_1, epoch4.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch4.sideband ().source_epoch); // Not used for epoch blocks nano::state_block epoch5 (destination.pub, epoch4.hash (), nano::genesis_account, 0, ledger.epoch_link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch4.hash ())); ASSERT_EQ (nano::process_result::representative_mismatch, ledger.process (transaction, epoch5).code); nano::state_block epoch6 (destination.pub, epoch4.hash (), 0, 0, ledger.epoch_link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch4.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch6).code); + ASSERT_EQ (nano::epoch::epoch_2, epoch6.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch6.sideband ().source_epoch); // Not used for epoch blocks nano::receive_block receive1 (epoch6.hash (), send1.hash (), destination.prv, destination.pub, *pool.generate (epoch6.hash ())); ASSERT_EQ (nano::process_result::block_position, ledger.process (transaction, receive1).code); nano::state_block receive2 (destination.pub, epoch6.hash (), destination.pub, nano::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, *pool.generate (epoch6.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive2).code); + ASSERT_EQ (nano::epoch::epoch_2, receive2.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_1, receive2.sideband ().source_epoch); ASSERT_EQ (0, ledger.balance (transaction, epoch6.hash ())); ASSERT_EQ (nano::Gxrb_ratio, ledger.balance (transaction, receive2.hash ())); ASSERT_EQ (nano::Gxrb_ratio, ledger.amount (transaction, receive2.hash ())); @@ -2485,19 +2507,32 @@ TEST (ledger, epoch_blocks_receive_upgrade) ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch1).code); nano::state_block send2 (nano::genesis_account, epoch1.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio * 2, 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, send2).code); + ASSERT_EQ (nano::epoch::epoch_1, send2.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, send2.sideband ().source_epoch); // Not used for send blocks nano::open_block open1 (send1.hash (), destination.pub, destination.pub, destination.prv, destination.pub, *pool.generate (destination.pub)); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, open1).code); + ASSERT_EQ (nano::epoch::epoch_0, open1.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, open1.sideband ().source_epoch); nano::receive_block receive1 (open1.hash (), send2.hash (), destination.prv, destination.pub, *pool.generate (open1.hash ())); ASSERT_EQ (nano::process_result::unreceivable, ledger.process (transaction, receive1).code); nano::state_block receive2 (destination.pub, open1.hash (), destination.pub, nano::Gxrb_ratio * 2, send2.hash (), destination.prv, destination.pub, *pool.generate (open1.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive2).code); + ASSERT_EQ (nano::epoch::epoch_1, receive2.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_1, receive2.sideband ().source_epoch); nano::account_info destination_info; ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info)); ASSERT_EQ (destination_info.epoch (), nano::epoch::epoch_1); ASSERT_FALSE (ledger.rollback (transaction, receive2.hash ())); ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info)); ASSERT_EQ (destination_info.epoch (), nano::epoch::epoch_0); + nano::pending_info pending_send2; + ASSERT_FALSE (ledger.store.pending_get (transaction, nano::pending_key (destination.pub, send2.hash ()), pending_send2)); + ASSERT_EQ (nano::test_genesis_key.pub, pending_send2.source); + ASSERT_EQ (nano::Gxrb_ratio, pending_send2.amount.number ()); + ASSERT_EQ (nano::epoch::epoch_1, pending_send2.epoch); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive2).code); + ASSERT_EQ (nano::epoch::epoch_1, receive2.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_1, receive2.sideband ().source_epoch); ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info)); ASSERT_EQ (destination_info.epoch (), nano::epoch::epoch_1); nano::keypair destination2; @@ -2520,6 +2555,8 @@ TEST (ledger, epoch_blocks_receive_upgrade) ASSERT_EQ (destination_info.epoch (), nano::epoch::epoch_1); nano::state_block receive3 (destination.pub, send3.hash (), destination.pub, nano::Gxrb_ratio * 2, send5.hash (), destination.prv, destination.pub, *pool.generate (send3.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive3).code); + ASSERT_EQ (nano::epoch::epoch_2, receive3.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_2, receive3.sideband ().source_epoch); ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info)); ASSERT_EQ (destination_info.epoch (), nano::epoch::epoch_2); // Upgrade an unopened account straight to epoch 2 @@ -2528,6 +2565,8 @@ TEST (ledger, epoch_blocks_receive_upgrade) ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send6).code); nano::state_block epoch4 (destination4.pub, 0, 0, 0, ledger.epoch_link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (destination4.pub)); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch4).code); + ASSERT_EQ (nano::epoch::epoch_2, epoch4.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch4.sideband ().source_epoch); // Not used for epoch blocks ASSERT_EQ (store->account_count (transaction), ledger.cache.account_count); } @@ -2551,6 +2590,8 @@ TEST (ledger, epoch_blocks_fork) ASSERT_EQ (nano::process_result::fork, ledger.process (transaction, epoch2).code); nano::state_block epoch3 (nano::genesis_account, send1.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 (send1.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch3).code); + ASSERT_EQ (nano::epoch::epoch_1, epoch3.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch3.sideband ().source_epoch); // Not used for epoch state blocks nano::state_block epoch4 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount, ledger.epoch_link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send1.hash ())); ASSERT_EQ (nano::process_result::fork, ledger.process (transaction, epoch2).code); } @@ -2576,6 +2617,8 @@ TEST (ledger, successor_epoch) ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, epoch_open).code); ASSERT_EQ (change, *node1.ledger.successor (transaction, change.qualified_root ())); ASSERT_EQ (epoch_open, *node1.ledger.successor (transaction, epoch_open.qualified_root ())); + ASSERT_EQ (nano::epoch::epoch_1, epoch_open.sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, epoch_open.sideband ().source_epoch); // Not used for epoch state blocks } TEST (ledger, epoch_open_pending) diff --git a/nano/core_test/vote_processor.cpp b/nano/core_test/vote_processor.cpp index 856e8e9ca..8388631ce 100644 --- a/nano/core_test/vote_processor.cpp +++ b/nano/core_test/vote_processor.cpp @@ -28,7 +28,7 @@ TEST (vote_processor, codes) ASSERT_EQ (nano::vote_code::indeterminate, node.vote_processor.vote_blocking (vote, channel)); // First vote from an account for an ongoing election - genesis.open->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false)); + genesis.open->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false, nano::epoch::epoch_0)); ASSERT_TRUE (node.active.insert (genesis.open).inserted); ASSERT_EQ (nano::vote_code::vote, node.vote_processor.vote_blocking (vote, channel)); @@ -77,7 +77,7 @@ TEST (vote_processor, invalid_signature) vote_invalid->signature.bytes[0] ^= 1; auto channel (std::make_shared (node.network.udp_channels, node.network.endpoint (), node.network_params.protocol.protocol_version)); - genesis.open->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false)); + genesis.open->sideband_set (nano::block_sideband (nano::genesis_account, 0, nano::genesis_amount, 1, nano::seconds_since_epoch (), nano::epoch::epoch_0, false, false, false, nano::epoch::epoch_0)); auto election (node.active.insert (genesis.open)); ASSERT_TRUE (election.election && election.inserted); ASSERT_EQ (1, election.election->last_votes.size ()); diff --git a/nano/core_test/wallet.cpp b/nano/core_test/wallet.cpp index 53f83e98e..0898c5da4 100644 --- a/nano/core_test/wallet.cpp +++ b/nano/core_test/wallet.cpp @@ -1240,6 +1240,8 @@ TEST (wallet, limited_difficulty) ASSERT_EQ (node.max_work_generate_difficulty (nano::work_version::work_1), node.active.limited_active_difficulty (*genesis.open)); auto send = wallet.send_action (nano::test_genesis_key.pub, nano::keypair ().pub, 1, 1); ASSERT_NE (nullptr, send); + ASSERT_EQ (nano::epoch::epoch_2, send->sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, send->sideband ().source_epoch); // Not used for send state blocks } TEST (wallet, epoch_2_validation) @@ -1263,12 +1265,16 @@ TEST (wallet, epoch_2_validation) { auto send = wallet.send_action (nano::test_genesis_key.pub, nano::test_genesis_key.pub, amount, 1); ASSERT_NE (nullptr, send); + ASSERT_EQ (nano::epoch::epoch_2, send->sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_0, send->sideband ().source_epoch); // Not used for send state blocks auto receive = wallet.receive_action (*send, nano::test_genesis_key.pub, amount, 1); ASSERT_NE (nullptr, receive); if (receive->difficulty () < node.network_params.network.publish_thresholds.base) { ASSERT_GE (receive->difficulty (), node.network_params.network.publish_thresholds.epoch_2_receive); + ASSERT_EQ (nano::epoch::epoch_2, receive->sideband ().details.epoch); + ASSERT_EQ (nano::epoch::epoch_2, receive->sideband ().source_epoch); break; } } @@ -1325,6 +1331,7 @@ TEST (wallet, epoch_2_receive_propagation) { ASSERT_GE (receive2->difficulty (), node.network_params.network.publish_thresholds.epoch_2_receive); ASSERT_EQ (nano::epoch::epoch_2, node.store.block_version (node.store.tx_begin_read (), receive2->hash ())); + ASSERT_EQ (nano::epoch::epoch_2, receive2->sideband ().source_epoch); break; } } @@ -1374,6 +1381,7 @@ TEST (wallet, epoch_2_receive_unopened) { ASSERT_GE (receive1->difficulty (), node.network_params.network.publish_thresholds.epoch_2_receive); ASSERT_EQ (nano::epoch::epoch_2, node.store.block_version (node.store.tx_begin_read (), receive1->hash ())); + ASSERT_EQ (nano::epoch::epoch_1, receive1->sideband ().source_epoch); break; } } diff --git a/nano/lib/blocks.cpp b/nano/lib/blocks.cpp index ff7673ffe..6a300641c 100644 --- a/nano/lib/blocks.cpp +++ b/nano/lib/blocks.cpp @@ -1656,11 +1656,6 @@ epoch (epoch_a), is_send (is_send_a), is_receive (is_receive_a), is_epoch (is_ep { } -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; @@ -1728,23 +1723,25 @@ std::string nano::state_subtype (nano::block_details const details_a) } } -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::block_details const & details_a) : +nano::block_sideband::block_sideband (nano::account const & account_a, nano::block_hash const & successor_a, nano::amount const & balance_a, uint64_t const height_a, uint64_t const timestamp_a, nano::block_details const & details_a, nano::epoch const source_epoch_a) : successor (successor_a), account (account_a), balance (balance_a), height (height_a), timestamp (timestamp_a), -details (details_a) +details (details_a), +source_epoch (source_epoch_a) { } -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) : +nano::block_sideband::block_sideband (nano::account const & account_a, nano::block_hash const & successor_a, nano::amount const & balance_a, uint64_t const height_a, uint64_t const timestamp_a, nano::epoch const epoch_a, bool const is_send, bool const is_receive, bool const is_epoch, nano::epoch const source_epoch_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) +details (epoch_a, is_send, is_receive, is_epoch), +source_epoch (source_epoch_a) { } @@ -1768,7 +1765,7 @@ size_t nano::block_sideband::size (nano::block_type type_a) 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 (); + result += nano::block_details::size () + sizeof (nano::epoch); } return result; } @@ -1792,6 +1789,7 @@ void nano::block_sideband::serialize (nano::stream & stream_a, nano::block_type if (type_a == nano::block_type::state) { details.serialize (stream_a); + nano::write (stream_a, static_cast (source_epoch)); } } @@ -1823,6 +1821,9 @@ bool nano::block_sideband::deserialize (nano::stream & stream_a, nano::block_typ if (type_a == nano::block_type::state) { result = details.deserialize (stream_a); + uint8_t source_epoch_uint8_t{ 0 }; + nano::read (stream_a, source_epoch_uint8_t); + source_epoch = static_cast (source_epoch_uint8_t); } } catch (std::runtime_error &) diff --git a/nano/lib/blocks.hpp b/nano/lib/blocks.hpp index ba86e5edd..02a59ebc1 100644 --- a/nano/lib/blocks.hpp +++ b/nano/lib/blocks.hpp @@ -35,7 +35,10 @@ class block_details 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 (); + static constexpr size_t size () + { + return 1; + } bool operator== (block_details const & other_a) const; void serialize (nano::stream &) const; bool deserialize (nano::stream &); @@ -55,8 +58,8 @@ 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::block_details const &); - 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); + block_sideband (nano::account const &, nano::block_hash const &, nano::amount const &, uint64_t const, uint64_t const, nano::block_details const &, nano::epoch const source_epoch_a); + block_sideband (nano::account const &, nano::block_hash const &, nano::amount const &, uint64_t const, uint64_t const, nano::epoch const epoch_a, bool const is_send, bool const is_receive, bool const is_epoch, nano::epoch const source_epoch_a); void serialize (nano::stream &, nano::block_type) const; bool deserialize (nano::stream &, nano::block_type); static size_t size (nano::block_type); @@ -66,6 +69,7 @@ public: uint64_t height{ 0 }; uint64_t timestamp{ 0 }; nano::block_details details; + nano::epoch source_epoch{ nano::epoch::epoch_0 }; }; class block { diff --git a/nano/nano_node/entry.cpp b/nano/nano_node/entry.cpp index 6ce6ca0d9..bfc0b431c 100644 --- a/nano/nano_node/entry.cpp +++ b/nano/nano_node/entry.cpp @@ -1544,6 +1544,14 @@ int main (int argc, char * const * argv) { print_error_message (boost::str (boost::format ("Incorrect sideband block details for block %1%\n") % hash.to_string ())); } + // Check link epoch version + if (sideband.details.is_receive) + { + if (sideband.source_epoch != node->store.block_version (transaction, block->link ())) + { + print_error_message (boost::str (boost::format ("Incorrect source epoch for block %1%\n") % hash.to_string ())); + } + } // Check if block work value is correct if (block->difficulty () < nano::work_threshold (block->work_version (), block->sideband ().details)) { diff --git a/nano/node/lmdb/lmdb.cpp b/nano/node/lmdb/lmdb.cpp index a49d878e8..6db093cdd 100644 --- a/nano/node/lmdb/lmdb.cpp +++ b/nano/node/lmdb/lmdb.cpp @@ -325,7 +325,7 @@ 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.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_v18 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 data; @@ -514,7 +514,7 @@ void nano::mdb_store::upgrade_v17_to_v18 (nano::write_transaction const & transa is_receive = true; } - nano::block_sideband new_sideband (sideband.account, sideband.successor, sideband.balance, sideband.height, sideband.timestamp, sideband.details.epoch, is_send, is_receive, is_epoch); + nano::block_sideband_v18 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 data; { @@ -551,17 +551,23 @@ void nano::mdb_store::upgrade_v18_to_v19 (nano::write_transaction const & transa for (auto i (nano::store_iterator> (std::make_unique>> (transaction_a, change_blocks))), n (nano::store_iterator> (nullptr)); i != n; ++i) { - legacy_open_receive_change_blocks[i->first] = { nano::block_w_sideband{ i->second.block, i->second.sideband } }; + nano::block_sideband_v18 const & old_sideband (i->second.sideband); + nano::block_sideband new_sideband (old_sideband.account, old_sideband.successor, old_sideband.balance, old_sideband.height, old_sideband.timestamp, nano::epoch::epoch_0, false, false, false, nano::epoch::epoch_0); + legacy_open_receive_change_blocks[i->first] = { nano::block_w_sideband{ i->second.block, new_sideband } }; } for (auto i (nano::store_iterator> (std::make_unique>> (transaction_a, open_blocks))), n (nano::store_iterator> (nullptr)); i != n; ++i) { - legacy_open_receive_change_blocks[i->first] = { nano::block_w_sideband{ i->second.block, i->second.sideband } }; + nano::block_sideband_v18 const & old_sideband (i->second.sideband); + nano::block_sideband new_sideband (old_sideband.account, old_sideband.successor, old_sideband.balance, old_sideband.height, old_sideband.timestamp, nano::epoch::epoch_0, false, false, false, nano::epoch::epoch_0); + legacy_open_receive_change_blocks[i->first] = { nano::block_w_sideband{ i->second.block, new_sideband } }; } for (auto i (nano::store_iterator> (std::make_unique>> (transaction_a, receive_blocks))), n (nano::store_iterator> (nullptr)); i != n; ++i) { - legacy_open_receive_change_blocks[i->first] = { nano::block_w_sideband{ i->second.block, i->second.sideband } }; + nano::block_sideband_v18 const & old_sideband (i->second.sideband); + nano::block_sideband new_sideband (old_sideband.account, old_sideband.successor, old_sideband.balance, old_sideband.height, old_sideband.timestamp, nano::epoch::epoch_0, false, false, false, nano::epoch::epoch_0); + legacy_open_receive_change_blocks[i->first] = { nano::block_w_sideband{ i->second.block, new_sideband } }; } release_assert (!mdb_drop (env.tx (transaction_a), receive_blocks, 1)); @@ -607,7 +613,7 @@ void nano::mdb_store::upgrade_v18_to_v19 (nano::write_transaction const & transa { nano::vectorstream stream (data); nano::serialize_block (stream, *block_w_sideband_v18.block); - block_w_sideband_v18.sideband.serialize (stream, nano::block_type::send); + block_w_sideband_v18.sideband.serialize (stream, nano::block_type::send); // Equal to new version for legacy blocks } nano::mdb_val value{ data.size (), (void *)data.data () }; @@ -643,17 +649,36 @@ void nano::mdb_store::upgrade_v18_to_v19 (nano::write_transaction const & transa // Write state blocks to a new table (this was not done in memory as it would push us above memory requirements) MDB_dbi temp_state_blocks; { + auto type_state (nano::block_type::state); mdb_dbi_open (env.tx (transaction_a), "temp_state_blocks", MDB_CREATE, &temp_state_blocks); for (auto i (nano::store_iterator> (std::make_unique>> (transaction_a, state_blocks))), n (nano::store_iterator> (nullptr)); i != n; ++i) { auto const & block_w_sideband_v18 (i->second); + nano::block_sideband_v18 const & old_sideband (block_w_sideband_v18.sideband); + nano::epoch source_epoch (nano::epoch::epoch_0); + // Source block v18 epoch + if (old_sideband.details.is_receive) + { + auto db_val (block_raw_get_by_type_v18 (transaction_a, block_w_sideband_v18.block->link (), type_state)); + if (db_val.is_initialized ()) + { + nano::bufferstream stream (reinterpret_cast (db_val.get ().data ()), db_val.get ().size ()); + auto source_block (nano::deserialize_block (stream, type_state)); + release_assert (source_block != nullptr); + nano::block_sideband_v18 source_sideband; + auto error (source_sideband.deserialize (stream, type_state)); + release_assert (!error); + source_epoch = source_sideband.details.epoch; + } + } + nano::block_sideband new_sideband (old_sideband.account, old_sideband.successor, old_sideband.balance, old_sideband.height, old_sideband.timestamp, old_sideband.details.epoch, old_sideband.details.is_send, old_sideband.details.is_receive, old_sideband.details.is_epoch, source_epoch); std::vector data; { nano::vectorstream stream (data); nano::serialize_block (stream, *block_w_sideband_v18.block); - block_w_sideband_v18.sideband.serialize (stream, nano::block_type::state); + new_sideband.serialize (stream, nano::block_type::state); } nano::mdb_val value{ data.size (), (void *)data.data () }; @@ -888,10 +913,10 @@ std::shared_ptr nano::mdb_store::block_get_v18 (nano::transaction c nano::bufferstream stream (reinterpret_cast (value.data ()), value.size ()); result = nano::deserialize_block (stream, type); release_assert (result != nullptr); - nano::block_sideband sideband; + nano::block_sideband_v18 sideband; auto error = (sideband.deserialize (stream, type)); release_assert (!error); - result->sideband_set (sideband); + result->sideband_set (nano::block_sideband (sideband.account, sideband.successor, sideband.balance, sideband.height, sideband.timestamp, sideband.details.epoch, sideband.details.is_send, sideband.details.is_receive, sideband.details.is_epoch, nano::epoch::epoch_0)); } return result; } diff --git a/nano/secure/blockstore.hpp b/nano/secure/blockstore.hpp index e783fe979..9c9a22fb9 100644 --- a/nano/secure/blockstore.hpp +++ b/nano/secure/blockstore.hpp @@ -23,7 +23,7 @@ class block_w_sideband_v18 { public: std::shared_ptr block; - nano::block_sideband sideband; + nano::block_sideband_v18 sideband; }; class block_w_sideband diff --git a/nano/secure/blockstore_partial.hpp b/nano/secure/blockstore_partial.hpp index 422136e34..5dbf4761d 100644 --- a/nano/secure/blockstore_partial.hpp +++ b/nano/secure/blockstore_partial.hpp @@ -31,7 +31,7 @@ public: { auto hash_l (genesis_a.hash ()); debug_assert (latest_begin (transaction_a) == latest_end ()); - 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)); + 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, nano::epoch::epoch_0)); 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 () }); @@ -371,7 +371,6 @@ public: nano::epoch block_version (nano::transaction const & transaction_a, nano::block_hash const & hash_a) override { - nano::db_val value; auto block = block_get (transaction_a, hash_a); if (block && block->type () == nano::block_type::state) { diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index bbc1a015c..a95271390 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -141,8 +141,7 @@ public: } else if (!block_a.hashables.link.is_zero () && !ledger.is_epoch_link (block_a.hashables.link)) { - auto source_version (ledger.store.block_version (transaction, block_a.hashables.link)); - nano::pending_info pending_info (ledger.account (transaction, block_a.hashables.link), block_a.hashables.balance.number () - balance, source_version); + nano::pending_info pending_info (ledger.account (transaction, block_a.hashables.link), block_a.hashables.balance.number () - balance, block_a.sideband ().source_epoch); ledger.store.pending_put (transaction, nano::pending_key (block_a.hashables.account, block_a.hashables.link), pending_info); ledger.stats.inc (nano::stat::type::rollback, nano::stat::detail::receive); } @@ -274,6 +273,7 @@ void ledger_processor::state_block_impl (nano::state_block & block_a) if (result.code == nano::process_result::progress) { nano::epoch epoch (nano::epoch::epoch_0); + nano::epoch source_epoch (nano::epoch::epoch_0); nano::account_info info; nano::amount amount (block_a.hashables.balance); auto is_send (false); @@ -323,7 +323,8 @@ void ledger_processor::state_block_impl (nano::state_block & block_a) if (result.code == nano::process_result::progress) { result.code = amount == pending.amount ? nano::process_result::progress : nano::process_result::balance_mismatch; - epoch = std::max (epoch, pending.epoch); + source_epoch = pending.epoch; + epoch = std::max (epoch, source_epoch); } } } @@ -341,7 +342,7 @@ void ledger_processor::state_block_impl (nano::state_block & block_a) if (result.code == nano::process_result::progress) { ledger.stats.inc (nano::stat::type::ledger, nano::stat::detail::state_block); - block_a.sideband_set (nano::block_sideband (block_a.hashables.account /* unused */, 0, 0 /* unused */, info.block_count + 1, nano::seconds_since_epoch (), block_details)); + block_a.sideband_set (nano::block_sideband (block_a.hashables.account /* unused */, 0, 0 /* unused */, info.block_count + 1, nano::seconds_since_epoch (), block_details, source_epoch)); ledger.store.block_put (transaction, hash, block_a); if (!info.head.is_zero ()) @@ -438,7 +439,7 @@ void ledger_processor::epoch_block_impl (nano::state_block & block_a) if (result.code == nano::process_result::progress) { ledger.stats.inc (nano::stat::type::ledger, nano::stat::detail::epoch_block); - block_a.sideband_set (nano::block_sideband (block_a.hashables.account /* unused */, 0, 0 /* unused */, info.block_count + 1, nano::seconds_since_epoch (), block_details)); + block_a.sideband_set (nano::block_sideband (block_a.hashables.account /* unused */, 0, 0 /* unused */, info.block_count + 1, nano::seconds_since_epoch (), block_details, nano::epoch::epoch_0 /* unused */)); 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); @@ -502,7 +503,7 @@ void ledger_processor::change_block (nano::change_block & block_a) { debug_assert (!validate_message (account, hash, block_a.signature)); result.verified = nano::signature_verification::valid; - block_a.sideband_set (nano::block_sideband (account, 0, info.balance, info.block_count + 1, nano::seconds_since_epoch (), block_details)); + block_a.sideband_set (nano::block_sideband (account, 0, info.balance, info.block_count + 1, nano::seconds_since_epoch (), block_details, nano::epoch::epoch_0 /* 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); @@ -562,7 +563,7 @@ void ledger_processor::send_block (nano::send_block & block_a) { auto amount (info.balance.number () - block_a.hashables.balance.number ()); ledger.cache.rep_weights.representation_add (info.representative, 0 - amount); - block_a.sideband_set (nano::block_sideband (account, 0, block_a.hashables.balance /* unused */, info.block_count + 1, nano::seconds_since_epoch (), block_details)); + block_a.sideband_set (nano::block_sideband (account, 0, block_a.hashables.balance /* unused */, info.block_count + 1, nano::seconds_since_epoch (), block_details, nano::epoch::epoch_0 /* 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); @@ -633,7 +634,7 @@ void ledger_processor::receive_block (nano::receive_block & block_a) (void)error; debug_assert (!error); ledger.store.pending_del (transaction, key); - block_a.sideband_set (nano::block_sideband (account, 0, new_balance, info.block_count + 1, nano::seconds_since_epoch (), block_details)); + block_a.sideband_set (nano::block_sideband (account, 0, new_balance, info.block_count + 1, nano::seconds_since_epoch (), block_details, nano::epoch::epoch_0 /* 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); @@ -701,7 +702,7 @@ void ledger_processor::open_block (nano::open_block & block_a) (void)error; debug_assert (!error); ledger.store.pending_del (transaction, key); - block_a.sideband_set (nano::block_sideband (block_a.hashables.account, 0, pending.amount, 1, nano::seconds_since_epoch (), block_details)); + block_a.sideband_set (nano::block_sideband (block_a.hashables.account, 0, pending.amount, 1, nano::seconds_since_epoch (), block_details, nano::epoch::epoch_0 /* 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); diff --git a/nano/secure/versioning.cpp b/nano/secure/versioning.cpp index 37fff8d4f..7de2f97c2 100644 --- a/nano/secure/versioning.cpp +++ b/nano/secure/versioning.cpp @@ -142,3 +142,108 @@ bool nano::block_sideband_v14::deserialize (nano::stream & stream_a) return result; } + +nano::block_sideband_v18::block_sideband_v18 (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::block_details const & details_a) : +successor (successor_a), +account (account_a), +balance (balance_a), +height (height_a), +timestamp (timestamp_a), +details (details_a) +{ +} + +nano::block_sideband_v18::block_sideband_v18 (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_v18::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_v18 is larger than the epoch enum"); + result += nano::block_details::size (); + } + return result; +} + +void nano::block_sideband_v18::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_v18::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; +} diff --git a/nano/secure/versioning.hpp b/nano/secure/versioning.hpp index 12d5e5093..953ab410b 100644 --- a/nano/secure/versioning.hpp +++ b/nano/secure/versioning.hpp @@ -55,4 +55,20 @@ public: std::shared_ptr state_block; nano::block_sideband_v14 sideband; }; +class block_sideband_v18 final +{ +public: + block_sideband_v18 () = default; + block_sideband_v18 (nano::account const &, nano::block_hash const &, nano::amount const &, uint64_t, uint64_t, nano::block_details const &); + block_sideband_v18 (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; +}; }