Adding ublock support.
This commit is contained in:
commit
450b3bbaf2
27 changed files with 2237 additions and 288 deletions
|
@ -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;
|
||||
}
|
||||
|
@ -663,8 +687,15 @@ std::unique_ptr<rai::block> rai::block_store::block_random (MDB_txn * transactio
|
|||
}
|
||||
else
|
||||
{
|
||||
// change
|
||||
result = block_random (transaction_a, change_blocks);
|
||||
region -= count.open;
|
||||
if (region < count.change)
|
||||
{
|
||||
result = block_random (transaction_a, change_blocks);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = block_random (transaction_a, utx_blocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -712,20 +743,25 @@ std::unique_ptr<rai::block> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -753,6 +789,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 +816,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -162,6 +162,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
|
||||
|
|
|
@ -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);
|
||||
|
@ -255,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 () :
|
||||
|
@ -439,6 +440,14 @@ void rai::amount_visitor::open_block (rai::open_block const & block_a)
|
|||
}
|
||||
}
|
||||
|
||||
void rai::amount_visitor::utx_block (rai::utx_block const & block_a)
|
||||
{
|
||||
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)
|
||||
{
|
||||
result = 0;
|
||||
|
@ -525,6 +534,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;
|
||||
|
@ -574,6 +589,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),
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
@ -217,9 +221,12 @@ 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'.
|
||||
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
|
||||
{
|
||||
|
@ -228,6 +235,7 @@ public:
|
|||
rai::account account;
|
||||
rai::amount amount;
|
||||
rai::account pending_account;
|
||||
boost::optional<bool> utx_is_send;
|
||||
};
|
||||
enum class tally_result
|
||||
{
|
||||
|
|
|
@ -325,3 +325,81 @@ 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, 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::uint256_union (4), block1.hashables.link);
|
||||
std::vector<uint8_t> 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);
|
||||
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);
|
||||
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);
|
||||
block3.hashables.account.clear ();
|
||||
block3.hashables.previous.clear ();
|
||||
block3.hashables.representative.clear ();
|
||||
block3.hashables.balance.clear ();
|
||||
block3.hashables.link.clear ();
|
||||
block3.signature.clear ();
|
||||
block3.work = 0;
|
||||
ASSERT_FALSE (block3.deserialize_json (tree));
|
||||
ASSERT_EQ (block1, block3);
|
||||
}
|
||||
|
||||
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;
|
||||
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.link.bytes[0] ^= 0x1;
|
||||
ASSERT_NE (hash, block.hash ());
|
||||
block.hashables.link.bytes[0] ^= 0x1;
|
||||
ASSERT_EQ (hash, block.hash ());
|
||||
}
|
||||
|
|
|
@ -986,3 +986,27 @@ 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, 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);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -1454,3 +1470,684 @@ TEST (ledger, bootstrap_rep_weight)
|
|||
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
ledger.utx_parse_canary = genesis.hash ();
|
||||
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);
|
||||
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::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);
|
||||
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::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.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 ()));
|
||||
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));
|
||||
ASSERT_FALSE (store.pending_exists (transaction, rai::pending_key (rai::genesis_account, send1.hash ())));
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
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, 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;
|
||||
ledger.utx_parse_canary = genesis.hash ();
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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));
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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, 1, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
|
||||
ASSERT_EQ (rai::process_result::gap_source, 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;
|
||||
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);
|
||||
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::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;
|
||||
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);
|
||||
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, 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;
|
||||
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);
|
||||
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, 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;
|
||||
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, 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;
|
||||
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::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, 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;
|
||||
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, 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);
|
||||
}
|
||||
|
||||
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);
|
||||
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 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);
|
||||
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;
|
||||
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);
|
||||
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, 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;
|
||||
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::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;
|
||||
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 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);
|
||||
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));
|
||||
}
|
||||
|
||||
TEST (ledger, utx_rollback_send)
|
||||
{
|
||||
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::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));
|
||||
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));
|
||||
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)
|
||||
{
|
||||
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::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_rollback_received_send)
|
||||
{
|
||||
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 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);
|
||||
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 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;
|
||||
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, 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;
|
||||
ledger.utx_parse_canary = genesis.hash ();
|
||||
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;
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -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<uint8_t> (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);
|
||||
}
|
||||
|
||||
|
|
|
@ -550,6 +550,38 @@ TEST (bootstrap_processor, process_two)
|
|||
node1->stop ();
|
||||
}
|
||||
|
||||
// Bootstrap can pull universal blocks
|
||||
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<rai::block> 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<rai::block> 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<rai::node> (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 ());
|
||||
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);
|
||||
|
|
|
@ -42,6 +42,23 @@ TEST (node, inactive_supply)
|
|||
node->stop ();
|
||||
}
|
||||
|
||||
TEST (node, utx_canaries)
|
||||
{
|
||||
rai::node_init init;
|
||||
auto service (boost::make_shared<boost::asio::io_service> ());
|
||||
rai::alarm alarm (*service);
|
||||
auto path (rai::unique_path ());
|
||||
rai::node_config config;
|
||||
config.logging.init (path);
|
||||
rai::work_pool work (std::numeric_limits<unsigned>::max (), nullptr);
|
||||
config.utx_parse_canary = 10;
|
||||
config.utx_generate_canary = 20;
|
||||
auto node (std::make_shared<rai::node> (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)
|
||||
|
@ -655,50 +679,6 @@ TEST (node_config, random_rep)
|
|||
ASSERT_NE (config1.preconfigured_representatives.end (), std::find (config1.preconfigured_representatives.begin (), config1.preconfigured_representatives.end (), rep));
|
||||
}
|
||||
|
||||
TEST (node, block_replace)
|
||||
{
|
||||
rai::system system (24000, 2);
|
||||
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
|
||||
auto block1 (system.wallet (0)->send_action (rai::test_genesis_key.pub, 0, rai::Gxrb_ratio));
|
||||
auto block3 (system.wallet (0)->send_action (rai::test_genesis_key.pub, 0, rai::Gxrb_ratio));
|
||||
ASSERT_NE (nullptr, block1);
|
||||
auto initial_work (block1->block_work ());
|
||||
while (rai::work_value (block1->root (), block1->block_work ()) <= rai::work_value (block1->root (), initial_work))
|
||||
{
|
||||
system.nodes[1]->generate_work (*block1);
|
||||
}
|
||||
{
|
||||
rai::transaction transaction (system.nodes[0]->store.environment, nullptr, false);
|
||||
ASSERT_EQ (block3->hash (), system.nodes[0]->store.block_successor (transaction, block1->hash ()));
|
||||
}
|
||||
for (auto i (0); i < 1; ++i)
|
||||
{
|
||||
rai::transaction transaction_a (system.nodes[1]->store.environment, nullptr, false);
|
||||
system.nodes[1]->network.republish_block (transaction_a, block1);
|
||||
}
|
||||
auto iterations1 (0);
|
||||
std::unique_ptr<rai::block> block2;
|
||||
while (block2 == nullptr)
|
||||
{
|
||||
system.poll ();
|
||||
++iterations1;
|
||||
ASSERT_LT (iterations1, 200);
|
||||
rai::transaction transaction (system.nodes[0]->store.environment, nullptr, false);
|
||||
auto block (system.nodes[0]->store.block_get (transaction, block1->hash ()));
|
||||
if (block->block_work () != initial_work)
|
||||
{
|
||||
block2 = std::move (block);
|
||||
}
|
||||
}
|
||||
{
|
||||
rai::transaction transaction (system.nodes[0]->store.environment, nullptr, false);
|
||||
ASSERT_EQ (block3->hash (), system.nodes[0]->store.block_successor (transaction, block1->hash ()));
|
||||
}
|
||||
ASSERT_NE (initial_work, block1->block_work ());
|
||||
ASSERT_EQ (block1->block_work (), block2->block_work ());
|
||||
ASSERT_GT (rai::work_value (block2->root (), block2->block_work ()), rai::work_value (block1->root (), initial_work));
|
||||
}
|
||||
|
||||
TEST (node, fork_publish)
|
||||
{
|
||||
std::weak_ptr<rai::node> node0;
|
||||
|
@ -1032,7 +1012,7 @@ TEST (node, coherent_observer)
|
|||
{
|
||||
rai::system system (24000, 1);
|
||||
auto & node1 (*system.nodes[0]);
|
||||
node1.observers.blocks.add ([&node1](std::shared_ptr<rai::block> block_a, rai::account const & account_a, rai::amount const &) {
|
||||
node1.observers.blocks.add ([&node1](std::shared_ptr<rai::block> block_a, rai::process_return const &) {
|
||||
rai::transaction transaction (node1.store.environment, nullptr, false);
|
||||
ASSERT_TRUE (node1.store.block_exists (transaction, block_a->hash ()));
|
||||
});
|
||||
|
|
|
@ -879,11 +879,23 @@ TEST (rpc, history)
|
|||
ASSERT_NE (nullptr, send);
|
||||
auto receive (system.wallet (0)->receive_action (static_cast<rai::send_block &> (*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::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);
|
||||
{
|
||||
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 +909,28 @@ TEST (rpc, history)
|
|||
{
|
||||
history_l.push_back (std::make_tuple (i->second.get<std::string> ("type"), i->second.get<std::string> ("account"), i->second.get<std::string> ("amount"), i->second.get<std::string> ("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::string> (), 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::string> (), 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::string> (), 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]));
|
||||
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::string> (), std::get<2> (history_l[4]));
|
||||
ASSERT_EQ (genesis.hash ().to_string (), std::get<3> (history_l[4]));
|
||||
}
|
||||
|
||||
TEST (rpc, history_count)
|
||||
|
@ -2923,6 +2943,8 @@ TEST (rpc, block_count_type)
|
|||
ASSERT_EQ ("1", open_count);
|
||||
std::string change_count (response.json.get<std::string> ("change"));
|
||||
ASSERT_EQ ("0", change_count);
|
||||
std::string utx_count (response.json.get<std::string> ("utx"));
|
||||
ASSERT_EQ ("0", utx_count);
|
||||
}
|
||||
|
||||
TEST (rpc, ledger)
|
||||
|
@ -3146,6 +3168,86 @@ 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.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");
|
||||
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<std::string> ());
|
||||
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<std::string> ("hash"));
|
||||
auto utx_text (response.json.get<std::string> ("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, 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<std::string> ());
|
||||
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<std::string> ("hash"));
|
||||
auto utx_text (response.json.get<std::string> ("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)
|
||||
{
|
||||
rai::system system (24000, 1);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
402
rai/ledger.cpp
402
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);
|
||||
|
@ -66,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
|
||||
|
@ -93,6 +95,64 @@ public:
|
|||
ledger.store.block_info_del (transaction, hash);
|
||||
}
|
||||
}
|
||||
void utx_block (rai::utx_block const & block_a) override
|
||||
{
|
||||
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);
|
||||
// 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, representative, balance);
|
||||
}
|
||||
|
||||
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 ())
|
||||
{
|
||||
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, block_a.hashables.link), 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));
|
||||
if (previous != nullptr)
|
||||
{
|
||||
ledger.store.block_successor_clear (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;
|
||||
};
|
||||
|
@ -106,11 +166,125 @@ 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 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));
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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 (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, true);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ledger_processor::change_block (rai::change_block const & block_a)
|
||||
{
|
||||
auto hash (block_a.hash ());
|
||||
|
@ -118,30 +292,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 +333,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 +379,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -304,10 +495,12 @@ bool rai::shared_ptr_block_hash::operator() (std::shared_ptr<rai::block> 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -432,6 +625,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<rai::send_block const *> (&block_a));
|
||||
rai::utx_block const * utx_block (dynamic_cast<rai::utx_block const *> (&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<rai::utx_block const *> (&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)
|
||||
{
|
||||
|
@ -473,20 +709,26 @@ 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));
|
||||
rai::account result;
|
||||
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))
|
||||
std::unique_ptr<rai::block> 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);
|
||||
}
|
||||
}
|
||||
rai::account result;
|
||||
if (successor.is_zero ())
|
||||
if (block->type () == rai::block_type::utx)
|
||||
{
|
||||
auto utx_block (dynamic_cast<rai::utx_block *> (block.get ()));
|
||||
result = utx_block->hashables.account;
|
||||
}
|
||||
else if (successor.is_zero ())
|
||||
{
|
||||
result = store.frontier_get (transaction_a, hash);
|
||||
}
|
||||
|
@ -552,6 +794,16 @@ void rai::ledger::dump_account_chain (rai::account const & account_a)
|
|||
}
|
||||
}
|
||||
|
||||
bool rai::ledger::utx_parsing_enabled (MDB_txn * transaction_a)
|
||||
{
|
||||
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)
|
||||
{
|
||||
rai::checksum value;
|
||||
|
@ -561,7 +813,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));
|
||||
|
@ -571,7 +823,7 @@ void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & a
|
|||
}
|
||||
else
|
||||
{
|
||||
assert (dynamic_cast<rai::open_block *> (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 ())
|
||||
|
@ -582,7 +834,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;
|
||||
|
|
|
@ -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<rai::uint128_t, std::shared_ptr<rai::block>> winner (MDB_txn *, rai::votes const & votes_a);
|
||||
// Map of weight -> associated block, ordered greatest to least
|
||||
std::map<rai::uint128_t, std::shared_ptr<rai::block>, std::greater<rai::uint128_t>> tally (MDB_txn *, rai::votes const &);
|
||||
|
@ -35,18 +35,25 @@ 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 &);
|
||||
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 &);
|
||||
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<rai::account, rai::uint128_t> bootstrap_weights;
|
||||
uint64_t bootstrap_weight_max_blocks;
|
||||
std::atomic<bool> check_bootstrap_weights;
|
||||
rai::block_hash utx_parse_canary;
|
||||
rai::block_hash utx_generate_canary;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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,309 @@ 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),
|
||||
representative (representative_a),
|
||||
balance (balance_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, link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rai::utx_hashables::utx_hashables (bool & error_a, boost::property_tree::ptree const & tree_a)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto account_l (tree_a.get<std::string> ("account"));
|
||||
auto previous_l (tree_a.get<std::string> ("previous"));
|
||||
auto representative_l (tree_a.get<std::string> ("representative"));
|
||||
auto balance_l (tree_a.get<std::string> ("balance"));
|
||||
auto link_l (tree_a.get<std::string> ("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 = link.decode_account (link_l) && 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, 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, link.bytes.data (), sizeof (link.bytes));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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 type_l (tree_a.get<std::string> ("type"));
|
||||
auto signature_l (tree_a.get<std::string> ("signature"));
|
||||
auto work_l (tree_a.get<std::string> ("work"));
|
||||
error_a = type_l != "utx";
|
||||
if (!error_a)
|
||||
{
|
||||
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<uint64_t> (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.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", "utx");
|
||||
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 ("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);
|
||||
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.account));
|
||||
if (!error)
|
||||
{
|
||||
error = read (stream_a, hashables.previous);
|
||||
if (!error)
|
||||
{
|
||||
error = read (stream_a, hashables.representative);
|
||||
if (!error)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
bool rai::utx_block::deserialize_json (boost::property_tree::ptree const & tree_a)
|
||||
{
|
||||
auto error (false);
|
||||
try
|
||||
{
|
||||
assert (tree_a.get<std::string> ("type") == "utx");
|
||||
auto account_l (tree_a.get<std::string> ("account"));
|
||||
auto previous_l (tree_a.get<std::string> ("previous"));
|
||||
auto representative_l (tree_a.get<std::string> ("representative"));
|
||||
auto balance_l (tree_a.get<std::string> ("balance"));
|
||||
auto link_l (tree_a.get<std::string> ("link"));
|
||||
auto work_l (tree_a.get<std::string> ("work"));
|
||||
auto signature_l (tree_a.get<std::string> ("signature"));
|
||||
error = hashables.account.decode_account (account_l);
|
||||
if (!error)
|
||||
{
|
||||
error = hashables.previous.decode_hex (previous_l);
|
||||
if (!error)
|
||||
{
|
||||
error = hashables.representative.decode_account (representative_l);
|
||||
if (!error)
|
||||
{
|
||||
error = hashables.balance.decode_dec (balance_l);
|
||||
if (!error)
|
||||
{
|
||||
error = hashables.link.decode_account (link_l) && hashables.link.decode_hex (link_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<rai::utx_block const *> (&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.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::block> rai::deserialize_block_json (boost::property_tree::ptree const & tree_a)
|
||||
{
|
||||
std::unique_ptr<rai::block> result;
|
||||
|
@ -832,6 +1176,15 @@ std::unique_ptr<rai::block> rai::deserialize_block_json (boost::property_tree::p
|
|||
result = std::move (obj);
|
||||
}
|
||||
}
|
||||
else if (type == "utx")
|
||||
{
|
||||
bool error;
|
||||
std::unique_ptr<rai::utx_block> obj (new rai::utx_block (error, tree_a));
|
||||
if (!error)
|
||||
{
|
||||
result = std::move (obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
{
|
||||
|
@ -896,6 +1249,16 @@ std::unique_ptr<rai::block> rai::deserialize_block (rai::stream & stream_a, rai:
|
|||
}
|
||||
break;
|
||||
}
|
||||
case rai::block_type::utx:
|
||||
{
|
||||
bool error;
|
||||
std::unique_ptr<rai::utx_block> obj (new rai::utx_block (error, stream_a));
|
||||
if (!error)
|
||||
{
|
||||
result = std::move (obj);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert (false);
|
||||
break;
|
||||
|
@ -1059,6 +1422,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;
|
||||
|
|
|
@ -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,65 @@ 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::uint256_union const &);
|
||||
utx_hashables (bool &, rai::stream &);
|
||||
utx_hashables (bool &, boost::property_tree::ptree const &);
|
||||
void hash (blake2b_state &) 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;
|
||||
// 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::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::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 +292,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<rai::block> deserialize_block (rai::stream &);
|
||||
|
|
|
@ -52,6 +52,18 @@ public:
|
|||
{
|
||||
add_dependency (block_a.hashables.previous);
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (!sync.synchronized (transaction, hash_a) && sync.retrieve (transaction, hash_a) != nullptr)
|
||||
|
@ -582,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.
|
||||
|
@ -2039,6 +2060,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 ();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -389,7 +389,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 ());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -813,6 +815,8 @@ lmdb_max_dbs (128)
|
|||
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");
|
||||
|
@ -833,7 +837,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 +879,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 +955,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 +1034,8 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree
|
|||
callback_target = tree_a.get<std::string> ("callback_target");
|
||||
auto lmdb_max_dbs_l = tree_a.get<std::string> ("lmdb_max_dbs");
|
||||
result |= parse_port (callback_port_l, callback_port);
|
||||
auto utx_parse_canary_l = tree_a.get<std::string> ("utx_parse_canary");
|
||||
auto utx_generate_canary_l = tree_a.get<std::string> ("utx_generate_canary");
|
||||
try
|
||||
{
|
||||
peering_port = std::stoul (peering_port_l);
|
||||
|
@ -1040,6 +1054,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 &)
|
||||
{
|
||||
|
@ -1246,7 +1262,7 @@ void rai::block_processor::process_receive_many (std::deque<rai::block_processor
|
|||
}
|
||||
for (auto & i : progress)
|
||||
{
|
||||
node.observers.blocks (i.first, i.second.account, i.second.amount);
|
||||
node.observers.blocks (i.first, i.second);
|
||||
if (i.second.amount > 0)
|
||||
{
|
||||
node.observers.account_balance (i.second.account, false);
|
||||
|
@ -1291,34 +1307,22 @@ 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;
|
||||
}
|
||||
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:
|
||||
{
|
||||
{
|
||||
auto root (block_a->root ());
|
||||
auto hash (block_a->hash ());
|
||||
auto existing (node.store.block_get (transaction_a, hash));
|
||||
if (existing != nullptr)
|
||||
{
|
||||
// Replace block with one that has higher work value
|
||||
if (rai::work_value (root, block_a->block_work ()) > rai::work_value (root, existing->block_work ()))
|
||||
{
|
||||
auto account (node.ledger.account (transaction_a, hash));
|
||||
if (!rai::validate_message (account, hash, block_a->block_signature ()))
|
||||
{
|
||||
node.store.block_put (transaction_a, hash, *block_a, node.store.block_successor (transaction_a, hash));
|
||||
BOOST_LOG (node.log) << boost::str (boost::format ("Replacing block %1% with one that has higher work value") % hash.to_string ());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could have been rolled back, maybe
|
||||
}
|
||||
}
|
||||
if (node.config.logging.ledger_duplicate_logging ())
|
||||
{
|
||||
BOOST_LOG (node.log) << boost::str (boost::format ("Old for: %1%") % block_a->hash ().to_string ());
|
||||
|
@ -1376,10 +1380,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;
|
||||
|
@ -1397,7 +1419,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),
|
||||
|
@ -1420,27 +1442,31 @@ block_processor_thread ([this]() { this->block_processor.process_blocks (); })
|
|||
peers.disconnect_observer = [this]() {
|
||||
observers.disconnect ();
|
||||
};
|
||||
observers.blocks.add ([this](std::shared_ptr<rai::block> block_a, rai::account const & account_a, rai::amount const & amount_a) {
|
||||
observers.blocks.add ([this](std::shared_ptr<rai::block> 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<rai::block> block_a, rai::account const & account_a, rai::amount const & amount_a) {
|
||||
observers.blocks.add ([this](std::shared_ptr<rai::block> 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 ();
|
||||
|
@ -2315,35 +2341,42 @@ 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<rai::block>) {});
|
||||
}
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -414,7 +416,7 @@ public:
|
|||
class node_observers
|
||||
{
|
||||
public:
|
||||
rai::observer_set<std::shared_ptr<rai::block>, rai::account const &, rai::amount const &> blocks;
|
||||
rai::observer_set<std::shared_ptr<rai::block>, rai::process_return const &> blocks;
|
||||
rai::observer_set<bool> wallet;
|
||||
rai::observer_set<std::shared_ptr<rai::vote>, rai::endpoint const &> vote;
|
||||
rai::observer_set<rai::account const &, bool> account_balance;
|
||||
|
|
115
rai/node/rpc.cpp
115
rai/node/rpc.cpp
|
@ -141,8 +141,8 @@ void rai::rpc::start ()
|
|||
}
|
||||
|
||||
acceptor.listen ();
|
||||
node.observers.blocks.add ([this](std::shared_ptr<rai::block> block_a, rai::account const & account_a, rai::amount const &) {
|
||||
observer_action (account_a);
|
||||
node.observers.blocks.add ([this](std::shared_ptr<rai::block> block_a, rai::process_return const & result_a) {
|
||||
observer_action (result_a.account);
|
||||
});
|
||||
|
||||
accept ();
|
||||
|
@ -961,18 +961,17 @@ void rai::rpc_handler::blocks_info ()
|
|||
entry.put ("contents", contents);
|
||||
if (pending)
|
||||
{
|
||||
auto block_l (dynamic_cast<rai::send_block *> (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<rai::block> block_a (node.store.block_get (transaction, source_hash));
|
||||
if (block_a != nullptr)
|
||||
{
|
||||
|
@ -1043,6 +1042,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);
|
||||
}
|
||||
|
||||
|
@ -1125,6 +1125,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));
|
||||
|
@ -1183,11 +1184,41 @@ void rai::rpc_handler::block_create ()
|
|||
error_response (response, "Bad balance number");
|
||||
}
|
||||
}
|
||||
boost::optional<std::string> link_text (request.get_optional<std::string> ("link"));
|
||||
if (link_text.is_initialized ())
|
||||
{
|
||||
auto error_link (link.decode_account (link_text.get ()));
|
||||
if (error_link)
|
||||
{
|
||||
auto error_link (link.decode_hex (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_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;
|
||||
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)
|
||||
{
|
||||
|
@ -1622,6 +1653,53 @@ public:
|
|||
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)
|
||||
{
|
||||
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<std::string> ());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (block_a.hashables.link.is_zero ())
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
tree.put ("subtype", "change");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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<std::string> ());
|
||||
}
|
||||
}
|
||||
}
|
||||
rai::rpc_handler & handler;
|
||||
bool raw;
|
||||
rai::transaction & transaction;
|
||||
|
@ -2178,12 +2256,11 @@ void rai::rpc_handler::pending_exists ()
|
|||
auto block (node.store.block_get (transaction, hash));
|
||||
if (block != nullptr)
|
||||
{
|
||||
auto block_l (dynamic_cast<rai::send_block *> (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");
|
||||
|
@ -2418,7 +2495,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);
|
||||
|
@ -2434,6 +2511,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");
|
||||
|
@ -2777,7 +2859,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<rai::block> block_a (node.store.block_get (transaction, source));
|
||||
std::vector<rai::block_hash> hashes;
|
||||
while (block_a != nullptr && hashes.size () < sources)
|
||||
|
@ -2803,10 +2885,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<rai::send_block *> (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)
|
||||
{
|
||||
|
@ -2817,7 +2898,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);
|
||||
}
|
||||
|
|
|
@ -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<rai::account> & 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<rai::open_block *> (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<rai::send_block> send_block;
|
||||
std::shared_ptr<rai::block> 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<rai::send_block *> (block.get ()) != nullptr);
|
||||
send_block.reset (static_cast<rai::send_block *> (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<rai::uint128_t>::max ()));
|
||||
auto receive_error (wallet (0)->receive_sync (send_block, rai::genesis_account, std::numeric_limits<rai::uint128_t>::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<rai::account> & 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<std::chrono::microseconds> (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% old: %5%\n") % i % us % (us / 256) % utx % (count - utx));
|
||||
previous = now;
|
||||
}
|
||||
generate_activity (node_a, accounts);
|
||||
|
|
|
@ -842,38 +842,63 @@ void rai::wallet_store::destroy (MDB_txn * transaction_a)
|
|||
assert (status == 0);
|
||||
}
|
||||
|
||||
std::shared_ptr<rai::block> 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::block> 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<rai::block> 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<rai::block> rep_block = node.ledger.store.block_get (transaction, info.rep_block);
|
||||
assert (rep_block != nullptr);
|
||||
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));
|
||||
}
|
||||
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_generation_enabled (transaction))
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
|
@ -890,7 +915,7 @@ std::shared_ptr<rai::block> 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);
|
||||
});
|
||||
|
@ -915,7 +940,14 @@ std::shared_ptr<rai::block> 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 (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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -983,7 +1015,16 @@ std::shared_ptr<rai::block> 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<rai::block> rep_block = node.ledger.store.block_get (transaction, info.rep_block);
|
||||
assert (rep_block != nullptr);
|
||||
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));
|
||||
}
|
||||
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));
|
||||
|
@ -1011,6 +1052,14 @@ std::shared_ptr<rai::block> 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<rai::utx_block *> (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<bool> result;
|
||||
|
@ -1041,9 +1090,9 @@ bool rai::wallet::receive_sync (std::shared_ptr<rai::block> block_a, rai::accoun
|
|||
|
||||
void rai::wallet::receive_async (std::shared_ptr<rai::block> block_a, rai::account const & representative_a, rai::uint128_t const & amount_a, std::function<void(std::shared_ptr<rai::block>)> const & action_a, bool generate_work_a)
|
||||
{
|
||||
assert (dynamic_cast<rai::send_block *> (block_a.get ()) != nullptr);
|
||||
//assert (dynamic_cast<rai::send_block *> (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<rai::send_block *> (block_a.get ()), representative_a, amount_a, generate_work_a));
|
||||
auto block (receive_action (*static_cast<rai::block *> (block_a.get ()), representative_a, amount_a, generate_work_a));
|
||||
action_a (block);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ class wallet : public std::enable_shared_from_this<rai::wallet>
|
|||
{
|
||||
public:
|
||||
std::shared_ptr<rai::block> change_action (rai::account const &, rai::account const &, bool = true);
|
||||
std::shared_ptr<rai::block> receive_action (rai::send_block const &, rai::account const &, rai::uint128_union const &, bool = true);
|
||||
std::shared_ptr<rai::block> receive_action (rai::block const &, rai::account const &, rai::uint128_union const &, bool = true);
|
||||
std::shared_ptr<rai::block> send_action (rai::account const &, rai::account const &, rai::uint128_t const &, bool = true, boost::optional<std::string> = {});
|
||||
wallet (bool &, rai::transaction &, rai::node &, std::string const &);
|
||||
wallet (bool &, rai::transaction &, rai::node &, std::string const &, std::string const &);
|
||||
|
@ -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<rai::account> free_accounts;
|
||||
|
|
|
@ -518,6 +518,29 @@ public:
|
|||
amount = 0;
|
||||
account = block_a.hashables.representative;
|
||||
}
|
||||
void utx_block (rai::utx_block const & block_a)
|
||||
{
|
||||
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;
|
||||
std::string type;
|
||||
|
@ -1076,17 +1099,18 @@ void rai_qt::wallet::start ()
|
|||
this_l->push_main_stack (this_l->send_blocks_window);
|
||||
}
|
||||
});
|
||||
node.observers.blocks.add ([this_w](std::shared_ptr<rai::block> block_a, rai::account const & account_a, rai::amount const &) {
|
||||
node.observers.blocks.add ([this_w](std::shared_ptr<rai::block> 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]() {
|
||||
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 (account_a))
|
||||
if (this_l->wallet_m->exists (account))
|
||||
{
|
||||
this_l->accounts.refresh ();
|
||||
}
|
||||
if (account_a == this_l->account)
|
||||
if (account == this_l->account)
|
||||
{
|
||||
this_l->history.refresh ();
|
||||
}
|
||||
|
@ -1993,10 +2017,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<rai::send_block *> (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))
|
||||
{
|
||||
|
@ -2117,10 +2141,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<rai::send_block *> (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))
|
||||
{
|
||||
|
|
|
@ -19,26 +19,52 @@ TEST (system, generate_mass_activity)
|
|||
|
||||
TEST (system, generate_mass_activity_long)
|
||||
{
|
||||
std::vector<std::thread> 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 ();
|
||||
++accounts;
|
||||
}
|
||||
for (auto i (threads.begin ()), n (threads.end ()); i != n; ++i)
|
||||
system.stop ();
|
||||
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)
|
||||
{
|
||||
i->join ();
|
||||
++accounts;
|
||||
}
|
||||
system.stop ();
|
||||
runner.join ();
|
||||
}
|
||||
|
||||
TEST (system, receive_while_synchronizing)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue