1
0
Fork 0
forked from lthn/blockchain

coretests: added test hardfork_4_wallet_sweep_bare_outs which exposes a bug in sweep_bare_outs() where it fails if there's not enough decoys

This commit is contained in:
sowle 2024-04-09 21:43:13 +02:00
parent 19eb7baaa2
commit 021fbb7d37
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
4 changed files with 143 additions and 6 deletions

View file

@ -2319,15 +2319,25 @@ bool check_ring_signature_at_gen_time(const std::vector<test_event_entry>& event
bool check_mixin_value_for_each_input(size_t mixin, const crypto::hash& tx_id, currency::core& c)
{
std::shared_ptr<const currency::transaction_chain_entry> ptce = c.get_blockchain_storage().get_tx_chain_entry(tx_id);
if (!ptce)
return false;
transaction tx_local;
const transaction* ptx = &tx_local;
for (size_t i = 0; i < ptce->tx.vin.size(); ++i)
std::shared_ptr<const currency::transaction_chain_entry> ptce = c.get_blockchain_storage().get_tx_chain_entry(tx_id);
if (ptce)
{
auto& input = ptce->tx.vin[i];
ptx = &ptce->tx;
}
else
{
if (!c.get_tx_pool().get_transaction(tx_id, tx_local))
return false;
}
for (size_t i = 0; i < ptx->vin.size(); ++i)
{
auto& input = ptx->vin[i];
const std::vector<currency::txout_ref_v>& key_offsets = get_key_offsets_from_txin_v(input);
CHECK_AND_ASSERT_MES(key_offsets.size() == mixin + 1, false, "for input #" << i << " mixin count is " << key_offsets.size() - 1 << ", expected is " << mixin);
CHECK_AND_ASSERT_MES(key_offsets.size() == mixin + 1, false, "for input #" << i << " ring size is " << key_offsets.size() << ", mixin count is " << key_offsets.size() - 1 << ", expected mixin count is " << mixin);
}
return true;

View file

@ -1248,6 +1248,7 @@ int main(int argc, char* argv[])
// HF4
GENERATE_AND_PLAY_HF(hard_fork_4_consolidated_txs, "3-*");
GENERATE_AND_PLAY_HF(hardfork_4_wallet_transfer_with_mandatory_mixins, "3-*");
GENERATE_AND_PLAY(hardfork_4_wallet_sweep_bare_outs);
// atomics
GENERATE_AND_PLAY(atomic_simple_test);

View file

@ -321,3 +321,121 @@ bool hardfork_4_wallet_transfer_with_mandatory_mixins::c1(currency::core& c, siz
return true;
}
//------------------------------------------------------------------------------
hardfork_4_wallet_sweep_bare_outs::hardfork_4_wallet_sweep_bare_outs()
{
REGISTER_CALLBACK_METHOD(hardfork_4_wallet_sweep_bare_outs, c1);
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 10);
}
bool hardfork_4_wallet_sweep_bare_outs::generate(std::vector<test_event_entry>& events) const
{
// Test idea: make sure wallet2::sweep_bare_outs works well even if there's not enough outputs to mix
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
// rebuild genesis miner tx
std::vector<tx_destination_entry> destinations;
destinations.emplace_back(MK_TEST_COINS(23), alice_acc.get_public_address());
destinations.emplace_back(MK_TEST_COINS(23), bob_acc.get_public_address());
destinations.emplace_back(MK_TEST_COINS(55), bob_acc.get_public_address()); // this output is unique and doesn't have decoys
for (size_t i = 0; i < 10; ++i)
destinations.emplace_back(MK_TEST_COINS(23), miner_acc.get_public_address()); // decoys (later Alice will spend her output using mixins)
destinations.emplace_back(COIN, miner_acc.get_public_address()); // leftover amount will be also send to the last destination
CHECK_AND_ASSERT_MES(replace_coinbase_in_genesis_block(destinations, generator, events, blk_0), false, "");
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
DO_CALLBACK_PARAMS(events, "check_hardfork_active", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
DO_CALLBACK(events, "c1");
return true;
}
bool hardfork_4_wallet_sweep_bare_outs::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(23), UINT64_MAX, MK_TEST_COINS(23), 0, 0), false, "");
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
bob_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", MK_TEST_COINS(23 + 55), UINT64_MAX, MK_TEST_COINS(23 + 55), 0, 0), false, "");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
// 1. Try to sweep bare out for Alice (enough decoys to mix with)
std::vector<tools::wallet2::batch_of_bare_unspent_outs> tids_grouped_by_txs;
CHECK_AND_ASSERT_MES(alice_wlt->get_bare_unspent_outputs_stats(tids_grouped_by_txs), false, "");
size_t total_txs_sent = 0;
uint64_t total_amount_sent = 0;
uint64_t total_fee_spent = 0;
uint64_t total_bare_outs_sent = 0;
CHECK_AND_ASSERT_MES(alice_wlt->sweep_bare_unspent_outputs(m_accounts[ALICE_ACC_IDX].get_public_address(), tids_grouped_by_txs, total_txs_sent, total_amount_sent, total_fee_spent, total_bare_outs_sent), false, "");
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_txs_sent, 1);
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_amount_sent, MK_TEST_COINS(23));
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_fee_spent, TESTS_DEFAULT_FEE);
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_bare_outs_sent, 1);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
std::list<transaction> txs;
c.get_pool_transactions(txs);
auto& tx = txs.back();
CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(CURRENCY_DEFAULT_DECOY_SET_SIZE, get_transaction_hash(tx), c), false, "");
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(23) - TESTS_DEFAULT_FEE, UINT64_MAX, MK_TEST_COINS(23) - TESTS_DEFAULT_FEE, 0, 0), false, "");
// 2. Try to sweep bare out for Bob (not enough decoys to mix with)
tids_grouped_by_txs.clear();
CHECK_AND_ASSERT_MES(bob_wlt->get_bare_unspent_outputs_stats(tids_grouped_by_txs), false, "");
CHECK_AND_ASSERT_MES(bob_wlt->sweep_bare_unspent_outputs(m_accounts[BOB_ACC_IDX].get_public_address(), tids_grouped_by_txs, total_txs_sent, total_amount_sent, total_fee_spent, total_bare_outs_sent), false, "");
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_txs_sent, 1);
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_amount_sent, MK_TEST_COINS(23 + 55));
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_fee_spent, TESTS_DEFAULT_FEE);
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_bare_outs_sent, 2);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
txs.clear();
c.get_pool_transactions(txs);
auto& tx2 = txs.back();
CHECK_V_EQ_EXPECTED_AND_ASSERT(tx2.vin.size(), 2);
const txin_to_key &input_with_enough_decoys = boost::get<txin_to_key>(tx2.vin[0]).amount == MK_TEST_COINS(23) ? boost::get<txin_to_key>(tx2.vin[0]) : boost::get<txin_to_key>(tx2.vin[1]);
const txin_to_key &input_with_not_enough_decoys = boost::get<txin_to_key>(tx2.vin[0]).amount == MK_TEST_COINS(23) ? boost::get<txin_to_key>(tx2.vin[1]) : boost::get<txin_to_key>(tx2.vin[0]);
CHECK_V_EQ_EXPECTED_AND_ASSERT(input_with_enough_decoys.key_offsets.size(), CURRENCY_DEFAULT_DECOY_SET_SIZE + 1);
CHECK_V_EQ_EXPECTED_AND_ASSERT(input_with_not_enough_decoys.key_offsets.size(), 1);
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
bob_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", MK_TEST_COINS(23 + 55) - TESTS_DEFAULT_FEE, UINT64_MAX, MK_TEST_COINS(23 + 55) - TESTS_DEFAULT_FEE, 0, 0), false, "");
return true;
}

View file

@ -34,3 +34,11 @@ struct hardfork_4_wallet_transfer_with_mandatory_mixins : public wallet_test
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
struct hardfork_4_wallet_sweep_bare_outs : public wallet_test
{
hardfork_4_wallet_sweep_bare_outs();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};