diff --git a/nano/core_test/ledger.cpp b/nano/core_test/ledger.cpp index 6a744622c..64fc0d246 100644 --- a/nano/core_test/ledger.cpp +++ b/nano/core_test/ledger.cpp @@ -5646,3 +5646,32 @@ TEST (ledger, unconfirmed_frontiers) ASSERT_EQ (uncemented_info1.cemented_frontier, uncemented_info2.cemented_frontier); ASSERT_EQ (uncemented_info1.frontier, uncemented_info2.frontier); } + +TEST (ledger, is_send_genesis) +{ + auto ctx = nano::test::context::ledger_empty (); + auto & ledger = ctx.ledger (); + auto & store = ctx.store (); + auto tx = store.tx_begin_read (); + ASSERT_FALSE (ledger.is_send (tx, *nano::dev::genesis)); +} + +TEST (ledger, is_send_state) +{ + auto ctx = nano::test::context::ledger_send_receive (); + auto & ledger = ctx.ledger (); + auto & store = ctx.store (); + auto tx = store.tx_begin_read (); + ASSERT_TRUE (ledger.is_send (tx, *ctx.blocks ()[0])); + ASSERT_FALSE (ledger.is_send (tx, *ctx.blocks ()[1])); +} + +TEST (ledger, is_send_legacy) +{ + auto ctx = nano::test::context::ledger_send_receive_legacy (); + auto & ledger = ctx.ledger (); + auto & store = ctx.store (); + auto tx = store.tx_begin_read (); + ASSERT_TRUE (ledger.is_send (tx, *ctx.blocks ()[0])); + ASSERT_FALSE (ledger.is_send (tx, *ctx.blocks ()[1])); +} diff --git a/nano/secure/ledger.cpp b/nano/secure/ledger.cpp index a52103c29..e650276b7 100644 --- a/nano/secure/ledger.cpp +++ b/nano/secure/ledger.cpp @@ -923,14 +923,19 @@ std::string nano::ledger::block_text (nano::block_hash const & hash_a) return result; } -bool nano::ledger::is_send (nano::transaction const & transaction_a, nano::state_block const & block_a) const +bool nano::ledger::is_send (nano::transaction const & transaction_a, nano::block const & block_a) const { + if (block_a.type () != nano::block_type::state) + { + return block_a.type () == nano::block_type::send; + } + nano::block_hash previous = block_a.previous (); /* * if block_a does not have a sideband, then is_send() * requires that the previous block exists in the database. * This is because it must retrieve the balance of the previous block. */ - debug_assert (block_a.has_sideband () || block_a.hashables.previous.is_zero () || store.block.exists (transaction_a, block_a.hashables.previous)); + debug_assert (block_a.has_sideband () || previous.is_zero () || store.block.exists (transaction_a, previous)); bool result (false); if (block_a.has_sideband ()) @@ -939,10 +944,9 @@ bool nano::ledger::is_send (nano::transaction const & transaction_a, nano::state } else { - nano::block_hash previous (block_a.hashables.previous); if (!previous.is_zero ()) { - if (block_a.hashables.balance < balance (transaction_a, previous)) + if (block_a.balance () < balance (transaction_a, previous)) { result = true; } diff --git a/nano/secure/ledger.hpp b/nano/secure/ledger.hpp index 3f6857ad8..489cf7857 100644 --- a/nano/secure/ledger.hpp +++ b/nano/secure/ledger.hpp @@ -51,7 +51,7 @@ public: bool root_exists (nano::transaction const &, nano::root const &); std::string block_text (char const *); std::string block_text (nano::block_hash const &); - bool is_send (nano::transaction const &, nano::state_block const &) const; + bool is_send (nano::transaction const &, nano::block const &) const; nano::account const & block_destination (nano::transaction const &, nano::block const &); nano::block_hash block_source (nano::transaction const &, nano::block const &); std::pair hash_root_random (nano::transaction const &) const; diff --git a/nano/test_common/ledger.cpp b/nano/test_common/ledger.cpp index 3189375ad..3753aa648 100644 --- a/nano/test_common/ledger.cpp +++ b/nano/test_common/ledger.cpp @@ -1,12 +1,19 @@ #include #include -nano::test::context::ledger_context::ledger_context () : +nano::test::context::ledger_context::ledger_context (std::deque> && blocks) : store_m{ nano::make_store (logger, nano::unique_path (), nano::dev::constants) }, - ledger_m{ *store_m, stats_m, nano::dev::constants } + ledger_m{ *store_m, stats_m, nano::dev::constants }, + blocks_m{ blocks } { debug_assert (!store_m->init_error ()); - store_m->initialize (store_m->tx_begin_write (), ledger_m.cache, ledger_m.constants); + auto tx = store_m->tx_begin_write (); + store_m->initialize (tx, ledger_m.cache, ledger_m.constants); + for (auto const & i : blocks_m) + { + auto process_result = ledger_m.process (tx, *i); + debug_assert (process_result.code == nano::process_result::progress); + } } nano::ledger & nano::test::context::ledger_context::ledger () @@ -24,7 +31,67 @@ nano::stat & nano::test::context::ledger_context::stats () return stats_m; } +std::deque> const & nano::test::context::ledger_context::blocks () const +{ + return blocks_m; +} + auto nano::test::context::ledger_empty () -> ledger_context { return ledger_context{}; } + +auto nano::test::context::ledger_send_receive () -> ledger_context +{ + std::deque> blocks; + nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits::max () }; + nano::block_builder builder; + auto send = builder.state () + .make_block () + .account (nano::dev::genesis_key.pub) + .previous (nano::dev::genesis->hash ()) + .representative (nano::dev::genesis_key.pub) + .balance (nano::dev::constants.genesis_amount - 1) + .link (nano::dev::genesis_key.pub) + .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) + .work (*pool.generate (nano::dev::genesis->hash ())) + .build_shared (); + blocks.push_back (send); + auto receive = builder.state () + .make_block () + .account (nano::dev::genesis_key.pub) + .previous (send->hash ()) + .representative (nano::dev::genesis_key.pub) + .balance (nano::dev::constants.genesis_amount) + .link (send->hash ()) + .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) + .work (*pool.generate (send->hash ())) + .build_shared (); + blocks.push_back (receive); + return ledger_context{ std::move (blocks) }; +} + +auto nano::test::context::ledger_send_receive_legacy () -> ledger_context +{ + std::deque> blocks; + nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits::max () }; + nano::block_builder builder; + auto send = builder.send () + .make_block () + .previous (nano::dev::genesis->hash ()) + .destination (nano::dev::genesis_key.pub) + .balance (nano::dev::constants.genesis_amount - 1) + .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) + .work (*pool.generate (nano::dev::genesis->hash ())) + .build_shared (); + blocks.push_back (send); + auto receive = builder.receive () + .make_block () + .previous (send->hash ()) + .source (send->hash ()) + .sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub) + .work (*pool.generate (send->hash ())) + .build_shared (); + blocks.push_back (receive); + return ledger_context{ std::move (blocks) }; +} diff --git a/nano/test_common/ledger.hpp b/nano/test_common/ledger.hpp index 19ccf4688..64992f8a8 100644 --- a/nano/test_common/ledger.hpp +++ b/nano/test_common/ledger.hpp @@ -15,19 +15,28 @@ namespace test class ledger_context { public: - ledger_context (); + /** 'blocks' initialises the ledger with each block in-order + Blocks must all return process_result::progress when processed */ + ledger_context (std::deque> && blocks = std::deque>{}); nano::ledger & ledger (); nano::store & store (); nano::stat & stats (); + std::deque> const & blocks () const; private: nano::logger_mt logger; std::unique_ptr store_m; nano::stat stats_m; nano::ledger ledger_m; + std::deque> blocks_m; }; + /** Only a genesis block */ ledger_context ledger_empty (); + /** Send/receive pair of state blocks on the genesis account*/ + ledger_context ledger_send_receive (); + /** Send/receive pair of legacy blocks on the genesis account*/ + ledger_context ledger_send_receive_legacy (); } } }