Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QT wallet: proper display of state open block in GUI history #4744

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
92 changes: 68 additions & 24 deletions nano/qt/qt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ class short_text_visitor : public nano::block_visitor
if (!amount_l)
{
type = "Send (pruned)";
amount = 0;
}
else
{
Expand All @@ -542,13 +543,21 @@ class short_text_visitor : public nano::block_visitor
type = "Receive";
auto account_l = ledger.any.block_account (transaction, block_a.hashables.source);
auto amount_l = ledger.any.block_amount (transaction, block_a.hash ());
if (!account_l || !amount_l)
if (!account_l)
{
type = "Receive (pruned)";
type = "Receive (pruned source)";
}
else
{
account = account_l.value ();
}
if (!amount_l)
{
type = "Receive (pruned)";
amount = 0;
}
else
{
amount = amount_l.value ().number ();
}
}
Expand All @@ -559,15 +568,16 @@ class short_text_visitor : public nano::block_visitor
{
auto account_l = ledger.any.block_account (transaction, block_a.hashables.source);
auto amount_l = ledger.any.block_amount (transaction, block_a.hash ());
if (!account_l || !amount_l)
if (!account_l)
{
type = "Receive (pruned)";
type = "Receive (pruned source)";
}
else
{
account = account_l.value ();
amount = amount_l.value ().number ();
}
debug_assert (amount_l);
amount = amount_l.value ().number ();
}
else
{
Expand All @@ -585,44 +595,78 @@ class short_text_visitor : public nano::block_visitor
{
auto balance (block_a.hashables.balance.number ());
auto previous_balance = ledger.any.block_balance (transaction, block_a.hashables.previous);
if (!previous_balance)
// Error to receive previous block balance means that previous block was pruned from the ledger
if ((!previous_balance || balance < previous_balance.value ().number ()) && block_a.sideband ().details.is_send)
{
type = "Send";
account = block_a.hashables.link.as_account ();
if (!previous_balance)
{
type = "Send (pruned)";
amount = 0;
}
else
{
amount = previous_balance.value ().number () - balance;
}
}
else if (block_a.hashables.link.is_zero () && !block_a.sideband ().details.is_send)
{
type = "Unknown (pruned)";
debug_assert (!block_a.sideband ().details.is_receive && !block_a.sideband ().details.is_epoch);
type = "Change";
account = block_a.hashables.representative;
amount = 0;
account = block_a.hashables.account;
if (!previous_balance)
{
type = "Change (pruned)";
}
else
{
debug_assert (balance == previous_balance);
}
}
else if (balance < previous_balance.value ().number ())
else if (ledger.is_epoch_link (block_a.hashables.link) && block_a.sideband ().details.is_epoch)
{
type = "Send";
amount = previous_balance.value ().number () - balance;
account = block_a.hashables.link.as_account ();
debug_assert (!previous_balance || balance == previous_balance);
type = "Epoch";
amount = 0;
if (!previous_balance && !block_a.hashables.previous.is_zero ())
{
// Epoch block with previous balance error is pruned only if it isn't open block for an account
type = "Epoch (pruned)";
}
account = ledger.epoch_signer (block_a.hashables.link);
}
else
{
if (block_a.hashables.link.is_zero ())
debug_assert (block_a.sideband ().details.is_receive);
type = "Receive";
auto account_l = ledger.any.block_account (transaction, block_a.hashables.link.as_block_hash ());
if (!account_l)
{
type = "Change";
account = block_a.hashables.representative;
type = "Receive (pruned source)";
}
else if (balance == previous_balance && ledger.is_epoch_link (block_a.hashables.link))
else
{
type = "Epoch";
account = ledger.epoch_signer (block_a.hashables.link);
account = account_l.value ();
}
else
if (!previous_balance)
{
type = "Receive";
auto account_l = ledger.any.block_account (transaction, block_a.hashables.link.as_block_hash ());
if (!account_l)
if (!block_a.hashables.previous.is_zero ())
{
// Receive block with previous balance error is pruned only if it isn't open block for an account
type = "Receive (pruned)";
amount = 0;
}
else
{
account = account_l.value ();
amount = balance;
}
}
amount = balance - previous_balance.value ().number ();
else
{
amount = balance - previous_balance.value ().number ();
}
}
}
nano::secure::transaction const & transaction;
Expand Down
139 changes: 133 additions & 6 deletions nano/qt_test/qt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,48 +572,175 @@ TEST (history, pruned_source)
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
auto send2 = std::make_shared<nano::send_block> (send1->hash (), key.pub, nano::dev::constants.genesis_amount - 200, nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *system.work.generate (send1->hash ()));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
auto receive = std::make_shared<nano::receive_block> (send2->hash (), send1->hash (), nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *system.work.generate (send2->hash ()));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive));
auto receive1 = std::make_shared<nano::receive_block> (send2->hash (), send1->hash (), nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *system.work.generate (send2->hash ()));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
auto open = std::make_shared<nano::open_block> (send2->hash (), key.pub, key.pub, key.prv, key.pub, *system.work.generate (key.pub));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open));
ledger.confirm (transaction, send1->hash ());
ASSERT_EQ (1, ledger.pruning_action (transaction, send1->hash (), 2));
next_pruning = send2->hash ();
}
// Set rendering ration to raw units
ASSERT_NE (wallet->rendering_ratio, nano::raw_ratio);
wallet->rendering_ratio = nano::raw_ratio;
// Genesis account pruned values
nano_qt::history history1 (ledger, nano::dev::genesis_key.pub, *wallet);
history1.refresh ();
ASSERT_EQ (2, history1.model->rowCount ());
// Source block send1 is removed
auto type1 (history1.model->item (0, 0));
ASSERT_EQ ("Receive (pruned source)", type1->text ().toStdString ());
// Source block account is unknown
auto account1 (history1.model->item (0, 1));
ASSERT_EQ (nano::account (0).to_account (), account1->text ().toStdString ());
// Amount is known because previous block (send2) isn't removed
auto amount1 (history1.model->item (0, 2));
ASSERT_EQ ("100 raw", amount1->text ().toStdString ());
// Last not pruned block in chain (send2)
auto type2 (history1.model->item (1, 0));
ASSERT_EQ ("Send (pruned)", type2->text ().toStdString ());
auto account2 (history1.model->item (1, 1));
// Amount is unknown because previous block (send1) is removed
ASSERT_EQ (key.pub.to_account (), account2->text ().toStdString ());
auto amount2 (history1.model->item (1, 2));
ASSERT_EQ ("0 raw", amount2->text ().toStdString ());
// New account pruned values
nano_qt::history history2 (ledger, key.pub, *wallet);
history2.refresh ();
ASSERT_EQ (1, history2.model->rowCount ());
auto type3 (history2.model->item (0, 0));
ASSERT_EQ ("Receive", type3->text ().toStdString ());
// Source block (send2) account is known
auto account3 (history2.model->item (0, 1));
ASSERT_EQ (nano::dev::genesis_key.pub.to_account (), account3->text ().toStdString ());
auto amount3 (history2.model->item (0, 2));
ASSERT_EQ ("100 raw", amount3->text ().toStdString ());
// Additional legacy test
{
auto transaction = ledger.tx_begin_write ();
ledger.confirm (transaction, next_pruning);
ASSERT_EQ (1, ledger.pruning_action (transaction, next_pruning, 2));
}
// Genesis account pruned values
history1.refresh ();
ASSERT_EQ (1, history1.model->rowCount ());
auto type4 (history1.model->item (0, 0));
ASSERT_EQ ("Receive (pruned)", type4->text ().toStdString ());
auto account4 (history1.model->item (0, 1));
ASSERT_EQ (nano::account (0).to_account (), account4->text ().toStdString ());
// Amount is unknown because previous block (send2) is removed
auto amount4 (history1.model->item (0, 2));
ASSERT_EQ ("0 raw", amount4->text ().toStdString ());
// New account pruned values
history2.refresh ();
ASSERT_EQ (1, history2.model->rowCount ());
auto type5 (history2.model->item (0, 0));
ASSERT_EQ ("Receive (pruned source)", type5->text ().toStdString ());
// Source block (send2) account is unknown
auto account5 (history2.model->item (0, 1));
ASSERT_EQ (nano::account (0).to_account (), account5->text ().toStdString ());
auto amount5 (history2.model->item (0, 2));
ASSERT_EQ ("100 raw", amount5->text ().toStdString ());
// Pruning for state blocks. Previous block is pruned, source is pruned
{
auto transaction = ledger.tx_begin_write ();
auto latest (ledger.any.account_head (transaction, nano::dev::genesis_key.pub));
auto send = std::make_shared<nano::state_block> (nano::dev::genesis_key.pub, latest, nano::dev::genesis_key.pub, nano::dev::constants.genesis_amount - 200, key.pub, nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *system.work.generate (latest));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
auto send3 = std::make_shared<nano::state_block> (nano::dev::genesis_key.pub, latest, nano::dev::genesis_key.pub, nano::dev::constants.genesis_amount - 200, key.pub, nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *system.work.generate (latest));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send3));
auto latest_key (ledger.any.account_head (transaction, key.pub));
auto receive = std::make_shared<nano::state_block> (key.pub, latest_key, key.pub, 200, send->hash (), key.prv, key.pub, *system.work.generate (latest_key));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive));
auto receive2 = std::make_shared<nano::state_block> (key.pub, latest_key, key.pub, 200, send3->hash (), key.prv, key.pub, *system.work.generate (latest_key));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive2));
ledger.confirm (transaction, latest);
ASSERT_EQ (1, ledger.pruning_action (transaction, latest, 2));
ledger.confirm (transaction, latest_key);
ASSERT_EQ (1, ledger.pruning_action (transaction, latest_key, 2));
}
// Genesis account pruned values
history1.refresh ();
ASSERT_EQ (1, history1.model->rowCount ());
auto type6 (history1.model->item (0, 0));
ASSERT_EQ ("Send (pruned)", type6->text ().toStdString ());
auto account6 (history1.model->item (0, 1));
ASSERT_EQ (key.pub.to_account (), account6->text ().toStdString ());
// Amount is unknown because previous block (receive1) is removed
auto amount6 (history1.model->item (0, 2));
ASSERT_EQ ("0 raw", amount6->text ().toStdString ());
// New account pruned values
history2.refresh ();
ASSERT_EQ (1, history2.model->rowCount ());
auto type7 (history2.model->item (0, 0));
ASSERT_EQ ("Receive (pruned)", type7->text ().toStdString ());
// Source block (send3) account is known
auto account7 (history2.model->item (0, 1));
ASSERT_EQ (nano::dev::genesis_key.pub.to_account (), account7->text ().toStdString ());
// Amount is unknown because previous block (receive1) is removed
auto amount7 (history2.model->item (0, 2));
ASSERT_EQ ("0 raw", amount7->text ().toStdString ());
// Pruning for state blocks. Change state block
{
auto transaction = ledger.tx_begin_write ();
auto latest (ledger.any.account_head (transaction, nano::dev::genesis_key.pub));
auto change = std::make_shared<nano::state_block> (nano::dev::genesis_key.pub, latest, key.pub, nano::dev::constants.genesis_amount - 200, 0, nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *system.work.generate (latest));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, change));
ledger.confirm (transaction, latest);
ASSERT_EQ (1, ledger.pruning_action (transaction, latest, 2));
}
// Genesis account pruned values
history1.refresh ();
ASSERT_EQ (1, history1.model->rowCount ());
auto type8 (history1.model->item (0, 0));
ASSERT_EQ ("Change (pruned)", type8->text ().toStdString ());
auto account8 (history1.model->item (0, 1));
ASSERT_EQ (key.pub.to_account (), account8->text ().toStdString ());
// Amount is 0 for change blocks
auto amount8 (history1.model->item (0, 2));
ASSERT_EQ ("0 raw", amount8->text ().toStdString ());
// New account pruned values
history2.refresh ();
ASSERT_EQ (1, history2.model->rowCount ());
auto type9 (history2.model->item (0, 0));
ASSERT_EQ ("Receive (pruned)", type9->text ().toStdString ());
// Source block (send3) account is unknown
auto account9 (history2.model->item (0, 1));
ASSERT_EQ (nano::account (0).to_account (), account9->text ().toStdString ());
// Amount is unknown because previous block (receive1) is removed
auto amount9 (history2.model->item (0, 2));
ASSERT_EQ ("0 raw", amount9->text ().toStdString ());
// Pruning for state blocks. Open state block
nano::keypair key2;
system.wallet (0)->insert_adhoc (key2.prv);
{
auto transaction = ledger.tx_begin_write ();
auto latest_key (ledger.any.account_head (transaction, key.pub));
auto send4 = std::make_shared<nano::state_block> (key.pub, latest_key, key.pub, 100, key2.pub, key.prv, key.pub, *system.work.generate (latest_key));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send4));
auto open2 = std::make_shared<nano::state_block> (key2.pub, 0, key2.pub, 100, send4->hash (), key2.prv, key2.pub, *system.work.generate (key2.pub));
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open2));
ledger.confirm (transaction, latest_key);
ASSERT_EQ (1, ledger.pruning_action (transaction, latest_key, 2));
}
// New account (key) pruned values
history2.refresh ();
ASSERT_EQ (1, history2.model->rowCount ());
auto type10 (history2.model->item (0, 0));
ASSERT_EQ ("Send (pruned)", type10->text ().toStdString ());
auto account10 (history2.model->item (0, 1));
ASSERT_EQ (key2.pub.to_account (), account10->text ().toStdString ());
// Amount is unknown because previous block (receive2) is removed
auto amount10 (history2.model->item (0, 2));
ASSERT_EQ ("0 raw", amount10->text ().toStdString ());
// Account (key2) pruned values
nano_qt::history history3 (ledger, key2.pub, *wallet);
history3.refresh ();
ASSERT_EQ (1, history3.model->rowCount ());
// Type is "Recieve" for open block because source block (send4) isn't removed
auto type11 (history3.model->item (0, 0));
ASSERT_EQ ("Receive", type11->text ().toStdString ());
auto account11 (history3.model->item (0, 1));
ASSERT_EQ (key.pub.to_account (), account11->text ().toStdString ());
// Amount is known for open blocks
auto amount11 (history3.model->item (0, 2));
ASSERT_EQ ("100 raw", amount11->text ().toStdString ());
}

TEST (wallet, startup_work)
Expand Down
Loading