From 16f00cb14e0a24077fa5ada4a174f2834d7dd4d9 Mon Sep 17 00:00:00 2001 From: Sergey Kroshnin Date: Fri, 11 Oct 2019 00:08:20 +0300 Subject: [PATCH] RPC epoch_upgrade (#2304) * RPC epoch_upgrade * Better naming of ledger epoch link & signer * Allow count limit for epoch_upgrade command --- nano/core_test/block_store.cpp | 6 +- nano/core_test/confirmation_height.cpp | 4 +- nano/core_test/conflicts.cpp | 6 +- nano/core_test/ledger.cpp | 48 ++--- nano/core_test/node.cpp | 4 +- nano/lib/errors.cpp | 4 + nano/lib/errors.hpp | 2 + nano/nano_node/entry.cpp | 2 +- nano/node/blockprocessor.cpp | 2 +- nano/node/json_handler.cpp | 244 ++++++++++++++++++++++++- nano/node/json_handler.hpp | 1 + nano/node/node.cpp | 2 +- nano/qt/qt.cpp | 2 +- nano/rpc/rpc_handler.cpp | 1 + nano/rpc_test/rpc.cpp | 121 ++++++++++++ nano/secure/ledger.cpp | 10 +- nano/secure/ledger.hpp | 4 +- 17 files changed, 417 insertions(+), 46 deletions(-) diff --git a/nano/core_test/block_store.cpp b/nano/core_test/block_store.cpp index 28c80247..89fc6b30 100644 --- a/nano/core_test/block_store.cpp +++ b/nano/core_test/block_store.cpp @@ -1326,7 +1326,7 @@ TEST (mdb_block_store, upgrade_sideband_epoch) auto transaction (store.tx_begin_write ()); store.version_put (transaction, 11); store.initialize (transaction, genesis, ledger.rep_weights, ledger.cemented_count, ledger.block_count_cache); - nano::state_block block1 (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount, ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ())); + nano::state_block block1 (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount, ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ())); hash2 = block1.hash (); ASSERT_FALSE (mdb_dbi_open (store.env.tx (transaction), "state_v1", MDB_CREATE, &store.state_blocks_v1)); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, block1).code); @@ -1388,10 +1388,10 @@ TEST (mdb_block_store, sideband_height) ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state_send3).code); nano::state_block state_open (key1.pub, 0, 0, nano::Gxrb_ratio, state_send1.hash (), key1.prv, key1.pub, *pool.generate (key1.pub)); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, state_open).code); - nano::state_block epoch (key1.pub, state_open.hash (), 0, nano::Gxrb_ratio, ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (state_open.hash ())); + nano::state_block epoch (key1.pub, state_open.hash (), 0, nano::Gxrb_ratio, ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (state_open.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch).code); ASSERT_EQ (nano::epoch::epoch_1, store.block_version (transaction, epoch.hash ())); - nano::state_block epoch_open (key2.pub, 0, 0, 0, ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (key2.pub)); + nano::state_block epoch_open (key2.pub, 0, 0, 0, ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (key2.pub)); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch_open).code); ASSERT_EQ (nano::epoch::epoch_1, store.block_version (transaction, epoch_open.hash ())); nano::state_block state_receive (key2.pub, epoch_open.hash (), 0, nano::Gxrb_ratio, state_send2.hash (), key2.prv, key2.pub, *pool.generate (epoch_open.hash ())); diff --git a/nano/core_test/confirmation_height.cpp b/nano/core_test/confirmation_height.cpp index 4d3032b3..542b85d2 100644 --- a/nano/core_test/confirmation_height.cpp +++ b/nano/core_test/confirmation_height.cpp @@ -512,9 +512,9 @@ TEST (confirmation_height, all_block_types) nano::state_block state_change (key2.pub, state_send.hash (), nano::test_genesis_key.pub, nano::Gxrb_ratio, 0, key2.prv, key2.pub, *system.work.generate (state_send.hash ())); - nano::state_block epoch (key2.pub, state_change.hash (), nano::test_genesis_key.pub, nano::Gxrb_ratio, node->ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (state_change.hash ())); + nano::state_block epoch (key2.pub, state_change.hash (), nano::test_genesis_key.pub, nano::Gxrb_ratio, node->ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (state_change.hash ())); - nano::state_block epoch1 (key1.pub, change.hash (), key2.pub, nano::Gxrb_ratio, node->ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (change.hash ())); + nano::state_block epoch1 (key1.pub, change.hash (), key2.pub, nano::Gxrb_ratio, node->ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (change.hash ())); nano::state_block state_send1 (key1.pub, epoch1.hash (), 0, nano::Gxrb_ratio - 1, key2.pub, key1.prv, key1.pub, *system.work.generate (epoch1.hash ())); nano::state_block state_receive2 (key2.pub, epoch.hash (), 0, nano::Gxrb_ratio + 1, state_send1.hash (), key2.prv, key2.pub, *system.work.generate (epoch.hash ())); diff --git a/nano/core_test/conflicts.cpp b/nano/core_test/conflicts.cpp index 889d8e63..c170bc24 100644 --- a/nano/core_test/conflicts.cpp +++ b/nano/core_test/conflicts.cpp @@ -241,8 +241,8 @@ TEST (conflicts, adjusted_difficulty) node1.process_active (send3); auto send4 (std::make_shared (key1.pub, send3->hash (), key1.pub, 0, key3.pub, key1.prv, key1.pub, *system.work.generate (send3->hash ()))); node1.process_active (send4); - ASSERT_EQ (node1.ledger.signer (node1.ledger.link (nano::epoch::epoch_1)), nano::test_genesis_key.pub); - auto open_epoch1 (std::make_shared (key2.pub, 0, 0, 0, node1.ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (key2.pub))); + ASSERT_EQ (node1.ledger.epoch_signer (node1.ledger.epoch_link (nano::epoch::epoch_1)), nano::test_genesis_key.pub); + auto open_epoch1 (std::make_shared (key2.pub, 0, 0, 0, node1.ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (key2.pub))); node1.process_active (open_epoch1); auto receive2 (std::make_shared (key2.pub, open_epoch1->hash (), 0, nano::xrb_ratio, send3->hash (), key2.prv, key2.pub, *system.work.generate (open_epoch1->hash ()))); node1.process_active (receive2); @@ -280,7 +280,7 @@ TEST (conflicts, adjusted_difficulty) ASSERT_GT (adjusted_difficulties.find (open2->hash ())->second, adjusted_difficulties.find (change1->hash ())->second); // Independent elections can have higher difficulty than adjusted tree nano::keypair key4; - auto open_epoch2 (std::make_shared (key4.pub, 0, 0, 0, node1.ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (key4.pub, adjusted_difficulties.find (send1->hash ())->second))); + auto open_epoch2 (std::make_shared (key4.pub, 0, 0, 0, node1.ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (key4.pub, adjusted_difficulties.find (send1->hash ())->second))); uint64_t difficulty; ASSERT_FALSE (nano::work_validate (*open_epoch2, &difficulty)); ASSERT_GT (difficulty, adjusted_difficulties.find (send1->hash ())->second); diff --git a/nano/core_test/ledger.cpp b/nano/core_test/ledger.cpp index 884312e6..0a7cc401 100644 --- a/nano/core_test/ledger.cpp +++ b/nano/core_test/ledger.cpp @@ -2296,9 +2296,9 @@ TEST (ledger, epoch_blocks_v1_general) store->initialize (transaction, genesis, ledger.rep_weights, ledger.cemented_count, ledger.block_count_cache); nano::work_pool pool (std::numeric_limits::max ()); nano::keypair destination; - nano::state_block epoch1 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount, ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ())); + 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::state_block epoch2 (nano::genesis_account, epoch1.hash (), nano::genesis_account, nano::genesis_amount, ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch1.hash ())); + 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; ASSERT_FALSE (ledger.store.account_get (transaction, nano::genesis_account, genesis_info)); @@ -2315,9 +2315,9 @@ TEST (ledger, epoch_blocks_v1_general) ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code); 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.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (destination.pub)); + 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.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (destination.pub)); + 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::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); @@ -2342,15 +2342,15 @@ TEST (ledger, epoch_blocks_v2_general) store->initialize (transaction, genesis, ledger.rep_weights, ledger.cemented_count, ledger.block_count_cache); nano::work_pool pool (std::numeric_limits::max ()); nano::keypair destination; - nano::state_block epoch1 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount, ledger.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ())); + nano::state_block epoch1 (nano::genesis_account, genesis.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 (genesis.hash ())); // Trying to upgrade from epoch 0 to epoch 2. It is a requirement epoch upgrades are sequential unless the account is unopened ASSERT_EQ (nano::process_result::block_position, ledger.process (transaction, epoch1).code); // 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.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, epoch1.work); + 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); - nano::state_block epoch2 (nano::genesis_account, epoch1.hash (), nano::genesis_account, nano::genesis_amount, ledger.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch1.hash ())); + 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); - nano::state_block epoch3 (nano::genesis_account, epoch2.hash (), nano::genesis_account, nano::genesis_amount, ledger.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch2.hash ())); + 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; ASSERT_FALSE (ledger.store.account_get (transaction, nano::genesis_account, genesis_info)); @@ -2367,11 +2367,11 @@ TEST (ledger, epoch_blocks_v2_general) ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send1).code); 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.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (destination.pub)); + 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::state_block epoch5 (destination.pub, epoch4.hash (), nano::genesis_account, 0, ledger.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch4.hash ())); + 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.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch4.hash ())); + 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); 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); @@ -2398,7 +2398,7 @@ TEST (ledger, epoch_blocks_receive_upgrade) nano::keypair destination; nano::state_block send1 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, destination.pub, 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); - nano::state_block epoch1 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send1.hash ())); + nano::state_block epoch1 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, 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, 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); @@ -2424,7 +2424,7 @@ TEST (ledger, epoch_blocks_receive_upgrade) ASSERT_EQ (nano::process_result::unreceivable, ledger.process (transaction, open2).code); // Upgrade to epoch 2 and send to destination. Try to create an open block from an epoch 2 source block. nano::keypair destination3; - nano::state_block epoch2 (nano::genesis_account, send2.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio * 2, ledger.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send2.hash ())); + nano::state_block epoch2 (nano::genesis_account, send2.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio * 2, ledger.epoch_link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send2.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, epoch2).code); nano::state_block send4 (nano::genesis_account, epoch2.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio * 3, destination3.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (epoch2.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send4).code); @@ -2443,7 +2443,7 @@ TEST (ledger, epoch_blocks_receive_upgrade) nano::keypair destination4; nano::state_block send6 (nano::genesis_account, send5.hash (), nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio * 5, destination4.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send5.hash ())); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, send6).code); - nano::state_block epoch4 (destination4.pub, 0, 0, 0, ledger.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (destination4.pub)); + 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); } @@ -2461,13 +2461,13 @@ TEST (ledger, epoch_blocks_fork) nano::keypair destination; nano::send_block send1 (genesis.hash (), nano::account (0), nano::genesis_amount, 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); - nano::state_block epoch1 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount, ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ())); + 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::fork, ledger.process (transaction, epoch1).code); - nano::state_block epoch2 (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount, ledger.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ())); + nano::state_block epoch2 (nano::genesis_account, genesis.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 (genesis.hash ())); 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.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send1.hash ())); + 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); - nano::state_block epoch4 (nano::genesis_account, send1.hash (), nano::genesis_account, nano::genesis_amount, ledger.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (send1.hash ())); + 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); } @@ -2481,7 +2481,7 @@ TEST (ledger, successor_epoch) nano::state_block open (key1.pub, 0, key1.pub, 1, send1.hash (), key1.prv, key1.pub, *pool.generate (key1.pub)); nano::state_block change (key1.pub, open.hash (), key1.pub, 1, 0, key1.prv, key1.pub, *pool.generate (open.hash ())); auto open_hash = open.hash (); - nano::state_block epoch_open (reinterpret_cast (open_hash), 0, 0, 0, system.nodes[0]->ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (open.hash ())); + nano::state_block epoch_open (reinterpret_cast (open_hash), 0, 0, 0, system.nodes[0]->ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (open.hash ())); auto transaction (system.nodes[0]->store.tx_begin_write ()); ASSERT_EQ (nano::process_result::progress, system.nodes[0]->ledger.process (transaction, send1).code); ASSERT_EQ (nano::process_result::progress, system.nodes[0]->ledger.process (transaction, open).code); @@ -2550,7 +2550,7 @@ TEST (ledger, block_hash_account_conflict) .previous (0) .representative (0) .balance (0) - .link (node1.ledger.link (nano::epoch::epoch_1)) + .link (node1.ledger.epoch_link (nano::epoch::epoch_1)) .sign (nano::test_genesis_key.prv, nano::test_genesis_key.pub) .work (*pool.generate (receive1->hash ())) .build (); @@ -2634,7 +2634,7 @@ TEST (ledger, could_fit) ASSERT_TRUE (ledger.could_fit (transaction, receive1)); ASSERT_TRUE (ledger.could_fit (transaction, receive2)); // Test epoch (state) - nano::state_block epoch1 (key1.pub, receive1.hash (), nano::genesis_account, 2, ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (receive1.hash ())); + nano::state_block epoch1 (key1.pub, receive1.hash (), nano::genesis_account, 2, ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (receive1.hash ())); ASSERT_FALSE (ledger.could_fit (transaction, epoch1)); ASSERT_EQ (nano::process_result::progress, ledger.process (transaction, receive1).code); ASSERT_TRUE (ledger.could_fit (transaction, receive1)); @@ -2654,7 +2654,7 @@ TEST (ledger, unchecked_epoch) node1.work_generate_blocking (*send1); auto open1 (std::make_shared (destination.pub, 0, destination.pub, nano::Gxrb_ratio, send1->hash (), destination.prv, destination.pub, 0)); node1.work_generate_blocking (*open1); - auto epoch1 (std::make_shared (destination.pub, open1->hash (), destination.pub, nano::Gxrb_ratio, node1.ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0)); + auto epoch1 (std::make_shared (destination.pub, open1->hash (), destination.pub, nano::Gxrb_ratio, node1.ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0)); node1.work_generate_blocking (*epoch1); node1.block_processor.add (epoch1); node1.block_processor.flush (); @@ -2693,10 +2693,10 @@ TEST (ledger, unchecked_epoch_invalid) auto open1 (std::make_shared (destination.pub, 0, destination.pub, nano::Gxrb_ratio, send1->hash (), destination.prv, destination.pub, 0)); node1.work_generate_blocking (*open1); // Epoch block with account own signature - auto epoch1 (std::make_shared (destination.pub, open1->hash (), destination.pub, nano::Gxrb_ratio, node1.ledger.link (nano::epoch::epoch_1), destination.prv, destination.pub, 0)); + auto epoch1 (std::make_shared (destination.pub, open1->hash (), destination.pub, nano::Gxrb_ratio, node1.ledger.epoch_link (nano::epoch::epoch_1), destination.prv, destination.pub, 0)); node1.work_generate_blocking (*epoch1); // Pseudo epoch block (send subtype, destination - epoch link) - auto epoch2 (std::make_shared (destination.pub, open1->hash (), destination.pub, nano::Gxrb_ratio - 1, node1.ledger.link (nano::epoch::epoch_1), destination.prv, destination.pub, 0)); + auto epoch2 (std::make_shared (destination.pub, open1->hash (), destination.pub, nano::Gxrb_ratio - 1, node1.ledger.epoch_link (nano::epoch::epoch_1), destination.prv, destination.pub, 0)); node1.work_generate_blocking (*epoch2); node1.block_processor.add (epoch1); node1.block_processor.add (epoch2); diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index b85d624e..135a0673 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -2554,7 +2554,7 @@ TEST (node, vote_by_hash_epoch_block_republish) system.wallet (1)->insert_adhoc (key2.prv); nano::genesis genesis; auto send1 (std::make_shared (genesis.hash (), key2.pub, std::numeric_limits::max () - system.nodes[0]->config.receive_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ()))); - auto epoch1 (std::make_shared (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount, system.nodes[0]->ledger.link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ()))); + auto epoch1 (std::make_shared (nano::genesis_account, genesis.hash (), nano::genesis_account, nano::genesis_amount, system.nodes[0]->ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ()))); system.nodes[0]->process_active (send1); system.deadline_set (5s); while (!system.nodes[1]->block (send1->hash ())) @@ -2594,7 +2594,7 @@ TEST (node, epoch_conflict_confirm) auto send (std::make_shared (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 1, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ()))); auto open (std::make_shared (key.pub, 0, key.pub, 1, send->hash (), key.prv, key.pub, *system.work.generate (key.pub))); auto change (std::make_shared (key.pub, open->hash (), key.pub, 1, 0, key.prv, key.pub, *system.work.generate (open->hash ()))); - auto epoch (std::make_shared (change->root (), 0, 0, 0, node0->ledger.link (nano::epoch::epoch_1), epoch_signer.prv, epoch_signer.pub, *system.work.generate (open->hash ()))); + auto epoch (std::make_shared (change->root (), 0, 0, 0, node0->ledger.epoch_link (nano::epoch::epoch_1), epoch_signer.prv, epoch_signer.pub, *system.work.generate (open->hash ()))); { auto transaction (node0->store.tx_begin_write ()); ASSERT_EQ (nano::process_result::progress, node0->block_processor.process_one (transaction, send).code); diff --git a/nano/lib/errors.cpp b/nano/lib/errors.cpp index a7a959c9..ef962c22 100644 --- a/nano/lib/errors.cpp +++ b/nano/lib/errors.cpp @@ -170,6 +170,10 @@ std::string nano::error_rpc_messages::message (int ev) const return "Invalid balance number"; case nano::error_rpc::invalid_destinations: return "Invalid destinations number"; + case nano::error_rpc::invalid_epoch: + return "Invalid epoch number"; + case nano::error_rpc::invalid_epoch_signer: + return "Incorrect epoch signer"; case nano::error_rpc::invalid_offset: return "Invalid offset"; case nano::error_rpc::invalid_missing_type: diff --git a/nano/lib/errors.hpp b/nano/lib/errors.hpp index 11378e53..772e148a 100644 --- a/nano/lib/errors.hpp +++ b/nano/lib/errors.hpp @@ -98,6 +98,8 @@ enum class error_rpc disabled_bootstrap_legacy, invalid_balance, invalid_destinations, + invalid_epoch, + invalid_epoch_signer, invalid_offset, invalid_missing_type, invalid_root, diff --git a/nano/nano_node/entry.cpp b/nano/nano_node/entry.cpp index 7f69c292..1913cba0 100644 --- a/nano/nano_node/entry.cpp +++ b/nano/nano_node/entry.cpp @@ -887,7 +887,7 @@ int main (int argc, char * const * argv) } if (node.node->ledger.is_epoch_link (state_block.hashables.link) && state_block.hashables.balance == prev_balance) { - invalid = validate_message (node.node->ledger.signer (block->link ()), hash, block->block_signature ()); + invalid = validate_message (node.node->ledger.epoch_signer (block->link ()), hash, block->block_signature ()); } } if (invalid) diff --git a/nano/node/blockprocessor.cpp b/nano/node/blockprocessor.cpp index b7fa6501..98a2f5c7 100644 --- a/nano/node/blockprocessor.cpp +++ b/nano/node/blockprocessor.cpp @@ -184,7 +184,7 @@ void nano::block_processor::verify_state_blocks (nano::unique_lock & nano::account account (item.block->account ()); if (!item.block->link ().is_zero () && node.ledger.is_epoch_link (item.block->link ())) { - account = node.ledger.signer (item.block->link ()); + account = node.ledger.epoch_signer (item.block->link ()); } else if (!item.account.is_zero ()) { diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index 1b51bf1d..99c954a5 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -2040,6 +2040,247 @@ void nano::json_handler::deterministic_key () response_errors (); } +void epoch_upgrader (std::shared_ptr node_a, nano::private_key const & prv_a, nano::epoch epoch_a, uint64_t count_limit) +{ + uint64_t const upgrade_batch_size = 1000; + nano::block_builder builder; + auto link (node_a->ledger.epoch_link (epoch_a)); + nano::raw_key raw_key; + raw_key.data = prv_a; + auto signer (nano::pub_key (prv_a)); + assert (signer == node_a->ledger.epoch_signer (link)); + + class account_upgrade_item final + { + public: + nano::account account{ 0 }; + uint64_t modified{ 0 }; + }; + class account_tag + { + }; + class modified_tag + { + }; + boost::multi_index_container< + account_upgrade_item, + boost::multi_index::indexed_by< + boost::multi_index::ordered_non_unique, boost::multi_index::member, std::greater>, + boost::multi_index::hashed_unique, boost::multi_index::member>>> + accounts_list; + + bool finished_upgrade (false); + + while (!finished_upgrade && !node_a->stopped) + { + bool finished_accounts (false); + uint64_t total_upgraded_accounts (0); + while (!finished_accounts && count_limit != 0 && !node_a->stopped) + { + { + auto transaction (node_a->store.tx_begin_read ()); + // Collect accounts to upgrade + for (auto i (node_a->store.latest_begin (transaction)), n (node_a->store.latest_end ()); i != n; ++i) + { + nano::account const & account (i->first); + nano::account_info const & info (i->second); + if (info.epoch () < epoch_a) + { + release_assert (nano::epochs::is_sequential (info.epoch (), epoch_a)); + accounts_list.insert (account_upgrade_item{ account, info.modified }); + } + } + } + + /* Upgrade accounts + Repeat until accounts with previous epoch exist in latest table */ + uint64_t upgraded_accounts (0); + for (auto i (accounts_list.get ().begin ()), n (accounts_list.get ().end ()); i != n && upgraded_accounts < upgrade_batch_size && upgraded_accounts < count_limit && !node_a->stopped; ++i) + { + auto transaction (node_a->store.tx_begin_read ()); + nano::account_info info; + if (!node_a->store.account_get (transaction, i->account, info) && info.epoch () < epoch_a) + { + auto epoch = builder.state () + .account (i->account) + .previous (info.head) + .representative (info.representative) + .balance (info.balance) + .link (link) + .sign (raw_key, signer) + .work (node_a->work_generate_blocking (info.head).value_or (0)) + .build (); + bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ())); + bool valid_work (!nano::work_validate (*epoch.get ())); + nano::process_result result (nano::process_result::old); + if (valid_signature && valid_work) + { + result = node_a->process_local (std::move (epoch)).code; + } + if (result == nano::process_result::progress) + { + ++upgraded_accounts; + } + else + { + bool fork (result == nano::process_result::fork); + node_a->logger.always_log (boost::str (boost::format ("Failed to upgrade account %1%. Valid signature: %2%. Valid work: %3%. Block processor fork: %4%") % i->account.to_account () % valid_signature % valid_work % fork)); + } + } + } + total_upgraded_accounts += upgraded_accounts; + count_limit -= upgraded_accounts; + + if (!accounts_list.empty ()) + { + node_a->logger.always_log (boost::str (boost::format ("%1% accounts were upgraded to new epoch, %2% remain...") % total_upgraded_accounts % (accounts_list.size () - upgraded_accounts))); + accounts_list.clear (); + } + else + { + node_a->logger.always_log (boost::str (boost::format ("%1% total accounts were upgraded to new epoch") % total_upgraded_accounts)); + finished_accounts = true; + } + } + + // Pending blocks upgrade + bool finished_pending (false); + uint64_t total_upgraded_pending (0); + while (!finished_pending && count_limit != 0 && !node_a->stopped) + { + uint64_t upgraded_pending (0); + auto transaction (node_a->store.tx_begin_read ()); + for (auto i (node_a->store.pending_begin (transaction, nano::pending_key (1, 0))), n (node_a->store.pending_end ()); i != n && upgraded_pending < upgrade_batch_size && upgraded_pending < count_limit && !node_a->stopped;) + { + bool to_next_account (false); + nano::pending_key const & key (i->first); + if (!node_a->store.account_exists (transaction, key.account)) + { + nano::pending_info const & info (i->second); + if (info.epoch < epoch_a) + { + release_assert (nano::epochs::is_sequential (info.epoch, epoch_a)); + auto epoch = builder.state () + .account (key.account) + .previous (0) + .representative (0) + .balance (0) + .link (link) + .sign (raw_key, signer) + .work (node_a->work_generate_blocking (key.account).value_or (0)) + .build (); + bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ())); + bool valid_work (!nano::work_validate (*epoch.get ())); + nano::process_result result (nano::process_result::old); + if (valid_signature && valid_work) + { + result = node_a->process_local (std::move (epoch)).code; + } + if (result == nano::process_result::progress) + { + ++upgraded_pending; + to_next_account = true; + } + else + { + bool fork (result == nano::process_result::fork); + node_a->logger.always_log (boost::str (boost::format ("Failed to upgrade account with pending blocks %1%. Valid signature: %2%. Valid work: %3%. Block processor fork: %4%") % key.account.to_account () % valid_signature % valid_work % fork)); + } + } + } + else + { + to_next_account = true; + } + if (to_next_account) + { + // Move to next account if pending account exists or was upgraded + if (key.account.number () == std::numeric_limits::max ()) + { + break; + } + else + { + i = node_a->store.pending_begin (transaction, nano::pending_key (key.account.number () + 1, 0)); + } + } + else + { + // Move to next pending item + ++i; + } + } + total_upgraded_pending += upgraded_pending; + count_limit -= upgraded_pending; + + // Repeat if some pending accounts were upgraded + if (upgraded_pending != 0) + { + node_a->logger.always_log (boost::str (boost::format ("%1% unopened accounts with pending blocks were upgraded to new epoch...") % total_upgraded_pending)); + } + else + { + node_a->logger.always_log (boost::str (boost::format ("%1% total unopened accounts with pending blocks were upgraded to new epoch") % total_upgraded_pending)); + finished_pending = true; + } + } + + finished_upgrade = (total_upgraded_accounts == 0) && (total_upgraded_pending == 0); + } + + node_a->logger.always_log ("Epoch upgrade is completed"); +} + +/* + * @warning This is an internal/diagnostic RPC, do not rely on its interface being stable + */ +void nano::json_handler::epoch_upgrade () +{ + nano::epoch epoch (nano::epoch::invalid); + uint8_t epoch_int (request.get ("epoch")); + switch (epoch_int) + { + case 1: + epoch = nano::epoch::epoch_1; + break; + case 2: + epoch = nano::epoch::epoch_2; + break; + default: + break; + } + if (epoch != nano::epoch::invalid) + { + uint64_t count_limit (count_optional_impl ()); + std::string key_text (request.get ("key")); + nano::private_key prv; + if (!prv.decode_hex (key_text)) + { + if (nano::pub_key (prv) == node.ledger.epoch_signer (node.ledger.epoch_link (epoch))) + { + auto node_l (node.shared ()); + node.worker.push_task ([node_l, prv, epoch, count_limit]() { + epoch_upgrader (node_l, prv, epoch, count_limit); + }); + response_l.put ("started", "1"); + } + else + { + ec = nano::error_rpc::invalid_epoch_signer; + } + } + else + { + ec = nano::error_common::bad_private_key; + } + } + else + { + ec = nano::error_rpc::invalid_epoch; + } + response_errors (); +} + void nano::json_handler::frontiers () { auto start (account_impl ()); @@ -2189,7 +2430,7 @@ public: if (raw && accounts_filter.empty ()) { tree.put ("subtype", "epoch"); - tree.put ("account", handler.node.ledger.signer (block_a.link ()).to_account ()); + tree.put ("account", handler.node.ledger.epoch_signer (block_a.link ()).to_account ()); } } else @@ -4765,6 +5006,7 @@ ipc_json_handler_no_arg_func_map create_ipc_json_handler_no_arg_func_map () no_arg_funcs.emplace ("delegators", &nano::json_handler::delegators); no_arg_funcs.emplace ("delegators_count", &nano::json_handler::delegators_count); no_arg_funcs.emplace ("deterministic_key", &nano::json_handler::deterministic_key); + no_arg_funcs.emplace ("epoch_upgrade", &nano::json_handler::epoch_upgrade); no_arg_funcs.emplace ("frontiers", &nano::json_handler::frontiers); no_arg_funcs.emplace ("frontier_count", &nano::json_handler::account_count); no_arg_funcs.emplace ("keepalive", &nano::json_handler::keepalive); diff --git a/nano/node/json_handler.hpp b/nano/node/json_handler.hpp index 11a6c40d..9a8031fd 100644 --- a/nano/node/json_handler.hpp +++ b/nano/node/json_handler.hpp @@ -63,6 +63,7 @@ public: void delegators (); void delegators_count (); void deterministic_key (); + void epoch_upgrade (); void frontiers (); void keepalive (); void key_create (); diff --git a/nano/node/node.cpp b/nano/node/node.cpp index ac1f74c1..2a26c728 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1302,7 +1302,7 @@ bool nano::node::validate_block_by_previous (nano::transaction const & transacti { if (block_l->hashables.balance == prev_balance && ledger.is_epoch_link (block_l->hashables.link)) { - account = ledger.signer (block_l->link ()); + account = ledger.epoch_signer (block_l->link ()); } } } diff --git a/nano/qt/qt.cpp b/nano/qt/qt.cpp index 01e19b33..ef4f05fb 100644 --- a/nano/qt/qt.cpp +++ b/nano/qt/qt.cpp @@ -571,7 +571,7 @@ public: else if (balance == previous_balance && ledger.is_epoch_link (block_a.hashables.link)) { type = "Epoch"; - account = ledger.signer (block_a.hashables.link); + account = ledger.epoch_signer (block_a.hashables.link); } else { diff --git a/nano/rpc/rpc_handler.cpp b/nano/rpc/rpc_handler.cpp index 14593591..2ad08b9b 100644 --- a/nano/rpc/rpc_handler.cpp +++ b/nano/rpc/rpc_handler.cpp @@ -127,6 +127,7 @@ std::unordered_set create_rpc_control_impls () set.emplace ("bootstrap_lazy"); set.emplace ("confirmation_height_currently_processing"); set.emplace ("database_txn_tracker"); + set.emplace ("epoch_upgrade"); set.emplace ("keepalive"); set.emplace ("ledger"); set.emplace ("node_id"); diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index 6a70802e..ca9c7b5d 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -7147,3 +7147,124 @@ TEST (rpc, deprecated_account_format) boost::optional deprecated_account_format2 (response2.json.get_optional ("deprecated_account_format")); ASSERT_TRUE (deprecated_account_format2.is_initialized ()); } + +TEST (rpc, epoch_upgrade) +{ + nano::system system (24000, 1); + auto node = system.nodes.front (); + nano::keypair key1, key2, key3; + nano::genesis genesis; + nano::keypair epoch_signer (nano::test_genesis_key); + auto send1 (std::make_shared (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 1, key1.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ()))); // to opened account + ASSERT_EQ (nano::process_result::progress, node->process (*send1).code); + auto send2 (std::make_shared (nano::test_genesis_key.pub, send1->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 2, key2.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send1->hash ()))); // to unopened account (pending) + ASSERT_EQ (nano::process_result::progress, node->process (*send2).code); + auto send3 (std::make_shared (nano::test_genesis_key.pub, send2->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 3, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send2->hash ()))); // to burn (0) + ASSERT_EQ (nano::process_result::progress, node->process (*send3).code); + nano::account max_account (std::numeric_limits::max ()); + auto send4 (std::make_shared (nano::test_genesis_key.pub, send3->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 4, max_account, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send3->hash ()))); // to max account + ASSERT_EQ (nano::process_result::progress, node->process (*send4).code); + auto open (std::make_shared (key1.pub, 0, key1.pub, 1, send1->hash (), key1.prv, key1.pub, *system.work.generate (key1.pub))); + ASSERT_EQ (nano::process_result::progress, node->process (*open).code); + // Check accounts epochs + { + auto transaction (node->store.tx_begin_read ()); + ASSERT_EQ (2, node->store.account_count (transaction)); + for (auto i (node->store.latest_begin (transaction)); i != node->store.latest_end (); ++i) + { + nano::account_info info (i->second); + ASSERT_EQ (info.epoch (), nano::epoch::epoch_0); + } + } + enable_ipc_transport_tcp (node->config.ipc_config.transport_tcp); + nano::node_rpc_config node_rpc_config; + nano::ipc::ipc_server ipc_server (*node, node_rpc_config); + nano::rpc_config rpc_config (true); + nano::ipc_rpc_processor ipc_rpc_processor (system.io_ctx, rpc_config); + nano::rpc rpc (system.io_ctx, rpc_config, ipc_rpc_processor); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "epoch_upgrade"); + request.put ("epoch", 1); + request.put ("key", epoch_signer.prv.data.to_string ()); + test_response response (request, rpc.config.port, system.io_ctx); + system.deadline_set (5s); + while (response.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response.status); + ASSERT_EQ ("1", response.json.get ("started")); + system.deadline_set (5s); + bool done (false); + while (!done) + { + auto transaction (node->store.tx_begin_read ()); + done = (4 == node->store.account_count (transaction)); + ASSERT_NO_ERROR (system.poll ()); + } + // Check upgrade + { + auto transaction (node->store.tx_begin_read ()); + ASSERT_EQ (4, node->store.account_count (transaction)); + for (auto i (node->store.latest_begin (transaction)); i != node->store.latest_end (); ++i) + { + nano::account_info info (i->second); + ASSERT_EQ (info.epoch (), nano::epoch::epoch_1); + } + ASSERT_TRUE (node->store.account_exists (transaction, key1.pub)); + ASSERT_TRUE (node->store.account_exists (transaction, key2.pub)); + ASSERT_TRUE (node->store.account_exists (transaction, std::numeric_limits::max ())); + ASSERT_FALSE (node->store.account_exists (transaction, 0)); + } + + // Epoch 2 upgrade + auto genesis_latest (node->latest (nano::test_genesis_key.pub)); + auto send5 (std::make_shared (nano::test_genesis_key.pub, genesis_latest, nano::test_genesis_key.pub, nano::genesis_amount - 5, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis_latest))); // to burn (0) + ASSERT_EQ (nano::process_result::progress, node->process (*send5).code); + auto send6 (std::make_shared (nano::test_genesis_key.pub, send5->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 6, key1.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send5->hash ()))); // to key1 (again) + ASSERT_EQ (nano::process_result::progress, node->process (*send6).code); + auto key1_latest (node->latest (key1.pub)); + auto send7 (std::make_shared (key1.pub, key1_latest, key1.pub, 0, key3.pub, key1.prv, key1.pub, *system.work.generate (key1_latest))); // to key3 + ASSERT_EQ (nano::process_result::progress, node->process (*send7).code); + { + // Check pending entry + auto transaction (node->store.tx_begin_read ()); + nano::pending_info info; + ASSERT_FALSE (node->store.pending_get (transaction, nano::pending_key (key3.pub, send7->hash ()), info)); + ASSERT_EQ (nano::epoch::epoch_1, info.epoch); + } + + request.put ("epoch", 2); + test_response response2 (request, rpc.config.port, system.io_ctx); + system.deadline_set (5s); + while (response2.status == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + ASSERT_EQ (200, response2.status); + ASSERT_EQ ("1", response2.json.get ("started")); + system.deadline_set (5s); + bool done2 (false); + while (!done2) + { + auto transaction (node->store.tx_begin_read ()); + done2 = (5 == node->store.account_count (transaction)); + ASSERT_NO_ERROR (system.poll ()); + } + // Check upgrade + { + auto transaction (node->store.tx_begin_read ()); + ASSERT_EQ (5, node->store.account_count (transaction)); + for (auto i (node->store.latest_begin (transaction)); i != node->store.latest_end (); ++i) + { + nano::account_info info (i->second); + ASSERT_EQ (info.epoch (), nano::epoch::epoch_2); + } + ASSERT_TRUE (node->store.account_exists (transaction, key1.pub)); + ASSERT_TRUE (node->store.account_exists (transaction, key2.pub)); + ASSERT_TRUE (node->store.account_exists (transaction, key3.pub)); + ASSERT_TRUE (node->store.account_exists (transaction, std::numeric_limits::max ())); + ASSERT_FALSE (node->store.account_exists (transaction, 0)); + } +} diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index e73b0f3e..34a33ad4 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -211,7 +211,7 @@ bool ledger_processor::validate_epoch_block (nano::state_block const & block_a) if (validate_message (block_a.hashables.account, block_a.hash (), block_a.signature)) { // Is epoch block signed correctly - if (validate_message (ledger.signer (block_a.link ()), block_a.hash (), block_a.signature)) + if (validate_message (ledger.epoch_signer (block_a.link ()), block_a.hash (), block_a.signature)) { result.verified = nano::signature_verification::invalid; result.code = nano::process_result::bad_signature; @@ -378,11 +378,11 @@ void ledger_processor::epoch_block_impl (nano::state_block const & block_a) // Validate block if not verified outside of ledger if (result.verified != nano::signature_verification::valid_epoch) { - result.code = validate_message (ledger.signer (block_a.hashables.link), hash, block_a.signature) ? nano::process_result::bad_signature : nano::process_result::progress; // Is this block signed correctly (Unambiguous) + result.code = validate_message (ledger.epoch_signer (block_a.hashables.link), hash, block_a.signature) ? nano::process_result::bad_signature : nano::process_result::progress; // Is this block signed correctly (Unambiguous) } if (result.code == nano::process_result::progress) { - assert (!validate_message (ledger.signer (block_a.hashables.link), hash, block_a.signature)); + assert (!validate_message (ledger.epoch_signer (block_a.hashables.link), hash, block_a.signature)); result.verified = nano::signature_verification::valid_epoch; result.code = block_a.hashables.account.is_zero () ? nano::process_result::opened_burn_account : nano::process_result::progress; // Is this for the burn account? (Unambiguous) if (result.code == nano::process_result::progress) @@ -1021,12 +1021,12 @@ bool nano::ledger::is_epoch_link (nano::link const & link_a) return network_params.ledger.epochs.is_epoch_link (link_a); } -nano::account const & nano::ledger::signer (nano::link const & link_a) const +nano::account const & nano::ledger::epoch_signer (nano::link const & link_a) const { return network_params.ledger.epochs.signer (network_params.ledger.epochs.epoch (link_a)); } -nano::link const & nano::ledger::link (nano::epoch epoch_a) const +nano::link const & nano::ledger::epoch_link (nano::epoch epoch_a) const { return network_params.ledger.epochs.link (epoch_a); } diff --git a/nano/secure/ledger.hpp b/nano/secure/ledger.hpp index 86940dc7..d8b6c854 100644 --- a/nano/secure/ledger.hpp +++ b/nano/secure/ledger.hpp @@ -43,8 +43,8 @@ public: void dump_account_chain (nano::account const &); bool could_fit (nano::transaction const &, nano::block const &); bool is_epoch_link (nano::link const &); - nano::account const & signer (nano::link const &) const; - nano::link const & link (nano::epoch) const; + nano::account const & epoch_signer (nano::link const &) const; + nano::link const & epoch_link (nano::epoch) const; static nano::uint128_t const unit; nano::network_params network_params; nano::block_store & store;