From ccacc49f590e141852292100e89ad2ccd3aca468 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Wed, 28 Feb 2018 02:12:33 -0600 Subject: [PATCH 01/36] First cut at adding universal transactions utx_block. --- rai/blockstore.cpp | 36 +++- rai/blockstore.hpp | 2 + rai/common.cpp | 21 ++ rai/common.hpp | 8 +- rai/core_test/block.cpp | 33 +++ rai/core_test/block_store.cpp | 20 ++ rai/core_test/ledger.cpp | 392 ++++++++++++++++++++++++++++++++++ rai/core_test/rpc.cpp | 2 + rai/ledger.cpp | 244 +++++++++++++++------ rai/lib/blocks.cpp | 368 +++++++++++++++++++++++++++++++ rai/lib/blocks.hpp | 76 ++++++- rai/node/bootstrap.cpp | 4 + rai/node/node.cpp | 38 +++- rai/node/rpc.cpp | 7 + 14 files changed, 1173 insertions(+), 78 deletions(-) diff --git a/rai/blockstore.cpp b/rai/blockstore.cpp index c62646b2..7b0f02e6 100644 --- a/rai/blockstore.cpp +++ b/rai/blockstore.cpp @@ -42,6 +42,13 @@ public: { fill_value (block_a); } + void utx_block (rai::utx_block const & block_a) override + { + if (!block_a.previous ().is_zero ()) + { + fill_value (block_a); + } + } MDB_txn * transaction; rai::block_store & store; }; @@ -256,6 +263,7 @@ checksum (0) error_a |= mdb_dbi_open (transaction, "receive", MDB_CREATE, &receive_blocks) != 0; error_a |= mdb_dbi_open (transaction, "open", MDB_CREATE, &open_blocks) != 0; error_a |= mdb_dbi_open (transaction, "change", MDB_CREATE, &change_blocks) != 0; + error_a |= mdb_dbi_open (transaction, "utx", MDB_CREATE, &utx_blocks) != 0; error_a |= mdb_dbi_open (transaction, "pending", MDB_CREATE, &pending) != 0; error_a |= mdb_dbi_open (transaction, "blocks_info", MDB_CREATE, &blocks_info) != 0; error_a |= mdb_dbi_open (transaction, "representation", MDB_CREATE, &representation) != 0; @@ -558,6 +566,9 @@ MDB_dbi rai::block_store::block_database (rai::block_type type_a) case rai::block_type::change: result = change_blocks; break; + case rai::block_type::utx: + result = utx_blocks; + break; default: assert (false); break; @@ -603,7 +614,20 @@ MDB_val rai::block_store::block_get_raw (MDB_txn * transaction_a, rai::block_has { auto status (mdb_get (transaction_a, change_blocks, rai::mdb_val (hash_a), result)); assert (status == 0 || status == MDB_NOTFOUND); - if (status == 0) + if (status != 0) + { + auto status (mdb_get (transaction_a, utx_blocks, rai::mdb_val (hash_a), result)); + assert (status == 0 || status == MDB_NOTFOUND); + if (status != 0) + { + // Block not found + } + else + { + type_a = rai::block_type::utx; + } + } + else { type_a = rai::block_type::change; } @@ -753,6 +777,12 @@ bool rai::block_store::block_exists (MDB_txn * transaction_a, rai::block_hash co auto status (mdb_get (transaction_a, change_blocks, rai::mdb_val (hash_a), junk)); assert (status == 0 || status == MDB_NOTFOUND); exists = status == 0; + if (!exists) + { + auto status (mdb_get (transaction_a, utx_blocks, rai::mdb_val (hash_a), junk)); + assert (status == 0 || status == MDB_NOTFOUND); + exists = status == 0; + } } } } @@ -774,10 +804,14 @@ rai::block_counts rai::block_store::block_count (MDB_txn * transaction_a) MDB_stat change_stats; auto status4 (mdb_stat (transaction_a, change_blocks, &change_stats)); assert (status4 == 0); + MDB_stat utx_stats; + auto status5 (mdb_stat (transaction_a, utx_blocks, &utx_stats)); + assert (status5 == 0); result.send = send_stats.ms_entries; result.receive = receive_stats.ms_entries; result.open = open_stats.ms_entries; result.change = change_stats.ms_entries; + result.utx = utx_stats.ms_entries; return result; } diff --git a/rai/blockstore.hpp b/rai/blockstore.hpp index a2f080b6..248c3567 100644 --- a/rai/blockstore.hpp +++ b/rai/blockstore.hpp @@ -163,6 +163,8 @@ public: MDB_dbi open_blocks; // block_hash -> change_block MDB_dbi change_blocks; + // block_hash -> utx_block + MDB_dbi utx_blocks; // block_hash -> sender, amount, destination // Pending blocks to sender account, amount, destination account MDB_dbi pending; // block_hash -> account, balance // Blocks info diff --git a/rai/common.cpp b/rai/common.cpp index 44369b1d..f5ea127d 100644 --- a/rai/common.cpp +++ b/rai/common.cpp @@ -89,6 +89,7 @@ size_t constexpr rai::send_block::size; size_t constexpr rai::receive_block::size; size_t constexpr rai::open_block::size; size_t constexpr rai::change_block::size; +size_t constexpr rai::utx_block::size; rai::keypair const & rai::zero_key (globals.zero_key); rai::keypair const & rai::test_genesis_key (globals.test_genesis_key); @@ -489,6 +490,15 @@ void rai::amount_visitor::open_block (rai::open_block const & block_a) } } +void rai::amount_visitor::utx_block (rai::utx_block const & block_a) +{ + result = block_a.hashables.amount.number (); + if (block_a.hashables.is_send ()) + { + result = 0 - result; + } +} + void rai::amount_visitor::change_block (rai::change_block const & block_a) { result = 0; @@ -575,6 +585,12 @@ void rai::balance_visitor::change_block (rai::change_block const & block_a) } } +void rai::balance_visitor::utx_block (rai::utx_block const & block_a) +{ + result = block_a.hashables.balance.number (); + current = 0; +} + void rai::balance_visitor::compute (rai::block_hash const & block_hash) { current = block_hash; @@ -624,6 +640,11 @@ void rai::representative_visitor::change_block (rai::change_block const & block_ result = block_a.hash (); } +void rai::representative_visitor::utx_block (rai::utx_block const & block_a) +{ + result = block_a.hash (); +} + rai::vote::vote (rai::vote const & other_a) : sequence (other_a.sequence), block (other_a.block), diff --git a/rai/common.hpp b/rai/common.hpp index 3a05ebf9..63bda498 100644 --- a/rai/common.hpp +++ b/rai/common.hpp @@ -37,6 +37,7 @@ public: void receive_block (rai::receive_block const &) override; void open_block (rai::open_block const &) override; void change_block (rai::change_block const &) override; + void utx_block (rai::utx_block const &) override; MDB_txn * transaction; rai::block_store & store; rai::block_hash current; @@ -56,6 +57,7 @@ public: void receive_block (rai::receive_block const &) override; void open_block (rai::open_block const &) override; void change_block (rai::change_block const &) override; + void utx_block (rai::utx_block const &) override; void from_send (rai::block_hash const &); MDB_txn * transaction; rai::block_store & store; @@ -75,6 +77,7 @@ public: void receive_block (rai::receive_block const & block_a) override; void open_block (rai::open_block const & block_a) override; void change_block (rai::change_block const & block_a) override; + void utx_block (rai::utx_block const & block_a) override; MDB_txn * transaction; rai::block_store & store; rai::block_hash current; @@ -170,6 +173,7 @@ public: size_t receive; size_t open; size_t change; + size_t utx; }; class vote { @@ -219,7 +223,9 @@ enum class process_result gap_source, // Block marked as source is unknown not_receive_from_send, // Receive does not have a send source account_mismatch, // Account number in open block doesn't match send destination - opened_burn_account // The impossible happened, someone found the private key associated with the public key '0'. + opened_burn_account, // The impossible happened, someone found the private key associated with the public key '0'. + balance_mismatch, // Balance and amount delta don't match + block_position // This block cannot follow the previous block }; class process_return { diff --git a/rai/core_test/block.cpp b/rai/core_test/block.cpp index 99052728..4f7dcb69 100644 --- a/rai/core_test/block.cpp +++ b/rai/core_test/block.cpp @@ -325,3 +325,36 @@ TEST (block, confirm_req_serialization) ASSERT_EQ (req, req2); ASSERT_EQ (*req.block, *req2.block); } + +TEST (utx, serialization) +{ + rai::keypair key1; + rai::keypair key2; + rai::utx_block block1 (key1.pub, 1, key2.pub, 2, 3, 4, key1.prv, key1.pub, 5); + ASSERT_EQ (key1.pub, block1.hashables.account); + ASSERT_EQ (rai::block_hash (1), block1.previous ()); + ASSERT_EQ (key2.pub, block1.hashables.representative); + ASSERT_EQ (rai::amount (2), block1.hashables.balance); + ASSERT_EQ (rai::amount (3), block1.hashables.amount); + ASSERT_EQ (rai::uint256_union (4), block1.hashables.link); + std::vector bytes; + { + rai::vectorstream stream (bytes); + block1.serialize (stream); + } + ASSERT_EQ (rai::utx_block::size, bytes.size ()); + bool error1; + rai::bufferstream stream (bytes.data (), bytes.size ()); + rai::utx_block block2 (error1, stream); + ASSERT_FALSE (error1); + ASSERT_EQ (block1, block2); + std::string json; + block1.serialize_json (json); + std::stringstream body (json); + boost::property_tree::ptree tree; + boost::property_tree::read_json (body, tree); + bool error2; + rai::utx_block block3 (error2, tree); + ASSERT_FALSE (error2); + ASSERT_EQ (block1, block3); +} diff --git a/rai/core_test/block_store.cpp b/rai/core_test/block_store.cpp index 3fc7bdf7..591555bb 100644 --- a/rai/core_test/block_store.cpp +++ b/rai/core_test/block_store.cpp @@ -986,3 +986,23 @@ TEST (block_store, upgrade_v9_v10) ASSERT_EQ (block_info.account, rai::test_genesis_key.pub); ASSERT_EQ (block_info.balance.number (), rai::genesis_amount - rai::Gxrb_ratio * 31); } + +TEST (block_store, utx_block) +{ + bool error (false); + rai::block_store store (error, rai::unique_path ()); + ASSERT_FALSE (error); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair key1; + rai::utx_block block1 (1, genesis.hash (), 3, 4, 5, 6, key1.prv, key1.pub, 7); + ASSERT_EQ (rai::block_type::utx, block1.type ()); + store.block_put (transaction, block1.hash (), block1); + ASSERT_TRUE (store.block_exists (transaction, block1.hash ())); + auto block2 (store.block_get (transaction, block1.hash ())); + ASSERT_NE (nullptr, block2); + ASSERT_EQ (block1, *block2); + auto count (store.block_count (transaction)); + ASSERT_EQ (1, count.utx); +} diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 32547d56..13549618 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1454,3 +1454,395 @@ TEST (ledger, bootstrap_rep_weight) ASSERT_EQ (0, ledger.weight (transaction, key2.pub)); } } + +TEST (ledger, utx_send_receive) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, rai::Gxrb_ratio, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); + ASSERT_TRUE (store.block_exists (transaction, receive1.hash ())); + auto receive2 (store.block_get (transaction, receive1.hash ())); + ASSERT_NE (nullptr, receive2); + ASSERT_EQ (receive1, *receive2); + ASSERT_EQ (rai::genesis_amount, ledger.balance (transaction, receive1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, receive1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); +} + +TEST (ledger, utx_receive) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::send_block send1 (genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, rai::Gxrb_ratio, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); + ASSERT_TRUE (store.block_exists (transaction, receive1.hash ())); + auto receive2 (store.block_get (transaction, receive1.hash ())); + ASSERT_NE (nullptr, receive2); + ASSERT_EQ (receive1, *receive2); + ASSERT_EQ (rai::genesis_amount, ledger.balance (transaction, receive1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, receive1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); +} + +TEST (ledger, utx_rep_change) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair rep; + rai::utx_block change1 (rai::genesis_account, genesis.hash (), rep.pub, rai::genesis_amount, 0, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, change1).code); + ASSERT_TRUE (store.block_exists (transaction, change1.hash ())); + auto change2 (store.block_get (transaction, change1.hash ())); + ASSERT_NE (nullptr, change2); + ASSERT_EQ (change1, *change2); + ASSERT_EQ (rai::genesis_amount, ledger.balance (transaction, change1.hash ())); + ASSERT_EQ (0, ledger.amount (transaction, change1.hash ())); + ASSERT_EQ (0, ledger.weight (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rep.pub)); +} + +TEST (ledger, utx_open) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair destination; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + rai::utx_block open1 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); + ASSERT_TRUE (store.block_exists (transaction, open1.hash ())); + auto open2 (store.block_get (transaction, open1.hash ())); + ASSERT_NE (nullptr, open2); + ASSERT_EQ (open1, *open2); + ASSERT_EQ (rai::Gxrb_ratio, ledger.balance (transaction, open1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, open1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); +} + +// Make sure old block types can't be inserted after a utx block. +TEST (ledger, send_after_utx_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::send_block send2 (send1.hash (), rai::genesis_account, rai::genesis_amount - (2 * rai::Gxrb_ratio), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::block_position, ledger.process (transaction, send2).code); +} + +// Make sure old block types can't be inserted after a utx block. +TEST (ledger, receive_after_utx_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::receive_block receive1 (send1.hash (), send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::block_position, ledger.process (transaction, receive1).code); +} + +// Make sure old block types can't be inserted after a utx block. +TEST (ledger, change_after_utx_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::keypair rep; + rai::change_block change1 (send1.hash (), rep.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::block_position, ledger.process (transaction, change1).code); +} + +TEST (ledger, utx_unreceivable_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::send_block send1 (genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, rai::Gxrb_ratio, 1, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::unreceivable, ledger.process (transaction, receive1).code); +} + +TEST (ledger, utx_receive_bad_amount_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::send_block send1 (genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::balance_mismatch, ledger.process (transaction, receive1).code); +} + +TEST (ledger, utx_no_link_amount_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::keypair rep; + rai::utx_block change1 (rai::genesis_account, send1.hash (), rep.pub, rai::genesis_amount, rai::Gxrb_ratio, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::balance_mismatch, ledger.process (transaction, change1).code); +} + +TEST (ledger, utx_receive_wrong_account_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + rai::keypair key; + rai::utx_block receive1 (key.pub, 0, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), key.prv, key.pub, 0); + ASSERT_EQ (rai::process_result::unreceivable, ledger.process (transaction, receive1).code); +} + +TEST (ledger, utx_open_utx_fork) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair destination; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::utx_block open1 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); + rai::open_block open2 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::fork, ledger.process (transaction, open2).code); + ASSERT_EQ (open1.root (), open2.root ()); +} + +TEST (ledger, utx_utx_open_fork) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair destination; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::open_block open1 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); + rai::utx_block open2 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::fork, ledger.process (transaction, open2).code); + ASSERT_EQ (open1.root (), open2.root ()); +} + +TEST (ledger, utx_open_previous_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair destination; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::utx_block open1 (destination.pub, destination.pub, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::gap_previous, ledger.process (transaction, open1).code); +} + +TEST (ledger, utx_send_change) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair rep; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rep.pub, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); + ASSERT_EQ (0, ledger.weight (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rep.pub)); +} + +TEST (ledger, utx_receive_change) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + rai::keypair rep; + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rep.pub, rai::genesis_amount, rai::Gxrb_ratio, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); + ASSERT_TRUE (store.block_exists (transaction, receive1.hash ())); + auto receive2 (store.block_get (transaction, receive1.hash ())); + ASSERT_NE (nullptr, receive2); + ASSERT_EQ (receive1, *receive2); + ASSERT_EQ (rai::genesis_amount, ledger.balance (transaction, receive1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, receive1.hash ())); + ASSERT_EQ (0, ledger.weight (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rep.pub)); +} + +TEST (ledger, utx_open_old) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair destination; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::open_block open1 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); + ASSERT_EQ (rai::Gxrb_ratio, ledger.balance (transaction, open1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, open1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); +} + +TEST (ledger, utx_receive_old) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair destination; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::utx_block send2 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount - (2 * rai::Gxrb_ratio), 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send2).code); + rai::open_block open1 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); + rai::receive_block receive1 (open1.hash (), send2.hash (), destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); + ASSERT_EQ (2 * rai::Gxrb_ratio, ledger.balance (transaction, receive1.hash ())); + ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, receive1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); +} + diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index b771914f..a1ed4d8a 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -2876,6 +2876,8 @@ TEST (rpc, block_count_type) ASSERT_EQ ("1", open_count); std::string change_count (response.json.get ("change")); ASSERT_EQ ("0", change_count); + std::string utx_count (response.json.get ("utx")); + ASSERT_EQ ("0", utx_count); } TEST (rpc, ledger) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 1461b2db..1022bc34 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -93,6 +93,10 @@ public: ledger.store.block_info_del (transaction, hash); } } + void utx_block (rai::utx_block const & block_a) override + { + assert (false); + } MDB_txn * transaction; rai::ledger & ledger; }; @@ -106,11 +110,104 @@ public: void receive_block (rai::receive_block const &) override; void open_block (rai::open_block const &) override; void change_block (rai::change_block const &) override; + void utx_block (rai::utx_block const &) override; rai::ledger & ledger; MDB_txn * transaction; rai::process_return result; }; +void ledger_processor::utx_block (rai::utx_block const & block_a) +{ + auto hash (block_a.hash ()); + auto existing (ledger.store.block_exists (transaction, hash)); + result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block before? (Unambiguous) + if (result.code == rai::process_result::progress) + { + result.code = validate_message (block_a.hashables.account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Unambiguous) + if (result.code == rai::process_result::progress) + { + rai::account_info info; + auto account_error (ledger.store.account_get (transaction, block_a.hashables.account, info)); + if (!account_error) + { + // Account already exists + result.code = block_a.hashables.previous.is_zero () ? rai::process_result::fork : rai::process_result::progress; // Has this account already been opened? (Ambigious) + if (result.code == rai::process_result::progress) + { + result.code = ledger.store.block_exists (transaction, block_a.hashables.previous) ? rai::process_result::progress : rai::process_result::gap_previous; // Does the previous block exist in the ledger? (Unambigious) + if (result.code == rai::process_result::progress) + { + result.code = block_a.hashables.previous == info.head ? rai::process_result::progress : rai::process_result::fork; // Is the previous block the account's head block? (Ambigious) + } + } + } + else + { + // Account does not yet exists + result.code = block_a.previous ().is_zero () ? rai::process_result::progress : rai::process_result::gap_previous; // Does the first block in an account yield 0 for previous() ? (Unambigious) + } + if (result.code == rai::process_result::progress) + { + if (block_a.hashables.is_send ()) + { + result.code = block_a.hashables.balance.number () < info.balance.number () ? rai::process_result::progress : rai::process_result::negative_spend; // If the amount is negative the new balance must be less than the old balance or it's underflowed (Unambiguous) + } + else + { + if (!block_a.hashables.link.is_zero ()) + { + rai::pending_key key (block_a.hashables.account, block_a.hashables.link); + rai::pending_info pending; + result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed) + if (result.code == rai::process_result::progress) + { + result.code = pending.amount == block_a.hashables.amount ? rai::process_result::progress : rai::process_result::balance_mismatch; + } + } + else + { + result.code = block_a.hashables.amount.is_zero () ? rai::process_result::progress : rai::process_result::balance_mismatch; + } + } + + } + if (result.code == rai::process_result::progress) + { + result.code = (info.balance.number () + block_a.hashables.amount.number ()) == block_a.hashables.balance.number () ? rai::process_result::progress : rai::process_result::balance_mismatch; // Does the amount delta match the actual change in balances to the last transaction (Unambiguous) + if (result.code == rai::process_result::progress) + { + ledger.store.block_put (transaction, hash, block_a); + + if (!info.rep_block.is_zero ()) + { + // Move existing representation + ledger.store.representation_add (transaction, info.rep_block, 0 - info.balance.number ()); + ledger.store.representation_add (transaction, hash, info.balance.number ()); + } + // Add in amount delta + ledger.store.representation_add (transaction, hash, block_a.hashables.amount.number ()); + + if (block_a.hashables.is_send ()) + { + rai::pending_key key (block_a.hashables.link, hash); + rai::pending_info info (block_a.hashables.account, 0 - block_a.hashables.amount.number ()); + ledger.store.pending_put (transaction, key, info); + } + + ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1); + if (!ledger.store.frontier_get (transaction, info.head).is_zero ()) + { + ledger.store.frontier_del (transaction, info.head); + } + // Frontier table is unnecessary for utx blocks and this also prevents old blocks from being inserted on top of utx blocks + result.account = block_a.hashables.account; + result.amount = block_a.hashables.amount; + } + } + } + } +} + void ledger_processor::change_block (rai::change_block const & block_a) { auto hash (block_a.hash ()); @@ -118,30 +215,34 @@ void ledger_processor::change_block (rai::change_block const & block_a) result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block before? (Harmless) if (result.code == rai::process_result::progress) { - auto previous (ledger.store.block_exists (transaction, block_a.hashables.previous)); - result.code = previous ? rai::process_result::progress : rai::process_result::gap_previous; // Have we seen the previous block already? (Harmless) + auto previous (ledger.store.block_get (transaction, block_a.hashables.previous)); + result.code = previous != nullptr ? rai::process_result::progress : rai::process_result::gap_previous; // Have we seen the previous block already? (Harmless) if (result.code == rai::process_result::progress) { - auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous)); - result.code = account.is_zero () ? rai::process_result::fork : rai::process_result::progress; + result.code = block_a.valid_predecessor (*previous) ? rai::process_result::progress : rai::process_result::block_position; if (result.code == rai::process_result::progress) { - rai::account_info info; - auto latest_error (ledger.store.account_get (transaction, account, info)); - assert (!latest_error); - assert (info.head == block_a.hashables.previous); - result.code = validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Malformed) + auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous)); + result.code = account.is_zero () ? rai::process_result::fork : rai::process_result::progress; if (result.code == rai::process_result::progress) { - ledger.store.block_put (transaction, hash, block_a); - auto balance (ledger.balance (transaction, block_a.hashables.previous)); - ledger.store.representation_add (transaction, hash, balance); - ledger.store.representation_add (transaction, info.rep_block, 0 - balance); - ledger.change_latest (transaction, account, hash, hash, info.balance, info.block_count + 1); - ledger.store.frontier_del (transaction, block_a.hashables.previous); - ledger.store.frontier_put (transaction, hash, account); - result.account = account; - result.amount = 0; + rai::account_info info; + auto latest_error (ledger.store.account_get (transaction, account, info)); + assert (!latest_error); + assert (info.head == block_a.hashables.previous); + result.code = validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Malformed) + if (result.code == rai::process_result::progress) + { + ledger.store.block_put (transaction, hash, block_a); + auto balance (ledger.balance (transaction, block_a.hashables.previous)); + ledger.store.representation_add (transaction, hash, balance); + ledger.store.representation_add (transaction, info.rep_block, 0 - balance); + ledger.change_latest (transaction, account, hash, hash, info.balance, info.block_count + 1); + ledger.store.frontier_del (transaction, block_a.hashables.previous); + ledger.store.frontier_put (transaction, hash, account); + result.account = account; + result.amount = 0; + } } } } @@ -155,34 +256,38 @@ void ledger_processor::send_block (rai::send_block const & block_a) result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block before? (Harmless) if (result.code == rai::process_result::progress) { - auto previous (ledger.store.block_exists (transaction, block_a.hashables.previous)); - result.code = previous ? rai::process_result::progress : rai::process_result::gap_previous; // Have we seen the previous block already? (Harmless) + auto previous (ledger.store.block_get (transaction, block_a.hashables.previous)); + result.code = previous != nullptr ? rai::process_result::progress : rai::process_result::gap_previous; // Have we seen the previous block already? (Harmless) if (result.code == rai::process_result::progress) { - auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous)); - result.code = account.is_zero () ? rai::process_result::fork : rai::process_result::progress; + result.code = block_a.valid_predecessor (*previous) ? rai::process_result::progress : rai::process_result::block_position; if (result.code == rai::process_result::progress) { - result.code = validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Malformed) + auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous)); + result.code = account.is_zero () ? rai::process_result::fork : rai::process_result::progress; if (result.code == rai::process_result::progress) { - rai::account_info info; - auto latest_error (ledger.store.account_get (transaction, account, info)); - assert (!latest_error); - assert (info.head == block_a.hashables.previous); - result.code = info.balance.number () >= block_a.hashables.balance.number () ? rai::process_result::progress : rai::process_result::negative_spend; // Is this trying to spend a negative amount (Malicious) + result.code = validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Malformed) if (result.code == rai::process_result::progress) { - auto amount (info.balance.number () - block_a.hashables.balance.number ()); - ledger.store.representation_add (transaction, info.rep_block, 0 - amount); - ledger.store.block_put (transaction, hash, block_a); - ledger.change_latest (transaction, account, hash, info.rep_block, block_a.hashables.balance, info.block_count + 1); - ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.destination, hash), { account, amount }); - ledger.store.frontier_del (transaction, block_a.hashables.previous); - ledger.store.frontier_put (transaction, hash, account); - result.account = account; - result.amount = amount; - result.pending_account = block_a.hashables.destination; + rai::account_info info; + auto latest_error (ledger.store.account_get (transaction, account, info)); + assert (!latest_error); + assert (info.head == block_a.hashables.previous); + result.code = info.balance.number () >= block_a.hashables.balance.number () ? rai::process_result::progress : rai::process_result::negative_spend; // Is this trying to spend a negative amount (Malicious) + if (result.code == rai::process_result::progress) + { + auto amount (info.balance.number () - block_a.hashables.balance.number ()); + ledger.store.representation_add (transaction, info.rep_block, 0 - amount); + ledger.store.block_put (transaction, hash, block_a); + ledger.change_latest (transaction, account, hash, info.rep_block, block_a.hashables.balance, info.block_count + 1); + ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.destination, hash), { account, amount }); + ledger.store.frontier_del (transaction, block_a.hashables.previous); + ledger.store.frontier_put (transaction, hash, account); + result.account = account; + result.amount = amount; + result.pending_account = block_a.hashables.destination; + } } } } @@ -197,46 +302,55 @@ void ledger_processor::receive_block (rai::receive_block const & block_a) result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block already? (Harmless) if (result.code == rai::process_result::progress) { - result.code = ledger.store.block_exists (transaction, block_a.hashables.source) ? rai::process_result::progress : rai::process_result::gap_source; // Have we seen the source block already? (Harmless) + auto previous (ledger.store.block_get (transaction, block_a.hashables.previous)); + result.code = previous != nullptr ? rai::process_result::progress : rai::process_result::gap_previous; if (result.code == rai::process_result::progress) { - auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous)); - result.code = account.is_zero () ? rai::process_result::gap_previous : rai::process_result::progress; //Have we seen the previous block? No entries for account at all (Harmless) + result.code = block_a.valid_predecessor (*previous) ? rai::process_result::progress : rai::process_result::block_position; if (result.code == rai::process_result::progress) { - result.code = rai::validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is the signature valid (Malformed) + result.code = ledger.store.block_exists (transaction, block_a.hashables.source) ? rai::process_result::progress : rai::process_result::gap_source; // Have we seen the source block already? (Harmless) if (result.code == rai::process_result::progress) { - rai::account_info info; - ledger.store.account_get (transaction, account, info); - result.code = info.head == block_a.hashables.previous ? rai::process_result::progress : rai::process_result::gap_previous; // Block doesn't immediately follow latest block (Harmless) + auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous)); + result.code = account.is_zero () ? rai::process_result::gap_previous : rai::process_result::progress; //Have we seen the previous block? No entries for account at all (Harmless) if (result.code == rai::process_result::progress) { - rai::pending_key key (account, block_a.hashables.source); - rai::pending_info pending; - result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed) + result.code = rai::validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is the signature valid (Malformed) if (result.code == rai::process_result::progress) { - auto new_balance (info.balance.number () + pending.amount.number ()); - rai::account_info source_info; - auto error (ledger.store.account_get (transaction, pending.source, source_info)); - assert (!error); - ledger.store.pending_del (transaction, key); - ledger.store.block_put (transaction, hash, block_a); - ledger.change_latest (transaction, account, hash, info.rep_block, new_balance, info.block_count + 1); - ledger.store.representation_add (transaction, info.rep_block, pending.amount.number ()); - ledger.store.frontier_del (transaction, block_a.hashables.previous); - ledger.store.frontier_put (transaction, hash, account); - result.account = account; - result.amount = pending.amount; + rai::account_info info; + ledger.store.account_get (transaction, account, info); + result.code = info.head == block_a.hashables.previous ? rai::process_result::progress : rai::process_result::gap_previous; // Block doesn't immediately follow latest block (Harmless) + if (result.code == rai::process_result::progress) + { + rai::pending_key key (account, block_a.hashables.source); + rai::pending_info pending; + result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed) + if (result.code == rai::process_result::progress) + { + auto new_balance (info.balance.number () + pending.amount.number ()); + rai::account_info source_info; + auto error (ledger.store.account_get (transaction, pending.source, source_info)); + assert (!error); + ledger.store.pending_del (transaction, key); + ledger.store.block_put (transaction, hash, block_a); + ledger.change_latest (transaction, account, hash, info.rep_block, new_balance, info.block_count + 1); + ledger.store.representation_add (transaction, info.rep_block, pending.amount.number ()); + ledger.store.frontier_del (transaction, block_a.hashables.previous); + ledger.store.frontier_put (transaction, hash, account); + result.account = account; + result.amount = pending.amount; + } + } } } + else + { + result.code = ledger.store.block_exists (transaction, block_a.hashables.previous) ? rai::process_result::fork : rai::process_result::gap_previous; // If we have the block but it's not the latest we have a signed fork (Malicious) + } } } - else - { - result.code = ledger.store.block_exists (transaction, block_a.hashables.previous) ? rai::process_result::fork : rai::process_result::gap_previous; // If we have the block but it's not the latest we have a signed fork (Malicious) - } } } } @@ -571,7 +685,7 @@ void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & a } else { - assert (dynamic_cast (store.block_get (transaction_a, hash_a).get ()) != nullptr); + assert (store.block_get (transaction_a, hash_a)->previous ().is_zero ()); info.open_block = hash_a; } if (!hash_a.is_zero ()) diff --git a/rai/lib/blocks.cpp b/rai/lib/blocks.cpp index 5d1b7c7e..d621e6af 100644 --- a/rai/lib/blocks.cpp +++ b/rai/lib/blocks.cpp @@ -270,6 +270,24 @@ bool rai::send_block::operator== (rai::block const & other_a) const return result; } +bool rai::send_block::valid_predecessor (rai::block const & block_a) const +{ + bool result; + switch (block_a.type ()) + { + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + result = true; + break; + default: + result = false; + break; + } + return result; +} + rai::block_type rai::send_block::type () const { return rai::block_type::send; @@ -541,6 +559,11 @@ bool rai::open_block::operator== (rai::open_block const & other_a) const return hashables.source == other_a.hashables.source && hashables.representative == other_a.hashables.representative && hashables.account == other_a.hashables.account && work == other_a.work && signature == other_a.signature; } +bool rai::open_block::valid_predecessor (rai::block const & block_a) const +{ + return false; +} + rai::block_hash rai::open_block::source () const { return hashables.source; @@ -765,6 +788,24 @@ bool rai::change_block::operator== (rai::change_block const & other_a) const return hashables.previous == other_a.hashables.previous && hashables.representative == other_a.hashables.representative && work == other_a.work && signature == other_a.signature; } +bool rai::change_block::valid_predecessor (rai::block const & block_a) const +{ + bool result; + switch (block_a.type ()) + { + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + result = true; + break; + default: + result = false; + break; + } + return result; +} + rai::block_hash rai::change_block::source () const { return 0; @@ -790,6 +831,305 @@ void rai::change_block::signature_set (rai::uint512_union const & signature_a) signature = signature_a; } + +rai::utx_hashables::utx_hashables (rai::account const & account_a, rai::block_hash const & previous_a, rai::account const & representative_a, rai::amount const & balance_a, rai::amount const & amount_a, rai::uint256_union const & link_a) : +account (account_a), +previous (previous_a), +representative (representative_a), +balance (balance_a), +amount (amount_a), +link (link_a) +{ +} + +rai::utx_hashables::utx_hashables (bool & error_a, rai::stream & stream_a) +{ + error_a = rai::read (stream_a, account); + if (!error_a) + { + error_a = rai::read (stream_a, previous); + if (!error_a) + { + error_a = rai::read (stream_a, representative); + if (!error_a) + { + error_a = rai::read (stream_a, balance); + if (!error_a) + { + error_a = rai::read (stream_a, amount); + if (!error_a) + { + error_a = rai::read (stream_a, link); + } + } + } + } + } +} + +rai::utx_hashables::utx_hashables (bool & error_a, boost::property_tree::ptree const & tree_a) +{ + try + { + auto account_l (tree_a.get ("account")); + auto previous_l (tree_a.get ("previous")); + auto representative_l (tree_a.get ("representative")); + auto amount_l (tree_a.get ("amount")); + auto balance_l (tree_a.get ("balance")); + auto link_l (tree_a.get ("link")); + error_a = account.decode_account (account_l); + if (!error_a) + { + error_a = previous.decode_hex (previous_l); + if (!error_a) + { + error_a = representative.decode_account (representative_l); + if (!error_a) + { + error_a = balance.decode_dec (balance_l); + if (!error_a) + { + error_a = amount.decode_dec (amount_l); + if (!error_a) + { + if (is_send ()) + { + error_a = link.decode_account (link_l); + } + else + { + error_a = link.decode_hex (link_l); + } + } + } + } + } + } + } + catch (std::runtime_error const &) + { + error_a = true; + } +} + +void rai::utx_hashables::hash (blake2b_state & hash_a) const +{ + blake2b_update (&hash_a, previous.bytes.data (), sizeof (previous.bytes)); + blake2b_update (&hash_a, representative.bytes.data (), sizeof (representative.bytes)); +} + +bool rai::utx_hashables::is_send () const +{ + return (amount.bytes [0] & 0x80) == 0x80; +} + +rai::utx_block::utx_block (rai::account const & account_a, rai::block_hash const & previous_a, rai::account const & representative_a, rai::amount const & balance_a, rai::amount const & amount_a, rai::uint256_union const & link_a, rai::raw_key const & prv_a, rai::public_key const & pub_a, uint64_t work_a) : +hashables (account_a, previous_a, representative_a, balance_a, amount_a, link_a), +signature (rai::sign_message (prv_a, pub_a, hash ())), +work (work_a) +{ +} + +rai::utx_block::utx_block (bool & error_a, rai::stream & stream_a) : +hashables (error_a, stream_a) +{ + if (!error_a) + { + error_a = rai::read (stream_a, signature); + if (!error_a) + { + error_a = rai::read (stream_a, work); + } + } +} + +rai::utx_block::utx_block (bool & error_a, boost::property_tree::ptree const & tree_a) : +hashables (error_a, tree_a) +{ + if (!error_a) + { + try + { + auto signature_l (tree_a.get ("signature")); + auto work_l (tree_a.get ("work")); + error_a = rai::from_string_hex (work_l, work); + if (!error_a) + { + error_a = signature.decode_hex (signature_l); + } + } + catch (std::runtime_error const &) + { + error_a = true; + } + } +} + +void rai::utx_block::hash (blake2b_state & hash_a) const +{ + rai::uint256_union preamble (static_cast (rai::block_type::utx)); + blake2b_update (&hash_a, preamble.bytes.data (), preamble.bytes.size ()); + hashables.hash (hash_a); +} + +uint64_t rai::utx_block::block_work () const +{ + return work; +} + +void rai::utx_block::block_work_set (uint64_t work_a) +{ + work = work_a; +} + +rai::block_hash rai::utx_block::previous () const +{ + return hashables.previous; +} + +void rai::utx_block::serialize (rai::stream & stream_a) const +{ + write (stream_a, hashables.account); + write (stream_a, hashables.previous); + write (stream_a, hashables.representative); + write (stream_a, hashables.balance); + write (stream_a, hashables.amount); + write (stream_a, hashables.link); + write (stream_a, signature); + write (stream_a, work); +} + +void rai::utx_block::serialize_json (std::string & string_a) const +{ + boost::property_tree::ptree tree; + tree.put ("type", "change"); + tree.put ("account", hashables.account.to_account ()); + tree.put ("previous", hashables.previous.to_string ()); + tree.put ("representative", representative ().to_account ()); + tree.put ("balance", hashables.balance.to_string_dec ()); + tree.put ("amount", hashables.amount.to_string_dec ()); + if (hashables.is_send ()) + { + tree.put ("link", hashables.link.to_account ()); + } + else + { + tree.put ("link", hashables.link.to_string ()); + } + std::string signature_l; + signature.encode_hex (signature_l); + tree.put ("signature", signature_l); + tree.put ("work", rai::to_string_hex (work)); + std::stringstream ostream; + boost::property_tree::write_json (ostream, tree); + string_a = ostream.str (); +} + +bool rai::utx_block::deserialize (rai::stream & stream_a) +{ + auto error (read (stream_a, hashables.previous)); + if (!error) + { + error = read (stream_a, hashables.representative); + if (!error) + { + error = read (stream_a, signature); + if (!error) + { + error = read (stream_a, work); + } + } + } + return error; +} + +bool rai::utx_block::deserialize_json (boost::property_tree::ptree const & tree_a) +{ + auto error (false); + try + { + assert (tree_a.get ("type") == "utx"); + auto previous_l (tree_a.get ("previous")); + auto representative_l (tree_a.get ("representative")); + auto work_l (tree_a.get ("work")); + auto signature_l (tree_a.get ("signature")); + error = hashables.previous.decode_hex (previous_l); + if (!error) + { + error = hashables.representative.decode_hex (representative_l); + if (!error) + { + error = rai::from_string_hex (work_l, work); + if (!error) + { + error = signature.decode_hex (signature_l); + } + } + } + } + catch (std::runtime_error const &) + { + error = true; + } + return error; +} + +void rai::utx_block::visit (rai::block_visitor & visitor_a) const +{ + visitor_a.utx_block (*this); +} + +rai::block_type rai::utx_block::type () const +{ + return rai::block_type::utx; +} + +bool rai::utx_block::operator== (rai::block const & other_a) const +{ + auto other_l (dynamic_cast (&other_a)); + auto result (other_l != nullptr); + if (result) + { + result = *this == *other_l; + } + return result; +} + +bool rai::utx_block::operator== (rai::utx_block const & other_a) const +{ + return hashables.account == other_a.hashables.account && hashables.previous == other_a.hashables.previous && hashables.representative == other_a.hashables.representative && hashables.balance == other_a.hashables.balance && hashables.amount == other_a.hashables.amount && hashables.link == other_a.hashables.link && signature == other_a.signature && work == other_a.work; +} + +bool rai::utx_block::valid_predecessor (rai::block const & block_a) const +{ + return true; +} + +rai::block_hash rai::utx_block::source () const +{ + return 0; +} + +rai::block_hash rai::utx_block::root () const +{ + return !hashables.previous.is_zero () ? hashables.previous : hashables.account; +} + +rai::account rai::utx_block::representative () const +{ + return hashables.representative; +} + +rai::signature rai::utx_block::block_signature () const +{ + return signature; +} + +void rai::utx_block::signature_set (rai::uint512_union const & signature_a) +{ + signature = signature_a; +} + std::unique_ptr rai::deserialize_block_json (boost::property_tree::ptree const & tree_a) { std::unique_ptr result; @@ -896,6 +1236,16 @@ std::unique_ptr rai::deserialize_block (rai::stream & stream_a, rai: } break; } + case rai::block_type::utx: + { + bool error; + std::unique_ptr obj (new rai::utx_block (error, stream_a)); + if (!error) + { + result = std::move (obj); + } + break; + } default: assert (false); break; @@ -1059,6 +1409,24 @@ bool rai::receive_block::operator== (rai::block const & other_a) const return result; } +bool rai::receive_block::valid_predecessor (rai::block const & block_a) const +{ + bool result; + switch (block_a.type ()) + { + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + result = true; + break; + default: + result = false; + break; + } + return result; +} + rai::block_hash rai::receive_block::previous () const { return hashables.previous; diff --git a/rai/lib/blocks.hpp b/rai/lib/blocks.hpp index 73971e86..a749855e 100644 --- a/rai/lib/blocks.hpp +++ b/rai/lib/blocks.hpp @@ -31,12 +31,13 @@ void write (rai::stream & stream_a, T const & value) class block_visitor; enum class block_type : uint8_t { - invalid, - not_a_block, - send, - receive, - open, - change + invalid = 0, + not_a_block = 1, + send = 2, + receive = 3, + open = 4, + change = 5, + utx = 6 }; class block { @@ -62,6 +63,7 @@ public: virtual rai::signature block_signature () const = 0; virtual void signature_set (rai::uint512_union const &) = 0; virtual ~block () = default; + virtual bool valid_predecessor (rai::block const &) const = 0; }; class send_hashables { @@ -99,6 +101,7 @@ public: void signature_set (rai::uint512_union const &) override; bool operator== (rai::block const &) const override; bool operator== (rai::send_block const &) const; + bool valid_predecessor (rai::block const &) const override; static size_t constexpr size = sizeof (rai::account) + sizeof (rai::block_hash) + sizeof (rai::amount) + sizeof (rai::signature) + sizeof (uint64_t); send_hashables hashables; rai::signature signature; @@ -139,6 +142,7 @@ public: void signature_set (rai::uint512_union const &) override; bool operator== (rai::block const &) const override; bool operator== (rai::receive_block const &) const; + bool valid_predecessor (rai::block const &) const override; static size_t constexpr size = sizeof (rai::block_hash) + sizeof (rai::block_hash) + sizeof (rai::signature) + sizeof (uint64_t); receive_hashables hashables; rai::signature signature; @@ -181,6 +185,7 @@ public: void signature_set (rai::uint512_union const &) override; bool operator== (rai::block const &) const override; bool operator== (rai::open_block const &) const; + bool valid_predecessor (rai::block const &) const override; static size_t constexpr size = sizeof (rai::block_hash) + sizeof (rai::account) + sizeof (rai::account) + sizeof (rai::signature) + sizeof (uint64_t); rai::open_hashables hashables; rai::signature signature; @@ -221,11 +226,69 @@ public: void signature_set (rai::uint512_union const &) override; bool operator== (rai::block const &) const override; bool operator== (rai::change_block const &) const; + bool valid_predecessor (rai::block const &) const override; static size_t constexpr size = sizeof (rai::block_hash) + sizeof (rai::account) + sizeof (rai::signature) + sizeof (uint64_t); rai::change_hashables hashables; rai::signature signature; uint64_t work; }; +class utx_hashables +{ +public: + utx_hashables (rai::account const &, rai::block_hash const &, rai::account const &, rai::amount const &, rai::amount const &, rai::uint256_union const &); + utx_hashables (bool &, rai::stream &); + utx_hashables (bool &, boost::property_tree::ptree const &); + void hash (blake2b_state &) const; + bool is_send () const; + // Account# / public key that operates this account + // Uses: + // Bulk signature validation in advance of further ledger processing + // Arranging uncomitted transactions by account + rai::account account; + // Previous transaction in this chain + rai::block_hash previous; + // Representative of this account + rai::account representative; + // Current balance of this account + // Allows lookup of account balance simply by looking at the head block + rai::amount balance; + // Balance delta from previous transaction + // This provides a fast way to find a transaction amount when receiving and changing balances or moving vote weight + rai::amount amount; + // Link field contains source block_hash if receiving, destination account if sending + rai::uint256_union link; +}; +class utx_block : public rai::block +{ +public: + utx_block (rai::account const &, rai::block_hash const &, rai::account const &, rai::amount const &, rai::amount const &, rai::uint256_union const &, rai::raw_key const &, rai::public_key const &, uint64_t); + utx_block (bool &, rai::stream &); + utx_block (bool &, boost::property_tree::ptree const &); + virtual ~utx_block () = default; + using rai::block::hash; + void hash (blake2b_state &) const override; + uint64_t block_work () const override; + void block_work_set (uint64_t) override; + rai::block_hash previous () const override; + rai::block_hash source () const override; + rai::block_hash root () const override; + rai::account representative () const override; + void serialize (rai::stream &) const override; + void serialize_json (std::string &) const override; + bool deserialize (rai::stream &); + bool deserialize_json (boost::property_tree::ptree const &); + void visit (rai::block_visitor &) const override; + rai::block_type type () const override; + rai::signature block_signature () const override; + void signature_set (rai::uint512_union const &) override; + bool operator== (rai::block const &) const override; + bool operator== (rai::utx_block const &) const; + bool valid_predecessor (rai::block const &) const override; + static size_t constexpr size = sizeof (rai::account) + sizeof (rai::block_hash) + sizeof (rai::account) + sizeof (rai::amount) + sizeof (rai::amount) + sizeof (rai::uint256_union) + sizeof (rai::signature) + sizeof (uint64_t); + rai::utx_hashables hashables; + rai::signature signature; + uint64_t work; // Only least 48 least significant bits are encoded +}; class block_visitor { public: @@ -233,6 +296,7 @@ public: virtual void receive_block (rai::receive_block const &) = 0; virtual void open_block (rai::open_block const &) = 0; virtual void change_block (rai::change_block const &) = 0; + virtual void utx_block (rai::utx_block const &) = 0; virtual ~block_visitor () = default; }; std::unique_ptr deserialize_block (rai::stream &); diff --git a/rai/node/bootstrap.cpp b/rai/node/bootstrap.cpp index 0882cf1f..16517524 100644 --- a/rai/node/bootstrap.cpp +++ b/rai/node/bootstrap.cpp @@ -51,6 +51,10 @@ public: void change_block (rai::change_block const & block_a) override { add_dependency (block_a.hashables.previous); + } + void utx_block (rai::utx_block const & block_a) override + { + } void add_dependency (rai::block_hash const & hash_a) { diff --git a/rai/node/node.cpp b/rai/node/node.cpp index a1c27bd2..a3bd1b12 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -1331,10 +1331,28 @@ rai::process_return rai::block_processor::process_receive_one (MDB_txn * transac { BOOST_LOG (node.log) << boost::str (boost::format ("Account mismatch for: %1%") % block_a->hash ().to_string ()); } + break; } case rai::process_result::opened_burn_account: { BOOST_LOG (node.log) << boost::str (boost::format ("*** Rejecting open block for burn account ***: %1%") % block_a->hash ().to_string ()); + break; + } + case rai::process_result::balance_mismatch: + { + if (node.config.logging.ledger_logging ()) + { + BOOST_LOG (node.log) << boost::str (boost::format ("Balance mismatch for: %1%") % block_a->hash ().to_string ()); + } + break; + } + case rai::process_result::block_position: + { + if (node.config.logging.ledger_logging ()) + { + BOOST_LOG (node.log) << boost::str (boost::format ("Block %1% cannot follow predecessor %2%") % block_a->hash ().to_string () % block_a->previous ().to_string ()); + } + break; } } return result; @@ -2261,35 +2279,45 @@ public: { } virtual ~confirmed_visitor () = default; - void send_block (rai::send_block const & block_a) override + void scan_receivable (rai::account const & account_a) { for (auto i (node.wallets.items.begin ()), n (node.wallets.items.end ()); i != n; ++i) { auto wallet (i->second); - if (wallet->exists (block_a.hashables.destination)) + if (wallet->exists (account_a)) { rai::account representative; rai::pending_info pending; rai::transaction transaction (node.store.environment, nullptr, false); representative = wallet->store.representative (transaction); - auto error (node.store.pending_get (transaction, rai::pending_key (block_a.hashables.destination, block_a.hash ()), pending)); + auto error (node.store.pending_get (transaction, rai::pending_key (account_a, block->hash ()), pending)); if (!error) { auto node_l (node.shared ()); auto amount (pending.amount.number ()); - assert (block.get () == &block_a); wallet->receive_async (block, representative, amount, [](std::shared_ptr) {}); } else { if (node.config.logging.ledger_duplicate_logging ()) { - BOOST_LOG (node.log) << boost::str (boost::format ("Block confirmed before timeout %1%") % block_a.hash ().to_string ()); + BOOST_LOG (node.log) << boost::str (boost::format ("Block confirmed before timeout %1%") % block->hash ().to_string ()); } } } } } + void utx_block (rai::utx_block const & block_a) override + { + if (block_a.hashables.is_send ()) + { + scan_receivable (block_a.hashables.link); + } + } + void send_block (rai::send_block const & block_a) override + { + scan_receivable (block_a.hashables.destination); + } void receive_block (rai::receive_block const &) override { } diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index bb8290b5..ffff5828 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -1083,6 +1083,7 @@ void rai::rpc_handler::block_count_type () response_l.put ("receive", std::to_string (count.receive)); response_l.put ("open", std::to_string (count.open)); response_l.put ("change", std::to_string (count.change)); + response_l.put ("utx", std::to_string (count.utx)); response (response_l); } @@ -1638,6 +1639,12 @@ public: { // Don't report change blocks } + void utx_block (rai::utx_block const & block_a) + { + tree.put ("type", "utx"); + tree.put ("account", block_a.hashables.account.to_account ()); + tree.put ("amount", block_a.hashables.amount.to_string_dec ()) ; + } rai::rpc_handler & handler; rai::transaction & transaction; boost::property_tree::ptree & tree; From 43cd73ca5eb03347a21b1ad6b1fcd3fc2bc2bab2 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Wed, 28 Feb 2018 23:34:07 -0600 Subject: [PATCH 02/36] Fixing visitor and verifying correct utx hashing. --- rai/core_test/block.cpp | 31 +++++++++++++++++++++++++++++++ rai/lib/blocks.cpp | 4 ++++ rai/qt/qt.cpp | 6 ++++++ 3 files changed, 41 insertions(+) diff --git a/rai/core_test/block.cpp b/rai/core_test/block.cpp index 4f7dcb69..5ff68a24 100644 --- a/rai/core_test/block.cpp +++ b/rai/core_test/block.cpp @@ -358,3 +358,34 @@ TEST (utx, serialization) ASSERT_FALSE (error2); ASSERT_EQ (block1, block3); } + +TEST (utx, hashing) +{ + rai::keypair key; + rai::utx_block block (key.pub, 0, key.pub, 0, 0, 0, key.prv, key.pub, 0); + auto hash (block.hash ()); + block.hashables.account.bytes [0] ^= 0x1; + ASSERT_NE (hash, block.hash ()); + block.hashables.account.bytes [0] ^= 0x1; + ASSERT_EQ (hash, block.hash ()); + block.hashables.previous.bytes [0] ^= 0x1; + ASSERT_NE (hash, block.hash ()); + block.hashables.previous.bytes [0] ^= 0x1; + ASSERT_EQ (hash, block.hash ()); + block.hashables.representative.bytes [0] ^= 0x1; + ASSERT_NE (hash, block.hash ()); + block.hashables.representative.bytes [0] ^= 0x1; + ASSERT_EQ (hash, block.hash ()); + block.hashables.balance.bytes [0] ^= 0x1; + ASSERT_NE (hash, block.hash ()); + block.hashables.balance.bytes [0] ^= 0x1; + ASSERT_EQ (hash, block.hash ()); + block.hashables.amount.bytes [0] ^= 0x1; + ASSERT_NE (hash, block.hash ()); + block.hashables.amount.bytes [0] ^= 0x1; + ASSERT_EQ (hash, block.hash ()); + block.hashables.link.bytes [0] ^= 0x1; + ASSERT_NE (hash, block.hash ()); + block.hashables.link.bytes [0] ^= 0x1; + ASSERT_EQ (hash, block.hash ()); +} diff --git a/rai/lib/blocks.cpp b/rai/lib/blocks.cpp index d621e6af..5b257bab 100644 --- a/rai/lib/blocks.cpp +++ b/rai/lib/blocks.cpp @@ -914,8 +914,12 @@ rai::utx_hashables::utx_hashables (bool & error_a, boost::property_tree::ptree c void rai::utx_hashables::hash (blake2b_state & hash_a) const { + blake2b_update (&hash_a, account.bytes.data (), sizeof (account.bytes)); blake2b_update (&hash_a, previous.bytes.data (), sizeof (previous.bytes)); blake2b_update (&hash_a, representative.bytes.data (), sizeof (representative.bytes)); + blake2b_update (&hash_a, balance.bytes.data (), sizeof (balance.bytes)); + blake2b_update (&hash_a, amount.bytes.data (), sizeof (amount.bytes)); + blake2b_update (&hash_a, link.bytes.data (), sizeof (link.bytes)); } bool rai::utx_hashables::is_send () const diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index b48c6235..d9031a50 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -518,6 +518,12 @@ public: amount = 0; account = block_a.hashables.representative; } + void utx_block (rai::utx_block const & block_a) + { + type = "Utx"; + amount = block_a.hashables.amount.number (); + account = block_a.hashables.account; + } MDB_txn * transaction; rai::ledger & ledger; std::string type; From fc3b301873069a53aaf63720e607bd8ce485edbe Mon Sep 17 00:00:00 2001 From: clemahieu Date: Thu, 1 Mar 2018 11:45:21 -0600 Subject: [PATCH 03/36] Correctly json deserializing utx_block. --- rai/core_test/block.cpp | 10 +++++++++ rai/lib/blocks.cpp | 46 ++++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/rai/core_test/block.cpp b/rai/core_test/block.cpp index 5ff68a24..bbacd6aa 100644 --- a/rai/core_test/block.cpp +++ b/rai/core_test/block.cpp @@ -357,6 +357,16 @@ TEST (utx, serialization) rai::utx_block block3 (error2, tree); ASSERT_FALSE (error2); ASSERT_EQ (block1, block3); + block3.hashables.account.clear (); + block3.hashables.previous.clear (); + block3.hashables.representative.clear (); + block3.hashables.balance.clear (); + block3.hashables.amount.clear (); + block3.hashables.link.clear (); + block3.signature.clear (); + block3.work = 0; + ASSERT_FALSE (block3.deserialize_json (tree)); + ASSERT_EQ (block1, block3); } TEST (utx, hashing) diff --git a/rai/lib/blocks.cpp b/rai/lib/blocks.cpp index 5b257bab..0c1d142b 100644 --- a/rai/lib/blocks.cpp +++ b/rai/lib/blocks.cpp @@ -954,12 +954,17 @@ hashables (error_a, tree_a) { try { + auto type_l (tree_a.get ("type")); auto signature_l (tree_a.get ("signature")); auto work_l (tree_a.get ("work")); - error_a = rai::from_string_hex (work_l, work); + error_a = type_l != "utx"; if (!error_a) { - error_a = signature.decode_hex (signature_l); + error_a = rai::from_string_hex (work_l, work); + if (!error_a) + { + error_a = signature.decode_hex (signature_l); + } } } catch (std::runtime_error const &) @@ -1006,7 +1011,7 @@ void rai::utx_block::serialize (rai::stream & stream_a) const void rai::utx_block::serialize_json (std::string & string_a) const { boost::property_tree::ptree tree; - tree.put ("type", "change"); + tree.put ("type", "utx"); tree.put ("account", hashables.account.to_account ()); tree.put ("previous", hashables.previous.to_string ()); tree.put ("representative", representative ().to_account ()); @@ -1053,20 +1058,47 @@ bool rai::utx_block::deserialize_json (boost::property_tree::ptree const & tree_ try { assert (tree_a.get ("type") == "utx"); + auto account_l (tree_a.get ("account")); auto previous_l (tree_a.get ("previous")); auto representative_l (tree_a.get ("representative")); + auto balance_l (tree_a.get ("balance")); + auto amount_l (tree_a.get ("amount")); + auto link_l (tree_a.get ("link")); auto work_l (tree_a.get ("work")); auto signature_l (tree_a.get ("signature")); - error = hashables.previous.decode_hex (previous_l); + error = hashables.account.decode_account (account_l); if (!error) { - error = hashables.representative.decode_hex (representative_l); + error = hashables.previous.decode_hex (previous_l); if (!error) { - error = rai::from_string_hex (work_l, work); + error = hashables.representative.decode_account (representative_l); if (!error) { - error = signature.decode_hex (signature_l); + error = hashables.balance.decode_dec (balance_l); + if (!error) + { + error = hashables.amount.decode_dec (amount_l); + if (!error) + { + if (hashables.is_send ()) + { + error = hashables.link.decode_account (link_l); + } + else + { + error = hashables.link.decode_hex (link_l); + } + if (!error) + { + error = rai::from_string_hex (work_l, work); + if (!error) + { + error = signature.decode_hex (signature_l); + } + } + } + } } } } From 0a9aea86294c30e47262c80a520dde84272a0c62 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Thu, 1 Mar 2018 16:38:02 -0600 Subject: [PATCH 04/36] Removing amount field in favor of calculating it as the balance difference to the previous block. --- rai/common.cpp | 9 ++-- rai/core_test/block.cpp | 20 +++++---- rai/core_test/block_store.cpp | 2 +- rai/core_test/ledger.cpp | 54 +++++++++++----------- rai/ledger.cpp | 65 +++++++++++++-------------- rai/lib/blocks.cpp | 84 +++++++++++------------------------ rai/lib/blocks.hpp | 10 ++--- rai/node/node.cpp | 5 +-- rai/node/rpc.cpp | 3 +- rai/qt/qt.cpp | 2 +- 10 files changed, 109 insertions(+), 145 deletions(-) diff --git a/rai/common.cpp b/rai/common.cpp index f5ea127d..48a5d86b 100644 --- a/rai/common.cpp +++ b/rai/common.cpp @@ -492,11 +492,10 @@ void rai::amount_visitor::open_block (rai::open_block const & block_a) void rai::amount_visitor::utx_block (rai::utx_block const & block_a) { - result = block_a.hashables.amount.number (); - if (block_a.hashables.is_send ()) - { - result = 0 - result; - } + balance_visitor prev (transaction, store); + prev.compute (block_a.hashables.previous); + result = block_a.hashables.balance.number (); + result = result < prev.result ? prev.result - result : result - prev.result; } void rai::amount_visitor::change_block (rai::change_block const & block_a) diff --git a/rai/core_test/block.cpp b/rai/core_test/block.cpp index bbacd6aa..9f23ab5d 100644 --- a/rai/core_test/block.cpp +++ b/rai/core_test/block.cpp @@ -330,12 +330,11 @@ TEST (utx, serialization) { rai::keypair key1; rai::keypair key2; - rai::utx_block block1 (key1.pub, 1, key2.pub, 2, 3, 4, key1.prv, key1.pub, 5); + rai::utx_block block1 (key1.pub, 1, key2.pub, 2, 4, key1.prv, key1.pub, 5); ASSERT_EQ (key1.pub, block1.hashables.account); ASSERT_EQ (rai::block_hash (1), block1.previous ()); ASSERT_EQ (key2.pub, block1.hashables.representative); ASSERT_EQ (rai::amount (2), block1.hashables.balance); - ASSERT_EQ (rai::amount (3), block1.hashables.amount); ASSERT_EQ (rai::uint256_union (4), block1.hashables.link); std::vector bytes; { @@ -348,6 +347,16 @@ TEST (utx, serialization) rai::utx_block block2 (error1, stream); ASSERT_FALSE (error1); ASSERT_EQ (block1, block2); + block2.hashables.account.clear (); + block2.hashables.previous.clear (); + block2.hashables.representative.clear (); + block2.hashables.balance.clear (); + block2.hashables.link.clear (); + block2.signature.clear (); + block2.work = 0; + rai::bufferstream stream2 (bytes.data (), bytes.size ()); + ASSERT_FALSE (block2.deserialize (stream2)); + ASSERT_EQ (block1, block2); std::string json; block1.serialize_json (json); std::stringstream body (json); @@ -361,7 +370,6 @@ TEST (utx, serialization) block3.hashables.previous.clear (); block3.hashables.representative.clear (); block3.hashables.balance.clear (); - block3.hashables.amount.clear (); block3.hashables.link.clear (); block3.signature.clear (); block3.work = 0; @@ -372,7 +380,7 @@ TEST (utx, serialization) TEST (utx, hashing) { rai::keypair key; - rai::utx_block block (key.pub, 0, key.pub, 0, 0, 0, key.prv, key.pub, 0); + rai::utx_block block (key.pub, 0, key.pub, 0, 0, key.prv, key.pub, 0); auto hash (block.hash ()); block.hashables.account.bytes [0] ^= 0x1; ASSERT_NE (hash, block.hash ()); @@ -390,10 +398,6 @@ TEST (utx, hashing) ASSERT_NE (hash, block.hash ()); block.hashables.balance.bytes [0] ^= 0x1; ASSERT_EQ (hash, block.hash ()); - block.hashables.amount.bytes [0] ^= 0x1; - ASSERT_NE (hash, block.hash ()); - block.hashables.amount.bytes [0] ^= 0x1; - ASSERT_EQ (hash, block.hash ()); block.hashables.link.bytes [0] ^= 0x1; ASSERT_NE (hash, block.hash ()); block.hashables.link.bytes [0] ^= 0x1; diff --git a/rai/core_test/block_store.cpp b/rai/core_test/block_store.cpp index 591555bb..4bc1007d 100644 --- a/rai/core_test/block_store.cpp +++ b/rai/core_test/block_store.cpp @@ -996,7 +996,7 @@ TEST (block_store, utx_block) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair key1; - rai::utx_block block1 (1, genesis.hash (), 3, 4, 5, 6, key1.prv, key1.pub, 7); + rai::utx_block block1 (1, genesis.hash (), 3, 4, 6, key1.prv, key1.pub, 7); ASSERT_EQ (rai::block_type::utx, block1.type ()); store.block_put (transaction, block1.hash (), block1); ASSERT_TRUE (store.block_exists (transaction, block1.hash ())); diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 13549618..202a3a89 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1464,7 +1464,7 @@ TEST (ledger, utx_send_receive) rai::genesis genesis; rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); auto send2 (store.block_get (transaction, send1.hash ())); @@ -1473,7 +1473,7 @@ TEST (ledger, utx_send_receive) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); - rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, rai::Gxrb_ratio, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); ASSERT_TRUE (store.block_exists (transaction, receive1.hash ())); auto receive2 (store.block_get (transaction, receive1.hash ())); @@ -1502,7 +1502,7 @@ TEST (ledger, utx_receive) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); - rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, rai::Gxrb_ratio, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); ASSERT_TRUE (store.block_exists (transaction, receive1.hash ())); auto receive2 (store.block_get (transaction, receive1.hash ())); @@ -1523,7 +1523,7 @@ TEST (ledger, utx_rep_change) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair rep; - rai::utx_block change1 (rai::genesis_account, genesis.hash (), rep.pub, rai::genesis_amount, 0, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block change1 (rai::genesis_account, genesis.hash (), rep.pub, rai::genesis_amount, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, change1).code); ASSERT_TRUE (store.block_exists (transaction, change1.hash ())); auto change2 (store.block_get (transaction, change1.hash ())); @@ -1545,7 +1545,7 @@ TEST (ledger, utx_open) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); auto send2 (store.block_get (transaction, send1.hash ())); @@ -1554,7 +1554,7 @@ TEST (ledger, utx_open) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); - rai::utx_block open1 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + rai::utx_block open1 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); ASSERT_TRUE (store.block_exists (transaction, open1.hash ())); auto open2 (store.block_get (transaction, open1.hash ())); @@ -1575,7 +1575,7 @@ TEST (ledger, send_after_utx_fail) rai::genesis genesis; rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); rai::send_block send2 (send1.hash (), rai::genesis_account, rai::genesis_amount - (2 * rai::Gxrb_ratio), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::block_position, ledger.process (transaction, send2).code); @@ -1591,7 +1591,7 @@ TEST (ledger, receive_after_utx_fail) rai::genesis genesis; rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); rai::receive_block receive1 (send1.hash (), send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::block_position, ledger.process (transaction, receive1).code); @@ -1607,7 +1607,7 @@ TEST (ledger, change_after_utx_fail) rai::genesis genesis; rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); rai::keypair rep; rai::change_block change1 (send1.hash (), rep.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1632,7 +1632,7 @@ TEST (ledger, utx_unreceivable_fail) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); - rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, rai::Gxrb_ratio, 1, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, 1, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::unreceivable, ledger.process (transaction, receive1).code); } @@ -1654,7 +1654,7 @@ TEST (ledger, utx_receive_bad_amount_fail) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); - rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::balance_mismatch, ledger.process (transaction, receive1).code); } @@ -1667,10 +1667,10 @@ TEST (ledger, utx_no_link_amount_fail) rai::genesis genesis; rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); rai::keypair rep; - rai::utx_block change1 (rai::genesis_account, send1.hash (), rep.pub, rai::genesis_amount, rai::Gxrb_ratio, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block change1 (rai::genesis_account, send1.hash (), rep.pub, rai::genesis_amount, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::balance_mismatch, ledger.process (transaction, change1).code); } @@ -1683,7 +1683,7 @@ TEST (ledger, utx_receive_wrong_account_fail) rai::genesis genesis; rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); auto send2 (store.block_get (transaction, send1.hash ())); @@ -1693,7 +1693,7 @@ TEST (ledger, utx_receive_wrong_account_fail) ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); rai::keypair key; - rai::utx_block receive1 (key.pub, 0, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), key.prv, key.pub, 0); + rai::utx_block receive1 (key.pub, 0, rai::genesis_account, rai::Gxrb_ratio, send1.hash (), key.prv, key.pub, 0); ASSERT_EQ (rai::process_result::unreceivable, ledger.process (transaction, receive1).code); } @@ -1707,9 +1707,9 @@ TEST (ledger, utx_open_utx_fork) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); - rai::utx_block open1 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + rai::utx_block open1 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); rai::open_block open2 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::fork, ledger.process (transaction, open2).code); @@ -1726,11 +1726,11 @@ TEST (ledger, utx_utx_open_fork) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); rai::open_block open1 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); - rai::utx_block open2 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + rai::utx_block open2 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::fork, ledger.process (transaction, open2).code); ASSERT_EQ (open1.root (), open2.root ()); } @@ -1745,9 +1745,9 @@ TEST (ledger, utx_open_previous_fail) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); - rai::utx_block open1 (destination.pub, destination.pub, rai::genesis_account, rai::Gxrb_ratio, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + rai::utx_block open1 (destination.pub, destination.pub, rai::genesis_account, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::gap_previous, ledger.process (transaction, open1).code); } @@ -1761,7 +1761,7 @@ TEST (ledger, utx_send_change) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair rep; - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rep.pub, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rep.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); auto send2 (store.block_get (transaction, send1.hash ())); @@ -1782,7 +1782,7 @@ TEST (ledger, utx_receive_change) rai::genesis genesis; rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); auto send2 (store.block_get (transaction, send1.hash ())); @@ -1792,7 +1792,7 @@ TEST (ledger, utx_receive_change) ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); rai::keypair rep; - rai::utx_block receive1 (rai::genesis_account, send1.hash (), rep.pub, rai::genesis_amount, rai::Gxrb_ratio, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rep.pub, rai::genesis_amount, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); ASSERT_TRUE (store.block_exists (transaction, receive1.hash ())); auto receive2 (store.block_get (transaction, receive1.hash ())); @@ -1814,7 +1814,7 @@ TEST (ledger, utx_open_old) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); rai::open_block open1 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); @@ -1833,9 +1833,9 @@ TEST (ledger, utx_receive_old) rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; - rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); - rai::utx_block send2 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount - (2 * rai::Gxrb_ratio), 0 - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block send2 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount - (2 * rai::Gxrb_ratio), destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send2).code); rai::open_block open1 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 1022bc34..8a78afcc 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -127,6 +127,8 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) if (result.code == rai::process_result::progress) { rai::account_info info; + result.amount = block_a.hashables.balance; + bool is_send (false); auto account_error (ledger.store.account_get (transaction, block_a.hashables.account, info)); if (!account_error) { @@ -137,6 +139,8 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) result.code = ledger.store.block_exists (transaction, block_a.hashables.previous) ? rai::process_result::progress : rai::process_result::gap_previous; // Does the previous block exist in the ledger? (Unambigious) if (result.code == rai::process_result::progress) { + is_send = block_a.hashables.balance < info.balance; + result.amount = result.amount.number () - info.balance.number (); result.code = block_a.hashables.previous == info.head ? rai::process_result::progress : rai::process_result::fork; // Is the previous block the account's head block? (Ambigious) } } @@ -148,7 +152,7 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) } if (result.code == rai::process_result::progress) { - if (block_a.hashables.is_send ()) + if (is_send) { result.code = block_a.hashables.balance.number () < info.balance.number () ? rai::process_result::progress : rai::process_result::negative_spend; // If the amount is negative the new balance must be less than the old balance or it's underflowed (Unambiguous) } @@ -161,49 +165,44 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed) if (result.code == rai::process_result::progress) { - result.code = pending.amount == block_a.hashables.amount ? rai::process_result::progress : rai::process_result::balance_mismatch; + result.code = result.amount == pending.amount ? rai::process_result::progress : rai::process_result::balance_mismatch; } } else { - result.code = block_a.hashables.amount.is_zero () ? rai::process_result::progress : rai::process_result::balance_mismatch; + result.code = result.amount.is_zero () ? rai::process_result::progress : rai::process_result::balance_mismatch; } } } if (result.code == rai::process_result::progress) + { + ledger.store.block_put (transaction, hash, block_a); + + if (!info.rep_block.is_zero ()) { - result.code = (info.balance.number () + block_a.hashables.amount.number ()) == block_a.hashables.balance.number () ? rai::process_result::progress : rai::process_result::balance_mismatch; // Does the amount delta match the actual change in balances to the last transaction (Unambiguous) - if (result.code == rai::process_result::progress) - { - ledger.store.block_put (transaction, hash, block_a); - - if (!info.rep_block.is_zero ()) - { - // Move existing representation - ledger.store.representation_add (transaction, info.rep_block, 0 - info.balance.number ()); - ledger.store.representation_add (transaction, hash, info.balance.number ()); - } - // Add in amount delta - ledger.store.representation_add (transaction, hash, block_a.hashables.amount.number ()); - - if (block_a.hashables.is_send ()) - { - rai::pending_key key (block_a.hashables.link, hash); - rai::pending_info info (block_a.hashables.account, 0 - block_a.hashables.amount.number ()); - ledger.store.pending_put (transaction, key, info); - } - - ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1); - if (!ledger.store.frontier_get (transaction, info.head).is_zero ()) - { - ledger.store.frontier_del (transaction, info.head); - } - // Frontier table is unnecessary for utx blocks and this also prevents old blocks from being inserted on top of utx blocks - result.account = block_a.hashables.account; - result.amount = block_a.hashables.amount; - } + // Move existing representation + ledger.store.representation_add (transaction, info.rep_block, 0 - info.balance.number ()); + ledger.store.representation_add (transaction, hash, info.balance.number ()); } + // Add in amount delta + ledger.store.representation_add (transaction, hash, result.amount.number ()); + + if (is_send) + { + rai::pending_key key (block_a.hashables.link, hash); + rai::pending_info info (block_a.hashables.account, 0 - result.amount.number ()); + ledger.store.pending_put (transaction, key, info); + } + + ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1); + if (!ledger.store.frontier_get (transaction, info.head).is_zero ()) + { + ledger.store.frontier_del (transaction, info.head); + } + // Frontier table is unnecessary for utx blocks and this also prevents old blocks from being inserted on top of utx blocks + result.account = block_a.hashables.account; + } } } } diff --git a/rai/lib/blocks.cpp b/rai/lib/blocks.cpp index 0c1d142b..774eb042 100644 --- a/rai/lib/blocks.cpp +++ b/rai/lib/blocks.cpp @@ -832,12 +832,11 @@ void rai::change_block::signature_set (rai::uint512_union const & signature_a) } -rai::utx_hashables::utx_hashables (rai::account const & account_a, rai::block_hash const & previous_a, rai::account const & representative_a, rai::amount const & balance_a, rai::amount const & amount_a, rai::uint256_union const & link_a) : +rai::utx_hashables::utx_hashables (rai::account const & account_a, rai::block_hash const & previous_a, rai::account const & representative_a, rai::amount const & balance_a, rai::uint256_union const & link_a) : account (account_a), previous (previous_a), representative (representative_a), balance (balance_a), -amount (amount_a), link (link_a) { } @@ -856,11 +855,7 @@ rai::utx_hashables::utx_hashables (bool & error_a, rai::stream & stream_a) error_a = rai::read (stream_a, balance); if (!error_a) { - error_a = rai::read (stream_a, amount); - if (!error_a) - { - error_a = rai::read (stream_a, link); - } + error_a = rai::read (stream_a, link); } } } @@ -874,7 +869,6 @@ rai::utx_hashables::utx_hashables (bool & error_a, boost::property_tree::ptree c auto account_l (tree_a.get ("account")); auto previous_l (tree_a.get ("previous")); auto representative_l (tree_a.get ("representative")); - auto amount_l (tree_a.get ("amount")); auto balance_l (tree_a.get ("balance")); auto link_l (tree_a.get ("link")); error_a = account.decode_account (account_l); @@ -889,18 +883,7 @@ rai::utx_hashables::utx_hashables (bool & error_a, boost::property_tree::ptree c error_a = balance.decode_dec (balance_l); if (!error_a) { - error_a = amount.decode_dec (amount_l); - if (!error_a) - { - if (is_send ()) - { - error_a = link.decode_account (link_l); - } - else - { - error_a = link.decode_hex (link_l); - } - } + error_a = link.decode_account (link_l); } } } @@ -918,17 +901,11 @@ void rai::utx_hashables::hash (blake2b_state & hash_a) const blake2b_update (&hash_a, previous.bytes.data (), sizeof (previous.bytes)); blake2b_update (&hash_a, representative.bytes.data (), sizeof (representative.bytes)); blake2b_update (&hash_a, balance.bytes.data (), sizeof (balance.bytes)); - blake2b_update (&hash_a, amount.bytes.data (), sizeof (amount.bytes)); blake2b_update (&hash_a, link.bytes.data (), sizeof (link.bytes)); } -bool rai::utx_hashables::is_send () const -{ - return (amount.bytes [0] & 0x80) == 0x80; -} - -rai::utx_block::utx_block (rai::account const & account_a, rai::block_hash const & previous_a, rai::account const & representative_a, rai::amount const & balance_a, rai::amount const & amount_a, rai::uint256_union const & link_a, rai::raw_key const & prv_a, rai::public_key const & pub_a, uint64_t work_a) : -hashables (account_a, previous_a, representative_a, balance_a, amount_a, link_a), +rai::utx_block::utx_block (rai::account const & account_a, rai::block_hash const & previous_a, rai::account const & representative_a, rai::amount const & balance_a, rai::uint256_union const & link_a, rai::raw_key const & prv_a, rai::public_key const & pub_a, uint64_t work_a) : +hashables (account_a, previous_a, representative_a, balance_a, link_a), signature (rai::sign_message (prv_a, pub_a, hash ())), work (work_a) { @@ -1002,7 +979,6 @@ void rai::utx_block::serialize (rai::stream & stream_a) const write (stream_a, hashables.previous); write (stream_a, hashables.representative); write (stream_a, hashables.balance); - write (stream_a, hashables.amount); write (stream_a, hashables.link); write (stream_a, signature); write (stream_a, work); @@ -1016,15 +992,7 @@ void rai::utx_block::serialize_json (std::string & string_a) const tree.put ("previous", hashables.previous.to_string ()); tree.put ("representative", representative ().to_account ()); tree.put ("balance", hashables.balance.to_string_dec ()); - tree.put ("amount", hashables.amount.to_string_dec ()); - if (hashables.is_send ()) - { - tree.put ("link", hashables.link.to_account ()); - } - else - { - tree.put ("link", hashables.link.to_string ()); - } + tree.put ("link", hashables.link.to_account ()); std::string signature_l; signature.encode_hex (signature_l); tree.put ("signature", signature_l); @@ -1036,16 +1004,28 @@ void rai::utx_block::serialize_json (std::string & string_a) const bool rai::utx_block::deserialize (rai::stream & stream_a) { - auto error (read (stream_a, hashables.previous)); + auto error (read (stream_a, hashables.account)); if (!error) { - error = read (stream_a, hashables.representative); + error = read (stream_a, hashables.previous); if (!error) { - error = read (stream_a, signature); + error = read (stream_a, hashables.representative); if (!error) { - error = read (stream_a, work); + error = read (stream_a, hashables.balance); + if (!error) + { + error = read (stream_a, hashables.link); + if (!error) + { + error = read (stream_a, signature); + if (!error) + { + error = read (stream_a, work); + } + } + } } } } @@ -1062,7 +1042,6 @@ bool rai::utx_block::deserialize_json (boost::property_tree::ptree const & tree_ auto previous_l (tree_a.get ("previous")); auto representative_l (tree_a.get ("representative")); auto balance_l (tree_a.get ("balance")); - auto amount_l (tree_a.get ("amount")); auto link_l (tree_a.get ("link")); auto work_l (tree_a.get ("work")); auto signature_l (tree_a.get ("signature")); @@ -1078,24 +1057,13 @@ bool rai::utx_block::deserialize_json (boost::property_tree::ptree const & tree_ error = hashables.balance.decode_dec (balance_l); if (!error) { - error = hashables.amount.decode_dec (amount_l); + error = hashables.link.decode_account (link_l); if (!error) { - if (hashables.is_send ()) - { - error = hashables.link.decode_account (link_l); - } - else - { - error = hashables.link.decode_hex (link_l); - } + error = rai::from_string_hex (work_l, work); if (!error) { - error = rai::from_string_hex (work_l, work); - if (!error) - { - error = signature.decode_hex (signature_l); - } + error = signature.decode_hex (signature_l); } } } @@ -1133,7 +1101,7 @@ bool rai::utx_block::operator== (rai::block const & other_a) const bool rai::utx_block::operator== (rai::utx_block const & other_a) const { - return hashables.account == other_a.hashables.account && hashables.previous == other_a.hashables.previous && hashables.representative == other_a.hashables.representative && hashables.balance == other_a.hashables.balance && hashables.amount == other_a.hashables.amount && hashables.link == other_a.hashables.link && signature == other_a.signature && work == other_a.work; + return hashables.account == other_a.hashables.account && hashables.previous == other_a.hashables.previous && hashables.representative == other_a.hashables.representative && hashables.balance == other_a.hashables.balance && hashables.link == other_a.hashables.link && signature == other_a.signature && work == other_a.work; } bool rai::utx_block::valid_predecessor (rai::block const & block_a) const diff --git a/rai/lib/blocks.hpp b/rai/lib/blocks.hpp index a749855e..1d641dbb 100644 --- a/rai/lib/blocks.hpp +++ b/rai/lib/blocks.hpp @@ -235,11 +235,10 @@ public: class utx_hashables { public: - utx_hashables (rai::account const &, rai::block_hash const &, rai::account const &, rai::amount const &, rai::amount const &, rai::uint256_union const &); + utx_hashables (rai::account const &, rai::block_hash const &, rai::account const &, rai::amount const &, rai::uint256_union const &); utx_hashables (bool &, rai::stream &); utx_hashables (bool &, boost::property_tree::ptree const &); void hash (blake2b_state &) const; - bool is_send () const; // Account# / public key that operates this account // Uses: // Bulk signature validation in advance of further ledger processing @@ -252,16 +251,13 @@ public: // Current balance of this account // Allows lookup of account balance simply by looking at the head block rai::amount balance; - // Balance delta from previous transaction - // This provides a fast way to find a transaction amount when receiving and changing balances or moving vote weight - rai::amount amount; // Link field contains source block_hash if receiving, destination account if sending rai::uint256_union link; }; class utx_block : public rai::block { public: - utx_block (rai::account const &, rai::block_hash const &, rai::account const &, rai::amount const &, rai::amount const &, rai::uint256_union const &, rai::raw_key const &, rai::public_key const &, uint64_t); + utx_block (rai::account const &, rai::block_hash const &, rai::account const &, rai::amount const &, rai::uint256_union const &, rai::raw_key const &, rai::public_key const &, uint64_t); utx_block (bool &, rai::stream &); utx_block (bool &, boost::property_tree::ptree const &); virtual ~utx_block () = default; @@ -284,7 +280,7 @@ public: bool operator== (rai::block const &) const override; bool operator== (rai::utx_block const &) const; bool valid_predecessor (rai::block const &) const override; - static size_t constexpr size = sizeof (rai::account) + sizeof (rai::block_hash) + sizeof (rai::account) + sizeof (rai::amount) + sizeof (rai::amount) + sizeof (rai::uint256_union) + sizeof (rai::signature) + sizeof (uint64_t); + static size_t constexpr size = sizeof (rai::account) + sizeof (rai::block_hash) + sizeof (rai::account) + sizeof (rai::amount) + sizeof (rai::uint256_union) + sizeof (rai::signature) + sizeof (uint64_t); rai::utx_hashables hashables; rai::signature signature; uint64_t work; // Only least 48 least significant bits are encoded diff --git a/rai/node/node.cpp b/rai/node/node.cpp index a3bd1b12..d12ec2fd 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -2309,10 +2309,7 @@ public: } void utx_block (rai::utx_block const & block_a) override { - if (block_a.hashables.is_send ()) - { - scan_receivable (block_a.hashables.link); - } + scan_receivable (block_a.hashables.link); } void send_block (rai::send_block const & block_a) override { diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index ffff5828..28b84f23 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -1643,7 +1643,8 @@ public: { tree.put ("type", "utx"); tree.put ("account", block_a.hashables.account.to_account ()); - tree.put ("amount", block_a.hashables.amount.to_string_dec ()) ; + auto amount (handler.node.ledger.amount (transaction, hash).convert_to ()); + tree.put ("amount", amount) ; } rai::rpc_handler & handler; rai::transaction & transaction; diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index d9031a50..321b6bc3 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -521,7 +521,7 @@ public: void utx_block (rai::utx_block const & block_a) { type = "Utx"; - amount = block_a.hashables.amount.number (); + amount = ledger.amount (transaction, block_a.hash ()); account = block_a.hashables.account; } MDB_txn * transaction; From b576abeff8c8e913cca18877255a6b5ad838f638 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Thu, 1 Mar 2018 16:42:50 -0600 Subject: [PATCH 05/36] Removing tautology since is_send is derived from the balance delta. --- rai/ledger.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 8a78afcc..55a9ff38 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -152,11 +152,7 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) } if (result.code == rai::process_result::progress) { - if (is_send) - { - result.code = block_a.hashables.balance.number () < info.balance.number () ? rai::process_result::progress : rai::process_result::negative_spend; // If the amount is negative the new balance must be less than the old balance or it's underflowed (Unambiguous) - } - else + if (!is_send) { if (!block_a.hashables.link.is_zero ()) { From fcde264cb68cbac22ee9588db10099189a61ec24 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Thu, 1 Mar 2018 17:58:52 -0600 Subject: [PATCH 06/36] Fixing and testing block_del for utx blocks Making sure pending entry is removed when utx receiving. Adding utx_block rollback visitor. --- rai/blockstore.cpp | 15 ++++-- rai/core_test/block_store.cpp | 4 ++ rai/core_test/ledger.cpp | 41 +++++++++++++++ rai/ledger.cpp | 95 ++++++++++++++++++++++++++++------- 4 files changed, 133 insertions(+), 22 deletions(-) diff --git a/rai/blockstore.cpp b/rai/blockstore.cpp index 7b0f02e6..eaa31591 100644 --- a/rai/blockstore.cpp +++ b/rai/blockstore.cpp @@ -736,20 +736,25 @@ std::unique_ptr rai::block_store::block_get (MDB_txn * transaction_a void rai::block_store::block_del (MDB_txn * transaction_a, rai::block_hash const & hash_a) { - auto status (mdb_del (transaction_a, send_blocks, rai::mdb_val (hash_a), nullptr)); + auto status (mdb_del (transaction_a, utx_blocks, rai::mdb_val (hash_a), nullptr)); assert (status == 0 || status == MDB_NOTFOUND); if (status != 0) { - auto status (mdb_del (transaction_a, receive_blocks, rai::mdb_val (hash_a), nullptr)); + auto status (mdb_del (transaction_a, send_blocks, rai::mdb_val (hash_a), nullptr)); assert (status == 0 || status == MDB_NOTFOUND); if (status != 0) { - auto status (mdb_del (transaction_a, open_blocks, rai::mdb_val (hash_a), nullptr)); + auto status (mdb_del (transaction_a, receive_blocks, rai::mdb_val (hash_a), nullptr)); assert (status == 0 || status == MDB_NOTFOUND); if (status != 0) { - auto status (mdb_del (transaction_a, change_blocks, rai::mdb_val (hash_a), nullptr)); - assert (status == 0); + auto status (mdb_del (transaction_a, open_blocks, rai::mdb_val (hash_a), nullptr)); + assert (status == 0 || status == MDB_NOTFOUND); + if (status != 0) + { + auto status (mdb_del (transaction_a, change_blocks, rai::mdb_val (hash_a), nullptr)); + assert (status == 0); + } } } } diff --git a/rai/core_test/block_store.cpp b/rai/core_test/block_store.cpp index 4bc1007d..d46cb6e3 100644 --- a/rai/core_test/block_store.cpp +++ b/rai/core_test/block_store.cpp @@ -1005,4 +1005,8 @@ TEST (block_store, utx_block) ASSERT_EQ (block1, *block2); auto count (store.block_count (transaction)); ASSERT_EQ (1, count.utx); + store.block_del (transaction, block1.hash ()); + ASSERT_FALSE (store.block_exists (transaction, block1.hash ())); + auto count2 (store.block_count (transaction)); + ASSERT_EQ (0, count2.utx); } diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 202a3a89..730a74c8 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1455,6 +1455,20 @@ TEST (ledger, bootstrap_rep_weight) } } +TEST (ledger, utx_account) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_EQ (rai::genesis_account, ledger.account (transaction, send1.hash ())); +} + TEST (ledger, utx_send_receive) { bool init (false); @@ -1473,6 +1487,7 @@ TEST (ledger, utx_send_receive) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + ASSERT_TRUE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ()))); rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); ASSERT_TRUE (store.block_exists (transaction, receive1.hash ())); @@ -1482,6 +1497,7 @@ TEST (ledger, utx_send_receive) ASSERT_EQ (rai::genesis_amount, ledger.balance (transaction, receive1.hash ())); ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, receive1.hash ())); ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); + ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ()))); } TEST (ledger, utx_receive) @@ -1846,3 +1862,28 @@ TEST (ledger, utx_receive_old) ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); } +TEST (ledger, utx_rollback) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ASSERT_TRUE (store.block_exists (transaction, send1.hash ())); + auto send2 (store.block_get (transaction, send1.hash ())); + ASSERT_NE (nullptr, send2); + ASSERT_EQ (send1, *send2); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.account_balance (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + ASSERT_TRUE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ()))); + ledger.rollback (transaction, send1.hash ()); + ASSERT_FALSE (store.block_exists (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.account_balance (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); + ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ()))); +} + diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 55a9ff38..1814a0f5 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -95,7 +95,55 @@ public: } void utx_block (rai::utx_block const & block_a) override { - assert (false); + auto hash (block_a.hash ()); + rai::block_hash representative (0); + if (!block_a.hashables.previous.is_zero ()) + { + representative = ledger.representative (transaction, block_a.hashables.previous); + } + auto balance (ledger.balance (transaction, block_a.hashables.previous)); + auto is_send (block_a.hashables.balance < balance); + ledger.store.block_put (transaction, hash, block_a); + // Add in amount delta + ledger.store.representation_add (transaction, hash, balance - block_a.hashables.balance.number ()); + if (!representative.is_zero ()) + { + // Move existing representation + ledger.store.representation_add (transaction, hash, 0 - block_a.hashables.balance.number ()); + ledger.store.representation_add (transaction, representative, block_a.hashables.balance.number ()); + } + + if (is_send) + { + rai::pending_key key (block_a.hashables.link, hash); + ledger.store.pending_del (transaction, key); + } + else if (!block_a.hashables.link.is_zero ()) + { + rai::pending_info info (ledger.account (transaction, block_a.hashables.link), block_a.hashables.balance.number () - balance); + ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.account, hash), info); + } + + rai::account_info info; + auto error (ledger.store.account_get (transaction, block_a.hashables.account, info)); + assert (!error); + ledger.change_latest (transaction, block_a.hashables.account, block_a.hashables.previous, representative, balance, info.block_count - 1); + + auto previous (ledger.store.block_get (transaction, block_a.hashables.previous)); + switch (previous->type ()) + { + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + { + ledger.store.frontier_put (transaction, block_a.hashables.previous, block_a.hashables.account); + break; + } + default: + break; + } + ledger.store.block_del (transaction, hash); } MDB_txn * transaction; rai::ledger & ledger; @@ -190,6 +238,10 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) rai::pending_info info (block_a.hashables.account, 0 - result.amount.number ()); ledger.store.pending_put (transaction, key, info); } + else if (!block_a.hashables.link.is_zero ()) + { + ledger.store.pending_del (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link)); + } ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1); if (!ledger.store.frontier_get (transaction, info.head).is_zero ()) @@ -582,28 +634,37 @@ void rai::ledger::rollback (MDB_txn * transaction_a, rai::block_hash const & blo // Return account containing hash rai::account rai::ledger::account (MDB_txn * transaction_a, rai::block_hash const & hash_a) { - assert (store.block_exists (transaction_a, hash_a)); - auto hash (hash_a); - rai::block_hash successor (1); - rai::block_info block_info; - while (!successor.is_zero () && store.block_info_get (transaction_a, successor, block_info)) - { - successor = store.block_successor (transaction_a, hash); - if (!successor.is_zero ()) - { - hash = successor; - } - } rai::account result; - if (successor.is_zero ()) + assert (store.block_exists (transaction_a, hash_a)); + auto block (store.block_get (transaction_a, hash_a)); + auto utx_block (dynamic_cast (block.get ())); + if (utx_block != nullptr) { - result = store.frontier_get (transaction_a, hash); + result = utx_block->hashables.account; } else { - result = block_info.account; + auto hash (hash_a); + rai::block_hash successor (1); + rai::block_info block_info; + while (!successor.is_zero () && store.block_info_get (transaction_a, successor, block_info)) + { + successor = store.block_successor (transaction_a, hash); + if (!successor.is_zero ()) + { + hash = successor; + } + } + if (successor.is_zero ()) + { + result = store.frontier_get (transaction_a, hash); + } + else + { + result = block_info.account; + } + assert (!result.is_zero ()); } - assert (!result.is_zero ()); return result; } From 9852348f2fb6f27084765e598004cee939456e4b Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Thu, 1 Mar 2018 21:28:10 -0700 Subject: [PATCH 07/36] Fix bootstrapping ublocks --- rai/core_test/network.cpp | 29 +++++++++++++++++++++++++ rai/ledger.cpp | 45 ++++++++++++++++++--------------------- rai/node/bootstrap.cpp | 26 +++++++++++++++++++++- rai/node/common.cpp | 2 +- 4 files changed, 76 insertions(+), 26 deletions(-) diff --git a/rai/core_test/network.cpp b/rai/core_test/network.cpp index 849491c0..14d221f4 100644 --- a/rai/core_test/network.cpp +++ b/rai/core_test/network.cpp @@ -550,6 +550,35 @@ TEST (bootstrap_processor, process_two) node1->stop (); } +// Bootstrap can pull universal blocks +TEST (bootstrap_processor, process_utx) +{ + rai::system system (24000, 1); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + auto node0 (system.nodes[0]); + std::unique_ptr block1 (new rai::utx_block (rai::test_genesis_key.pub, node0->latest (rai::test_genesis_key.pub), rai::test_genesis_key.pub, rai::genesis_amount - 100, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0)); + std::unique_ptr block2 (new rai::utx_block (rai::test_genesis_key.pub, block1->hash (), rai::test_genesis_key.pub, rai::genesis_amount, block1->hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0)); + node0->generate_work (*block1); + node0->generate_work (*block2); + node0->process (*block1); + node0->process (*block2); + rai::node_init init1; + auto node1 (std::make_shared (init1, system.service, 24001, rai::unique_path (), system.alarm, system.logging, system.work)); + ASSERT_EQ (node0->latest (rai::test_genesis_key.pub), block2->hash ()); + ASSERT_NE (node1->latest (rai::test_genesis_key.pub), block2->hash ()); + node1->bootstrap_initiator.bootstrap (node0->network.endpoint ()); + auto iterations (0); + ASSERT_NE (node1->latest (rai::test_genesis_key.pub), node0->latest (rai::test_genesis_key.pub)); + while (node1->latest (rai::test_genesis_key.pub) != node0->latest (rai::test_genesis_key.pub)) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } + ASSERT_EQ (0, node1->active.roots.size ()); + node1->stop (); +} + TEST (bootstrap_processor, process_new) { rai::system system (24000, 2); diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 1814a0f5..4e89332e 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -635,36 +635,33 @@ void rai::ledger::rollback (MDB_txn * transaction_a, rai::block_hash const & blo rai::account rai::ledger::account (MDB_txn * transaction_a, rai::block_hash const & hash_a) { rai::account result; - assert (store.block_exists (transaction_a, hash_a)); - auto block (store.block_get (transaction_a, hash_a)); - auto utx_block (dynamic_cast (block.get ())); - if (utx_block != nullptr) + auto hash (hash_a); + rai::block_hash successor (1); + rai::block_info block_info; + std::unique_ptr block (store.block_get (transaction_a, hash)); + while (!successor.is_zero () && block->type () != rai::block_type::utx && store.block_info_get (transaction_a, successor, block_info)) { + successor = store.block_successor (transaction_a, hash); + if (!successor.is_zero ()) + { + hash = successor; + block = store.block_get (transaction_a, hash); + } + } + if (block->type () == rai::block_type::utx) + { + auto utx_block (dynamic_cast (block.get ())); result = utx_block->hashables.account; } + else if (successor.is_zero ()) + { + result = store.frontier_get (transaction_a, hash); + } else { - auto hash (hash_a); - rai::block_hash successor (1); - rai::block_info block_info; - while (!successor.is_zero () && store.block_info_get (transaction_a, successor, block_info)) - { - successor = store.block_successor (transaction_a, hash); - if (!successor.is_zero ()) - { - hash = successor; - } - } - if (successor.is_zero ()) - { - result = store.frontier_get (transaction_a, hash); - } - else - { - result = block_info.account; - } - assert (!result.is_zero ()); + result = block_info.account; } + assert (!result.is_zero ()); return result; } diff --git a/rai/node/bootstrap.cpp b/rai/node/bootstrap.cpp index 16517524..07e61611 100644 --- a/rai/node/bootstrap.cpp +++ b/rai/node/bootstrap.cpp @@ -54,7 +54,15 @@ public: } void utx_block (rai::utx_block const & block_a) override { - + if (!block_a.hashables.previous.is_zero ()) + { + add_dependency (block_a.hashables.previous); + } + if (complete) + { + // Might not be a dependency block (if this is a send) but that's okay + add_dependency (block_a.hashables.link); + } } void add_dependency (rai::block_hash const & hash_a) { @@ -586,6 +594,15 @@ void rai::bulk_pull_client::received_type () }); break; } + case rai::block_type::utx: + { + connection->start_timeout (); + boost::asio::async_read (connection->socket, boost::asio::buffer (connection->receive_buffer.data () + 1, rai::utx_block::size), [this_l](boost::system::error_code const & ec, size_t size_a) { + this_l->connection->stop_timeout (); + this_l->received_block (ec, size_a); + }); + break; + } case rai::block_type::not_a_block: { // Avoid re-using slow peers, or peers that sent the wrong blocks. @@ -2040,6 +2057,13 @@ void rai::bulk_push_server::received_type () }); break; } + case rai::block_type::utx: + { + boost::asio::async_read (*connection->socket, boost::asio::buffer (receive_buffer.data () + 1, rai::utx_block::size), [this_l](boost::system::error_code const & ec, size_t size_a) { + this_l->received_block (ec, size_a); + }); + break; + } case rai::block_type::not_a_block: { connection->finish_request (); diff --git a/rai/node/common.cpp b/rai/node/common.cpp index 10cb1fce..dd535002 100644 --- a/rai/node/common.cpp +++ b/rai/node/common.cpp @@ -384,7 +384,7 @@ bool rai::confirm_ack::deserialize (rai::stream & stream_a) void rai::confirm_ack::serialize (rai::stream & stream_a) { - assert (block_type () == rai::block_type::send || block_type () == rai::block_type::receive || block_type () == rai::block_type::open || block_type () == rai::block_type::change); + assert (block_type () == rai::block_type::send || block_type () == rai::block_type::receive || block_type () == rai::block_type::open || block_type () == rai::block_type::change || block_type () == rai::block_type::utx); write_header (stream_a); vote->serialize (stream_a, block_type ()); } From 5197c2003b585c0a258af8d68c3118bd93c7398c Mon Sep 17 00:00:00 2001 From: clemahieu Date: Thu, 1 Mar 2018 23:17:33 -0600 Subject: [PATCH 08/36] Adding rollback visitor and tests. --- rai/blockstore.cpp | 1 + rai/core_test/ledger.cpp | 116 ++++++++++++++++++++++++++++++++++++++- rai/ledger.cpp | 30 +++++----- 3 files changed, 131 insertions(+), 16 deletions(-) diff --git a/rai/blockstore.cpp b/rai/blockstore.cpp index eaa31591..8bbd2be8 100644 --- a/rai/blockstore.cpp +++ b/rai/blockstore.cpp @@ -546,6 +546,7 @@ void rai::block_store::representation_add (MDB_txn * transaction_a, rai::block_h auto source_rep (source_block->representative ()); assert (!source_rep.is_zero ()); auto source_previous (representation_get (transaction_a, source_rep)); + std::cerr << boost::str (boost::format ("Adding %1% to %2%\n") % amount_a.convert_to () % source_rep.to_account ()); representation_put (transaction_a, source_rep, source_previous + amount_a); } diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 730a74c8..d2826dab 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1570,8 +1570,10 @@ TEST (ledger, utx_open) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.balance (transaction, send1.hash ())); ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + ASSERT_TRUE (store.pending_exists (transaction, rai::pending_key (destination.pub, send1.hash ()))); rai::utx_block open1 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); + ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (destination.pub, send1.hash ()))); ASSERT_TRUE (store.block_exists (transaction, open1.hash ())); auto open2 (store.block_get (transaction, open1.hash ())); ASSERT_NE (nullptr, open2); @@ -1862,7 +1864,7 @@ TEST (ledger, utx_receive_old) ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); } -TEST (ledger, utx_rollback) +TEST (ledger, utx_rollback_send) { bool init (false); rai::block_store store (init, rai::unique_path ()); @@ -1879,7 +1881,10 @@ TEST (ledger, utx_rollback) ASSERT_EQ (send1, *send2); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.account_balance (transaction, rai::genesis_account)); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); - ASSERT_TRUE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ()))); + rai::pending_info info; + ASSERT_FALSE (store.pending_get (transaction, rai::pending_key (rai::genesis_account, send1.hash ()), info)); + ASSERT_EQ (rai::genesis_account, info.source); + ASSERT_EQ (rai::Gxrb_ratio, info.amount.number ()); ledger.rollback (transaction, send1.hash ()); ASSERT_FALSE (store.block_exists (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount, ledger.account_balance (transaction, rai::genesis_account)); @@ -1887,3 +1892,110 @@ TEST (ledger, utx_rollback) ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ()))); } +TEST (ledger, utx_rollback_receive) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); + ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, receive1.hash ()))); + ledger.rollback (transaction, receive1.hash ()); + rai::pending_info info; + ASSERT_FALSE (store.pending_get (transaction, rai::pending_key (rai::genesis_account, send1.hash ()), info)); + ASSERT_EQ (rai::genesis_account, info.source); + ASSERT_EQ (rai::Gxrb_ratio, info.amount.number ()); + ASSERT_FALSE (store.block_exists (transaction, receive1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.account_balance (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); +} + +TEST (ledger, utx_rep_change_rollback) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair rep; + rai::utx_block change1 (rai::genesis_account, genesis.hash (), rep.pub, rai::genesis_amount, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, change1).code); + ledger.rollback (transaction, change1.hash ()); + ASSERT_FALSE (store.block_exists (transaction, change1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.account_balance (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); + ASSERT_EQ (0, ledger.weight (transaction, rep.pub)); +} + +TEST (ledger, utx_open_rollback) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair destination; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::utx_block open1 (destination.pub, 0, rai::genesis_account, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code); + ledger.rollback (transaction, open1.hash ()); + ASSERT_FALSE (store.block_exists (transaction, open1.hash ())); + ASSERT_EQ (0, ledger.account_balance (transaction, destination.pub)); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + rai::pending_info info; + ASSERT_FALSE (store.pending_get (transaction, rai::pending_key (destination.pub, send1.hash ()), info)); + ASSERT_EQ (rai::genesis_account, info.source); + ASSERT_EQ (rai::Gxrb_ratio, info.amount.number ()); +} + +TEST (ledger, utx_send_change_rollback) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair rep; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rep.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + ledger.rollback (transaction, send1.hash ()); + ASSERT_FALSE (store.block_exists (transaction, send1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.account_balance (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); + ASSERT_EQ (0, ledger.weight (transaction, rep.pub)); +} + +TEST (ledger, utx_receive_change_rollback) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::keypair rep; + rai::utx_block receive1 (rai::genesis_account, send1.hash (), rep.pub, rai::genesis_amount, send1.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); + ledger.rollback (transaction, receive1.hash ()); + ASSERT_FALSE (store.block_exists (transaction, receive1.hash ())); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.account_balance (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); + ASSERT_EQ (0, ledger.weight (transaction, rep.pub)); +} + diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 1814a0f5..72ea6c7a 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -103,15 +103,14 @@ public: } auto balance (ledger.balance (transaction, block_a.hashables.previous)); auto is_send (block_a.hashables.balance < balance); - ledger.store.block_put (transaction, hash, block_a); // Add in amount delta - ledger.store.representation_add (transaction, hash, balance - block_a.hashables.balance.number ()); if (!representative.is_zero ()) { // Move existing representation ledger.store.representation_add (transaction, hash, 0 - block_a.hashables.balance.number ()); ledger.store.representation_add (transaction, representative, block_a.hashables.balance.number ()); } + ledger.store.representation_add (transaction, hash, balance - block_a.hashables.balance.number ()); if (is_send) { @@ -121,7 +120,7 @@ public: else if (!block_a.hashables.link.is_zero ()) { rai::pending_info info (ledger.account (transaction, block_a.hashables.link), block_a.hashables.balance.number () - balance); - ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.account, hash), info); + ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link), info); } rai::account_info info; @@ -130,18 +129,21 @@ public: ledger.change_latest (transaction, block_a.hashables.account, block_a.hashables.previous, representative, balance, info.block_count - 1); auto previous (ledger.store.block_get (transaction, block_a.hashables.previous)); - switch (previous->type ()) + if (previous != nullptr) { - case rai::block_type::send: - case rai::block_type::receive: - case rai::block_type::open: - case rai::block_type::change: - { - ledger.store.frontier_put (transaction, block_a.hashables.previous, block_a.hashables.account); - break; - } - default: - break; + switch (previous->type ()) + { + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + { + ledger.store.frontier_put (transaction, block_a.hashables.previous, block_a.hashables.account); + break; + } + default: + break; + } } ledger.store.block_del (transaction, hash); } From 4822c1cc11085c7fb1f6e50e6e96a84f1c1c3ad5 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Thu, 1 Mar 2018 23:55:03 -0600 Subject: [PATCH 09/36] Fixing tx/rep change rollback tests. --- rai/ledger.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 5ebfc035..835fa5c2 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -104,13 +104,13 @@ public: auto balance (ledger.balance (transaction, block_a.hashables.previous)); auto is_send (block_a.hashables.balance < balance); // Add in amount delta + ledger.store.representation_add (transaction, hash, 0 - block_a.hashables.balance.number ()); if (!representative.is_zero ()) { // Move existing representation - ledger.store.representation_add (transaction, hash, 0 - block_a.hashables.balance.number ()); ledger.store.representation_add (transaction, representative, block_a.hashables.balance.number ()); + ledger.store.representation_add (transaction, representative, balance - block_a.hashables.balance.number ()); } - ledger.store.representation_add (transaction, hash, balance - block_a.hashables.balance.number ()); if (is_send) { From 8688ac21a77e09a1f4546934475db96f10c73dc6 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Fri, 2 Mar 2018 10:58:04 -0600 Subject: [PATCH 10/36] Doing rep calculation in 2 steps instead of 3. --- rai/ledger.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 835fa5c2..392e18df 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -108,8 +108,7 @@ public: if (!representative.is_zero ()) { // Move existing representation - ledger.store.representation_add (transaction, representative, block_a.hashables.balance.number ()); - ledger.store.representation_add (transaction, representative, balance - block_a.hashables.balance.number ()); + ledger.store.representation_add (transaction, representative, balance); } if (is_send) @@ -224,16 +223,15 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) if (result.code == rai::process_result::progress) { ledger.store.block_put (transaction, hash, block_a); - + if (!info.rep_block.is_zero ()) { // Move existing representation ledger.store.representation_add (transaction, info.rep_block, 0 - info.balance.number ()); - ledger.store.representation_add (transaction, hash, info.balance.number ()); } // Add in amount delta - ledger.store.representation_add (transaction, hash, result.amount.number ()); - + ledger.store.representation_add (transaction, hash, block_a.hashables.balance.number ()); + if (is_send) { rai::pending_key key (block_a.hashables.link, hash); @@ -244,7 +242,7 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) { ledger.store.pending_del (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link)); } - + ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1); if (!ledger.store.frontier_get (transaction, info.head).is_zero ()) { From 3f290c8199666bcdcc278ae21ea233fb93a50036 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 2 Mar 2018 11:15:55 -0700 Subject: [PATCH 11/36] Change ublocks UI display to match old blocks (#690) --- rai/qt/qt.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index 321b6bc3..43da006b 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -520,9 +520,26 @@ public: } void utx_block (rai::utx_block const & block_a) { - type = "Utx"; - amount = ledger.amount (transaction, block_a.hash ()); + auto balance (block_a.hashables.balance.number ()); + auto previous_balance (ledger.balance (transaction, block_a.hashables.previous)); account = block_a.hashables.account; + if (balance < previous_balance) + { + type = "Send"; + amount = previous_balance - balance; + } + else + { + if (block_a.hashables.link.is_zero ()) + { + type = "Change"; + } + else + { + type = "Receive"; + } + amount = balance - previous_balance; + } } MDB_txn * transaction; rai::ledger & ledger; From 9fad4ccc9ed7b45b8906bc81cc636c11556e7521 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 2 Mar 2018 11:17:10 -0700 Subject: [PATCH 12/36] Fix ublocks send rollback (#689) --- rai/core_test/ledger.cpp | 25 +++++++++++++++++++++++++ rai/ledger.cpp | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index d2826dab..7cface50 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1916,6 +1916,31 @@ TEST (ledger, utx_rollback_receive) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); } +TEST (ledger, utx_rollback_received_send) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair key; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::utx_block receive1 (key.pub, 0, key.pub, rai::Gxrb_ratio, send1.hash (), key.prv, key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive1).code); + ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, receive1.hash ()))); + ledger.rollback (transaction, send1.hash ()); + ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ()))); + ASSERT_FALSE (store.block_exists (transaction, send1.hash ())); + ASSERT_FALSE (store.block_exists (transaction, receive1.hash ())); + ASSERT_EQ (rai::genesis_amount, ledger.account_balance (transaction, rai::genesis_account)); + ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); + ASSERT_EQ (0, ledger.account_balance (transaction, key.pub)); + ASSERT_EQ (0, ledger.weight (transaction, key.pub)); +} + TEST (ledger, utx_rep_change_rollback) { bool init (false); diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 392e18df..a9364ab8 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -114,6 +114,10 @@ public: if (is_send) { rai::pending_key key (block_a.hashables.link, hash); + while (!ledger.store.pending_exists (transaction, key)) + { + ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.link)); + } ledger.store.pending_del (transaction, key); } else if (!block_a.hashables.link.is_zero ()) From 1d030aa1c5b2b0226241b7786e248467873a7737 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 2 Mar 2018 11:29:12 -0700 Subject: [PATCH 13/36] Fix RPC history endpoint with ublocks (#692) --- rai/core_test/rpc.cpp | 39 +++++++++++++++++++++++++++++---------- rai/node/rpc.cpp | 25 +++++++++++++++++++++---- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index a1ed4d8a..7f7f2883 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -879,11 +879,21 @@ TEST (rpc, history) ASSERT_NE (nullptr, send); auto receive (system.wallet (0)->receive_action (static_cast (*send), rai::test_genesis_key.pub, system.nodes[0]->config.receive_minimum.number ())); ASSERT_NE (nullptr, receive); - rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true)); + auto node0 (system.nodes[0]); + rai::utx_block usend (rai::genesis_account, node0->latest (rai::genesis_account), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block ureceive (rai::genesis_account, usend.hash (), rai::genesis_account, rai::genesis_amount, usend.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::utx_block uchange (rai::genesis_account, ureceive.hash (), rai::keypair ().pub, rai::genesis_amount, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + { + rai::transaction transaction (node0->store.environment, nullptr, true); + ASSERT_EQ (rai::process_result::progress, node0->ledger.process (transaction, usend).code); + ASSERT_EQ (rai::process_result::progress, node0->ledger.process (transaction, ureceive).code); + ASSERT_EQ (rai::process_result::progress, node0->ledger.process (transaction, uchange).code); + } + rai::rpc rpc (system.service, *node0, rai::rpc_config (true)); rpc.start (); boost::property_tree::ptree request; request.put ("action", "history"); - request.put ("hash", receive->hash ().to_string ()); + request.put ("hash", uchange.hash ().to_string ()); request.put ("count", 100); test_response response (request, rpc, system.service); while (response.status == 0) @@ -897,20 +907,29 @@ TEST (rpc, history) { history_l.push_back (std::make_tuple (i->second.get ("type"), i->second.get ("account"), i->second.get ("amount"), i->second.get ("hash"))); } - ASSERT_EQ (3, history_l.size ()); + ASSERT_EQ (5, history_l.size ()); ASSERT_EQ ("receive", std::get<0> (history_l[0])); + ASSERT_EQ (ureceive.hash ().to_string (), std::get<3> (history_l[0])); ASSERT_EQ (rai::test_genesis_key.pub.to_account (), std::get<1> (history_l[0])); - ASSERT_EQ (system.nodes[0]->config.receive_minimum.to_string_dec (), std::get<2> (history_l[0])); - ASSERT_EQ (receive->hash ().to_string (), std::get<3> (history_l[0])); + ASSERT_EQ (rai::Gxrb_ratio.convert_to (), std::get<2> (history_l[0])); + ASSERT_EQ (5, history_l.size ()); ASSERT_EQ ("send", std::get<0> (history_l[1])); + ASSERT_EQ (usend.hash ().to_string (), std::get<3> (history_l[1])); ASSERT_EQ (rai::test_genesis_key.pub.to_account (), std::get<1> (history_l[1])); - ASSERT_EQ (system.nodes[0]->config.receive_minimum.to_string_dec (), std::get<2> (history_l[1])); - ASSERT_EQ (send->hash ().to_string (), std::get<3> (history_l[1])); - rai::genesis genesis; + ASSERT_EQ (rai::Gxrb_ratio.convert_to (), std::get<2> (history_l[1])); ASSERT_EQ ("receive", std::get<0> (history_l[2])); ASSERT_EQ (rai::test_genesis_key.pub.to_account (), std::get<1> (history_l[2])); - ASSERT_EQ (rai::genesis_amount.convert_to (), std::get<2> (history_l[2])); - ASSERT_EQ (genesis.hash ().to_string (), std::get<3> (history_l[2])); + ASSERT_EQ (system.nodes[0]->config.receive_minimum.to_string_dec (), std::get<2> (history_l[2])); + ASSERT_EQ (receive->hash ().to_string (), std::get<3> (history_l[2])); + ASSERT_EQ ("send", std::get<0> (history_l[3])); + ASSERT_EQ (rai::test_genesis_key.pub.to_account (), std::get<1> (history_l[3])); + ASSERT_EQ (system.nodes[0]->config.receive_minimum.to_string_dec (), std::get<2> (history_l[3])); + ASSERT_EQ (send->hash ().to_string (), std::get<3> (history_l[3])); + rai::genesis genesis; + ASSERT_EQ ("receive", std::get<0> (history_l[4])); + ASSERT_EQ (rai::test_genesis_key.pub.to_account (), std::get<1> (history_l[4])); + ASSERT_EQ (rai::genesis_amount.convert_to (), std::get<2> (history_l[4])); + ASSERT_EQ (genesis.hash ().to_string (), std::get<3> (history_l[4])); } TEST (rpc, history_count) diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 28b84f23..0da0a83e 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -1641,10 +1641,27 @@ public: } void utx_block (rai::utx_block const & block_a) { - tree.put ("type", "utx"); - tree.put ("account", block_a.hashables.account.to_account ()); - auto amount (handler.node.ledger.amount (transaction, hash).convert_to ()); - tree.put ("amount", amount) ; + auto balance (block_a.hashables.balance.number ()); + auto previous_balance (handler.node.ledger.balance (transaction, block_a.hashables.previous)); + if (balance < previous_balance) + { + tree.put ("type", "send"); + tree.put ("account", block_a.hashables.account.to_account ()); + tree.put ("amount", (previous_balance - balance).convert_to ()); + } + else + { + if (block_a.hashables.link.is_zero ()) + { + // Don't report change blocks + } + else + { + tree.put ("type", "receive"); + tree.put ("account", block_a.hashables.account.to_account ()); + tree.put ("amount", (balance - previous_balance).convert_to ()); + } + } } rai::rpc_handler & handler; rai::transaction & transaction; From e25bf93e25ae0cff43faf396e036b5183071643d Mon Sep 17 00:00:00 2001 From: clemahieu Date: Fri, 2 Mar 2018 13:37:27 -0600 Subject: [PATCH 14/36] Fixing formatting. --- rai/core_test/block.cpp | 20 +++++++------- rai/core_test/ledger.cpp | 1 - rai/ledger.cpp | 31 ++++++++++----------- rai/lib/blocks.cpp | 59 ++++++++++++++++++++-------------------- 4 files changed, 54 insertions(+), 57 deletions(-) diff --git a/rai/core_test/block.cpp b/rai/core_test/block.cpp index 9f23ab5d..35e73863 100644 --- a/rai/core_test/block.cpp +++ b/rai/core_test/block.cpp @@ -382,24 +382,24 @@ TEST (utx, hashing) rai::keypair key; rai::utx_block block (key.pub, 0, key.pub, 0, 0, key.prv, key.pub, 0); auto hash (block.hash ()); - block.hashables.account.bytes [0] ^= 0x1; + block.hashables.account.bytes[0] ^= 0x1; ASSERT_NE (hash, block.hash ()); - block.hashables.account.bytes [0] ^= 0x1; + block.hashables.account.bytes[0] ^= 0x1; ASSERT_EQ (hash, block.hash ()); - block.hashables.previous.bytes [0] ^= 0x1; + block.hashables.previous.bytes[0] ^= 0x1; ASSERT_NE (hash, block.hash ()); - block.hashables.previous.bytes [0] ^= 0x1; + block.hashables.previous.bytes[0] ^= 0x1; ASSERT_EQ (hash, block.hash ()); - block.hashables.representative.bytes [0] ^= 0x1; + block.hashables.representative.bytes[0] ^= 0x1; ASSERT_NE (hash, block.hash ()); - block.hashables.representative.bytes [0] ^= 0x1; + block.hashables.representative.bytes[0] ^= 0x1; ASSERT_EQ (hash, block.hash ()); - block.hashables.balance.bytes [0] ^= 0x1; + block.hashables.balance.bytes[0] ^= 0x1; ASSERT_NE (hash, block.hash ()); - block.hashables.balance.bytes [0] ^= 0x1; + block.hashables.balance.bytes[0] ^= 0x1; ASSERT_EQ (hash, block.hash ()); - block.hashables.link.bytes [0] ^= 0x1; + block.hashables.link.bytes[0] ^= 0x1; ASSERT_NE (hash, block.hash ()); - block.hashables.link.bytes [0] ^= 0x1; + block.hashables.link.bytes[0] ^= 0x1; ASSERT_EQ (hash, block.hash ()); } diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 7cface50..f19a01a6 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -2023,4 +2023,3 @@ TEST (ledger, utx_receive_change_rollback) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); ASSERT_EQ (0, ledger.weight (transaction, rep.pub)); } - diff --git a/rai/ledger.cpp b/rai/ledger.cpp index a9364ab8..56bbf5ff 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -130,22 +130,22 @@ public: auto error (ledger.store.account_get (transaction, block_a.hashables.account, info)); assert (!error); ledger.change_latest (transaction, block_a.hashables.account, block_a.hashables.previous, representative, balance, info.block_count - 1); - + auto previous (ledger.store.block_get (transaction, block_a.hashables.previous)); if (previous != nullptr) { switch (previous->type ()) { - case rai::block_type::send: - case rai::block_type::receive: - case rai::block_type::open: - case rai::block_type::change: - { - ledger.store.frontier_put (transaction, block_a.hashables.previous, block_a.hashables.account); - break; - } - default: - break; + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + { + ledger.store.frontier_put (transaction, block_a.hashables.previous, block_a.hashables.account); + break; + } + default: + break; } } ledger.store.block_del (transaction, hash); @@ -222,7 +222,6 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) result.code = result.amount.is_zero () ? rai::process_result::progress : rai::process_result::balance_mismatch; } } - } if (result.code == rai::process_result::progress) { @@ -644,7 +643,7 @@ rai::account rai::ledger::account (MDB_txn * transaction_a, rai::block_hash cons rai::block_info block_info; std::unique_ptr block (store.block_get (transaction_a, hash)); while (!successor.is_zero () && block->type () != rai::block_type::utx && store.block_info_get (transaction_a, successor, block_info)) - { + { successor = store.block_successor (transaction_a, hash); if (!successor.is_zero ()) { @@ -654,9 +653,9 @@ rai::account rai::ledger::account (MDB_txn * transaction_a, rai::block_hash cons } if (block->type () == rai::block_type::utx) { - auto utx_block (dynamic_cast (block.get ())); - result = utx_block->hashables.account; - } + auto utx_block (dynamic_cast (block.get ())); + result = utx_block->hashables.account; + } else if (successor.is_zero ()) { result = store.frontier_get (transaction_a, hash); diff --git a/rai/lib/blocks.cpp b/rai/lib/blocks.cpp index 774eb042..65bcc14d 100644 --- a/rai/lib/blocks.cpp +++ b/rai/lib/blocks.cpp @@ -275,15 +275,15 @@ bool rai::send_block::valid_predecessor (rai::block const & block_a) const bool result; switch (block_a.type ()) { - case rai::block_type::send: - case rai::block_type::receive: - case rai::block_type::open: - case rai::block_type::change: - result = true; - break; - default: - result = false; - break; + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + result = true; + break; + default: + result = false; + break; } return result; } @@ -793,15 +793,15 @@ bool rai::change_block::valid_predecessor (rai::block const & block_a) const bool result; switch (block_a.type ()) { - case rai::block_type::send: - case rai::block_type::receive: - case rai::block_type::open: - case rai::block_type::change: - result = true; - break; - default: - result = false; - break; + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + result = true; + break; + default: + result = false; + break; } return result; } @@ -831,7 +831,6 @@ void rai::change_block::signature_set (rai::uint512_union const & signature_a) signature = signature_a; } - rai::utx_hashables::utx_hashables (rai::account const & account_a, rai::block_hash const & previous_a, rai::account const & representative_a, rai::amount const & balance_a, rai::uint256_union const & link_a) : account (account_a), previous (previous_a), @@ -953,7 +952,7 @@ hashables (error_a, tree_a) void rai::utx_block::hash (blake2b_state & hash_a) const { - rai::uint256_union preamble (static_cast (rai::block_type::utx)); + rai::uint256_union preamble (static_cast (rai::block_type::utx)); blake2b_update (&hash_a, preamble.bytes.data (), preamble.bytes.size ()); hashables.hash (hash_a); } @@ -1243,7 +1242,7 @@ std::unique_ptr rai::deserialize_block (rai::stream & stream_a, rai: case rai::block_type::utx: { bool error; - std::unique_ptr obj (new rai::utx_block (error, stream_a)); + std::unique_ptr obj (new rai::utx_block (error, stream_a)); if (!error) { result = std::move (obj); @@ -1418,15 +1417,15 @@ bool rai::receive_block::valid_predecessor (rai::block const & block_a) const bool result; switch (block_a.type ()) { - case rai::block_type::send: - case rai::block_type::receive: - case rai::block_type::open: - case rai::block_type::change: - result = true; - break; - default: - result = false; - break; + case rai::block_type::send: + case rai::block_type::receive: + case rai::block_type::open: + case rai::block_type::change: + result = true; + break; + default: + result = false; + break; } return result; } From 96c99e89f256f9b51479c640bf5b12367edb655e Mon Sep 17 00:00:00 2001 From: clemahieu Date: Fri, 2 Mar 2018 19:38:24 -0600 Subject: [PATCH 15/36] Clearing out successor when rolling back a utx. --- rai/core_test/ledger.cpp | 1 + rai/ledger.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index f19a01a6..0c387b6a 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1890,6 +1890,7 @@ TEST (ledger, utx_rollback_send) ASSERT_EQ (rai::genesis_amount, ledger.account_balance (transaction, rai::genesis_account)); ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::genesis_account)); ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ()))); + ASSERT_TRUE (store.block_successor (transaction, genesis.hash ()).is_zero ()); } TEST (ledger, utx_rollback_receive) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 56bbf5ff..54334881 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -149,6 +149,7 @@ public: } } ledger.store.block_del (transaction, hash); + ledger.store.block_successor_clear (transaction, block_a.hashables.previous); } MDB_txn * transaction; rai::ledger & ledger; From 429fa8ecc666a7a2ebd499950946e5bed80c5c22 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sat, 3 Mar 2018 12:35:57 -0700 Subject: [PATCH 16/36] Fix ublocks open rollback (#694) --- rai/ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 54334881..a535d314 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -134,6 +134,7 @@ public: auto previous (ledger.store.block_get (transaction, block_a.hashables.previous)); if (previous != nullptr) { + ledger.store.block_successor_clear (transaction, block_a.hashables.previous); switch (previous->type ()) { case rai::block_type::send: @@ -149,7 +150,6 @@ public: } } ledger.store.block_del (transaction, hash); - ledger.store.block_successor_clear (transaction, block_a.hashables.previous); } MDB_txn * transaction; rai::ledger & ledger; From 33ff92fd03eb25d68a73fc89cdf77b0bee81aef4 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Sat, 3 Mar 2018 16:08:42 -0600 Subject: [PATCH 17/36] Checking source account before making rollback modifications to ledger. --- rai/core_test/ledger.cpp | 16 ++++++++++++++++ rai/ledger.cpp | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 0c387b6a..2566150f 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -322,6 +322,22 @@ TEST (ledger, rollback_representation) ASSERT_EQ (0, ledger.weight (transaction, key3.pub)); } +TEST (ledger, receive_rollback) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::send_block send (genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send).code); + rai::receive_block receive (send.hash (), send.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive).code); + ledger.rollback(transaction, receive.hash ()); +} + TEST (ledger, process_duplicate) { bool init (false); diff --git a/rai/ledger.cpp b/rai/ledger.cpp index a535d314..8a30de58 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -46,13 +46,14 @@ public: auto representative (ledger.representative (transaction, block_a.hashables.previous)); auto amount (ledger.amount (transaction, block_a.hashables.source)); auto destination_account (ledger.account (transaction, hash)); + auto source_account (ledger.account (transaction, block_a.hashables.source)); rai::account_info info; auto error (ledger.store.account_get (transaction, destination_account, info)); assert (!error); ledger.store.representation_add (transaction, ledger.representative (transaction, hash), 0 - amount); ledger.change_latest (transaction, destination_account, block_a.hashables.previous, representative, ledger.balance (transaction, block_a.hashables.previous), info.block_count - 1); ledger.store.block_del (transaction, hash); - ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { ledger.account (transaction, block_a.hashables.source), amount }); + ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { source_account, amount }); ledger.store.frontier_del (transaction, hash); ledger.store.frontier_put (transaction, block_a.hashables.previous, destination_account); ledger.store.block_successor_clear (transaction, block_a.hashables.previous); From c2ee4f35d2dd409f24bc0aab35e2696595237c69 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sun, 4 Mar 2018 12:30:07 -0700 Subject: [PATCH 18/36] Add ledger functions for utx compatible info (#701) --- rai/core_test/ledger.cpp | 44 ++++++++++++++++++++++++++++++++++++++++ rai/ledger.cpp | 43 +++++++++++++++++++++++++++++++++++++++ rai/ledger.hpp | 3 +++ rai/node/node.cpp | 2 +- rai/node/rpc.cpp | 23 +++++++++------------ rai/qt/qt.cpp | 12 +++++------ 6 files changed, 107 insertions(+), 20 deletions(-) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 2566150f..f3699b56 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1471,6 +1471,50 @@ TEST (ledger, bootstrap_rep_weight) } } +TEST (ledger, block_destination_source) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair dest; + rai::uint128_t balance (rai::genesis_amount); + balance -= rai::Gxrb_ratio; + rai::send_block block1 (genesis.hash (), dest.pub, balance, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + balance -= rai::Gxrb_ratio; + rai::send_block block2 (block1.hash (), rai::genesis_account, balance, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + balance += rai::Gxrb_ratio; + rai::receive_block block3 (block2.hash (), block2.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + balance -= rai::Gxrb_ratio; + rai::utx_block block4 (rai::genesis_account, block3.hash (), rai::genesis_account, balance, dest.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + balance -= rai::Gxrb_ratio; + rai::utx_block block5 (rai::genesis_account, block4.hash (), rai::genesis_account, balance, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + balance += rai::Gxrb_ratio; + rai::utx_block block6 (rai::genesis_account, block5.hash (), rai::genesis_account, balance, block5.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, block1).code); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, block2).code); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, block3).code); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, block4).code); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, block5).code); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, block6).code); + ASSERT_EQ (balance, ledger.balance (transaction, block6.hash ())); + ASSERT_EQ (dest.pub, ledger.block_destination (transaction, block1)); + ASSERT_TRUE (ledger.block_source (transaction, block1).is_zero ()); + ASSERT_EQ (rai::genesis_account, ledger.block_destination (transaction, block2)); + ASSERT_TRUE (ledger.block_source (transaction, block2).is_zero ()); + ASSERT_TRUE (ledger.block_destination (transaction, block3).is_zero ()); + ASSERT_EQ (block2.hash (), ledger.block_source (transaction, block3)); + ASSERT_EQ (dest.pub, ledger.block_destination (transaction, block4)); + ASSERT_TRUE (ledger.block_source (transaction, block4).is_zero ()); + ASSERT_EQ (rai::genesis_account, ledger.block_destination (transaction, block5)); + ASSERT_TRUE (ledger.block_source (transaction, block5).is_zero ()); + ASSERT_TRUE (ledger.block_destination (transaction, block6).is_zero ()); + ASSERT_EQ (block5.hash (), ledger.block_source (transaction, block6)); +} + TEST (ledger, utx_account) { bool init (false); diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 8a30de58..61dbba8d 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -598,6 +598,49 @@ std::string rai::ledger::block_text (rai::block_hash const & hash_a) return result; } +bool rai::ledger::is_utx_send (MDB_txn * transaction_a, rai::utx_block const & block_a) +{ + bool result (false); + rai::block_hash previous (block_a.hashables.previous); + if (!previous.is_zero ()) + { + if (block_a.hashables.balance < balance (transaction_a, previous)) + { + result = true; + } + } + return result; +} + +rai::block_hash rai::ledger::block_destination (MDB_txn * transaction_a, rai::block const & block_a) +{ + rai::block_hash result (0); + rai::send_block const * send_block (dynamic_cast (&block_a)); + rai::utx_block const * utx_block (dynamic_cast (&block_a)); + if (send_block != nullptr) + { + result = send_block->hashables.destination; + } + else if (utx_block != nullptr && is_utx_send (transaction_a, *utx_block)) + { + result = utx_block->hashables.link; + } + return result; +} + +rai::block_hash rai::ledger::block_source (MDB_txn * transaction_a, rai::block const & block_a) +{ + // If block_a.source () is nonzero, then we have our source. + // However, universal blocks will always return zero. + rai::block_hash result (block_a.source ()); + rai::utx_block const * utx_block (dynamic_cast (&block_a)); + if (utx_block != nullptr && !is_utx_send (transaction_a, *utx_block)) + { + result = utx_block->hashables.link; + } + return result; +} + // Vote weight of an account rai::uint128_t rai::ledger::weight (MDB_txn * transaction_a, rai::account const & account_a) { diff --git a/rai/ledger.hpp b/rai/ledger.hpp index eb16f999..e372d489 100644 --- a/rai/ledger.hpp +++ b/rai/ledger.hpp @@ -35,6 +35,9 @@ public: bool block_exists (rai::block_hash const &); std::string block_text (char const *); std::string block_text (rai::block_hash const &); + bool is_utx_send (MDB_txn *, rai::utx_block const &); + rai::block_hash block_destination (MDB_txn *, rai::block const &); + rai::block_hash block_source (MDB_txn *, rai::block const &); rai::uint128_t supply (MDB_txn *); rai::process_return process (MDB_txn *, rai::block const &); void rollback (MDB_txn *, rai::block_hash const &); diff --git a/rai/node/node.cpp b/rai/node/node.cpp index d12ec2fd..64a26f6d 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -1246,7 +1246,7 @@ rai::process_return rai::block_processor::process_receive_one (MDB_txn * transac { BOOST_LOG (node.log) << boost::str (boost::format ("Gap source for: %1%") % block_a->hash ().to_string ()); } - node.store.unchecked_put (transaction_a, block_a->source (), block_a); + node.store.unchecked_put (transaction_a, node.ledger.block_source (transaction_a, *block_a), block_a); node.gap_cache.add (transaction_a, block_a); break; } diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 0da0a83e..483ecd4c 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -1001,18 +1001,17 @@ void rai::rpc_handler::blocks_info () entry.put ("contents", contents); if (pending) { - auto block_l (dynamic_cast (block.get ())); bool exists (false); - if (block_l != nullptr) + auto destination (node.ledger.block_destination (transaction, *block)); + if (!destination.is_zero ()) { - auto destination (block_l->hashables.destination); exists = node.store.pending_exists (transaction, rai::pending_key (destination, hash)); } entry.put ("pending", exists ? "1" : "0"); } if (source) { - rai::block_hash source_hash (block->source ()); + rai::block_hash source_hash (node.ledger.block_source (transaction, *block)); std::unique_ptr block_a (node.store.block_get (transaction, source_hash)); if (block_a != nullptr) { @@ -2227,12 +2226,11 @@ void rai::rpc_handler::pending_exists () auto block (node.store.block_get (transaction, hash)); if (block != nullptr) { - auto block_l (dynamic_cast (block.get ())); auto exists (false); - if (block_l != nullptr) + auto destination (node.ledger.block_destination (transaction, *block)); + if (!destination.is_zero ()) { - auto account (block_l->hashables.destination); - exists = node.store.pending_exists (transaction, rai::pending_key (account, hash)); + exists = node.store.pending_exists (transaction, rai::pending_key (destination, hash)); } boost::property_tree::ptree response_l; response_l.put ("exists", exists ? "1" : "0"); @@ -2831,7 +2829,7 @@ void rai::rpc_handler::republish () block = node.store.block_get (transaction, hash); if (sources != 0) // Republish source chain { - rai::block_hash source (block->source ()); + rai::block_hash source (node.ledger.block_source (transaction, *block)); std::unique_ptr block_a (node.store.block_get (transaction, source)); std::vector hashes; while (block_a != nullptr && hashes.size () < sources) @@ -2857,10 +2855,9 @@ void rai::rpc_handler::republish () if (destinations != 0) // Republish destination chain { auto block_b (node.store.block_get (transaction, hash)); - auto block_s (dynamic_cast (block_b.get ())); - if (block_s != nullptr) + auto destination (node.ledger.block_destination (transaction, *block_b)); + if (!destination.is_zero ()) { - auto destination (block_s->hashables.destination); auto exists (node.store.pending_exists (transaction, rai::pending_key (destination, hash))); if (!exists) { @@ -2871,7 +2868,7 @@ void rai::rpc_handler::republish () while (block_d != nullptr && hash != source) { hashes.push_back (previous); - source = block_d->source (); + source = node.ledger.block_source (transaction, *block_d); previous = block_d->previous (); block_d = node.store.block_get (transaction, previous); } diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index 43da006b..5db861be 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -2016,10 +2016,10 @@ void rai_qt::block_creation::create_receive () auto block_l (wallet.node.store.block_get (transaction, source_l)); if (block_l != nullptr) { - auto send_block (dynamic_cast (block_l.get ())); - if (send_block != nullptr) + auto destination (wallet.node.ledger.block_destination (transaction, *block_l)); + if (!destination.is_zero ()) { - rai::pending_key pending_key (send_block->hashables.destination, source_l); + rai::pending_key pending_key (destination, source_l); rai::pending_info pending; if (!wallet.node.store.pending_get (transaction, pending_key, pending)) { @@ -2140,10 +2140,10 @@ void rai_qt::block_creation::create_open () auto block_l (wallet.node.store.block_get (transaction, source_l)); if (block_l != nullptr) { - auto send_block (dynamic_cast (block_l.get ())); - if (send_block != nullptr) + auto destination (wallet.node.ledger.block_destination (transaction, *block_l)); + if (!destination.is_zero ()) { - rai::pending_key pending_key (send_block->hashables.destination, source_l); + rai::pending_key pending_key (destination, source_l); rai::pending_info pending; if (!wallet.node.store.pending_get (transaction, pending_key, pending)) { From 21c4b283ebe305818865520a99482b05b802a234 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sun, 4 Mar 2018 12:30:14 -0700 Subject: [PATCH 19/36] Clang format (#700) --- rai/core_test/ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index f3699b56..7ff84554 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -335,7 +335,7 @@ TEST (ledger, receive_rollback) ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send).code); rai::receive_block receive (send.hash (), send.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive).code); - ledger.rollback(transaction, receive.hash ()); + ledger.rollback (transaction, receive.hash ()); } TEST (ledger, process_duplicate) From d98782d5ec8b5914a739794d47f3178253a4068b Mon Sep 17 00:00:00 2001 From: clemahieu Date: Sun, 4 Mar 2018 14:42:12 -0600 Subject: [PATCH 20/36] Enabling ublock generation --- rai/blockstore.cpp | 11 +++++-- rai/common.cpp | 2 +- rai/ledger.cpp | 8 ++++- rai/ledger.hpp | 1 + rai/node/testing.cpp | 59 +++++++++++++++------------------ rai/node/wallet.cpp | 75 ++++++++++++++++++++++++++++++++---------- rai/node/wallet.hpp | 2 +- rai/slow_test/node.cpp | 29 +++++++--------- 8 files changed, 114 insertions(+), 73 deletions(-) diff --git a/rai/blockstore.cpp b/rai/blockstore.cpp index eaa31591..2c042529 100644 --- a/rai/blockstore.cpp +++ b/rai/blockstore.cpp @@ -687,8 +687,15 @@ std::unique_ptr rai::block_store::block_random (MDB_txn * transactio } else { - // change - result = block_random (transaction_a, change_blocks); + region -= count.change; + if (region < count.change) + { + result = block_random (transaction_a, change_blocks); + } + else + { + result = block_random (transaction_a, utx_blocks); + } } } } diff --git a/rai/common.cpp b/rai/common.cpp index 48a5d86b..bc3acd11 100644 --- a/rai/common.cpp +++ b/rai/common.cpp @@ -256,7 +256,7 @@ change (0) size_t rai::block_counts::sum () { - return send + receive + open + change; + return send + receive + open + change + utx; } rai::pending_info::pending_info () : diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 61dbba8d..33740f4c 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -67,10 +67,11 @@ public: auto hash (block_a.hash ()); auto amount (ledger.amount (transaction, block_a.hashables.source)); auto destination_account (ledger.account (transaction, hash)); + auto source_account (ledger.account (transaction, block_a.hashables.source)); ledger.store.representation_add (transaction, ledger.representative (transaction, hash), 0 - amount); ledger.change_latest (transaction, destination_account, 0, 0, 0, 0); ledger.store.block_del (transaction, hash); - ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { ledger.account (transaction, block_a.hashables.source), amount }); + ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { source_account, amount }); ledger.store.frontier_del (transaction, hash); } void change_block (rai::change_block const & block_a) override @@ -767,6 +768,11 @@ void rai::ledger::dump_account_chain (rai::account const & account_a) } } +bool rai::ledger::utx_enabled (MDB_txn * transaction_a) +{ + return false; +} + void rai::ledger::checksum_update (MDB_txn * transaction_a, rai::block_hash const & hash_a) { rai::checksum value; diff --git a/rai/ledger.hpp b/rai/ledger.hpp index e372d489..c345e29d 100644 --- a/rai/ledger.hpp +++ b/rai/ledger.hpp @@ -45,6 +45,7 @@ public: void checksum_update (MDB_txn *, rai::block_hash const &); rai::checksum checksum (MDB_txn *, rai::account const &, rai::account const &); void dump_account_chain (rai::account const &); + bool utx_enabled (MDB_txn *); static rai::uint128_t const unit; rai::block_store & store; rai::uint128_t inactive_supply; diff --git a/rai/node/testing.cpp b/rai/node/testing.cpp index 70c4be18..f11fee58 100644 --- a/rai/node/testing.cpp +++ b/rai/node/testing.cpp @@ -128,40 +128,27 @@ void rai::system::generate_usage_traffic (uint32_t count_a, uint32_t wait_a, siz void rai::system::generate_rollback (rai::node & node_a, std::vector & accounts_a) { - rai::block_hash current (node_a.latest (get_random_account (accounts_a))); - rai::block_hash target (current); rai::transaction transaction (node_a.store.environment, nullptr, true); - while (!current.is_zero ()) + auto index (random_pool.GenerateWord32 (0, accounts_a.size () - 1)); + auto account (accounts_a [index]); + rai::account_info info; + auto error (node_a.store.account_get (transaction, account, info)); + if (!error) { - auto block1 (node_a.store.block_get (transaction, current)); - assert (block1 != nullptr); - current = block1->previous (); - auto block2 (node_a.store.block_get (transaction, target)); - assert (block2 != nullptr); - target = block2->previous (); - if (!current.is_zero ()) + auto hash (info.open_block); + rai::genesis genesis; + if (hash != genesis.hash ()) { - auto block2 (node_a.store.block_get (transaction, current)); - current = block2->previous (); + accounts_a [index] = accounts_a [accounts_a.size () - 1]; + accounts_a.pop_back (); + node_a.ledger.rollback (transaction, hash); } - auto open (dynamic_cast (block2.get ())); - if (open != nullptr) - { - if (!node_a.ledger.block_exists (open->hashables.source)) - { - target = 0; - } - } - } - if (!target.is_zero ()) - { - node_a.ledger.rollback (transaction, target); } } void rai::system::generate_receive (rai::node & node_a) { - std::shared_ptr send_block; + std::shared_ptr send_block; { rai::transaction transaction (node_a.store.environment, nullptr, false); rai::uint256_union random_block; @@ -171,14 +158,12 @@ void rai::system::generate_receive (rai::node & node_a) { rai::pending_key send_hash (i->first); rai::pending_info info (i->second); - auto block (node_a.store.block_get (transaction, send_hash.hash)); - assert (dynamic_cast (block.get ()) != nullptr); - send_block.reset (static_cast (block.release ())); + send_block = node_a.store.block_get (transaction, send_hash.hash); } } if (send_block != nullptr) { - auto receive_error (wallet (0)->receive_sync (std::move (send_block), rai::genesis_account, std::numeric_limits::max ())); + auto receive_error (wallet (0)->receive_sync (send_block, rai::genesis_account, std::numeric_limits::max ())); (void)receive_error; } } @@ -186,11 +171,11 @@ void rai::system::generate_receive (rai::node & node_a) void rai::system::generate_activity (rai::node & node_a, std::vector & accounts_a) { auto what (random_pool.GenerateByte ()); - if (what < 0x10) + if (what < 0x1) { generate_rollback (node_a, accounts_a); } - else if (what < 0x1) + else if (what < 0x10) { generate_change_known (node_a, accounts_a); } @@ -306,11 +291,19 @@ void rai::system::generate_mass_activity (uint32_t count_a, rai::node & node_a) auto previous (std::chrono::steady_clock::now ()); for (uint32_t i (0); i < count_a; ++i) { - if ((i & 0xfff) == 0) + if ((i & 0xff) == 0) { auto now (std::chrono::steady_clock::now ()); auto us (std::chrono::duration_cast (now - previous).count ()); - std::cerr << boost::str (boost::format ("Mass activity iteration %1% us %2% us/t %3%\n") % i % us % (us / 256)); + uint64_t count (0); + uint64_t utx (0); + { + rai::transaction transaction (node_a.store.environment, nullptr, false); + auto block_counts (node_a.store.block_count (transaction)); + count = block_counts.sum (); + utx = block_counts.utx; + } + std::cerr << boost::str (boost::format ("Mass activity iteration %1% us %2% us/t %3% utx: %4% count: %5%\n") % i % us % (us / 256) % utx % count); previous = now; } generate_activity (node_a, accounts); diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index b128427f..98d4312f 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -832,38 +832,63 @@ void rai::wallet_store::destroy (MDB_txn * transaction_a) assert (status == 0); } -std::shared_ptr rai::wallet::receive_action (rai::send_block const & send_a, rai::account const & representative_a, rai::uint128_union const & amount_a, bool generate_work_a) +std::shared_ptr rai::wallet::receive_action (rai::block const & send_a, rai::account const & representative_a, rai::uint128_union const & amount_a, bool generate_work_a) { + rai::account account; auto hash (send_a.hash ()); std::shared_ptr block; if (node.config.receive_minimum.number () <= amount_a.number ()) { rai::transaction transaction (node.ledger.store.environment, nullptr, false); - if (node.ledger.store.pending_exists (transaction, rai::pending_key (send_a.hashables.destination, hash))) + rai::pending_info pending_info; + if (node.store.block_exists(transaction, hash)) { - rai::raw_key prv; - if (!store.fetch (transaction, send_a.hashables.destination, prv)) + account = node.ledger.block_destination (transaction, send_a); + if (!node.ledger.store.pending_get (transaction, rai::pending_key (account, hash), pending_info)) { - rai::account_info info; - auto new_account (node.ledger.store.account_get (transaction, send_a.hashables.destination, info)); - if (!new_account) + rai::raw_key prv; + if (!store.fetch (transaction, account, prv)) { - auto receive (new rai::receive_block (info.head, hash, prv, send_a.hashables.destination, generate_work_a ? work_fetch (transaction, send_a.hashables.destination, info.head) : 0)); - block.reset (receive); + rai::account_info info; + auto new_account (node.ledger.store.account_get (transaction, account, info)); + if (!new_account) + { + std::shared_ptr rep_block = node.ledger.store.block_get (transaction, info.rep_block); + assert (rep_block != nullptr); + if (node.ledger.utx_enabled (transaction)) + { + block.reset (new rai::utx_block (account, info.head, rep_block->representative (), info.balance.number () + pending_info.amount.number (), hash, prv, account, generate_work_a ? work_fetch (transaction, account, info.head) : 0)); + } + else + { + block.reset (new rai::receive_block (info.head, hash, prv, account, generate_work_a ? work_fetch (transaction, account, info.head) : 0)); + } + } + else + { + if (node.ledger.utx_enabled (transaction)) + { + block.reset (new rai::utx_block (account, info.head, representative_a, pending_info.amount, hash, prv, account, generate_work_a ? work_fetch (transaction, account, account) : 0)); + } + else + { + block.reset (new rai::open_block (hash, representative_a, account, prv, account, generate_work_a ? work_fetch (transaction, account, account) : 0)); + } + } } else { - block.reset (new rai::open_block (hash, representative_a, send_a.hashables.destination, prv, send_a.hashables.destination, generate_work_a ? work_fetch (transaction, send_a.hashables.destination, send_a.hashables.destination) : 0)); + BOOST_LOG (node.log) << "Unable to receive, wallet locked"; } } else { - BOOST_LOG (node.log) << "Unable to receive, wallet locked"; + // Ledger doesn't have this marked as available to receive anymore } } else { - // Ledger doesn't have this marked as available to receive anymore + // Ledger doesn't have this block anymore. } } else @@ -880,7 +905,7 @@ std::shared_ptr rai::wallet::receive_action (rai::send_block const & { auto hash (block->hash ()); auto this_l (shared_from_this ()); - auto source (send_a.hashables.destination); + auto source (account); node.wallets.queue_wallet_action (rai::wallets::generate_priority, [this_l, source, hash] { this_l->work_generate (source, hash); }); @@ -905,7 +930,14 @@ std::shared_ptr rai::wallet::change_action (rai::account const & sou rai::raw_key prv; auto error2 (store.fetch (transaction, source_a, prv)); assert (!error2); - block.reset (new rai::change_block (info.head, representative_a, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); + if (node.ledger.utx_enabled (transaction)) + { + block.reset (new rai::utx_block (source_a, info.head, representative_a, info.balance, 0, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); + } + else + { + block.reset (new rai::change_block (info.head, representative_a, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); + } } } } @@ -973,7 +1005,16 @@ std::shared_ptr rai::wallet::send_action (rai::account const & sourc rai::raw_key prv; auto error2 (store.fetch (transaction, source_a, prv)); assert (!error2); - block.reset (new rai::send_block (info.head, account_a, balance - amount_a, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); + std::shared_ptr rep_block = node.ledger.store.block_get (transaction, info.rep_block); + assert (rep_block != nullptr); + if (node.ledger.utx_enabled (transaction)) + { + block.reset (new rai::utx_block (source_a, info.head, rep_block->representative (), balance - amount_a, account_a, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); + } + else + { + block.reset (new rai::send_block (info.head, account_a, balance - amount_a, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); + } if (id_mdb_val) { auto status (mdb_put (transaction, node.wallets.send_action_ids, *id_mdb_val, rai::mdb_val (block->hash ()), 0)); @@ -1031,9 +1072,9 @@ bool rai::wallet::receive_sync (std::shared_ptr block_a, rai::accoun void rai::wallet::receive_async (std::shared_ptr block_a, rai::account const & representative_a, rai::uint128_t const & amount_a, std::function)> const & action_a, bool generate_work_a) { - assert (dynamic_cast (block_a.get ()) != nullptr); + //assert (dynamic_cast (block_a.get ()) != nullptr); node.wallets.queue_wallet_action (amount_a, [this, block_a, representative_a, amount_a, action_a, generate_work_a]() { - auto block (receive_action (*static_cast (block_a.get ()), representative_a, amount_a, generate_work_a)); + auto block (receive_action (*static_cast (block_a.get ()), representative_a, amount_a, generate_work_a)); action_a (block); }); } diff --git a/rai/node/wallet.hpp b/rai/node/wallet.hpp index 0bcc7d8a..b354b95b 100644 --- a/rai/node/wallet.hpp +++ b/rai/node/wallet.hpp @@ -123,7 +123,7 @@ class wallet : public std::enable_shared_from_this { public: std::shared_ptr change_action (rai::account const &, rai::account const &, bool = true); - std::shared_ptr receive_action (rai::send_block const &, rai::account const &, rai::uint128_union const &, bool = true); + std::shared_ptr receive_action (rai::block const &, rai::account const &, rai::uint128_union const &, bool = true); std::shared_ptr send_action (rai::account const &, rai::account const &, rai::uint128_t const &, bool = true, boost::optional = {}); wallet (bool &, rai::transaction &, rai::node &, std::string const &); wallet (bool &, rai::transaction &, rai::node &, std::string const &, std::string const &); diff --git a/rai/slow_test/node.cpp b/rai/slow_test/node.cpp index 78074667..efd29cad 100644 --- a/rai/slow_test/node.cpp +++ b/rai/slow_test/node.cpp @@ -19,26 +19,19 @@ TEST (system, generate_mass_activity) TEST (system, generate_mass_activity_long) { - std::vector threads; + rai::system system (24000, 1); + rai::thread_runner runner (system.service, system.nodes[0]->config.io_threads); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + size_t count (1000000000); + system.generate_mass_activity (count, *system.nodes[0]); + size_t accounts (0); + rai::transaction transaction (system.nodes[0]->store.environment, nullptr, false); + for (auto i (system.nodes[0]->store.latest_begin (transaction)), n (system.nodes[0]->store.latest_end ()); i != n; ++i) { - rai::system system (24000, 1); - rai::thread_runner runner (system.service, system.nodes[0]->config.io_threads); - system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); - size_t count (1000000000); - system.generate_mass_activity (count, *system.nodes[0]); - size_t accounts (0); - rai::transaction transaction (system.nodes[0]->store.environment, nullptr, false); - for (auto i (system.nodes[0]->store.latest_begin (transaction)), n (system.nodes[0]->store.latest_end ()); i != n; ++i) - { - ++accounts; - } - system.stop (); - runner.join (); - } - for (auto i (threads.begin ()), n (threads.end ()); i != n; ++i) - { - i->join (); + ++accounts; } + system.stop (); + runner.join (); } TEST (system, receive_while_synchronizing) From 75da89b3c9851d441172ab2350afbd65c6c89a57 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Mon, 5 Mar 2018 15:59:23 -0600 Subject: [PATCH 21/36] Fixing formatting. --- rai/core_test/ledger.cpp | 6 +++--- rai/node/testing.cpp | 4 ++-- rai/node/wallet.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 7ff84554..c02f9350 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1483,11 +1483,11 @@ TEST (ledger, block_destination_source) rai::keypair dest; rai::uint128_t balance (rai::genesis_amount); balance -= rai::Gxrb_ratio; - rai::send_block block1 (genesis.hash (), dest.pub, balance, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::send_block block1 (genesis.hash (), dest.pub, balance, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); balance -= rai::Gxrb_ratio; - rai::send_block block2 (block1.hash (), rai::genesis_account, balance, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::send_block block2 (block1.hash (), rai::genesis_account, balance, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); balance += rai::Gxrb_ratio; - rai::receive_block block3 (block2.hash (), block2.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::receive_block block3 (block2.hash (), block2.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); balance -= rai::Gxrb_ratio; rai::utx_block block4 (rai::genesis_account, block3.hash (), rai::genesis_account, balance, dest.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); balance -= rai::Gxrb_ratio; diff --git a/rai/node/testing.cpp b/rai/node/testing.cpp index f11fee58..a8f0d1dd 100644 --- a/rai/node/testing.cpp +++ b/rai/node/testing.cpp @@ -130,7 +130,7 @@ void rai::system::generate_rollback (rai::node & node_a, std::vector rai::wallet::receive_action (rai::block const & send { rai::transaction transaction (node.ledger.store.environment, nullptr, false); rai::pending_info pending_info; - if (node.store.block_exists(transaction, hash)) + if (node.store.block_exists (transaction, hash)) { account = node.ledger.block_destination (transaction, send_a); if (!node.ledger.store.pending_get (transaction, rai::pending_key (account, hash), pending_info)) From c15b77f11cdb35e6af941b06d6000bf3e3e8dd0e Mon Sep 17 00:00:00 2001 From: clemahieu Date: Wed, 7 Mar 2018 15:37:55 -0600 Subject: [PATCH 22/36] Subtracting correct block count. --- rai/blockstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rai/blockstore.cpp b/rai/blockstore.cpp index 2c042529..88b01b6a 100644 --- a/rai/blockstore.cpp +++ b/rai/blockstore.cpp @@ -687,7 +687,7 @@ std::unique_ptr rai::block_store::block_random (MDB_txn * transactio } else { - region -= count.change; + region -= count.open; if (region < count.change) { result = block_random (transaction_a, change_blocks); From fbaf67ac68ff2d146b71d04aebcc5294e0c8e405 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 7 Mar 2018 16:40:14 -0700 Subject: [PATCH 23/36] Support gap_source for ublocks (#695) --- rai/core_test/ledger.cpp | 2 +- rai/ledger.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index c02f9350..f7dcf36a 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1711,7 +1711,7 @@ TEST (ledger, utx_unreceivable_fail) ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, send1.hash ())); ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); rai::utx_block receive1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount, 1, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); - ASSERT_EQ (rai::process_result::unreceivable, ledger.process (transaction, receive1).code); + ASSERT_EQ (rai::process_result::gap_source, ledger.process (transaction, receive1).code); } TEST (ledger, utx_receive_bad_amount_fail) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 33740f4c..745f95a2 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -212,12 +212,16 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) { if (!block_a.hashables.link.is_zero ()) { - rai::pending_key key (block_a.hashables.account, block_a.hashables.link); - rai::pending_info pending; - result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed) + result.code = ledger.store.block_exists (transaction, block_a.hashables.link) ? rai::process_result::progress : rai::process_result::gap_source; // Have we seen the source block already? (Harmless) if (result.code == rai::process_result::progress) { - result.code = result.amount == pending.amount ? rai::process_result::progress : rai::process_result::balance_mismatch; + rai::pending_key key (block_a.hashables.account, block_a.hashables.link); + rai::pending_info pending; + result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed) + if (result.code == rai::process_result::progress) + { + result.code = result.amount == pending.amount ? rai::process_result::progress : rai::process_result::balance_mismatch; + } } } else From f5c462aad0cd8aedd83c410db3bdb08df8b034d0 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Wed, 7 Mar 2018 23:18:46 -0600 Subject: [PATCH 24/36] Adding utx support for block_create and deserialize_block_json. --- rai/core_test/rpc.cpp | 37 +++++++++++++++++++++++++++++++++++++ rai/lib/blocks.cpp | 9 +++++++++ rai/node/rpc.cpp | 29 ++++++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index 7f7f2883..02845c4c 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -3093,6 +3093,43 @@ TEST (rpc, block_create) ASSERT_EQ (receive_hash, latest.to_string ()); } +TEST (rpc, block_create_utx) +{ + rai::system system (24000, 1); + rai::keypair key; + rai::genesis genesis; + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + boost::property_tree::ptree request; + request.put ("action", "block_create"); + request.put ("type", "utx"); + request.put ("wallet", system.nodes[0]->wallets.items.begin ()->first.to_string ()); + request.put ("account", rai::test_genesis_key.pub.to_account ()); + request.put ("previous", genesis.hash ().to_string ()); + request.put ("representative", rai::test_genesis_key.pub.to_account ()); + request.put ("balance", (rai::genesis_amount - rai::Gxrb_ratio).convert_to ()); + request.put ("link", key.pub.to_account ()); + request.put ("work", rai::to_string_hex (system.nodes[0]->generate_work (genesis.hash ()))); + rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true)); + rpc.start (); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + std::string utx_hash (response.json.get ("hash")); + auto utx_text (response.json.get ("block")); + std::stringstream block_stream (utx_text); + boost::property_tree::ptree block_l; + boost::property_tree::read_json (block_stream, block_l); + auto utx_block (rai::deserialize_block_json (block_l)); + ASSERT_NE (nullptr, utx_block); + ASSERT_EQ (rai::block_type::utx, utx_block->type ()); + ASSERT_EQ (utx_hash, utx_block->hash ().to_string ()); + auto process_result (system.nodes[0]->process (*utx_block)); + ASSERT_EQ (rai::process_result::progress, process_result.code); +} + TEST (rpc, wallet_lock) { rai::system system (24000, 1); diff --git a/rai/lib/blocks.cpp b/rai/lib/blocks.cpp index 65bcc14d..908f3604 100644 --- a/rai/lib/blocks.cpp +++ b/rai/lib/blocks.cpp @@ -1175,6 +1175,15 @@ std::unique_ptr rai::deserialize_block_json (boost::property_tree::p result = std::move (obj); } } + else if (type == "utx") + { + bool error; + std::unique_ptr obj (new rai::utx_block (error, tree_a)); + if (!error) + { + result = std::move (obj); + } + } } catch (std::runtime_error const &) { diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 483ecd4c..285bc657 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -1165,6 +1165,7 @@ void rai::rpc_handler::block_create () prv.data.clear (); rai::uint256_union previous (0); rai::uint128_union balance (0); + rai::uint256_union link (0); if (wallet != 0 && account != 0) { auto existing (node.wallets.items.find (wallet)); @@ -1223,11 +1224,37 @@ void rai::rpc_handler::block_create () error_response (response, "Bad balance number"); } } + boost::optional link_text (request.get_optional ("link")); + if (link_text.is_initialized ()) + { + auto error_link (link.decode_account (link_text.get ())); + if (error_link) + { + error_response (response, "Bad link number"); + } + } if (prv.data != 0) { rai::uint256_union pub; ed25519_publickey (prv.data.bytes.data (), pub.bytes.data ()); - if (type == "open") + if (type == "utx") + { + if (!account.is_zero () && !previous.is_zero () && !representative.is_zero () && !balance.is_zero () && link_text.is_initialized ()) + { + rai::utx_block utx (account, previous, representative, balance, link, prv, pub, work); + boost::property_tree::ptree response_l; + response_l.put ("hash", utx.hash ().to_string ()); + std::string contents; + utx.serialize_json (contents); + response_l.put ("block", contents); + response (response_l); + } + else + { + error_response (response, "Account, previous, representative, balance, and link are required"); + } + } + else if (type == "open") { if (representative != 0 && source != 0) { From 755dae86123f4c5a46adc0f304a63582d885d520 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Thu, 8 Mar 2018 16:50:48 -0700 Subject: [PATCH 25/36] Merge master into ublocks (#714) * Fix typos (#683) * Move to C++14 Replaces a single reset with make_unique to see if things compile in CI. Also reverts a CI-specific RPATH change which prevented the wallet from running on macOS dev machines * Update CMakeLists.txt to support gtest linking for Windows * Fix test for wallet_create_max to allow for utx database addition (#691) * Remove unused code (#686) * Fix docker boost url * Revert nonWalletDbs Revert to fix failing tests * Improved error handling in message parser (#704) * Replacing bool get_optional with get default values (#670) * Revert "Watch only accounts" This reverts commit 1b0809a3af05c6a75242feadf40e5f80525f2eef. * Replacing bool get_optional with get default values * RPC tests for optional bool values * RPC tests for wallet_ledger & wallet_add_watch * Improve account history RPC endpoint (#668) * Checking ledger::forked_block preconditions which were asserting. * Update README (#709) * update docs to add guides and update "what is nano?" system * add whitepaper to guides and docs * update features list * update what is nano header level * Build of Boost Cleanup (#707) * Updated to check the boost SHA256 when downloading * Fixed invalid shell option * Allow the user to request a minimal build of Boost * Ensure boost build script exits on error * Removed apparently unused "mkdir" * Docker altnets (#708) * Updated to check the boost SHA256 when downloading * Fixed invalid shell option * Allow the user to request a minimal build of Boost * Ensure boost build script exits on error * Removed apparently unused "mkdir" * Updated Docker build for node to support altnets * Allow user-supplied arguments to "docker build" * Updated Docker auto deploy to build a live and beta image for each tag * Print the correct image name when building the docker image * Corrected typo for the test network * Broadcasting active elections blocks to discovered representatives (#711) * Broadcasting active elections blocks * Improve formatting for clang * Connecting to rai-beta for beta network. * Specify beta network representatives (#712) * Update the beta network configuration (#713) * Specify beta network representatives * Update beta network genesis block * Use port 54000 for beta nodes * Add history RPC raw support to ublocks * Fix test for wallet_create_max to allow for utx database addition (#691) --- CMakeLists.txt | 15 +- FindBoost.cmake | 2 +- README.md | 58 +- ci/bootstrap_boost.sh | 31 +- ci/build-docker-image.sh | 15 +- ci/deploy-docker.sh | 26 +- docker/ci/Dockerfile | 2 +- docker/node/Dockerfile | 26 +- docker/node/build.sh | 38 +- docker/node/config/beta.json | 60 +++ docker/node/{config.json => config/live.json} | 0 docker/node/config/test.json | 67 +++ docker/node/entry.sh | 25 +- images/logo.svg | 1 + rai/blockstore.cpp | 31 +- rai/blockstore.hpp | 1 - rai/common.cpp | 64 +-- rai/core_test/ledger.cpp | 2 +- rai/core_test/message_parser.cpp | 24 +- rai/core_test/network.cpp | 2 +- rai/core_test/rpc.cpp | 172 +++++- rai/core_test/wallets.cpp | 2 +- rai/lib/interface.h | 2 +- rai/node/bootstrap.cpp | 83 +-- rai/node/common.cpp | 43 +- rai/node/common.hpp | 14 +- rai/node/node.cpp | 116 +++- rai/node/node.hpp | 9 +- rai/node/rpc.cpp | 498 +++++++++++------- rai/node/rpc.hpp | 2 + rai/node/testing.cpp | 4 +- rai/node/utility.hpp | 2 +- rai/node/wallet.cpp | 18 +- rai/node/wallet.hpp | 2 + rai/qt/qt.cpp | 2 +- rai/rai_node/daemon.cpp | 2 +- 36 files changed, 1006 insertions(+), 455 deletions(-) create mode 100644 docker/node/config/beta.json rename docker/node/{config.json => config/live.json} (100%) create mode 100644 docker/node/config/test.json create mode 100644 images/logo.svg diff --git a/CMakeLists.txt b/CMakeLists.txt index 2727b92e..27d83ec4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,12 +7,8 @@ set (CPACK_PACKAGE_VERSION_PATCH "1") set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) -if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks") -else() - set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib:\$ORIGIN/") - set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -endif() +set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib:\$ORIGIN/") +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) set (RAIBLOCKS_GUI OFF CACHE BOOL "") set (RAIBLOCKS_TEST OFF CACHE BOOL "") @@ -70,7 +66,7 @@ endif (WIN32) if (WIN32) set (PLATFORM_CXX_FLAGS "/bigobj") else (WIN32) - set (PLATFORM_CXX_FLAGS "-std=c++11") + set (PLATFORM_CXX_FLAGS "-std=c++14") endif (WIN32) if (WIN32) @@ -146,6 +142,11 @@ else () set (ARGON_CORE phc-winner-argon2/src/ref.c) endif () +if (WIN32) + set (gtest_force_shared_crt ON) +else () + set (gtest_force_shared_crt OFF) +endif() add_subdirectory (gtest) include_directories ("gtest/include") diff --git a/FindBoost.cmake b/FindBoost.cmake index e9677074..224934b5 100644 --- a/FindBoost.cmake +++ b/FindBoost.cmake @@ -925,7 +925,7 @@ function(_Boost_MISSING_DEPENDENCIES componentvar extravar) endfunction() # -# Some boost libraries may require particular set of compler features. +# Some boost libraries may require particular set of compiler features. # The very first one was `boost::fiber` introduced in Boost 1.62. # One can check required compiler features of it in # `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`. diff --git a/README.md b/README.md index c51abd7a..af73e99b 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,53 @@ +
+
+ Logo +
+
+ [![Build Status](https://travis-ci.org/nanocurrency/raiblocks.svg?branch=master)](https://travis-ci.org/nanocurrency/raiblocks) -# What is Nano? -Nano is designed to be a feeless, instant, high throughput cryptocurrency. +### What is Nano? -We've applied the philosophy of "do one thing and do it well", giving you performance and scalability unmatched by any other platform. +--- -### Key features -* Nano utilizes a novel block-lattice architecture, unlike conventional blockchains used in many other cryptocurrencies. +Nano's goal is to become _"a global currency with instantaneous transactions and zero fees over a secure, decentralized network."_ + +We've applied the philosophy of _"do one thing and do it well"_, we are focused on building the best medium for value exchange in the world. + +--- + +### Key Features + +* Nano utilizes a novel [block-lattice](https://github.com/nanocurrency/raiblocks/wiki/Block-lattice) architecture, unlike conventional blockchains used in many other cryptocurrencies. * The network requires minimal resources, no high-power mining hardware, and can process high transaction throughput. -* Offers feeless, instantaneous transactions, as well as unlimited scalability, making Nano ideal for peer-to-peer transactions. +* Offers instantaneous transactions with zero fees and unlimited scalability, making Nano an ideal solution for peer-to-peer transactions. * As of December 2017, the Nano network has processed over four million transactions with an unpruned ledger size of only 1.7GB. For more information, see [Nano.org](https://nano.org/) or read the [whitepaper](https://nano.org/en/whitepaper). -### Resources -- [Nano website](https://nano.org) -- [Whitepaper](https://nano.org/en/whitepaper) -- [Roadmap](https://raiblocks.net/media/raiblocks-roadmap-v2-en.png) -- [Discord chat](https://chat.nano.org/) -- [Reddit](https://reddit.com/r/nanocurrency) -- [Medium](https://medium.com/@nanocurrency) -- [Twitter](https://twitter.com/nanocurrency) -- [Forum](https://forum.raiblocks.net/) -- [GitHub wiki](https://github.com/nanocurrency/raiblocks/wiki) +### Guides & Documentation -### Build instructions -https://github.com/nanocurrency/raiblocks/wiki/Build-Instructions +* [White Paper](https://nano.org/en/whitepaper) +* [Build Instructions](https://github.com/nanocurrency/raiblocks/wiki/Build-Instructions) +* [Command Line Interface](https://github.com/nanocurrency/raiblocks/wiki/Command-line-interface) +* [RPC Protocol](https://github.com/nanocurrency/raiblocks/wiki/RPC-protocol) +* [Wallet Design](https://github.com/nanocurrency/raiblocks/wiki/Wallet-design) +* [Block Lattice](https://github.com/nanocurrency/raiblocks/wiki/Block-lattice) +* [Design Features](https://github.com/nanocurrency/raiblocks/wiki/Design-features) + +### Links & Resources + +* [Nano Website](https://nano.org) +* [Nano Roadmap](https://raiblocks.net/media/raiblocks-roadmap-v2-en.png) +* [Discord Chat](https://chat.nano.org/) +* [Reddit](https://reddit.com/r/nanocurrency) +* [Medium](https://medium.com/@nanocurrency) +* [Twitter](https://twitter.com/nanocurrency) +* [Forum](https://forum.raiblocks.net/) +* [GitHub wiki](https://github.com/nanocurrency/raiblocks/wiki) + +### Want to Contribute? -### Want to contribute? Please see the [contributors guide](https://github.com/nanocurrency/raiblocks/wiki/Contributing). ### Contact us diff --git a/ci/bootstrap_boost.sh b/ci/bootstrap_boost.sh index 90424cd8..f866f872 100755 --- a/ci/bootstrap_boost.sh +++ b/ci/bootstrap_boost.sh @@ -1,18 +1,37 @@ #!/usr/bin/env bash -set -o unset +set -o nounset +set -o errexit set -o xtrace +bootstrapArgs=() +while getopts 'm' OPT; do + case "${OPT}" in + m) + bootstrapArgs+=('--with-libraries=atomic,chrono,thread,log,date_time,filesystem,program_options,regex') + ;; + esac +done + BOOST_BASENAME=boost_1_66_0 BOOST_ROOT=${BOOST_ROOT-/usr/local/boost} BOOST_URL=https://downloads.sourceforge.net/project/boost/boost/1.66.0/${BOOST_BASENAME}.tar.bz2 +BOOST_ARCHIVE="${BOOST_BASENAME}.tar.bz2" +BOOST_ARCHIVE_SHA256='5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9' -wget --quiet -O ${BOOST_BASENAME}.tar.gz "${BOOST_URL}" -tar xf ${BOOST_BASENAME}.tar.gz +wget --quiet -O "${BOOST_ARCHIVE}.new" "${BOOST_URL}" +checkHash="$(openssl dgst -sha256 "${BOOST_ARCHIVE}.new" | sed 's@^.*= *@@')" +if [ "${checkHash}" != "${BOOST_ARCHIVE_SHA256}" ]; then + echo "Checksum mismatch. Expected ${BOOST_ARCHIVE_SHA256}, got ${checkHash}" >&2 + + exit 1 +fi +mv "${BOOST_ARCHIVE}.new" "${BOOST_ARCHIVE}" + +tar xf "${BOOST_ARCHIVE}" cd ${BOOST_BASENAME} -./bootstrap.sh +./bootstrap.sh "${bootstrapArgs[@]}" ./b2 -d0 --prefix=${BOOST_ROOT} link=static install cd .. rm -rf ${BOOST_BASENAME} -rm -f ${BOOST_BASENAME}.tar.gz -mkdir -p app +rm -f "${BOOST_ARCHIVE}" diff --git a/ci/build-docker-image.sh b/ci/build-docker-image.sh index e5e34488..6268adb3 100755 --- a/ci/build-docker-image.sh +++ b/ci/build-docker-image.sh @@ -1,8 +1,17 @@ #!/bin/bash set -eu +if [ "$#" -lt 2 ]; then + echo 'Usage: build-docker-image.sh [...]' >&2 + exit 1 +fi + +dockerFile="$1" +dockerTag="$2" +shift; shift + scripts="$(dirname "$0")" -"$scripts"/custom-timeout.sh 20 docker pull "$2" || true -echo "Building $2" -"$scripts"/custom-timeout.sh 30 docker build -f "$1" -t "$2" --cache-from "$2" . +"$scripts"/custom-timeout.sh 20 docker pull "${dockerTag}" || true +echo "Building $dockerTag" +"$scripts"/custom-timeout.sh 30 docker build "$@" -f "${dockerFile}" -t "${dockerTag}" --cache-from "${dockerTag}" . diff --git a/ci/deploy-docker.sh b/ci/deploy-docker.sh index 7669e33c..d82a3984 100755 --- a/ci/deploy-docker.sh +++ b/ci/deploy-docker.sh @@ -15,13 +15,23 @@ elif [ -n "$TRAVIS_TAG" ]; then tags+=("$TRAVIS_TAG" latest) fi -ci/build-docker-image.sh docker/node/Dockerfile nanocurrency/nano -for tag in "${tags[@]}"; do - # Sanitize docker tag - # https://docs.docker.com/engine/reference/commandline/tag/ - tag="$(printf '%s' "$tag" | tr -c '[a-z][A-Z][0-9]_.-' -)" - if [ "$tag" != "latest" ]; then - docker tag nanocurrency/nano nanocurrency/nano:"$tag" +for network in live beta; do + if [ "${network}" = 'live' ]; then + network_tag_suffix='' + else + network_tag_suffix="-${network}" fi - "$scripts"/custom-timeout.sh 30 docker push nanocurrency/nano:"$tag" + + docker_image_name="nanocurrency/nano${network_tag_suffix}" + + ci/build-docker-image.sh docker/node/Dockerfile "$docker_image_name" --build-arg NETWORK="${network}" + for tag in "${tags[@]}"; do + # Sanitize docker tag + # https://docs.docker.com/engine/reference/commandline/tag/ + tag="$(printf '%s' "$tag" | tr -c '[a-z][A-Z][0-9]_.-' -)" + if [ "$tag" != "latest" ]; then + docker tag "$docker_image_name" "${docker_image_name}:$tag" + fi + "$scripts"/custom-timeout.sh 30 docker push "${docker_image_name}:$tag" + done done diff --git a/docker/ci/Dockerfile b/docker/ci/Dockerfile index 4bd6065a..2e9c112a 100644 --- a/docker/ci/Dockerfile +++ b/docker/ci/Dockerfile @@ -1,7 +1,7 @@ FROM ubuntu:16.04 ENV BOOST_BASENAME=boost_1_66_0 \ - BOOST_URL=https://sourceforge.net/projects/boost/files/boost/1.66.0/boost_1_66_0.tar.gz/download + BOOST_URL=https://netix.dl.sourceforge.net/project/boost/boost/1.66.0/boost_1_66_0.tar.gz RUN apt-get update -qq && apt-get install -yqq \ build-essential \ diff --git a/docker/node/Dockerfile b/docker/node/Dockerfile index ff7467f4..ece9f9a4 100644 --- a/docker/node/Dockerfile +++ b/docker/node/Dockerfile @@ -1,35 +1,31 @@ FROM ubuntu:16.04 -ENV BOOST_BASENAME=boost_1_66_0 \ - BOOST_ROOT=/tmp/boost_install \ - BOOST_URL=https://sourceforge.net/projects/boost/files/boost/1.66.0/boost_1_66_0.tar.gz/download +ARG NETWORK=live + +ENV BOOST_ROOT=/tmp/boost_install + +ADD ci /tmp/ci RUN apt-get update -qq && apt-get install -yqq \ build-essential \ cmake \ g++ \ wget && \ - wget -qO ${BOOST_BASENAME}.tar.gz ${BOOST_URL} && \ - tar xzf ${BOOST_BASENAME}.tar.gz && \ - cd ${BOOST_BASENAME} && \ - ./bootstrap.sh && \ - ./b2 -d0 --prefix=${BOOST_ROOT} link=static install && \ - rm -rf ${BOOST_BASENAME} && \ - rm -f ${BOOST_BASENAME}.tar.gz && \ - cd .. && \ - mkdir /usr/share/raiblocks/ + /tmp/ci/bootstrap_boost.sh -m ADD ./ /tmp/src RUN mkdir /tmp/build && \ cd /tmp/build && \ - cmake /tmp/src -DBOOST_ROOT=${BOOST_ROOT} && \ + cmake /tmp/src -DBOOST_ROOT=${BOOST_ROOT} -DACTIVE_NETWORK=rai_${NETWORK}_network && \ make rai_node && \ - cd .. + cd .. && \ + echo ${NETWORK} > /etc/nano-network FROM ubuntu:16.04 COPY --from=0 /tmp/build/rai_node /usr/bin +COPY --from=0 /etc/nano-network /etc COPY docker/node/entry.sh /entry.sh -COPY docker/node/config.json /usr/share/raiblocks/config.json +COPY docker/node/config /usr/share/raiblocks/config RUN chmod +x /entry.sh CMD ["/bin/bash", "/entry.sh"] diff --git a/docker/node/build.sh b/docker/node/build.sh index c873913b..7885e5eb 100755 --- a/docker/node/build.sh +++ b/docker/node/build.sh @@ -1,6 +1,42 @@ #!/bin/bash + +network='live' + +print_usage() { + echo 'build.sh [-h] [-n {live|beta|test}]' +} + +while getopts 'hn:' OPT; do + case "${OPT}" in + h) + print_usage + exit 0 + ;; + n) + network="${OPTARG}" + ;; + *) + print_usage >&2 + exit 1 + ;; + esac +done + +case "${network}" in + live) + network_tag='' + ;; + test|beta) + network_tag="-${network}" + ;; + *) + echo "Invalid network: ${network}" >&2 + exit 1 + ;; +esac + REPO_ROOT=`git rev-parse --show-toplevel` COMMIT_SHA=`git rev-parse --short HEAD` pushd $REPO_ROOT -docker build -f docker/node/Dockerfile -t raiblocks-node:latest . +docker build --build-arg NETWORK="${network}" -f docker/node/Dockerfile -t raiblocks-node${network_tag}:latest . popd diff --git a/docker/node/config/beta.json b/docker/node/config/beta.json new file mode 100644 index 00000000..f7bc0221 --- /dev/null +++ b/docker/node/config/beta.json @@ -0,0 +1,60 @@ +{ + "version": "2", + "rpc_enable": "true", + "rpc": { + "address": "::ffff:0.0.0.0", + "port": "7076", + "enable_control": "true", + "frontier_request_limit": "16384", + "chain_request_limit": "16384" + }, + "node": { + "version": "8", + "peering_port": "54000", + "bootstrap_fraction_numerator": "1", + "receive_minimum": "1000000000000000000000000", + "logging": { + "version": "2", + "ledger": "false", + "ledger_duplicate": "false", + "vote": "false", + "network": "true", + "network_message": "false", + "network_publish": "false", + "network_packet": "false", + "network_keepalive": "false", + "node_lifetime_tracing": "false", + "insufficient_work": "true", + "log_rpc": "true", + "bulk_pull": "false", + "work_generation_time": "true", + "log_to_cerr": "false", + "max_size": "16777216", + "rotation_size": "4194304", + "flush": "false" + }, + "work_peers": "", + "preconfigured_peers": [ + "rai-beta.raiblocks.net" + ], + "preconfigured_representatives": [ + "xrb_3kbzg73bjsi85scbwnouj44iinrsqtdqphzay1x3pwmgmhkdwg8yjntxff33" + ], + "inactive_supply": "0", + "password_fanout": "1024", + "io_threads": "4", + "work_threads": "4", + "enable_voting": "true", + "bootstrap_connections": "16", + "callback_address": "", + "callback_port": "0", + "callback_target": "", + "lmdb_max_dbs": "128" + }, + "opencl_enable": "false", + "opencl": { + "platform": "0", + "device": "0", + "threads": "1048576" + } +} diff --git a/docker/node/config.json b/docker/node/config/live.json similarity index 100% rename from docker/node/config.json rename to docker/node/config/live.json diff --git a/docker/node/config/test.json b/docker/node/config/test.json new file mode 100644 index 00000000..bdd6c191 --- /dev/null +++ b/docker/node/config/test.json @@ -0,0 +1,67 @@ +{ + "version": "2", + "rpc_enable": "true", + "rpc": { + "address": "::ffff:0.0.0.0", + "port": "7076", + "enable_control": "true", + "frontier_request_limit": "16384", + "chain_request_limit": "16384" + }, + "node": { + "version": "8", + "peering_port": "7075", + "bootstrap_fraction_numerator": "1", + "receive_minimum": "1000000000000000000000000", + "logging": { + "version": "2", + "ledger": "false", + "ledger_duplicate": "false", + "vote": "false", + "network": "true", + "network_message": "false", + "network_publish": "false", + "network_packet": "false", + "network_keepalive": "false", + "node_lifetime_tracing": "false", + "insufficient_work": "true", + "log_rpc": "true", + "bulk_pull": "false", + "work_generation_time": "true", + "log_to_cerr": "false", + "max_size": "16777216", + "rotation_size": "4194304", + "flush": "false" + }, + "work_peers": "", + "preconfigured_peers": [ + "rai-test.raiblocks.net" + ], + "preconfigured_representatives": [ + "xrb_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4", + "xrb_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou", + "xrb_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p", + "xrb_3dmtrrws3pocycmbqwawk6xs7446qxa36fcncush4s1pejk16ksbmakis78m", + "xrb_3hd4ezdgsp15iemx7h81in7xz5tpxi43b6b41zn3qmwiuypankocw3awes5k", + "xrb_1awsn43we17c1oshdru4azeqjz9wii41dy8npubm4rg11so7dx3jtqgoeahy", + "xrb_1anrzcuwe64rwxzcco8dkhpyxpi8kd7zsjc1oeimpc3ppca4mrjtwnqposrs", + "xrb_1hza3f7wiiqa7ig3jczyxj5yo86yegcmqk3criaz838j91sxcckpfhbhhra1" + ], + "inactive_supply": "0", + "password_fanout": "1024", + "io_threads": "4", + "work_threads": "4", + "enable_voting": "true", + "bootstrap_connections": "16", + "callback_address": "", + "callback_port": "0", + "callback_target": "", + "lmdb_max_dbs": "128" + }, + "opencl_enable": "false", + "opencl": { + "platform": "0", + "device": "0", + "threads": "1048576" + } +} diff --git a/docker/node/entry.sh b/docker/node/entry.sh index a38dc03d..02d38d09 100644 --- a/docker/node/entry.sh +++ b/docker/node/entry.sh @@ -1,10 +1,27 @@ #!/bin/bash + set -euo pipefail IFS=$'\n\t' -mkdir -p ~/RaiBlocks -if [ ! -f ~/RaiBlocks/config.json ]; then - echo "Config File not found, adding default." - cp /usr/share/raiblocks/config.json ~/RaiBlocks/ +network="$(cat /etc/nano-network)" +case "${network}" in + live|'') + network='live' + dirSuffix='' + ;; + beta) + dirSuffix='Beta' + ;; + test) + dirSuffix='Test' + ;; +esac + +nanodir="${HOME}/RaiBlocks${dirSuffix}" +mkdir -p "${nanodir}" +if [ ! -f "${nanodir}/config.json" ]; then + echo "Config File not found, adding default." + cp "/usr/share/raiblocks/config/${network}.json" "${nanodir}/config.json" fi + /usr/bin/rai_node --daemon diff --git a/images/logo.svg b/images/logo.svg new file mode 100644 index 00000000..95d96fb9 --- /dev/null +++ b/images/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rai/blockstore.cpp b/rai/blockstore.cpp index 88b01b6a..c83ebee6 100644 --- a/rai/blockstore.cpp +++ b/rai/blockstore.cpp @@ -827,35 +827,6 @@ rai::block_counts rai::block_store::block_count (MDB_txn * transaction_a) return result; } -std::unordered_multimap rai::block_store::block_dependencies (MDB_txn * transaction_a) -{ - std::unordered_multimap result; - // For every block type - for (auto type : { rai::block_type::send, rai::block_type::receive, rai::block_type::open, rai::block_type::change }) - { - auto db (block_database (type)); - // For every block in that type's table - for (auto i (rai::store_iterator (transaction_a, db)), n (rai::store_iterator (nullptr)); i != n; ++i) - { - rai::block_hash hash (i->first.uint256 ()); - auto block (block_get (transaction_a, hash)); - if (type != rai::block_type::open) - { - auto previous (block->previous ()); - assert (!previous.is_zero ()); - result.insert (std::make_pair (previous, hash)); - } - if (type == rai::block_type::open || type == rai::block_type::receive) - { - auto source (block->source ()); - assert (!source.is_zero ()); - result.insert (std::make_pair (source, hash)); - } - } - } - return result; -} - void rai::block_store::account_del (MDB_txn * transaction_a, rai::account const & account_a) { auto status (mdb_del (transaction_a, accounts, rai::mdb_val (account_a), nullptr)); @@ -1074,7 +1045,7 @@ void rai::block_store::unchecked_put (MDB_txn * transaction_a, rai::block_hash c exists = true; } } - // Insering block if it wasn't found in database + // Inserting block if it wasn't found in database if (!exists) { std::lock_guard lock (cache_mutex); diff --git a/rai/blockstore.hpp b/rai/blockstore.hpp index 248c3567..77ecce89 100644 --- a/rai/blockstore.hpp +++ b/rai/blockstore.hpp @@ -60,7 +60,6 @@ public: void block_del (MDB_txn *, rai::block_hash const &); bool block_exists (MDB_txn *, rai::block_hash const &); rai::block_counts block_count (MDB_txn *); - std::unordered_multimap block_dependencies (MDB_txn *); void frontier_put (MDB_txn *, rai::block_hash const &, rai::account const &); rai::account frontier_get (MDB_txn *, rai::block_hash const &); diff --git a/rai/common.cpp b/rai/common.cpp index bc3acd11..a6d32f83 100644 --- a/rai/common.cpp +++ b/rai/common.cpp @@ -16,7 +16,7 @@ namespace { char const * test_private_key_data = "34F0A37AAD20F4A260F0A5B3CB3D7FB50673212263E58A380BC10474BB039CE4"; char const * test_public_key_data = "B0311EA55708D6A53C75CDBF88300259C6D018522FE3D4D0A242E431F9E8B6D0"; // xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo -char const * beta_public_key_data = "9D3A5B66B478670455B241D6BAC3D3FE1CBB7E7B7EAA429FA036C2704C3DC0A4"; // xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk +char const * beta_public_key_data = "0311B25E0D1E1D7724BBA5BD523954F1DBCFC01CB8671D55ED2D32C7549FB252"; // xrb_11rjpbh1t9ixgwkdqbfxcawobwgusz13sg595ocytdbkrxcbzekkcqkc3dn1 char const * live_public_key_data = "E89208DD038FBB269987689621D52292AE9C35941A7484756ECCED92A65093BA"; // xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3 char const * test_genesis_data = R"%%%({ "type": "open", @@ -29,11 +29,11 @@ char const * test_genesis_data = R"%%%({ char const * beta_genesis_data = R"%%%({ "type": "open", - "source": "9D3A5B66B478670455B241D6BAC3D3FE1CBB7E7B7EAA429FA036C2704C3DC0A4", - "representative": "xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk", - "account": "xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk", - "work": "6eb12d4c42dba31e", - "signature": "BD0D374FCEB33EAABDF728E9B4DCDBF3B226DA97EEAB8EA5B7EDE286B1282C24D6EB544644FE871235E4F58CD94DF66D9C555309895F67A7D1F922AAC12CE907" + "source": "0311B25E0D1E1D7724BBA5BD523954F1DBCFC01CB8671D55ED2D32C7549FB252", + "representative": "xrb_11rjpbh1t9ixgwkdqbfxcawobwgusz13sg595ocytdbkrxcbzekkcqkc3dn1", + "account": "xrb_11rjpbh1t9ixgwkdqbfxcawobwgusz13sg595ocytdbkrxcbzekkcqkc3dn1", + "work": "869e17b2bfa36639", + "signature": "34DF447C7F185673128C3516A657DFEC7906F16C68FB5A8879432E2E4FB908C8ED0DD24BBECFAB3C7852898231544A421DC8CB636EF66C82E1245083EB08EA0F" })%%%"; char const * live_genesis_data = R"%%%({ @@ -63,7 +63,7 @@ public: burn_account (0) { CryptoPP::AutoSeededRandomPool random_pool; - // Randomly generating these mean no two nodes will ever have the same sentinal values which protects against some insecure algorithms + // Randomly generating these mean no two nodes will ever have the same sentinel values which protects against some insecure algorithms random_pool.GenerateBlock (not_a_block.bytes.data (), not_a_block.bytes.size ()); random_pool.GenerateBlock (not_an_account.bytes.data (), not_an_account.bytes.size ()); } @@ -410,56 +410,6 @@ std::string rai::vote::to_json () const return stream.str (); } -namespace -{ -class root_visitor : public rai::block_visitor -{ -public: - root_visitor (rai::block_store & store_a) : - store (store_a) - { - } - virtual ~root_visitor () = default; - void send_block (rai::send_block const & block_a) override - { - result = block_a.previous (); - } - void receive_block (rai::receive_block const & block_a) override - { - result = block_a.previous (); - } - // Open blocks have no previous () so we use the account number - void open_block (rai::open_block const & block_a) override - { - rai::transaction transaction (store.environment, nullptr, false); - auto hash (block_a.source ()); - auto source (store.block_get (transaction, hash)); - if (source != nullptr) - { - auto send (dynamic_cast (source.get ())); - if (send != nullptr) - { - result = send->hashables.destination; - } - else - { - result.clear (); - } - } - else - { - result.clear (); - } - } - void change_block (rai::change_block const & block_a) override - { - result = block_a.previous (); - } - rai::block_store & store; - rai::block_hash result; -}; -} // namespace - rai::amount_visitor::amount_visitor (MDB_txn * transaction_a, rai::block_store & store_a) : transaction (transaction_a), store (store_a) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index f7dcf36a..e76f579c 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -12,7 +12,7 @@ TEST (ledger, store_error) rai::ledger ledger (store); } -// Ledger can be initialized and retuns a basic query for an empty account +// Ledger can be initialized and returns a basic query for an empty account TEST (ledger, empty) { bool init (false); diff --git a/rai/core_test/message_parser.cpp b/rai/core_test/message_parser.cpp index 6fdd1f69..937fc407 100644 --- a/rai/core_test/message_parser.cpp +++ b/rai/core_test/message_parser.cpp @@ -74,14 +74,14 @@ TEST (message_parser, exact_confirm_ack_size) message.serialize (stream); } ASSERT_EQ (0, visitor.confirm_ack_count); - ASSERT_FALSE (parser.error); + ASSERT_EQ (parser.status, rai::message_parser::parse_status::success); parser.deserialize_confirm_ack (bytes.data (), bytes.size ()); ASSERT_EQ (1, visitor.confirm_ack_count); - ASSERT_FALSE (parser.error); + ASSERT_EQ (parser.status, rai::message_parser::parse_status::success); bytes.push_back (0); parser.deserialize_confirm_ack (bytes.data (), bytes.size ()); ASSERT_EQ (1, visitor.confirm_ack_count); - ASSERT_TRUE (parser.error); + ASSERT_NE (parser.status, rai::message_parser::parse_status::success); } TEST (message_parser, exact_confirm_req_size) @@ -97,14 +97,14 @@ TEST (message_parser, exact_confirm_req_size) message.serialize (stream); } ASSERT_EQ (0, visitor.confirm_req_count); - ASSERT_FALSE (parser.error); + ASSERT_EQ (parser.status, rai::message_parser::parse_status::success); parser.deserialize_confirm_req (bytes.data (), bytes.size ()); ASSERT_EQ (1, visitor.confirm_req_count); - ASSERT_FALSE (parser.error); + ASSERT_EQ (parser.status, rai::message_parser::parse_status::success); bytes.push_back (0); parser.deserialize_confirm_req (bytes.data (), bytes.size ()); ASSERT_EQ (1, visitor.confirm_req_count); - ASSERT_TRUE (parser.error); + ASSERT_NE (parser.status, rai::message_parser::parse_status::success); } TEST (message_parser, exact_publish_size) @@ -120,14 +120,14 @@ TEST (message_parser, exact_publish_size) message.serialize (stream); } ASSERT_EQ (0, visitor.publish_count); - ASSERT_FALSE (parser.error); + ASSERT_EQ (parser.status, rai::message_parser::parse_status::success); parser.deserialize_publish (bytes.data (), bytes.size ()); ASSERT_EQ (1, visitor.publish_count); - ASSERT_FALSE (parser.error); + ASSERT_EQ (parser.status, rai::message_parser::parse_status::success); bytes.push_back (0); parser.deserialize_publish (bytes.data (), bytes.size ()); ASSERT_EQ (1, visitor.publish_count); - ASSERT_TRUE (parser.error); + ASSERT_NE (parser.status, rai::message_parser::parse_status::success); } TEST (message_parser, exact_keepalive_size) @@ -142,12 +142,12 @@ TEST (message_parser, exact_keepalive_size) message.serialize (stream); } ASSERT_EQ (0, visitor.keepalive_count); - ASSERT_FALSE (parser.error); + ASSERT_EQ (parser.status, rai::message_parser::parse_status::success); parser.deserialize_keepalive (bytes.data (), bytes.size ()); ASSERT_EQ (1, visitor.keepalive_count); - ASSERT_FALSE (parser.error); + ASSERT_EQ (parser.status, rai::message_parser::parse_status::success); bytes.push_back (0); parser.deserialize_keepalive (bytes.data (), bytes.size ()); ASSERT_EQ (1, visitor.keepalive_count); - ASSERT_TRUE (parser.error); + ASSERT_NE (parser.status, rai::message_parser::parse_status::success); } diff --git a/rai/core_test/network.cpp b/rai/core_test/network.cpp index 14d221f4..dcab2e67 100644 --- a/rai/core_test/network.cpp +++ b/rai/core_test/network.cpp @@ -206,7 +206,7 @@ TEST (network, send_valid_confirm_ack) ++iterations; ASSERT_LT (iterations, 200); } - // Make sure the balance has decreased after procssing the block. + // Make sure the balance has decreased after processing the block. ASSERT_EQ (50, system.nodes[1]->balance (rai::test_genesis_key.pub)); } diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index 02845c4c..584fef99 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -379,7 +379,6 @@ TEST (rpc, wallet_add) rai::keypair key1; std::string key_text; key1.prv.data.encode_hex (key_text); - system.wallet (0)->insert_adhoc (key1.prv); boost::property_tree::ptree request; std::string wallet; system.nodes[0]->wallets.items.begin ()->first.encode_hex (wallet); @@ -394,6 +393,7 @@ TEST (rpc, wallet_add) ASSERT_EQ (200, response.status); std::string account_text1 (response.json.get ("account")); ASSERT_EQ (account_text1, key1.pub.to_account ()); + ASSERT_TRUE (system.wallet (0)->exists (key1.pub)); } TEST (rpc, wallet_password_valid) @@ -1337,6 +1337,8 @@ TEST (rpc, pending) rai::uint128_union amount; amount.decode_dec (i->second.get ("")); blocks[hash] = amount; + boost::optional source (i->second.get_optional ("source")); + ASSERT_FALSE (source.is_initialized ()); } ASSERT_EQ (blocks[block1->hash ()], 100); request.put ("threshold", "101"); @@ -2265,6 +2267,8 @@ TEST (rpc, accounts_pending) rai::uint128_union amount; amount.decode_dec (i->second.get ("")); blocks[hash] = amount; + boost::optional source (i->second.get_optional ("source")); + ASSERT_FALSE (source.is_initialized ()); } } ASSERT_EQ (blocks[block1->hash ()], 100); @@ -2465,6 +2469,8 @@ TEST (rpc, wallet_pending) rai::uint128_union amount; amount.decode_dec (i->second.get ("")); blocks[hash] = amount; + boost::optional source (i->second.get_optional ("source")); + ASSERT_FALSE (source.is_initialized ()); } } ASSERT_EQ (blocks[block1->hash ()], 100); @@ -2780,6 +2786,27 @@ TEST (rpc, account_info) ASSERT_TRUE (time - stol (modified_timestamp) < 5); std::string block_count (response.json.get ("block_count")); ASSERT_EQ ("2", block_count); + boost::optional weight (response.json.get_optional ("weight")); + ASSERT_FALSE (weight.is_initialized ()); + boost::optional pending (response.json.get_optional ("pending")); + ASSERT_FALSE (pending.is_initialized ()); + boost::optional representative (response.json.get_optional ("representative")); + ASSERT_FALSE (representative.is_initialized ()); + // Test for optional values + request.put ("weight", "true"); + request.put ("pending", "1"); + request.put ("representative", "1"); + test_response response2 (request, rpc, system.service); + while (response2.status == 0) + { + system.poll (); + } + std::string weight2 (response2.json.get ("weight")); + ASSERT_EQ ("100", weight2); + std::string pending2 (response2.json.get ("pending")); + ASSERT_EQ ("0", pending2); + std::string representative2 (response2.json.get ("representative")); + ASSERT_EQ (rai::test_genesis_key.pub.to_account (), representative2); } TEST (rpc, blocks_info) @@ -2810,6 +2837,26 @@ TEST (rpc, blocks_info) ASSERT_EQ (rai::genesis_amount.convert_to (), amount_text); std::string blocks_text (blocks.second.get ("contents")); ASSERT_FALSE (blocks_text.empty ()); + boost::optional pending (blocks.second.get_optional ("pending")); + ASSERT_FALSE (pending.is_initialized ()); + boost::optional source (blocks.second.get_optional ("source_account")); + ASSERT_FALSE (source.is_initialized ()); + } + // Test for optional values + request.put ("source", "true"); + request.put ("pending", "1"); + test_response response2 (request, rpc, system.service); + while (response2.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response2.status); + for (auto & blocks : response2.json.get_child ("blocks")) + { + std::string source (blocks.second.get ("source_account")); + ASSERT_EQ ("0", source); + std::string pending (blocks.second.get ("pending")); + ASSERT_EQ ("0", pending); } } @@ -2940,6 +2987,33 @@ TEST (rpc, ledger) ASSERT_EQ (std::to_string (time), modified_timestamp); std::string block_count (accounts.second.get ("block_count")); ASSERT_EQ ("1", block_count); + boost::optional weight (accounts.second.get_optional ("weight")); + ASSERT_FALSE (weight.is_initialized ()); + boost::optional pending (accounts.second.get_optional ("pending")); + ASSERT_FALSE (pending.is_initialized ()); + boost::optional representative (accounts.second.get_optional ("representative")); + ASSERT_FALSE (representative.is_initialized ()); + } + // Test for optional values + request.put ("weight", "1"); + request.put ("pending", "1"); + request.put ("representative", "true"); + test_response response2 (request, rpc, system.service); + while (response2.status == 0) + { + system.poll (); + } + for (auto & accounts : response2.json.get_child ("accounts")) + { + boost::optional weight (accounts.second.get_optional ("weight")); + ASSERT_TRUE (weight.is_initialized ()); + ASSERT_EQ ("0", weight.get ()); + boost::optional pending (accounts.second.get_optional ("pending")); + ASSERT_TRUE (pending.is_initialized ()); + ASSERT_EQ ("0", pending.get ()); + boost::optional representative (accounts.second.get_optional ("representative")); + ASSERT_TRUE (representative.is_initialized ()); + ASSERT_EQ (rai::test_genesis_key.pub.to_account (), representative.get ()); } } @@ -3193,3 +3267,99 @@ TEST (rpc, wallet_create_fail) } ASSERT_EQ ("Failed to create wallet. Increase lmdb_max_dbs in node config.", response.json.get ("error")); } + +TEST (rpc, wallet_ledger) +{ + rai::system system (24000, 1); + rai::keypair key; + rai::genesis genesis; + system.wallet (0)->insert_adhoc (key.prv); + auto & node1 (*system.nodes[0]); + auto latest (system.nodes[0]->latest (rai::test_genesis_key.pub)); + rai::send_block send (latest, key.pub, 100, rai::test_genesis_key.prv, rai::test_genesis_key.pub, node1.generate_work (latest)); + system.nodes[0]->process (send); + rai::open_block open (send.hash (), rai::test_genesis_key.pub, key.pub, key.prv, key.pub, node1.generate_work (key.pub)); + ASSERT_EQ (rai::process_result::progress, system.nodes[0]->process (open).code); + auto time (rai::seconds_since_epoch ()); + rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "wallet_ledger"); + request.put ("wallet", system.nodes[0]->wallets.items.begin ()->first.to_string ()); + request.put ("sorting", "1"); + request.put ("count", "1"); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + for (auto & accounts : response.json.get_child ("accounts")) + { + std::string account_text (accounts.first); + ASSERT_EQ (key.pub.to_account (), account_text); + std::string frontier (accounts.second.get ("frontier")); + ASSERT_EQ (open.hash ().to_string (), frontier); + std::string open_block (accounts.second.get ("open_block")); + ASSERT_EQ (open.hash ().to_string (), open_block); + std::string representative_block (accounts.second.get ("representative_block")); + ASSERT_EQ (open.hash ().to_string (), representative_block); + std::string balance_text (accounts.second.get ("balance")); + ASSERT_EQ ("340282366920938463463374607431768211355", balance_text); + std::string modified_timestamp (accounts.second.get ("modified_timestamp")); + ASSERT_EQ (std::to_string (time), modified_timestamp); + std::string block_count (accounts.second.get ("block_count")); + ASSERT_EQ ("1", block_count); + boost::optional weight (accounts.second.get_optional ("weight")); + ASSERT_FALSE (weight.is_initialized ()); + boost::optional pending (accounts.second.get_optional ("pending")); + ASSERT_FALSE (pending.is_initialized ()); + boost::optional representative (accounts.second.get_optional ("representative")); + ASSERT_FALSE (representative.is_initialized ()); + } + // Test for optional values + request.put ("weight", "true"); + request.put ("pending", "1"); + request.put ("representative", "false"); + test_response response2 (request, rpc, system.service); + while (response2.status == 0) + { + system.poll (); + } + for (auto & accounts : response2.json.get_child ("accounts")) + { + boost::optional weight (accounts.second.get_optional ("weight")); + ASSERT_TRUE (weight.is_initialized ()); + ASSERT_EQ ("0", weight.get ()); + boost::optional pending (accounts.second.get_optional ("pending")); + ASSERT_TRUE (pending.is_initialized ()); + ASSERT_EQ ("0", pending.get ()); + boost::optional representative (accounts.second.get_optional ("representative")); + ASSERT_FALSE (representative.is_initialized ()); + } +} + +TEST (rpc, wallet_add_watch) +{ + rai::system system (24000, 1); + rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + std::string wallet; + system.nodes[0]->wallets.items.begin ()->first.encode_hex (wallet); + request.put ("wallet", wallet); + request.put ("action", "wallet_add_watch"); + boost::property_tree::ptree entry; + boost::property_tree::ptree peers_l; + entry.put ("", rai::test_genesis_key.pub.to_account ()); + peers_l.push_back (std::make_pair ("", entry)); + request.add_child ("accounts", peers_l); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + std::string success (response.json.get ("success")); + ASSERT_TRUE (success.empty ()); + ASSERT_TRUE (system.wallet (0)->exists (rai::test_genesis_key.pub)); +} diff --git a/rai/core_test/wallets.cpp b/rai/core_test/wallets.cpp index 8f08492b..f8ede908 100644 --- a/rai/core_test/wallets.cpp +++ b/rai/core_test/wallets.cpp @@ -76,7 +76,7 @@ TEST (wallets, wallet_create_max) rai::system system (24000, 1); bool error (false); rai::wallets wallets (error, *system.nodes[0]); - const int nonWalletDbs = 16; + const int nonWalletDbs = 17; for (int i = 0; i < system.nodes[0]->config.lmdb_max_dbs - nonWalletDbs; i++) { rai::keypair key; diff --git a/rai/lib/interface.h b/rai/lib/interface.h index 283454ce..d16db966 100644 --- a/rai/lib/interface.h +++ b/rai/lib/interface.h @@ -29,7 +29,7 @@ int xrb_valid_address (const char * account); // Create a new random number in to 'destination' void xrb_generate_random (xrb_uint256 destination); -// Retrieve the detereministic private key for 'seed' at 'index' +// Retrieve the deterministic private key for 'seed' at 'index' void xrb_seed_key (const xrb_uint256 seed, int index, xrb_uint256); // Derive the public key 'pub' from 'key' void xrb_key_account (xrb_uint256 key, xrb_uint256 pub); diff --git a/rai/node/bootstrap.cpp b/rai/node/bootstrap.cpp index 07e61611..98a7bac3 100644 --- a/rai/node/bootstrap.cpp +++ b/rai/node/bootstrap.cpp @@ -988,55 +988,58 @@ void rai::bootstrap_attempt::process_fork (MDB_txn * transaction_a, std::shared_ void rai::bootstrap_attempt::try_resolve_fork (MDB_txn * transaction_a, std::shared_ptr block_a, bool from_processor) { std::weak_ptr this_w (shared_from_this ()); - std::shared_ptr ledger_block (node->ledger.forked_block (transaction_a, *block_a)); - if (ledger_block) + if (!node->store.block_exists (transaction_a, block_a->hash ()) && node->store.block_exists (transaction_a, block_a->root ())) { - node->active.start (transaction_a, ledger_block, [this_w, block_a](std::shared_ptr, bool resolved) { - if (auto this_l = this_w.lock ()) - { - if (resolved) + std::shared_ptr ledger_block (node->ledger.forked_block (transaction_a, *block_a)); + if (ledger_block) + { + node->active.start (transaction_a, ledger_block, [this_w, block_a](std::shared_ptr, bool resolved) { + if (auto this_l = this_w.lock ()) { + if (resolved) { - std::unique_lock lock (this_l->mutex); - this_l->unresolved_forks.erase (block_a->hash ()); - this_l->condition.notify_all (); - } - rai::transaction transaction (this_l->node->store.environment, nullptr, false); - auto account (this_l->node->ledger.store.frontier_get (transaction, block_a->root ())); - if (!account.is_zero ()) - { - this_l->requeue_pull (rai::pull_info (account, block_a->root (), block_a->root ())); - } - else if (this_l->node->ledger.store.account_exists (transaction, block_a->root ())) - { - this_l->requeue_pull (rai::pull_info (block_a->root (), rai::block_hash (0), rai::block_hash (0))); + { + std::unique_lock lock (this_l->mutex); + this_l->unresolved_forks.erase (block_a->hash ()); + this_l->condition.notify_all (); + } + rai::transaction transaction (this_l->node->store.environment, nullptr, false); + auto account (this_l->node->ledger.store.frontier_get (transaction, block_a->root ())); + if (!account.is_zero ()) + { + this_l->requeue_pull (rai::pull_info (account, block_a->root (), block_a->root ())); + } + else if (this_l->node->ledger.store.account_exists (transaction, block_a->root ())) + { + this_l->requeue_pull (rai::pull_info (block_a->root (), rai::block_hash (0), rai::block_hash (0))); + } } } - } - }); + }); + + auto hash = block_a->hash (); + bool exists = true; + if (from_processor) + { + // Only add the block to the unresolved fork tracker if it's the first time we've seen it (i.e. this call came from the block processor). + std::unique_lock lock (mutex); + exists = unresolved_forks.find (hash) != unresolved_forks.end (); + if (!exists) + { + unresolved_forks[hash] = block_a; + } + } - auto hash = block_a->hash (); - bool exists = true; - if (from_processor) - { - // Only add the block to the unresolved fork tracker if it's the first time we've seen it (i.e. this call came from the block processor). - std::unique_lock lock (mutex); - exists = unresolved_forks.find (hash) != unresolved_forks.end (); if (!exists) { - unresolved_forks[hash] = block_a; + BOOST_LOG (node->log) << boost::str (boost::format ("While bootstrappping, fork between our block: %1% and block %2% both with root %3%") % ledger_block->hash ().to_string () % hash.to_string () % block_a->root ().to_string ()); + } + if (!exists || !from_processor) + { + // Only broadcast if it's a new fork, or if the request is coming from the retry loop. + node->network.broadcast_confirm_req (ledger_block); + node->network.broadcast_confirm_req (block_a); } - } - - if (!exists) - { - BOOST_LOG (node->log) << boost::str (boost::format ("While bootstrappping, fork between our block: %1% and block %2% both with root %3%") % ledger_block->hash ().to_string () % hash.to_string () % block_a->root ().to_string ()); - } - if (!exists || !from_processor) - { - // Only broadcast if it's a new fork, or if the request is coming from the retry loop. - node->network.broadcast_confirm_req (ledger_block); - node->network.broadcast_confirm_req (block_a); } } } diff --git a/rai/node/common.cpp b/rai/node/common.cpp index dd535002..67365575 100644 --- a/rai/node/common.cpp +++ b/rai/node/common.cpp @@ -1,3 +1,4 @@ + #include #include @@ -73,14 +74,13 @@ bool rai::message::read_header (rai::stream & stream_a, uint8_t & version_max_a, rai::message_parser::message_parser (rai::message_visitor & visitor_a, rai::work_pool & pool_a) : visitor (visitor_a), pool (pool_a), -error (false), -insufficient_work (false) +status (parse_status::success) { } void rai::message_parser::deserialize_buffer (uint8_t const * buffer_a, size_t size_a) { - error = false; + status = parse_status::success; rai::bufferstream header_stream (buffer_a, size_a); uint8_t version_max; uint8_t version_using; @@ -113,14 +113,14 @@ void rai::message_parser::deserialize_buffer (uint8_t const * buffer_a, size_t s } default: { - error = true; + status = parse_status::invalid_message_type; break; } } } else { - error = true; + status = parse_status::invalid_header; } } @@ -135,7 +135,7 @@ void rai::message_parser::deserialize_keepalive (uint8_t const * buffer_a, size_ } else { - error = true; + status = parse_status::invalid_keepalive_message; } } @@ -152,12 +152,12 @@ void rai::message_parser::deserialize_publish (uint8_t const * buffer_a, size_t } else { - insufficient_work = true; + status = parse_status::insufficient_work; } } else { - error = true; + status = parse_status::invalid_publish_message; } } @@ -174,12 +174,12 @@ void rai::message_parser::deserialize_confirm_req (uint8_t const * buffer_a, siz } else { - insufficient_work = true; + status = parse_status::insufficient_work; } } else { - error = true; + status = parse_status::invalid_confirm_req_message; } } @@ -196,12 +196,12 @@ void rai::message_parser::deserialize_confirm_ack (uint8_t const * buffer_a, siz } else { - insufficient_work = true; + status = parse_status::insufficient_work; } } else { - error = true; + status = parse_status::invalid_confirm_ack_message; } } @@ -241,18 +241,23 @@ void rai::keepalive::serialize (rai::stream & stream_a) bool rai::keepalive::deserialize (rai::stream & stream_a) { - auto result (read_header (stream_a, version_max, version_using, version_min, type, extensions)); - assert (!result); + auto error (read_header (stream_a, version_max, version_using, version_min, type, extensions)); + assert (!error); assert (type == rai::message_type::keepalive); - for (auto i (peers.begin ()), j (peers.end ()); i != j; ++i) + for (auto i (peers.begin ()), j (peers.end ()); i != j && !error; ++i) { std::array address; uint16_t port; - read (stream_a, address); - read (stream_a, port); - *i = rai::endpoint (boost::asio::ip::address_v6 (address), port); + if (!read (stream_a, address) && !read (stream_a, port)) + { + *i = rai::endpoint (boost::asio::ip::address_v6 (address), port); + } + else + { + error = true; + } } - return result; + return error; } bool rai::keepalive::operator== (rai::keepalive const & other_a) const diff --git a/rai/node/common.hpp b/rai/node/common.hpp index fb94c9c9..5bc6fc03 100644 --- a/rai/node/common.hpp +++ b/rai/node/common.hpp @@ -130,6 +130,17 @@ class work_pool; class message_parser { public: + enum class parse_status + { + success, + insufficient_work, + invalid_header, + invalid_message_type, + invalid_keepalive_message, + invalid_publish_message, + invalid_confirm_req_message, + invalid_confirm_ack_message + }; message_parser (rai::message_visitor &, rai::work_pool &); void deserialize_buffer (uint8_t const *, size_t); void deserialize_keepalive (uint8_t const *, size_t); @@ -139,8 +150,7 @@ public: bool at_end (rai::bufferstream &); rai::message_visitor & visitor; rai::work_pool & pool; - bool error; - bool insufficient_work; + parse_status status; }; class keepalive : public message { diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 64a26f6d..13b24c94 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -254,7 +254,7 @@ void rai::network::broadcast_confirm_req (std::shared_ptr block_a) } if (node.config.logging.network_logging ()) { - BOOST_LOG (node.log) << boost::str (boost::format ("Broadcasted confirm req to %1% representatives") % list.size ()); + BOOST_LOG (node.log) << boost::str (boost::format ("Broadcasted confirm req for block %1% to %2% representatives") % block_a->hash ().to_string () % list.size ()); } } @@ -419,17 +419,65 @@ void rai::network::receive_action (boost::system::error_code const & error, size network_message_visitor visitor (node, remote); rai::message_parser parser (visitor, node.work); parser.deserialize_buffer (buffer.data (), size_a); - if (parser.error) + if (parser.status != rai::message_parser::parse_status::success) { ++error_count; - } - else if (parser.insufficient_work) - { - if (node.config.logging.insufficient_work_logging ()) + + if (parser.status == rai::message_parser::parse_status::insufficient_work) { - BOOST_LOG (node.log) << "Insufficient work in message"; + if (node.config.logging.insufficient_work_logging ()) + { + BOOST_LOG (node.log) << "Insufficient work in message"; + } + + ++insufficient_work_count; + } + else if (parser.status == rai::message_parser::parse_status::invalid_message_type) + { + if (node.config.logging.network_logging ()) + { + BOOST_LOG (node.log) << "Invalid message type in message"; + } + } + else if (parser.status == rai::message_parser::parse_status::invalid_header) + { + if (node.config.logging.network_logging ()) + { + BOOST_LOG (node.log) << "Invalid header in message"; + } + } + else if (parser.status == rai::message_parser::parse_status::invalid_keepalive_message) + { + if (node.config.logging.network_logging ()) + { + BOOST_LOG (node.log) << "Invalid keepalive message"; + } + } + else if (parser.status == rai::message_parser::parse_status::invalid_publish_message) + { + if (node.config.logging.network_logging ()) + { + BOOST_LOG (node.log) << "Invalid publish message"; + } + } + else if (parser.status == rai::message_parser::parse_status::invalid_confirm_req_message) + { + if (node.config.logging.network_logging ()) + { + BOOST_LOG (node.log) << "Invalid confirm_req message"; + } + } + else if (parser.status == rai::message_parser::parse_status::invalid_confirm_ack_message) + { + if (node.config.logging.network_logging ()) + { + BOOST_LOG (node.log) << "Invalid confirm_ack message"; + } + } + else + { + BOOST_LOG (node.log) << "Could not deserialize buffer"; } - ++insufficient_work_count; } } else @@ -763,11 +811,8 @@ lmdb_max_dbs (128) preconfigured_representatives.push_back (rai::genesis_account); break; case rai::rai_networks::rai_beta_network: - preconfigured_peers.push_back ("rai.raiblocks.net"); - preconfigured_representatives.push_back (rai::account ("59750C057F42806F40C5D9EAA1E0263E9DB48FE385BD0172BFC573BD37EEC4A7")); - preconfigured_representatives.push_back (rai::account ("8B05C9B160DE9B006FA27DD6A368D7CA122A2EE7537C308CF22EFD3ABF5B36C3")); - preconfigured_representatives.push_back (rai::account ("91D51BF05F02698EBB4649FB06D1BBFD2E4AE2579660E8D784A002D9C0CB1BD2")); - preconfigured_representatives.push_back (rai::account ("CB35ED23D47E1A16667EDE415CD4CD05961481D7D23A43958FAE81FC12FA49FF")); + preconfigured_peers.push_back ("rai-beta.raiblocks.net"); + preconfigured_representatives.push_back (rai::account ("5DF352F3E7367A17F2ADB52B8123959602F8D94C2F295B23F6BDFFFC5FEFCA5E")); break; case rai::rai_networks::rai_live_network: preconfigured_peers.push_back ("rai.raiblocks.net"); @@ -1518,6 +1563,15 @@ block_processor_thread ([this]() { this->block_processor.process_blocks (); }) if (peers.rep_response (endpoint_a, weight_l)) { BOOST_LOG (log) << boost::str (boost::format ("Found a representative at %1%") % endpoint_a); + // Rebroadcasting all active votes to new representative + auto blocks (active.list_blocks ()); + for (auto i (blocks.begin ()), n (blocks.end ()); i != n; ++i) + { + if (*i != nullptr) + { + this->network.send_confirm_req (endpoint_a, *i); + } + } } } }); @@ -2534,16 +2588,18 @@ void rai::peer_container::rep_request (rai::endpoint const & endpoint_a) bool rai::peer_container::reachout (rai::endpoint const & endpoint_a) { - auto result (false); // Don't contact invalid IPs - result |= not_a_peer (endpoint_a); - // Don't keepalive to nodes that already sent us something - result |= known_peer (endpoint_a); - std::lock_guard lock (mutex); - auto existing (attempts.find (endpoint_a)); - result |= existing != attempts.end (); - attempts.insert ({ endpoint_a, std::chrono::steady_clock::now () }); - return result; + bool error = not_a_peer (endpoint_a); + if (!error) + { + // Don't keepalive to nodes that already sent us something + error |= known_peer (endpoint_a); + std::lock_guard lock (mutex); + auto existing (attempts.find (endpoint_a)); + error |= existing != attempts.end (); + attempts.insert ({ endpoint_a, std::chrono::steady_clock::now () }); + } + return error; } bool rai::peer_container::insert (rai::endpoint const & endpoint_a, unsigned version_a) @@ -2761,7 +2817,7 @@ rai::uint128_t rai::election::quorum_threshold (MDB_txn * transaction_a, rai::le rai::uint128_t rai::election::minimum_threshold (MDB_txn * transaction_a, rai::ledger & ledger_a) { - // Minimum number of votes needed to change our ledger, underwhich we're probably disconnected + // Minimum number of votes needed to change our ledger, under which we're probably disconnected return ledger_a.supply (transaction_a) / 16; } @@ -2854,7 +2910,7 @@ void rai::active_transactions::announce_votes () { auto election_l (i->election); node.background ([election_l]() { election_l->broadcast_winner (); }); - if (i->announcements >= contigious_announcements - 1) + if (i->announcements >= contiguous_announcements - 1) { // These blocks have reached the confirmation interval for forks i->election->confirm_cutoff (transaction); @@ -2939,6 +2995,18 @@ bool rai::active_transactions::active (rai::block const & block_a) return roots.find (block_a.root ()) != roots.end (); } +// List of active blocks in elections +std::deque> rai::active_transactions::list_blocks () +{ + std::deque> result; + std::lock_guard lock (mutex); + for (auto i (roots.begin ()), n (roots.end ()); i != n; ++i) + { + result.push_back (i->election->last_winner); + } + return result; +} + rai::active_transactions::active_transactions (rai::node & node_a) : node (node_a) { diff --git a/rai/node/node.hpp b/rai/node/node.hpp index 125000b5..4b6792f6 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -70,7 +70,7 @@ public: // Number of announcements in a row for this fork unsigned announcements; }; -// Core class for determining concensus +// Core class for determining consensus // Holds all active blocks i.e. recently added blocks that need confirmation class active_transactions { @@ -83,6 +83,7 @@ public: // Is the root of this block in the roots container bool active (rai::block const &); void announce_votes (); + std::deque> list_blocks (); void stop (); boost::multi_index_container< rai::conflict_info, @@ -94,7 +95,7 @@ public: // Maximum number of conflicts to vote on per interval, lowest root hash first static unsigned constexpr announcements_per_interval = 32; // After this many successive vote announcements, block is confirmed - static unsigned constexpr contigious_announcements = 4; + static unsigned constexpr contiguous_announcements = 4; static unsigned constexpr announce_interval_ms = (rai::rai_network == rai::rai_networks::rai_test_network) ? 10 : 16000; }; class operation @@ -247,7 +248,7 @@ public: void refresh_devices (); // Refresh when the lease ends void refresh_mapping (); - // Refresh ocassionally in case router loses mapping + // Refresh occasionally in case router loses mapping void check_mapping_loop (); int check_mapping (); bool has_address (); @@ -428,7 +429,7 @@ public: rai::vote_result vote (std::shared_ptr, rai::endpoint); rai::node & node; }; -// The network is crawled for representatives by ocassionally sending a unicast confirm_req for a specific block and watching to see if it's acknowledged with a vote. +// The network is crawled for representatives by occasionally sending a unicast confirm_req for a specific block and watching to see if it's acknowledged with a vote. class rep_crawler { public: diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 285bc657..47366e9c 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -282,12 +282,7 @@ void rai::rpc_handler::account_create () auto existing (node.wallets.items.find (wallet)); if (existing != node.wallets.items.end ()) { - bool generate_work (true); - boost::optional work (request.get_optional ("work")); - if (work.is_initialized ()) - { - generate_work = work.get (); - } + const bool generate_work = request.get ("work", true); rai::account new_key (existing->second->deterministic_insert (generate_work)); if (!new_key.is_zero ()) { @@ -340,24 +335,9 @@ void rai::rpc_handler::account_info () auto error (account.decode_account (account_text)); if (!error) { - bool representative (false); - boost::optional representative_optional (request.get_optional ("representative")); - if (representative_optional.is_initialized ()) - { - representative = representative_optional.get (); - } - bool weight (false); - boost::optional weight_optional (request.get_optional ("weight")); - if (weight_optional.is_initialized ()) - { - weight = weight_optional.get (); - } - bool pending (false); - boost::optional pending_optional (request.get_optional ("pending")); - if (pending_optional.is_initialized ()) - { - pending = pending_optional.get (); - } + const bool representative = request.get ("representative", false); + const bool weight = request.get ("weight", false); + const bool pending = request.get ("pending", false); rai::transaction transaction (node.store.environment, nullptr, false); rai::account_info info; if (!node.store.account_get (transaction, account, info)) @@ -742,12 +722,7 @@ void rai::rpc_handler::accounts_create () auto existing (node.wallets.items.find (wallet)); if (existing != node.wallets.items.end ()) { - bool generate_work (true); - boost::optional work (request.get_optional ("work")); - if (work.is_initialized ()) - { - generate_work = work.get (); - } + const bool generate_work = request.get ("work", true); boost::property_tree::ptree response_l; boost::property_tree::ptree accounts; for (auto i (0); accounts.size () < count; ++i) @@ -815,7 +790,6 @@ void rai::rpc_handler::accounts_pending () { uint64_t count (std::numeric_limits::max ()); rai::uint128_union threshold (0); - bool source (false); boost::optional count_text (request.get_optional ("count")); if (count_text.is_initialized ()) { @@ -834,11 +808,7 @@ void rai::rpc_handler::accounts_pending () error_response (response, "Bad threshold number"); } } - boost::optional source_optional (request.get_optional ("source")); - if (source_optional.is_initialized ()) - { - source = source_optional.get (); - } + const bool source = request.get ("source", false); boost::property_tree::ptree response_l; boost::property_tree::ptree pending; rai::transaction transaction (node.store.environment, nullptr, false); @@ -965,18 +935,8 @@ void rai::rpc_handler::blocks () void rai::rpc_handler::blocks_info () { - bool pending (false); - boost::optional pending_optional (request.get_optional ("pending")); - if (pending_optional.is_initialized ()) - { - pending = pending_optional.get (); - } - bool source (false); - boost::optional source_optional (request.get_optional ("source")); - if (source_optional.is_initialized ()) - { - source = source_optional.get (); - } + const bool pending = request.get ("pending", false); + const bool source = request.get ("source", false); std::vector hashes; boost::property_tree::ptree response_l; boost::property_tree::ptree blocks; @@ -1622,7 +1582,8 @@ namespace class history_visitor : public rai::block_visitor { public: - history_visitor (rai::rpc_handler & handler_a, rai::transaction & transaction_a, boost::property_tree::ptree & tree_a, rai::block_hash const & hash_a) : + history_visitor (rai::rpc_handler & handler_a, bool raw_a, rai::transaction & transaction_a, boost::property_tree::ptree & tree_a, rai::block_hash const & hash_a) : + raw (raw_a), handler (handler_a), transaction (transaction_a), tree (tree_a), @@ -1637,6 +1598,11 @@ public: tree.put ("account", account); auto amount (handler.node.ledger.amount (transaction, hash).convert_to ()); tree.put ("amount", amount); + if (raw) + { + tree.put ("destination", account); + tree.put ("balance", block_a.hashables.balance.to_string_dec ()); + } } void receive_block (rai::receive_block const & block_a) { @@ -1645,11 +1611,25 @@ public: tree.put ("account", account); auto amount (handler.node.ledger.amount (transaction, hash).convert_to ()); tree.put ("amount", amount); + if (raw) + { + tree.put ("source", block_a.hashables.source.to_string ()); + } } void open_block (rai::open_block const & block_a) { - // Report opens as a receive - tree.put ("type", "receive"); + if (raw) + { + tree.put ("type", "open"); + tree.put ("representative", block_a.hashables.representative.to_account ()); + tree.put ("source", block_a.hashables.source.to_string ()); + tree.put ("opened", block_a.hashables.account.to_account ()); + } + else + { + // Report opens as a receive + tree.put ("type", "receive"); + } if (block_a.hashables.source != rai::genesis_account) { tree.put ("account", handler.node.ledger.account (transaction, block_a.hashables.source).to_account ()); @@ -1661,17 +1641,34 @@ public: tree.put ("amount", rai::genesis_amount.convert_to ()); } } - void change_block (rai::change_block const &) + void change_block (rai::change_block const & block_a) { - // Don't report change blocks + if (raw) + { + tree.put ("type", "change"); + tree.put ("representative", block_a.hashables.representative.to_account ()); + } } void utx_block (rai::utx_block const & block_a) { + if (raw) + { + tree.put ("type", "utx"); + tree.put ("representative", block_a.hashables.representative.to_account ()); + tree.put ("link", block_a.hashables.link.to_string ()); + } auto balance (block_a.hashables.balance.number ()); auto previous_balance (handler.node.ledger.balance (transaction, block_a.hashables.previous)); if (balance < previous_balance) { - tree.put ("type", "send"); + if (raw) + { + tree.put ("subtype", "send"); + } + else + { + tree.put ("type", "send"); + } tree.put ("account", block_a.hashables.account.to_account ()); tree.put ("amount", (previous_balance - balance).convert_to ()); } @@ -1679,107 +1676,121 @@ public: { if (block_a.hashables.link.is_zero ()) { - // Don't report change blocks + if (raw) + { + tree.put ("subtype", "change"); + } } else { - tree.put ("type", "receive"); + if (raw) + { + tree.put ("subtype", "receive"); + } + else + { + tree.put ("type", "receive"); + } tree.put ("account", block_a.hashables.account.to_account ()); tree.put ("amount", (balance - previous_balance).convert_to ()); } } } rai::rpc_handler & handler; + bool raw; rai::transaction & transaction; boost::property_tree::ptree & tree; rai::block_hash const & hash; }; } -void rai::rpc_handler::history () +void rai::rpc_handler::account_history () { - std::string hash_text (request.get ("hash")); std::string count_text (request.get ("count")); + bool output_raw (request.get_optional ("raw") == true); + auto error (false); rai::block_hash hash; - if (!hash.decode_hex (hash_text)) + auto head_str (request.get_optional ("head")); + rai::transaction transaction (node.store.environment, nullptr, false); + if (head_str) { - uint64_t count; - if (!decode_unsigned (count_text, count)) + error = hash.decode_hex (*head_str); + if (error) { - boost::property_tree::ptree response_l; - boost::property_tree::ptree history; - rai::transaction transaction (node.store.environment, nullptr, false); - auto block (node.store.block_get (transaction, hash)); - while (block != nullptr && count > 0) - { - boost::property_tree::ptree entry; - history_visitor visitor (*this, transaction, entry, hash); - block->visit (visitor); - if (!entry.empty ()) - { - entry.put ("hash", hash.to_string ()); - history.push_back (std::make_pair ("", entry)); - } - hash = block->previous (); - block = node.store.block_get (transaction, hash); - --count; - } - response_l.add_child ("history", history); - response (response_l); - } - else - { - error_response (response, "Invalid count limit"); + error_response (response, "Invalid block hash"); } } else { - error_response (response, "Invalid block hash"); + std::string account_text (request.get ("account")); + rai::uint256_union account; + error = account.decode_account (account_text); + if (!error) + { + hash = node.ledger.latest (transaction, account); + } + else + { + error_response (response, "Bad account number"); + } } -} - -void rai::rpc_handler::account_history () -{ - std::string account_text (request.get ("account")); - std::string count_text (request.get ("count")); - rai::uint256_union account; - auto error (account.decode_account (account_text)); if (!error) { uint64_t count; if (!decode_unsigned (count_text, count)) { - boost::property_tree::ptree response_l; - boost::property_tree::ptree history; - rai::transaction transaction (node.store.environment, nullptr, false); - auto hash (node.ledger.latest (transaction, account)); - auto block (node.store.block_get (transaction, hash)); - while (block != nullptr && count > 0) + uint64_t offset = 0; + auto offset_text (request.get_optional ("offset")); + if (!offset_text || !decode_unsigned (*offset_text, offset)) { - boost::property_tree::ptree entry; - history_visitor visitor (*this, transaction, entry, hash); - block->visit (visitor); - if (!entry.empty ()) + boost::property_tree::ptree response_l; + boost::property_tree::ptree history; + if (!error) { - entry.put ("hash", hash.to_string ()); - history.push_back (std::make_pair ("", entry)); + auto block (node.store.block_get (transaction, hash)); + while (block != nullptr && count > 0) + { + if (offset > 0) + { + --offset; + } + else + { + boost::property_tree::ptree entry; + history_visitor visitor (*this, output_raw, transaction, entry, hash); + block->visit (visitor); + if (!entry.empty ()) + { + entry.put ("hash", hash.to_string ()); + history.push_back (std::make_pair ("", entry)); + } + --count; + } + hash = block->previous (); + block = node.store.block_get (transaction, hash); + } + response_l.add_child ("history", history); + if (!hash.is_zero ()) + { + response_l.put ("previous", hash.to_string ()); + } + response (response_l); + } + else + { + error_response (response, "Failed to decode head block hash"); } - hash = block->previous (); - block = node.store.block_get (transaction, hash); - --count; } - response_l.add_child ("history", history); - response (response_l); + else + { + error_response (response, "Invalid offset"); + } } else { error_response (response, "Invalid count limit"); } } - else - { - error_response (response, "Bad account number"); - } } void rai::rpc_handler::keepalive () @@ -1843,7 +1854,6 @@ void rai::rpc_handler::ledger () { rai::account start (0); uint64_t count (std::numeric_limits::max ()); - bool sorting (false); boost::optional account_text (request.get_optional ("account")); if (account_text.is_initialized ()) { @@ -1862,29 +1872,16 @@ void rai::rpc_handler::ledger () error_response (response, "Invalid count limit"); } } - boost::optional sorting_optional (request.get_optional ("sorting")); - if (sorting_optional.is_initialized ()) + uint64_t modified_since (0); + boost::optional modified_since_text (request.get_optional ("modified_since")); + if (modified_since_text.is_initialized ()) { - sorting = sorting_optional.get (); - } - bool representative (false); - boost::optional representative_optional (request.get_optional ("representative")); - if (representative_optional.is_initialized ()) - { - representative = representative_optional.get (); - } - bool weight (false); - boost::optional weight_optional (request.get_optional ("weight")); - if (weight_optional.is_initialized ()) - { - weight = weight_optional.get (); - } - bool pending (false); - boost::optional pending_optional (request.get_optional ("pending")); - if (pending_optional.is_initialized ()) - { - pending = pending_optional.get (); + modified_since = strtoul (modified_since_text.get ().c_str (), NULL, 10); } + const bool sorting = request.get ("sorting", false); + const bool representative = request.get ("representative", false); + const bool weight = request.get ("weight", false); + const bool pending = request.get ("pending", false); boost::property_tree::ptree response_a; boost::property_tree::ptree response_l; boost::property_tree::ptree accounts; @@ -1894,33 +1891,36 @@ void rai::rpc_handler::ledger () for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n && accounts.size () < count; ++i) { rai::account_info info (i->second); - rai::account account (i->first.uint256 ()); - boost::property_tree::ptree response_l; - response_l.put ("frontier", info.head.to_string ()); - response_l.put ("open_block", info.open_block.to_string ()); - response_l.put ("representative_block", info.rep_block.to_string ()); - std::string balance; - rai::uint128_union (info.balance).encode_dec (balance); - response_l.put ("balance", balance); - response_l.put ("modified_timestamp", std::to_string (info.modified)); - response_l.put ("block_count", std::to_string (info.block_count)); - if (representative) + if (info.modified >= modified_since) { - auto block (node.store.block_get (transaction, info.rep_block)); - assert (block != nullptr); - response_l.put ("representative", block->representative ().to_account ()); + rai::account account (i->first.uint256 ()); + boost::property_tree::ptree response_l; + response_l.put ("frontier", info.head.to_string ()); + response_l.put ("open_block", info.open_block.to_string ()); + response_l.put ("representative_block", info.rep_block.to_string ()); + std::string balance; + rai::uint128_union (info.balance).encode_dec (balance); + response_l.put ("balance", balance); + response_l.put ("modified_timestamp", std::to_string (info.modified)); + response_l.put ("block_count", std::to_string (info.block_count)); + if (representative) + { + auto block (node.store.block_get (transaction, info.rep_block)); + assert (block != nullptr); + response_l.put ("representative", block->representative ().to_account ()); + } + if (weight) + { + auto account_weight (node.ledger.weight (transaction, account)); + response_l.put ("weight", account_weight.convert_to ()); + } + if (pending) + { + auto account_pending (node.ledger.account_pending (transaction, account)); + response_l.put ("pending", account_pending.convert_to ()); + } + accounts.push_back (std::make_pair (account.to_account (), response_l)); } - if (weight) - { - auto account_weight (node.ledger.weight (transaction, account)); - response_l.put ("weight", account_weight.convert_to ()); - } - if (pending) - { - auto account_pending (node.ledger.account_pending (transaction, account)); - response_l.put ("pending", account_pending.convert_to ()); - } - accounts.push_back (std::make_pair (account.to_account (), response_l)); } } else // Sorting @@ -1928,8 +1928,12 @@ void rai::rpc_handler::ledger () std::vector> ledger_l; for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n; ++i) { - rai::uint128_union balance (rai::account_info (i->second).balance); - ledger_l.push_back (std::make_pair (balance, rai::account (i->first.uint256 ()))); + rai::account_info info (i->second); + rai::uint128_union balance (info.balance); + if (info.modified >= modified_since) + { + ledger_l.push_back (std::make_pair (balance, rai::account (i->first.uint256 ()))); + } } std::sort (ledger_l.begin (), ledger_l.end ()); std::reverse (ledger_l.begin (), ledger_l.end ()); @@ -2175,7 +2179,6 @@ void rai::rpc_handler::pending () { uint64_t count (std::numeric_limits::max ()); rai::uint128_union threshold (0); - bool source (false); boost::optional count_text (request.get_optional ("count")); if (count_text.is_initialized ()) { @@ -2194,11 +2197,7 @@ void rai::rpc_handler::pending () error_response (response, "Bad threshold number"); } } - boost::optional source_optional (request.get_optional ("source")); - if (source_optional.is_initialized ()) - { - source = source_optional.get (); - } + const bool source = request.get ("source", false); boost::property_tree::ptree response_l; boost::property_tree::ptree peers_l; { @@ -2761,7 +2760,6 @@ void rai::rpc_handler::receive_minimum_set () void rai::rpc_handler::representatives () { uint64_t count (std::numeric_limits::max ()); - bool sorting (false); boost::optional count_text (request.get_optional ("count")); if (count_text.is_initialized ()) { @@ -2771,11 +2769,7 @@ void rai::rpc_handler::representatives () error_response (response, "Invalid count limit"); } } - boost::optional sorting_optional (request.get_optional ("sorting")); - if (sorting_optional.is_initialized ()) - { - sorting = sorting_optional.get (); - } + const bool sorting = request.get ("sorting", false); boost::property_tree::ptree response_l; boost::property_tree::ptree representatives; rai::transaction transaction (node.store.environment, nullptr, false); @@ -3265,12 +3259,7 @@ void rai::rpc_handler::wallet_add () auto existing (node.wallets.items.find (wallet)); if (existing != node.wallets.items.end ()) { - bool generate_work (true); - boost::optional work (request.get_optional ("work")); - if (work.is_initialized ()) - { - generate_work = work.get (); - } + const bool generate_work = request.get ("work", true); auto pub (existing->second->insert_adhoc (key, generate_work)); if (!pub.is_zero ()) { @@ -3304,6 +3293,60 @@ void rai::rpc_handler::wallet_add () } } +void rai::rpc_handler::wallet_add_watch () +{ + if (rpc.config.enable_control) + { + std::string wallet_text (request.get ("wallet")); + rai::uint256_union wallet; + auto error (wallet.decode_hex (wallet_text)); + if (!error) + { + auto existing (node.wallets.items.find (wallet)); + if (existing != node.wallets.items.end ()) + { + rai::transaction transaction (node.store.environment, nullptr, true); + if (existing->second->store.valid_password (transaction)) + { + for (auto & accounts : request.get_child ("accounts")) + { + std::string account_text = accounts.second.data (); + rai::uint256_union account; + auto error (account.decode_account (account_text)); + if (!error) + { + existing->second->insert_watch (transaction, account); + } + else + { + error_response (response, "Bad account number"); + } + } + boost::property_tree::ptree response_l; + response_l.put ("success", ""); + response (response_l); + } + else + { + error_response (response, "Wallet locked"); + } + } + else + { + error_response (response, "Wallet not found"); + } + } + else + { + error_response (response, "Bad wallet number"); + } + } + else + { + error_response (response, "RPC control is disabled"); + } +} + void rai::rpc_handler::wallet_balance_total () { std::string wallet_text (request.get ("wallet")); @@ -3636,6 +3679,79 @@ void rai::rpc_handler::wallet_key_valid () } } +void rai::rpc_handler::wallet_ledger () +{ + const bool representative = request.get ("representative", false); + const bool weight = request.get ("weight", false); + const bool pending = request.get ("pending", false); + uint64_t modified_since (0); + boost::optional modified_since_text (request.get_optional ("modified_since")); + if (modified_since_text.is_initialized ()) + { + modified_since = strtoul (modified_since_text.get ().c_str (), NULL, 10); + } + std::string wallet_text (request.get ("wallet")); + rai::uint256_union wallet; + auto error (wallet.decode_hex (wallet_text)); + if (!error) + { + auto existing (node.wallets.items.find (wallet)); + if (existing != node.wallets.items.end ()) + { + boost::property_tree::ptree response_l; + boost::property_tree::ptree accounts; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i) + { + rai::account account (i->first.uint256 ()); + rai::account_info info; + if (!node.store.account_get (transaction, account, info)) + { + if (info.modified >= modified_since) + { + boost::property_tree::ptree entry; + entry.put ("frontier", info.head.to_string ()); + entry.put ("open_block", info.open_block.to_string ()); + entry.put ("representative_block", info.rep_block.to_string ()); + std::string balance; + rai::uint128_union (info.balance).encode_dec (balance); + entry.put ("balance", balance); + entry.put ("modified_timestamp", std::to_string (info.modified)); + entry.put ("block_count", std::to_string (info.block_count)); + if (representative) + { + auto block (node.store.block_get (transaction, info.rep_block)); + assert (block != nullptr); + entry.put ("representative", block->representative ().to_account ()); + } + if (weight) + { + auto account_weight (node.ledger.weight (transaction, account)); + entry.put ("weight", account_weight.convert_to ()); + } + if (pending) + { + auto account_pending (node.ledger.account_pending (transaction, account)); + entry.put ("pending", account_pending.convert_to ()); + } + accounts.push_back (std::make_pair (account.to_account (), entry)); + } + } + } + response_l.add_child ("accounts", accounts); + response (response_l); + } + else + { + error_response (response, "Wallet not found"); + } + } + else + { + error_response (response, "Bad wallet number"); + } +} + void rai::rpc_handler::wallet_lock () { if (rpc.config.enable_control) @@ -3683,7 +3799,6 @@ void rai::rpc_handler::wallet_pending () { uint64_t count (std::numeric_limits::max ()); rai::uint128_union threshold (0); - bool source (false); boost::optional count_text (request.get_optional ("count")); if (count_text.is_initialized ()) { @@ -3702,11 +3817,7 @@ void rai::rpc_handler::wallet_pending () error_response (response, "Bad threshold number"); } } - boost::optional source_optional (request.get_optional ("source")); - if (source_optional.is_initialized ()) - { - source = source_optional.get (); - } + const bool source = request.get ("source", false); boost::property_tree::ptree response_l; boost::property_tree::ptree pending; rai::transaction transaction (node.store.environment, nullptr, false); @@ -4453,7 +4564,8 @@ void rai::rpc_handler::process_request () } else if (action == "history") { - history (); + request.put ("head", request.get ("hash")); + account_history (); } else if (action == "keepalive") { @@ -4603,6 +4715,10 @@ void rai::rpc_handler::process_request () { wallet_add (); } + else if (action == "wallet_add_watch") + { + wallet_add_watch (); + } else if (action == "wallet_balance_total") { wallet_balance_total (); @@ -4639,6 +4755,10 @@ void rai::rpc_handler::process_request () { wallet_key_valid (); } + else if (action == "wallet_ledger") + { + wallet_ledger (); + } else if (action == "wallet_lock") { wallet_lock (); diff --git a/rai/node/rpc.hpp b/rai/node/rpc.hpp index 2bf0b6f9..91ca8a39 100644 --- a/rai/node/rpc.hpp +++ b/rai/node/rpc.hpp @@ -185,6 +185,7 @@ public: void validate_account_number (); void version (); void wallet_add (); + void wallet_add_watch (); void wallet_balance_total (); void wallet_balances (); void wallet_change_seed (); @@ -194,6 +195,7 @@ public: void wallet_export (); void wallet_frontiers (); void wallet_key_valid (); + void wallet_ledger (); void wallet_lock (); void wallet_pending (); void wallet_representative (); diff --git a/rai/node/testing.cpp b/rai/node/testing.cpp index a8f0d1dd..ff3f0021 100644 --- a/rai/node/testing.cpp +++ b/rai/node/testing.cpp @@ -410,13 +410,13 @@ void rai::landing::write_store () rai::uint128_t rai::landing::distribution_amount (uint64_t interval) { - // Halfing period ~= Exponent of 2 in secounds approixmately 1 year = 2^25 = 33554432 + // Halving period ~= Exponent of 2 in seconds approximately 1 year = 2^25 = 33554432 // Interval = Exponent of 2 in seconds approximately 1 minute = 2^10 = 64 uint64_t intervals_per_period (1 << (25 - interval_exponent)); rai::uint128_t result; if (interval < intervals_per_period * 1) { - // Total supply / 2^halfing period / intervals per period + // Total supply / 2^halving period / intervals per period // 2^128 / 2^1 / (2^25 / 2^10) result = rai::uint128_t (1) << (127 - (25 - interval_exponent)); // 50% } diff --git a/rai/node/utility.hpp b/rai/node/utility.hpp index c6b55955..d5fb7c87 100644 --- a/rai/node/utility.hpp +++ b/rai/node/utility.hpp @@ -26,7 +26,7 @@ using vectorstream = boost::iostreams::stream_buffer diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index 27347a6d..d0297d1e 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -252,7 +252,7 @@ unsigned const rai::wallet_store::version_3 (3); unsigned const rai::wallet_store::version_current (version_3); // Wallet version number rai::uint256_union const rai::wallet_store::version_special (0); -// Random number used to salt private key encription +// Random number used to salt private key encryption rai::uint256_union const rai::wallet_store::salt_special (1); // Key used to encrypt wallet keys, encrypted itself by the user password rai::uint256_union const rai::wallet_store::wallet_key_special (2); @@ -420,6 +420,11 @@ rai::public_key rai::wallet_store::insert_adhoc (MDB_txn * transaction_a, rai::r return pub; } +void rai::wallet_store::insert_watch (MDB_txn * transaction_a, rai::public_key const & pub) +{ + entry_put_raw (transaction_a, pub, rai::wallet_value (rai::uint256_union (0), 0)); +} + void rai::wallet_store::erase (MDB_txn * transaction_a, rai::public_key const & pub) { auto status (mdb_del (transaction_a, handle, rai::mdb_val (pub), nullptr)); @@ -790,6 +795,11 @@ rai::public_key rai::wallet::insert_adhoc (rai::raw_key const & account_a, bool return result; } +void rai::wallet::insert_watch (MDB_txn * transaction_a, rai::public_key const & pub_a) +{ + store.insert_watch (transaction_a, pub_a); +} + bool rai::wallet::exists (rai::public_key const & account_a) { rai::transaction transaction (store.environment, nullptr, false); @@ -1159,7 +1169,11 @@ public: { for (auto i (wallet_a->store.begin (transaction_a)), n (wallet_a->store.end ()); i != n; ++i) { - keys.insert (i->first.uint256 ()); + // Don't search pending for watch-only accounts + if (!rai::wallet_value (i->second).key.is_zero ()) + { + keys.insert (i->first.uint256 ()); + } } } void run () diff --git a/rai/node/wallet.hpp b/rai/node/wallet.hpp index b354b95b..836aedfa 100644 --- a/rai/node/wallet.hpp +++ b/rai/node/wallet.hpp @@ -74,6 +74,7 @@ public: rai::account representative (MDB_txn *); void representative_set (MDB_txn *, rai::account const &); rai::public_key insert_adhoc (MDB_txn *, rai::raw_key const &); + void insert_watch (MDB_txn *, rai::public_key const &); void erase (MDB_txn *, rai::public_key const &); rai::wallet_value entry_get_raw (MDB_txn *, rai::public_key const &); void entry_put_raw (MDB_txn *, rai::public_key const &, rai::wallet_value const &); @@ -132,6 +133,7 @@ public: bool enter_password (std::string const &); rai::public_key insert_adhoc (rai::raw_key const &, bool = true); rai::public_key insert_adhoc (MDB_txn *, rai::raw_key const &, bool = true); + void insert_watch (MDB_txn *, rai::public_key const &); rai::public_key deterministic_insert (MDB_txn *, bool = true); rai::public_key deterministic_insert (bool = true); bool exists (rai::public_key const &); diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index 5db861be..42dd4f4a 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -1394,7 +1394,7 @@ wallet (wallet_a) auto block (this->wallet.wallet_m->change_sync (this->wallet.account, representative_l)); change_rep->setEnabled (true); show_button_success (*change_rep); - change_rep->setText ("Represenative was changed"); + change_rep->setText ("Representative was changed"); current_representative->setText (QString (representative_l.to_account_split ().c_str ())); new_representative->clear (); this->wallet.node.alarm.add (std::chrono::steady_clock::now () + std::chrono::seconds (5), [this]() { diff --git a/rai/rai_node/daemon.cpp b/rai/rai_node/daemon.cpp index 6c84bc3c..181aac00 100644 --- a/rai/rai_node/daemon.cpp +++ b/rai/rai_node/daemon.cpp @@ -124,7 +124,7 @@ void rai_daemon::daemon::run (boost::filesystem::path const & data_path) { rpc->start (); } - runner.reset (new rai::thread_runner (service, node->config.io_threads)); + runner = std::make_unique (service, node->config.io_threads); runner->join (); } else From 0bc0493194f35a170017d26a8265602de0870219 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Thu, 8 Mar 2018 16:52:02 -0700 Subject: [PATCH 26/36] Add is_send to utx block callbacks (#715) --- rai/common.hpp | 1 + rai/core_test/node.cpp | 2 +- rai/ledger.cpp | 1 + rai/node/node.cpp | 16 ++++++++++------ rai/node/node.hpp | 2 +- rai/node/rpc.cpp | 6 +++--- rai/qt/qt.cpp | 8 ++++---- 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/rai/common.hpp b/rai/common.hpp index 63bda498..de6d9b9a 100644 --- a/rai/common.hpp +++ b/rai/common.hpp @@ -234,6 +234,7 @@ public: rai::account account; rai::amount amount; rai::account pending_account; + boost::optional utx_is_send; }; enum class tally_result { diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index 7d6ca1ff..aeb91ed1 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -1032,7 +1032,7 @@ TEST (node, coherent_observer) { rai::system system (24000, 1); auto & node1 (*system.nodes[0]); - node1.observers.blocks.add ([&node1](std::shared_ptr block_a, rai::account const & account_a, rai::amount const &) { + node1.observers.blocks.add ([&node1](std::shared_ptr block_a, rai::process_return const &) { rai::transaction transaction (node1.store.environment, nullptr, false); ASSERT_TRUE (node1.store.block_exists (transaction, block_a->hash ())); }); diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 745f95a2..78892b66 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -206,6 +206,7 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) // Account does not yet exists result.code = block_a.previous ().is_zero () ? rai::process_result::progress : rai::process_result::gap_previous; // Does the first block in an account yield 0 for previous() ? (Unambigious) } + result.utx_is_send = is_send; if (result.code == rai::process_result::progress) { if (!is_send) diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 13b24c94..8007259a 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -1246,7 +1246,7 @@ void rai::block_processor::process_receive_many (std::deque 0) { node.observers.account_balance (i.second.account, false); @@ -1438,27 +1438,31 @@ block_processor_thread ([this]() { this->block_processor.process_blocks (); }) peers.disconnect_observer = [this]() { observers.disconnect (); }; - observers.blocks.add ([this](std::shared_ptr block_a, rai::account const & account_a, rai::amount const & amount_a) { + observers.blocks.add ([this](std::shared_ptr block_a, rai::process_return const & result_a) { if (this->block_arrival.recent (block_a->hash ())) { rai::transaction transaction (store.environment, nullptr, true); active.start (transaction, block_a); } }); - observers.blocks.add ([this](std::shared_ptr block_a, rai::account const & account_a, rai::amount const & amount_a) { + observers.blocks.add ([this](std::shared_ptr block_a, rai::process_return const & result_a) { if (this->block_arrival.recent (block_a->hash ())) { auto node_l (shared_from_this ()); - background ([node_l, block_a, account_a, amount_a]() { + background ([node_l, block_a, result_a]() { if (!node_l->config.callback_address.empty ()) { boost::property_tree::ptree event; - event.add ("account", account_a.to_account ()); + event.add ("account", result_a.account.to_account ()); event.add ("hash", block_a->hash ().to_string ()); std::string block_text; block_a->serialize_json (block_text); event.add ("block", block_text); - event.add ("amount", amount_a.to_string_dec ()); + event.add ("amount", result_a.amount.to_string_dec ()); + if (result_a.utx_is_send) + { + event.add ("is_send", *result_a.utx_is_send); + } std::stringstream ostream; boost::property_tree::write_json (ostream, event); ostream.flush (); diff --git a/rai/node/node.hpp b/rai/node/node.hpp index 4b6792f6..5811328c 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -414,7 +414,7 @@ public: class node_observers { public: - rai::observer_set, rai::account const &, rai::amount const &> blocks; + rai::observer_set, rai::process_return const &> blocks; rai::observer_set wallet; rai::observer_set, rai::endpoint const &> vote; rai::observer_set account_balance; diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 47366e9c..d16c252b 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -141,8 +141,8 @@ void rai::rpc::start () } acceptor.listen (); - node.observers.blocks.add ([this](std::shared_ptr block_a, rai::account const & account_a, rai::amount const &) { - observer_action (account_a); + node.observers.blocks.add ([this](std::shared_ptr block_a, rai::process_return const & result_a) { + observer_action (result_a.account); }); accept (); @@ -2491,7 +2491,7 @@ void rai::rpc_handler::process () { case rai::process_result::progress: { - node.observers.blocks (block_a, result.account, result.amount); + node.observers.blocks (block_a, result); boost::property_tree::ptree response_l; response_l.put ("hash", hash.to_string ()); response (response_l); diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index 42dd4f4a..6543f349 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -1099,17 +1099,17 @@ void rai_qt::wallet::start () this_l->push_main_stack (this_l->send_blocks_window); } }); - node.observers.blocks.add ([this_w](std::shared_ptr block_a, rai::account const & account_a, rai::amount const &) { + node.observers.blocks.add ([this_w](std::shared_ptr block_a, rai::process_return const & result_a) { if (auto this_l = this_w.lock ()) { - this_l->application.postEvent (&this_l->processor, new eventloop_event ([this_w, block_a, account_a]() { + this_l->application.postEvent (&this_l->processor, new eventloop_event ([ this_w, block_a, result_a.account ]() { if (auto this_l = this_w.lock ()) { - if (this_l->wallet_m->exists (account_a)) + if (this_l->wallet_m->exists (result_a.account)) { this_l->accounts.refresh (); } - if (account_a == this_l->account) + if (result_a.account == this_l->account) { this_l->history.refresh (); } From e926378b8a1370ce23b81eae62e55c9003fc1723 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Fri, 9 Mar 2018 11:33:01 -0600 Subject: [PATCH 27/36] Fixing new callback signature. --- rai/qt/qt.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index 6543f349..16cf212d 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -1102,14 +1102,15 @@ void rai_qt::wallet::start () node.observers.blocks.add ([this_w](std::shared_ptr block_a, rai::process_return const & result_a) { if (auto this_l = this_w.lock ()) { - this_l->application.postEvent (&this_l->processor, new eventloop_event ([ this_w, block_a, result_a.account ]() { + auto account (result_a.account); + this_l->application.postEvent (&this_l->processor, new eventloop_event ([ this_w, block_a, account ]() { if (auto this_l = this_w.lock ()) { - if (this_l->wallet_m->exists (result_a.account)) + if (this_l->wallet_m->exists (account)) { this_l->accounts.refresh (); } - if (result_a.account == this_l->account) + if (account == this_l->account) { this_l->history.refresh (); } From ffd0770a940a18e5f23c67ebd199300484ac3046 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Fri, 9 Mar 2018 12:51:22 -0600 Subject: [PATCH 28/36] Adding explicit check for opening the burn account in utx blocks. --- rai/ledger.cpp | 133 +++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 78892b66..fe34a077 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -182,85 +182,90 @@ void ledger_processor::utx_block (rai::utx_block const & block_a) result.code = validate_message (block_a.hashables.account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Unambiguous) if (result.code == rai::process_result::progress) { - rai::account_info info; - result.amount = block_a.hashables.balance; - bool is_send (false); - auto account_error (ledger.store.account_get (transaction, block_a.hashables.account, info)); - if (!account_error) + result.code = block_a.hashables.account.is_zero () ? rai::process_result::opened_burn_account : rai::process_result::progress; // Is this for the burn account? (Unambiguous) + if (result.code == rai::process_result::progress) { - // Account already exists - result.code = block_a.hashables.previous.is_zero () ? rai::process_result::fork : rai::process_result::progress; // Has this account already been opened? (Ambigious) - if (result.code == rai::process_result::progress) + rai::account_info info; + result.amount = block_a.hashables.balance; + auto is_send (false); + auto account_error (ledger.store.account_get (transaction, block_a.hashables.account, info)); + if (!account_error) { - result.code = ledger.store.block_exists (transaction, block_a.hashables.previous) ? rai::process_result::progress : rai::process_result::gap_previous; // Does the previous block exist in the ledger? (Unambigious) + // Account already exists + result.code = block_a.hashables.previous.is_zero () ? rai::process_result::fork : rai::process_result::progress; // Has this account already been opened? (Ambigious) if (result.code == rai::process_result::progress) { - is_send = block_a.hashables.balance < info.balance; - result.amount = result.amount.number () - info.balance.number (); - result.code = block_a.hashables.previous == info.head ? rai::process_result::progress : rai::process_result::fork; // Is the previous block the account's head block? (Ambigious) - } - } - } - else - { - // Account does not yet exists - result.code = block_a.previous ().is_zero () ? rai::process_result::progress : rai::process_result::gap_previous; // Does the first block in an account yield 0 for previous() ? (Unambigious) - } - result.utx_is_send = is_send; - if (result.code == rai::process_result::progress) - { - if (!is_send) - { - if (!block_a.hashables.link.is_zero ()) - { - result.code = ledger.store.block_exists (transaction, block_a.hashables.link) ? rai::process_result::progress : rai::process_result::gap_source; // Have we seen the source block already? (Harmless) + result.code = ledger.store.block_exists (transaction, block_a.hashables.previous) ? rai::process_result::progress : rai::process_result::gap_previous; // Does the previous block exist in the ledger? (Unambigious) if (result.code == rai::process_result::progress) { - rai::pending_key key (block_a.hashables.account, block_a.hashables.link); - rai::pending_info pending; - result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed) - if (result.code == rai::process_result::progress) - { - result.code = result.amount == pending.amount ? rai::process_result::progress : rai::process_result::balance_mismatch; - } + is_send = block_a.hashables.balance < info.balance; + result.amount = result.amount.number () - info.balance.number (); + result.code = block_a.hashables.previous == info.head ? rai::process_result::progress : rai::process_result::fork; // Is the previous block the account's head block? (Ambigious) } } - else + } + else + { + // Account does not yet exists + result.code = block_a.previous ().is_zero () ? rai::process_result::progress : rai::process_result::gap_previous; // Does the first block in an account yield 0 for previous() ? (Unambigious) + } + if (result.code == rai::process_result::progress) + { + if (!is_send) { - result.code = result.amount.is_zero () ? rai::process_result::progress : rai::process_result::balance_mismatch; + if (!block_a.hashables.link.is_zero ()) + { + result.code = ledger.store.block_exists (transaction, block_a.hashables.link) ? rai::process_result::progress : rai::process_result::gap_source; // Have we seen the source block already? (Harmless) + if (result.code == rai::process_result::progress) + { + rai::pending_key key (block_a.hashables.account, block_a.hashables.link); + rai::pending_info pending; + result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed) + if (result.code == rai::process_result::progress) + { + result.code = result.amount == pending.amount ? rai::process_result::progress : rai::process_result::balance_mismatch; + } + } + } + else + { + // If there's no link, the balance must remain the same, only the representative can change + result.code = result.amount.is_zero () ? rai::process_result::progress : rai::process_result::balance_mismatch; + } } } - } - if (result.code == rai::process_result::progress) - { - ledger.store.block_put (transaction, hash, block_a); + if (result.code == rai::process_result::progress) + { + result.utx_is_send = is_send; + ledger.store.block_put (transaction, hash, block_a); - if (!info.rep_block.is_zero ()) - { - // Move existing representation - ledger.store.representation_add (transaction, info.rep_block, 0 - info.balance.number ()); - } - // Add in amount delta - ledger.store.representation_add (transaction, hash, block_a.hashables.balance.number ()); + if (!info.rep_block.is_zero ()) + { + // Move existing representation + ledger.store.representation_add (transaction, info.rep_block, 0 - info.balance.number ()); + } + // Add in amount delta + ledger.store.representation_add (transaction, hash, block_a.hashables.balance.number ()); - if (is_send) - { - rai::pending_key key (block_a.hashables.link, hash); - rai::pending_info info (block_a.hashables.account, 0 - result.amount.number ()); - ledger.store.pending_put (transaction, key, info); - } - else if (!block_a.hashables.link.is_zero ()) - { - ledger.store.pending_del (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link)); - } + if (is_send) + { + rai::pending_key key (block_a.hashables.link, hash); + rai::pending_info info (block_a.hashables.account, 0 - result.amount.number ()); + ledger.store.pending_put (transaction, key, info); + } + else if (!block_a.hashables.link.is_zero ()) + { + ledger.store.pending_del (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link)); + } - ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1); - if (!ledger.store.frontier_get (transaction, info.head).is_zero ()) - { - ledger.store.frontier_del (transaction, info.head); + ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1); + if (!ledger.store.frontier_get (transaction, info.head).is_zero ()) + { + ledger.store.frontier_del (transaction, info.head); + } + // Frontier table is unnecessary for utx blocks and this also prevents old blocks from being inserted on top of utx blocks + result.account = block_a.hashables.account; } - // Frontier table is unnecessary for utx blocks and this also prevents old blocks from being inserted on top of utx blocks - result.account = block_a.hashables.account; } } } From 91099d9d8483b318220d17e2838b99dc927ef6ab Mon Sep 17 00:00:00 2001 From: clemahieu Date: Fri, 9 Mar 2018 18:23:57 -0600 Subject: [PATCH 29/36] Adding canary hashes for enabling ublock parsing and generation. --- rai/common.hpp | 1 + rai/core_test/ledger.cpp | 50 +++++++++++++++++++++++++++++++++++++++ rai/core_test/network.cpp | 3 +++ rai/core_test/rpc.cpp | 4 +++- rai/ledger.cpp | 25 ++++++++++++++++---- rai/ledger.hpp | 7 ++++-- rai/node/node.cpp | 10 ++++++++ rai/node/rpc.cpp | 5 ++++ rai/node/testing.cpp | 2 +- rai/node/wallet.cpp | 8 +++---- rai/qt/qt.cpp | 2 +- rai/slow_test/node.cpp | 33 ++++++++++++++++++++++++++ 12 files changed, 137 insertions(+), 13 deletions(-) diff --git a/rai/common.hpp b/rai/common.hpp index de6d9b9a..b8e545a8 100644 --- a/rai/common.hpp +++ b/rai/common.hpp @@ -221,6 +221,7 @@ enum class process_result unreceivable, // Source block doesn't exist or has already been received gap_previous, // Block marked as previous is unknown gap_source, // Block marked as source is unknown + utx_disabled, // Awaiting UTX canary block not_receive_from_send, // Receive does not have a send source account_mismatch, // Account number in open block doesn't match send destination opened_burn_account, // The impossible happened, someone found the private key associated with the public key '0'. diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index e76f579c..83f5aeab 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1478,6 +1478,7 @@ TEST (ledger, block_destination_source) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair dest; @@ -1522,6 +1523,7 @@ TEST (ledger, utx_account) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1536,6 +1538,7 @@ TEST (ledger, utx_send_receive) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1567,6 +1570,7 @@ TEST (ledger, utx_receive) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::send_block send1 (genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1596,6 +1600,7 @@ TEST (ledger, utx_rep_change) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair rep; @@ -1618,6 +1623,7 @@ TEST (ledger, utx_open) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; @@ -1651,6 +1657,7 @@ TEST (ledger, send_after_utx_fail) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1667,6 +1674,7 @@ TEST (ledger, receive_after_utx_fail) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1683,6 +1691,7 @@ TEST (ledger, change_after_utx_fail) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1699,6 +1708,7 @@ TEST (ledger, utx_unreceivable_fail) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::send_block send1 (genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1721,6 +1731,7 @@ TEST (ledger, utx_receive_bad_amount_fail) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::send_block send1 (genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1743,6 +1754,7 @@ TEST (ledger, utx_no_link_amount_fail) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1759,6 +1771,7 @@ TEST (ledger, utx_receive_wrong_account_fail) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1782,6 +1795,7 @@ TEST (ledger, utx_open_utx_fork) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; @@ -1801,6 +1815,7 @@ TEST (ledger, utx_utx_open_fork) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; @@ -1820,6 +1835,7 @@ TEST (ledger, utx_open_previous_fail) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; @@ -1836,6 +1852,7 @@ TEST (ledger, utx_send_change) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair rep; @@ -1858,6 +1875,7 @@ TEST (ledger, utx_receive_change) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1889,6 +1907,7 @@ TEST (ledger, utx_open_old) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; @@ -1908,6 +1927,7 @@ TEST (ledger, utx_receive_old) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; @@ -1931,6 +1951,7 @@ TEST (ledger, utx_rollback_send) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1960,6 +1981,7 @@ TEST (ledger, utx_rollback_receive) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -1984,6 +2006,7 @@ TEST (ledger, utx_rollback_received_send) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair key; @@ -2009,6 +2032,7 @@ TEST (ledger, utx_rep_change_rollback) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair rep; @@ -2028,6 +2052,7 @@ TEST (ledger, utx_open_rollback) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair destination; @@ -2052,6 +2077,7 @@ TEST (ledger, utx_send_change_rollback) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::keypair rep; @@ -2071,6 +2097,7 @@ TEST (ledger, utx_receive_change_rollback) ASSERT_TRUE (!init); rai::ledger ledger (store); rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -2084,3 +2111,26 @@ TEST (ledger, utx_receive_change_rollback) ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account)); ASSERT_EQ (0, ledger.weight (transaction, rep.pub)); } + +TEST (ledger, utx_canary_blocks) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::genesis genesis; + rai::send_block parse_canary (genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::send_block generate_canary (parse_canary.hash (), rai::test_genesis_key.pub, rai::genesis_amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + rai::ledger ledger (store, 0, parse_canary.hash (), generate_canary.hash ()); + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::utx_block utx (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_FALSE (ledger.utx_parsing_enabled (transaction)); + ASSERT_FALSE (ledger.utx_generation_enabled (transaction)); + ASSERT_EQ (rai::process_result::utx_disabled, ledger.process (transaction, utx).code); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, parse_canary).code); + ASSERT_TRUE (ledger.utx_parsing_enabled (transaction)); + ASSERT_FALSE (ledger.utx_generation_enabled (transaction)); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, generate_canary).code); + ASSERT_TRUE (ledger.utx_parsing_enabled (transaction)); + ASSERT_TRUE (ledger.utx_generation_enabled (transaction)); +} diff --git a/rai/core_test/network.cpp b/rai/core_test/network.cpp index dcab2e67..480e902c 100644 --- a/rai/core_test/network.cpp +++ b/rai/core_test/network.cpp @@ -554,8 +554,10 @@ TEST (bootstrap_processor, process_two) TEST (bootstrap_processor, process_utx) { rai::system system (24000, 1); + rai::genesis genesis; system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); auto node0 (system.nodes[0]); + node0->ledger.utx_parse_canary = genesis.hash (); std::unique_ptr block1 (new rai::utx_block (rai::test_genesis_key.pub, node0->latest (rai::test_genesis_key.pub), rai::test_genesis_key.pub, rai::genesis_amount - 100, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0)); std::unique_ptr block2 (new rai::utx_block (rai::test_genesis_key.pub, block1->hash (), rai::test_genesis_key.pub, rai::genesis_amount, block1->hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0)); node0->generate_work (*block1); @@ -564,6 +566,7 @@ TEST (bootstrap_processor, process_utx) node0->process (*block2); rai::node_init init1; auto node1 (std::make_shared (init1, system.service, 24001, rai::unique_path (), system.alarm, system.logging, system.work)); + node1->ledger.utx_parse_canary = genesis.hash (); ASSERT_EQ (node0->latest (rai::test_genesis_key.pub), block2->hash ()); ASSERT_NE (node1->latest (rai::test_genesis_key.pub), block2->hash ()); node1->bootstrap_initiator.bootstrap (node0->network.endpoint ()); diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index 584fef99..537e772b 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -880,6 +880,8 @@ TEST (rpc, history) auto receive (system.wallet (0)->receive_action (static_cast (*send), rai::test_genesis_key.pub, system.nodes[0]->config.receive_minimum.number ())); ASSERT_NE (nullptr, receive); auto node0 (system.nodes[0]); + rai::genesis genesis; + node0->ledger.utx_parse_canary = genesis.hash (); rai::utx_block usend (rai::genesis_account, node0->latest (rai::genesis_account), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); rai::utx_block ureceive (rai::genesis_account, usend.hash (), rai::genesis_account, rai::genesis_amount, usend.hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); rai::utx_block uchange (rai::genesis_account, ureceive.hash (), rai::keypair ().pub, rai::genesis_amount, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); @@ -925,7 +927,6 @@ TEST (rpc, history) ASSERT_EQ (rai::test_genesis_key.pub.to_account (), std::get<1> (history_l[3])); ASSERT_EQ (system.nodes[0]->config.receive_minimum.to_string_dec (), std::get<2> (history_l[3])); ASSERT_EQ (send->hash ().to_string (), std::get<3> (history_l[3])); - rai::genesis genesis; ASSERT_EQ ("receive", std::get<0> (history_l[4])); ASSERT_EQ (rai::test_genesis_key.pub.to_account (), std::get<1> (history_l[4])); ASSERT_EQ (rai::genesis_amount.convert_to (), std::get<2> (history_l[4])); @@ -3172,6 +3173,7 @@ TEST (rpc, block_create_utx) rai::system system (24000, 1); rai::keypair key; rai::genesis genesis; + system.nodes[0]->ledger.utx_parse_canary = genesis.hash (); system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); boost::property_tree::ptree request; request.put ("action", "block_create"); diff --git a/rai/ledger.cpp b/rai/ledger.cpp index fe34a077..fb31f140 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -167,12 +167,22 @@ public: void open_block (rai::open_block const &) override; void change_block (rai::change_block const &) override; void utx_block (rai::utx_block const &) override; + void utx_block_impl (rai::utx_block const &); rai::ledger & ledger; MDB_txn * transaction; rai::process_return result; }; void ledger_processor::utx_block (rai::utx_block const & block_a) +{ + result.code = ledger.utx_parsing_enabled (transaction) ? rai::process_result::progress : rai::process_result::utx_disabled; + if (result.code == rai::process_result::progress) + { + utx_block_impl (block_a); + } +} + +void ledger_processor::utx_block_impl (rai::utx_block const & block_a) { auto hash (block_a.hash ()); auto existing (ledger.store.block_exists (transaction, hash)); @@ -481,10 +491,12 @@ bool rai::shared_ptr_block_hash::operator() (std::shared_ptr const & return *lhs == *rhs; } -rai::ledger::ledger (rai::block_store & store_a, rai::uint128_t const & inactive_supply_a) : +rai::ledger::ledger (rai::block_store & store_a, rai::uint128_t const & inactive_supply_a, rai::block_hash const & utx_parse_canary_a, rai::block_hash const & utx_generate_canary_a) : store (store_a), inactive_supply (inactive_supply_a), -check_bootstrap_weights (true) +check_bootstrap_weights (true), +utx_parse_canary (utx_parse_canary_a), +utx_generate_canary (utx_generate_canary_a) { } @@ -778,9 +790,14 @@ void rai::ledger::dump_account_chain (rai::account const & account_a) } } -bool rai::ledger::utx_enabled (MDB_txn * transaction_a) +bool rai::ledger::utx_parsing_enabled (MDB_txn * transaction_a) { - return false; + return store.block_exists (transaction_a, utx_parse_canary); +} + +bool rai::ledger::utx_generation_enabled (MDB_txn * transaction_a) +{ + return utx_parsing_enabled (transaction_a) && store.block_exists (transaction_a, utx_generate_canary); } void rai::ledger::checksum_update (MDB_txn * transaction_a, rai::block_hash const & hash_a) diff --git a/rai/ledger.hpp b/rai/ledger.hpp index c345e29d..3cd17fec 100644 --- a/rai/ledger.hpp +++ b/rai/ledger.hpp @@ -16,7 +16,7 @@ public: class ledger { public: - ledger (rai::block_store &, rai::uint128_t const & = 0); + ledger (rai::block_store &, rai::uint128_t const & = 0, rai::block_hash const & = 0, rai::block_hash const & = 0); std::pair> winner (MDB_txn *, rai::votes const & votes_a); // Map of weight -> associated block, ordered greatest to least std::map, std::greater> tally (MDB_txn *, rai::votes const &); @@ -45,12 +45,15 @@ public: void checksum_update (MDB_txn *, rai::block_hash const &); rai::checksum checksum (MDB_txn *, rai::account const &, rai::account const &); void dump_account_chain (rai::account const &); - bool utx_enabled (MDB_txn *); + bool utx_parsing_enabled (MDB_txn *); + bool utx_generation_enabled (MDB_txn *); static rai::uint128_t const unit; rai::block_store & store; rai::uint128_t inactive_supply; std::unordered_map bootstrap_weights; uint64_t bootstrap_weight_max_blocks; std::atomic check_bootstrap_weights; + rai::block_hash utx_parse_canary; + rai::block_hash utx_generate_canary; }; }; diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 8007259a..add91a1d 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -1295,6 +1295,16 @@ rai::process_return rai::block_processor::process_receive_one (MDB_txn * transac node.gap_cache.add (transaction_a, block_a); break; } + case rai::process_result::utx_disabled: + { + if (node.config.logging.ledger_logging ()) + { + BOOST_LOG (node.log) << boost::str (boost::format ("UTX blocks are disabled: %1%") % block_a->hash ().to_string ()); + } + node.store.unchecked_put (transaction_a, node.ledger.utx_parse_canary, block_a); + node.gap_cache.add (transaction_a, block_a); + break; + } case rai::process_result::old: { { diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index d16c252b..6059cf3c 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -2507,6 +2507,11 @@ void rai::rpc_handler::process () error_response (response, "Gap source block"); break; } + case rai::process_result::utx_disabled: + { + error_response (response, "UTX blocks are disabled"); + break; + } case rai::process_result::old: { error_response (response, "Old block"); diff --git a/rai/node/testing.cpp b/rai/node/testing.cpp index ff3f0021..9703fd5f 100644 --- a/rai/node/testing.cpp +++ b/rai/node/testing.cpp @@ -303,7 +303,7 @@ void rai::system::generate_mass_activity (uint32_t count_a, rai::node & node_a) count = block_counts.sum (); utx = block_counts.utx; } - std::cerr << boost::str (boost::format ("Mass activity iteration %1% us %2% us/t %3% utx: %4% count: %5%\n") % i % us % (us / 256) % utx % count); + std::cerr << boost::str (boost::format ("Mass activity iteration %1% us %2% us/t %3% utx: %4% old: %5%\n") % i % us % (us / 256) % utx % (count - utx)); previous = now; } generate_activity (node_a, accounts); diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index d0297d1e..04d62957 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -865,7 +865,7 @@ std::shared_ptr rai::wallet::receive_action (rai::block const & send { std::shared_ptr rep_block = node.ledger.store.block_get (transaction, info.rep_block); assert (rep_block != nullptr); - if (node.ledger.utx_enabled (transaction)) + if (node.ledger.utx_generation_enabled (transaction)) { block.reset (new rai::utx_block (account, info.head, rep_block->representative (), info.balance.number () + pending_info.amount.number (), hash, prv, account, generate_work_a ? work_fetch (transaction, account, info.head) : 0)); } @@ -876,7 +876,7 @@ std::shared_ptr rai::wallet::receive_action (rai::block const & send } else { - if (node.ledger.utx_enabled (transaction)) + if (node.ledger.utx_generation_enabled (transaction)) { block.reset (new rai::utx_block (account, info.head, representative_a, pending_info.amount, hash, prv, account, generate_work_a ? work_fetch (transaction, account, account) : 0)); } @@ -940,7 +940,7 @@ std::shared_ptr rai::wallet::change_action (rai::account const & sou rai::raw_key prv; auto error2 (store.fetch (transaction, source_a, prv)); assert (!error2); - if (node.ledger.utx_enabled (transaction)) + if (node.ledger.utx_generation_enabled (transaction)) { block.reset (new rai::utx_block (source_a, info.head, representative_a, info.balance, 0, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); } @@ -1017,7 +1017,7 @@ std::shared_ptr rai::wallet::send_action (rai::account const & sourc assert (!error2); std::shared_ptr rep_block = node.ledger.store.block_get (transaction, info.rep_block); assert (rep_block != nullptr); - if (node.ledger.utx_enabled (transaction)) + if (node.ledger.utx_generation_enabled (transaction)) { block.reset (new rai::utx_block (source_a, info.head, rep_block->representative (), balance - amount_a, account_a, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); } diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index 16cf212d..15fc8ea9 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -1103,7 +1103,7 @@ void rai_qt::wallet::start () if (auto this_l = this_w.lock ()) { auto account (result_a.account); - this_l->application.postEvent (&this_l->processor, new eventloop_event ([ this_w, block_a, account ]() { + this_l->application.postEvent (&this_l->processor, new eventloop_event ([this_w, block_a, account]() { if (auto this_l = this_w.lock ()) { if (this_l->wallet_m->exists (account)) diff --git a/rai/slow_test/node.cpp b/rai/slow_test/node.cpp index efd29cad..8b441405 100644 --- a/rai/slow_test/node.cpp +++ b/rai/slow_test/node.cpp @@ -34,6 +34,39 @@ TEST (system, generate_mass_activity_long) runner.join (); } +TEST (system, generate_mass_activity_utx_enable) +{ + rai::system system (24000, 1); + rai::thread_runner runner (system.service, system.nodes[0]->config.io_threads); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + system.nodes[0]->alarm.add (std::chrono::steady_clock::now () + std::chrono::minutes (1), [&system]() { + std::cerr << boost::str (boost::format ("Enabling utx block parsing\n")); + rai::transaction transaction (system.nodes[0]->store.environment, nullptr, true); + ASSERT_FALSE (system.nodes[0]->ledger.utx_parsing_enabled (transaction)); + rai::genesis genesis; + system.nodes[0]->ledger.utx_parse_canary = genesis.hash (); + ASSERT_TRUE (system.nodes[0]->ledger.utx_parsing_enabled (transaction)); + }); + system.nodes[0]->alarm.add (std::chrono::steady_clock::now () + std::chrono::minutes (2), [&system]() { + std::cerr << boost::str (boost::format ("Enabling utx block generation\n")); + rai::transaction transaction (system.nodes[0]->store.environment, nullptr, true); + ASSERT_FALSE (system.nodes[0]->ledger.utx_generation_enabled (transaction)); + rai::genesis genesis; + system.nodes[0]->ledger.utx_generate_canary = genesis.hash (); + ASSERT_TRUE (system.nodes[0]->ledger.utx_generation_enabled (transaction)); + }); + size_t count (1000000000); + system.generate_mass_activity (count, *system.nodes[0]); + size_t accounts (0); + rai::transaction transaction (system.nodes[0]->store.environment, nullptr, false); + for (auto i (system.nodes[0]->store.latest_begin (transaction)), n (system.nodes[0]->store.latest_end ()); i != n; ++i) + { + ++accounts; + } + system.stop (); + runner.join (); +} + TEST (system, receive_while_synchronizing) { std::vector threads; From cc6b5bdb7e1d9128dceccbc921a8bb0bb713284b Mon Sep 17 00:00:00 2001 From: clemahieu Date: Sat, 10 Mar 2018 13:38:59 -0600 Subject: [PATCH 30/36] Exposing canaries to node config file. --- rai/core_test/node.cpp | 24 ++++++++++++++++++++++++ rai/node/node.cpp | 20 +++++++++++++++++--- rai/node/node.hpp | 2 ++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index aeb91ed1..b998c5b7 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -42,6 +42,23 @@ TEST (node, inactive_supply) node->stop (); } +TEST (node, utx_canaries) +{ + rai::node_init init; + auto service (boost::make_shared ()); + rai::alarm alarm (*service); + auto path (rai::unique_path ()); + rai::node_config config; + config.logging.init (path); + rai::work_pool work (std::numeric_limits::max (), nullptr); + config.utx_parse_canary = 10; + config.utx_generate_canary = 20; + auto node (std::make_shared (init, *service, path, alarm, config, work)); + ASSERT_EQ (rai::block_hash (10), node->ledger.utx_parse_canary); + ASSERT_EQ (rai::block_hash (20), node->ledger.utx_generate_canary); + node->stop (); +} + TEST (node, password_fanout) { rai::node_init init; @@ -495,6 +512,8 @@ TEST (node_config, serialization) config1.callback_port = 10; config1.callback_target = "test"; config1.lmdb_max_dbs = 256; + config1.utx_parse_canary = 10; + config1.utx_generate_canary = 10; boost::property_tree::ptree tree; config1.serialize_json (tree); rai::logging logging2; @@ -510,6 +529,9 @@ TEST (node_config, serialization) ASSERT_NE (config2.callback_address, config1.callback_address); ASSERT_NE (config2.callback_port, config1.callback_port); ASSERT_NE (config2.callback_target, config1.callback_target); + ASSERT_NE (config2.lmdb_max_dbs, config1.lmdb_max_dbs); + ASSERT_NE (config2.utx_parse_canary, config1.utx_parse_canary); + ASSERT_NE (config2.utx_generate_canary, config1.utx_generate_canary); bool upgraded (false); config2.deserialize_json (upgraded, tree); @@ -524,6 +546,8 @@ TEST (node_config, serialization) ASSERT_EQ (config2.callback_port, config1.callback_port); ASSERT_EQ (config2.callback_target, config1.callback_target); ASSERT_EQ (config2.lmdb_max_dbs, config1.lmdb_max_dbs); + ASSERT_EQ (config2.utx_parse_canary, config1.utx_parse_canary); + ASSERT_EQ (config2.utx_generate_canary, config1.utx_generate_canary); } TEST (node_config, v1_v2_upgrade) diff --git a/rai/node/node.cpp b/rai/node/node.cpp index add91a1d..d27659d5 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -803,7 +803,9 @@ enable_voting (true), bootstrap_connections (4), bootstrap_connections_max (64), callback_port (0), -lmdb_max_dbs (128) +lmdb_max_dbs (128), +utx_parse_canary (0), +utx_generate_canary (0) { switch (rai::rai_network) { @@ -833,7 +835,7 @@ lmdb_max_dbs (128) void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) const { - tree_a.put ("version", "9"); + tree_a.put ("version", "10"); tree_a.put ("peering_port", std::to_string (peering_port)); tree_a.put ("bootstrap_fraction_numerator", std::to_string (bootstrap_fraction_numerator)); tree_a.put ("receive_minimum", receive_minimum.to_string_dec ()); @@ -875,6 +877,8 @@ void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) con tree_a.put ("callback_port", std::to_string (callback_port)); tree_a.put ("callback_target", callback_target); tree_a.put ("lmdb_max_dbs", lmdb_max_dbs); + tree_a.put ("utx_parse_canary", utx_parse_canary.to_string ()); + tree_a.put ("utx_generate_canary", utx_generate_canary.to_string ()); } bool rai::node_config::upgrade_json (unsigned version, boost::property_tree::ptree & tree_a) @@ -949,6 +953,12 @@ bool rai::node_config::upgrade_json (unsigned version, boost::property_tree::ptr tree_a.put ("version", "9"); result = true; case 9: + tree_a.put ("utx_parse_canary", utx_parse_canary.to_string ()); + tree_a.put ("utx_generate_canary", utx_generate_canary.to_string ()); + tree_a.erase ("version"); + tree_a.put ("version", "10"); + result = true; + case 10: break; default: throw std::runtime_error ("Unknown node_config version"); @@ -1022,6 +1032,8 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree callback_target = tree_a.get ("callback_target"); auto lmdb_max_dbs_l = tree_a.get ("lmdb_max_dbs"); result |= parse_port (callback_port_l, callback_port); + auto utx_parse_canary_l = tree_a.get ("utx_parse_canary"); + auto utx_generate_canary_l = tree_a.get ("utx_generate_canary"); try { peering_port = std::stoul (peering_port_l); @@ -1040,6 +1052,8 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree result |= password_fanout > 1024 * 1024; result |= io_threads == 0; result |= work_threads == 0; + result |= utx_parse_canary.decode_hex (utx_parse_canary_l); + result |= utx_generate_canary.decode_hex (utx_generate_canary_l); } catch (std::logic_error const &) { @@ -1425,7 +1439,7 @@ alarm (alarm_a), work (work_a), store (init_a.block_store_init, application_path_a / "data.ldb", config_a.lmdb_max_dbs), gap_cache (*this), -ledger (store, config_a.inactive_supply.number ()), +ledger (store, config_a.inactive_supply.number (), config.utx_parse_canary, config.utx_generate_canary), active (*this), wallets (init_a.block_store_init, *this), network (*this, config.peering_port), diff --git a/rai/node/node.hpp b/rai/node/node.hpp index 5811328c..ab603b6d 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -407,6 +407,8 @@ public: uint16_t callback_port; std::string callback_target; int lmdb_max_dbs; + rai::block_hash utx_parse_canary; + rai::block_hash utx_generate_canary; static std::chrono::seconds constexpr keepalive_period = std::chrono::seconds (60); static std::chrono::seconds constexpr keepalive_cutoff = keepalive_period * 5; static std::chrono::minutes constexpr wallet_backup_interval = std::chrono::minutes (5); From 0ee9035cb1b150fa993a385f0d72e84564f4d336 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Sun, 11 Mar 2018 03:42:26 +0300 Subject: [PATCH 31/36] Disable block_info table for utx blocks (#720) --- rai/ledger.cpp | 6 +++--- rai/ledger.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index fb31f140..65adc48b 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -268,7 +268,7 @@ void ledger_processor::utx_block_impl (rai::utx_block const & block_a) ledger.store.pending_del (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link)); } - ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1); + ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1, true); if (!ledger.store.frontier_get (transaction, info.head).is_zero ()) { ledger.store.frontier_del (transaction, info.head); @@ -809,7 +809,7 @@ void rai::ledger::checksum_update (MDB_txn * transaction_a, rai::block_hash cons store.checksum_put (transaction_a, 0, 0, value); } -void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & account_a, rai::block_hash const & hash_a, rai::block_hash const & rep_block_a, rai::amount const & balance_a, uint64_t block_count_a) +void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & account_a, rai::block_hash const & hash_a, rai::block_hash const & rep_block_a, rai::amount const & balance_a, uint64_t block_count_a, bool is_utx) { rai::account_info info; auto exists (!store.account_get (transaction_a, account_a, info)); @@ -830,7 +830,7 @@ void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & a info.modified = rai::seconds_since_epoch (); info.block_count = block_count_a; store.account_put (transaction_a, account_a, info); - if (!(block_count_a % store.block_info_max)) + if (!(block_count_a % store.block_info_max) && !is_utx) { rai::block_info block_info; block_info.account = account_a; diff --git a/rai/ledger.hpp b/rai/ledger.hpp index 3cd17fec..a2c49ee3 100644 --- a/rai/ledger.hpp +++ b/rai/ledger.hpp @@ -41,7 +41,7 @@ public: rai::uint128_t supply (MDB_txn *); rai::process_return process (MDB_txn *, rai::block const &); void rollback (MDB_txn *, rai::block_hash const &); - void change_latest (MDB_txn *, rai::account const &, rai::block_hash const &, rai::account const &, rai::uint128_union const &, uint64_t); + void change_latest (MDB_txn *, rai::account const &, rai::block_hash const &, rai::account const &, rai::uint128_union const &, uint64_t, bool = false); void checksum_update (MDB_txn *, rai::block_hash const &); rai::checksum checksum (MDB_txn *, rai::account const &, rai::account const &); void dump_account_chain (rai::account const &); From 025f37080cab4d9c08dc206fbb881f3fa042aac5 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Sun, 11 Mar 2018 20:12:47 -0500 Subject: [PATCH 32/36] Adding beta utx canaries. --- rai/core_test/message.cpp | 8 ++++---- rai/node/common.cpp | 4 ++-- rai/node/node.cpp | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/rai/core_test/message.cpp b/rai/core_test/message.cpp index f565f460..2d886625 100644 --- a/rai/core_test/message.cpp +++ b/rai/core_test/message.cpp @@ -54,8 +54,8 @@ TEST (message, publish_serialization) ASSERT_EQ (8, bytes.size ()); ASSERT_EQ (0x52, bytes[0]); ASSERT_EQ (0x41, bytes[1]); - ASSERT_EQ (0x06, bytes[2]); - ASSERT_EQ (0x06, bytes[3]); + ASSERT_EQ (0x07, bytes[2]); + ASSERT_EQ (0x07, bytes[3]); ASSERT_EQ (0x01, bytes[4]); ASSERT_EQ (static_cast (rai::message_type::publish), bytes[5]); ASSERT_EQ (0x02, bytes[6]); @@ -68,8 +68,8 @@ TEST (message, publish_serialization) std::bitset<16> extensions; ASSERT_FALSE (rai::message::read_header (stream, version_max, version_using, version_min, type, extensions)); ASSERT_EQ (0x01, version_min); - ASSERT_EQ (0x06, version_using); - ASSERT_EQ (0x06, version_max); + ASSERT_EQ (0x07, version_using); + ASSERT_EQ (0x07, version_max); ASSERT_EQ (rai::message_type::publish, type); } diff --git a/rai/node/common.cpp b/rai/node/common.cpp index 67365575..84853c7e 100644 --- a/rai/node/common.cpp +++ b/rai/node/common.cpp @@ -10,8 +10,8 @@ size_t constexpr rai::message::bootstrap_server_position; std::bitset<16> constexpr rai::message::block_type_mask; rai::message::message (rai::message_type type_a) : -version_max (0x06), -version_using (0x06), +version_max (0x07), +version_using (0x07), version_min (0x01), type (type_a) { diff --git a/rai/node/node.cpp b/rai/node/node.cpp index d27659d5..284a1351 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -815,6 +815,8 @@ utx_generate_canary (0) case rai::rai_networks::rai_beta_network: preconfigured_peers.push_back ("rai-beta.raiblocks.net"); preconfigured_representatives.push_back (rai::account ("5DF352F3E7367A17F2ADB52B8123959602F8D94C2F295B23F6BDFFFC5FEFCA5E")); + utx_parse_canary = rai::block_hash ("5005F5283DE8D2DAB0DAC41DE9BD23640F962B4F0EA7D3128C2EA3D78D578E27"); + utx_generate_canary = rai::block_hash ("FC18E2265FB835E8CF60E63531053A768CEDF5194263B01A5C95574944E4660D"); break; case rai::rai_networks::rai_live_network: preconfigured_peers.push_back ("rai.raiblocks.net"); From 63aa1fc0f9257988647295d808194c12247ebabd Mon Sep 17 00:00:00 2001 From: clemahieu Date: Mon, 12 Mar 2018 21:19:30 -0500 Subject: [PATCH 33/36] Adding test to make sure block_create can be used to create utx open blocks. --- rai/core_test/rpc.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ rai/node/rpc.cpp | 8 ++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index 537e772b..f82e4377 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -3205,6 +3205,48 @@ TEST (rpc, block_create_utx) auto process_result (system.nodes[0]->process (*utx_block)); ASSERT_EQ (rai::process_result::progress, process_result.code); } +TEST (rpc, block_create_utx_open) +{ + rai::system system (24000, 1); + rai::keypair key; + rai::genesis genesis; + system.nodes[0]->ledger.utx_parse_canary = genesis.hash (); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + system.wallet (0)->insert_adhoc (key.prv); + auto send_block (system.wallet (0)->send_action (rai::test_genesis_key.pub, key.pub, rai::Gxrb_ratio)); + ASSERT_NE (nullptr, send_block); + boost::property_tree::ptree request; + request.put ("action", "block_create"); + request.put ("type", "utx"); + request.put ("wallet", system.nodes[0]->wallets.items.begin ()->first.to_string ()); + request.put ("account", key.pub.to_account ()); + request.put ("previous", 0); + request.put ("representative", rai::test_genesis_key.pub.to_account ()); + request.put ("balance", rai::Gxrb_ratio.convert_to ()); + request.put ("link", send_block->hash ().to_string ()); + request.put ("work", rai::to_string_hex (system.nodes[0]->generate_work (send_block->hash ()))); + rai::rpc rpc (system.service, *system.nodes[0], rai::rpc_config (true)); + rpc.start (); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + std::string utx_hash (response.json.get ("hash")); + auto utx_text (response.json.get ("block")); + std::stringstream block_stream (utx_text); + boost::property_tree::ptree block_l; + boost::property_tree::read_json (block_stream, block_l); + auto utx_block (rai::deserialize_block_json (block_l)); + ASSERT_NE (nullptr, utx_block); + ASSERT_EQ (rai::block_type::utx, utx_block->type ()); + ASSERT_EQ (utx_hash, utx_block->hash ().to_string ()); + ASSERT_TRUE (system.nodes [0]->latest (key.pub).is_zero ()); + auto process_result (system.nodes[0]->process (*utx_block)); + ASSERT_EQ (rai::process_result::progress, process_result.code); + ASSERT_FALSE (system.nodes [0]->latest (key.pub).is_zero ()); +} TEST (rpc, wallet_lock) { diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 6059cf3c..aeae92cd 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -1190,7 +1190,11 @@ void rai::rpc_handler::block_create () auto error_link (link.decode_account (link_text.get ())); if (error_link) { - error_response (response, "Bad link number"); + auto error_link (link.decode_hex (link_text.get ())); + if (error_link) + { + error_response (response, "Bad link number"); + } } } if (prv.data != 0) @@ -1199,7 +1203,7 @@ void rai::rpc_handler::block_create () ed25519_publickey (prv.data.bytes.data (), pub.bytes.data ()); if (type == "utx") { - if (!account.is_zero () && !previous.is_zero () && !representative.is_zero () && !balance.is_zero () && link_text.is_initialized ()) + if (!account.is_zero () && previous_text.is_initialized () && !representative.is_zero () && !balance.is_zero () && link_text.is_initialized ()) { rai::utx_block utx (account, previous, representative, balance, link, prv, pub, work); boost::property_tree::ptree response_l; From 9c8a3669d40eb7c62582960f14e9330791d16223 Mon Sep 17 00:00:00 2001 From: clemahieu Date: Mon, 12 Mar 2018 23:26:15 -0500 Subject: [PATCH 34/36] Require that the first block for an account receive something to match existing behavior. --- rai/core_test/ledger.cpp | 17 +++++++++++++++++ rai/core_test/rpc.cpp | 4 ++-- rai/ledger.cpp | 4 ++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 83f5aeab..364f17c2 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1845,6 +1845,23 @@ TEST (ledger, utx_open_previous_fail) ASSERT_EQ (rai::process_result::gap_previous, ledger.process (transaction, open1).code); } +TEST (ledger, utx_open_source_fail) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store); + rai::genesis genesis; + ledger.utx_parse_canary = genesis.hash (); + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + rai::keypair destination; + rai::utx_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code); + rai::utx_block open1 (destination.pub, 0, rai::genesis_account, 0, 0, destination.prv, destination.pub, 0); + ASSERT_EQ (rai::process_result::gap_source, ledger.process (transaction, open1).code); +} + TEST (ledger, utx_send_change) { bool init (false); diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index f82e4377..004cb01f 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -3242,10 +3242,10 @@ TEST (rpc, block_create_utx_open) ASSERT_NE (nullptr, utx_block); ASSERT_EQ (rai::block_type::utx, utx_block->type ()); ASSERT_EQ (utx_hash, utx_block->hash ().to_string ()); - ASSERT_TRUE (system.nodes [0]->latest (key.pub).is_zero ()); + ASSERT_TRUE (system.nodes[0]->latest (key.pub).is_zero ()); auto process_result (system.nodes[0]->process (*utx_block)); ASSERT_EQ (rai::process_result::progress, process_result.code); - ASSERT_FALSE (system.nodes [0]->latest (key.pub).is_zero ()); + ASSERT_FALSE (system.nodes[0]->latest (key.pub).is_zero ()); } TEST (rpc, wallet_lock) diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 65adc48b..2def6910 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -218,6 +218,10 @@ void ledger_processor::utx_block_impl (rai::utx_block const & block_a) { // Account does not yet exists result.code = block_a.previous ().is_zero () ? rai::process_result::progress : rai::process_result::gap_previous; // Does the first block in an account yield 0 for previous() ? (Unambigious) + if (result.code == rai::process_result::progress) + { + result.code = !block_a.hashables.link.is_zero () ? rai::process_result::progress : rai::process_result::gap_source; // Is the first block receiving from a send ? (Unambigious) + } } if (result.code == rai::process_result::progress) { From 7c215ed41d652547652808f107fe7f3c5e77c13c Mon Sep 17 00:00:00 2001 From: clemahieu Date: Tue, 13 Mar 2018 16:34:46 -0500 Subject: [PATCH 35/36] Generate ublocks if we control an account that already has one as its head block even if the generate canary hasn't been deployed. --- rai/core_test/wallet.cpp | 23 +++++++++++++++++++++++ rai/node/wallet.cpp | 16 ++++++++++++---- rai/node/wallet.hpp | 1 + 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/rai/core_test/wallet.cpp b/rai/core_test/wallet.cpp index ee4e84d2..d9d11108 100644 --- a/rai/core_test/wallet.cpp +++ b/rai/core_test/wallet.cpp @@ -978,3 +978,26 @@ TEST (wallet, password_race_corrupt_seed) } } } + +TEST (wallet, utx_implicit_generate) +{ + rai::system system (24000, 1); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + rai::genesis genesis; + system.nodes [0]->ledger.utx_parse_canary = genesis.hash (); + { + rai::transaction transaction (system.nodes [0]->store.environment, nullptr, true); + ASSERT_FALSE (system.wallet (0)->should_generate_utx (transaction, genesis.hash ())); + rai::utx_block block (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ASSERT_EQ (rai::process_result::progress, system.nodes [0]->ledger.process (transaction, block).code); + ASSERT_TRUE (system.wallet (0)->should_generate_utx (transaction, block.hash ())); + } + ASSERT_FALSE (system.wallet (0)->search_pending ()); + auto iterations (0); + while (system.nodes [0]->balance (rai::test_genesis_key.pub) != rai::genesis_amount) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } +} diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index 04d62957..59e72aba 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -865,7 +865,7 @@ std::shared_ptr rai::wallet::receive_action (rai::block const & send { std::shared_ptr rep_block = node.ledger.store.block_get (transaction, info.rep_block); assert (rep_block != nullptr); - if (node.ledger.utx_generation_enabled (transaction)) + if (should_generate_utx (transaction, info.head)) { block.reset (new rai::utx_block (account, info.head, rep_block->representative (), info.balance.number () + pending_info.amount.number (), hash, prv, account, generate_work_a ? work_fetch (transaction, account, info.head) : 0)); } @@ -878,7 +878,7 @@ std::shared_ptr rai::wallet::receive_action (rai::block const & send { if (node.ledger.utx_generation_enabled (transaction)) { - block.reset (new rai::utx_block (account, info.head, representative_a, pending_info.amount, hash, prv, account, generate_work_a ? work_fetch (transaction, account, account) : 0)); + block.reset (new rai::utx_block (account, 0, representative_a, pending_info.amount, hash, prv, account, generate_work_a ? work_fetch (transaction, account, account) : 0)); } else { @@ -940,7 +940,7 @@ std::shared_ptr rai::wallet::change_action (rai::account const & sou rai::raw_key prv; auto error2 (store.fetch (transaction, source_a, prv)); assert (!error2); - if (node.ledger.utx_generation_enabled (transaction)) + if (should_generate_utx (transaction, info.head)) { block.reset (new rai::utx_block (source_a, info.head, representative_a, info.balance, 0, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); } @@ -1017,7 +1017,7 @@ std::shared_ptr rai::wallet::send_action (rai::account const & sourc assert (!error2); std::shared_ptr rep_block = node.ledger.store.block_get (transaction, info.rep_block); assert (rep_block != nullptr); - if (node.ledger.utx_generation_enabled (transaction)) + if (should_generate_utx (transaction, info.head)) { block.reset (new rai::utx_block (source_a, info.head, rep_block->representative (), balance - amount_a, account_a, prv, source_a, generate_work_a ? work_fetch (transaction, source_a, info.head) : 0)); } @@ -1052,6 +1052,14 @@ std::shared_ptr rai::wallet::send_action (rai::account const & sourc return block; } +bool rai::wallet::should_generate_utx (MDB_txn * transaction_a, rai::block_hash const & hash_a) +{ + auto head (node.store.block_get(transaction_a, hash_a)); + assert (head != nullptr); + auto is_utx (dynamic_cast (head.get ()) != nullptr); + return is_utx || node.ledger.utx_generation_enabled (transaction_a); +} + bool rai::wallet::change_sync (rai::account const & source_a, rai::account const & representative_a) { std::promise result; diff --git a/rai/node/wallet.hpp b/rai/node/wallet.hpp index 836aedfa..198d552e 100644 --- a/rai/node/wallet.hpp +++ b/rai/node/wallet.hpp @@ -151,6 +151,7 @@ public: void work_ensure (MDB_txn *, rai::account const &); bool search_pending (); void init_free_accounts (MDB_txn *); + bool should_generate_utx (MDB_txn *, rai::block_hash const &); /** Changes the wallet seed and returns the first account */ rai::public_key change_seed (MDB_txn * transaction_a, rai::raw_key const & prv_a); std::unordered_set free_accounts; From 6c2a8c5f7b3be154309b358d1083c800dc91a920 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Wed, 14 Mar 2018 13:08:49 -0600 Subject: [PATCH 36/36] Serialize ublock link as both hex and account (#735) --- rai/lib/blocks.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rai/lib/blocks.cpp b/rai/lib/blocks.cpp index 908f3604..cc8e9fc3 100644 --- a/rai/lib/blocks.cpp +++ b/rai/lib/blocks.cpp @@ -882,7 +882,7 @@ rai::utx_hashables::utx_hashables (bool & error_a, boost::property_tree::ptree c error_a = balance.decode_dec (balance_l); if (!error_a) { - error_a = link.decode_account (link_l); + error_a = link.decode_account (link_l) && link.decode_hex (link_l); } } } @@ -991,7 +991,8 @@ void rai::utx_block::serialize_json (std::string & string_a) const tree.put ("previous", hashables.previous.to_string ()); tree.put ("representative", representative ().to_account ()); tree.put ("balance", hashables.balance.to_string_dec ()); - tree.put ("link", hashables.link.to_account ()); + tree.put ("link", hashables.link.to_string ()); + tree.put ("link_as_account", hashables.link.to_account ()); std::string signature_l; signature.encode_hex (signature_l); tree.put ("signature", signature_l); @@ -1056,7 +1057,7 @@ bool rai::utx_block::deserialize_json (boost::property_tree::ptree const & tree_ error = hashables.balance.decode_dec (balance_l); if (!error) { - error = hashables.link.decode_account (link_l); + error = hashables.link.decode_account (link_l) && hashables.link.decode_hex (link_l); if (!error) { error = rai::from_string_hex (work_l, work);