1
0
Fork 0
forked from lthn/blockchain
blockchain/tests/core_tests/offers_test.cpp

1407 lines
66 KiB
C++
Raw Normal View History

2018-12-27 18:50:45 +03:00
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chaingen.h"
#include "offers_test.h"
#include "offers_tests_common.h"
#include "offers_helper.h"
#include "currency_core/offers_services_helpers.h"
#include "currency_core/bc_offers_service.h"
using namespace epee;
using namespace currency;
bool sign_an_offer(const transaction &offer_source_tx, size_t offer_tx_index, const account_keys& offer_owner, const blobdata &blob_for_sig, crypto::signature &sig)
{
crypto::public_key related_tx_pub_key = get_tx_pub_key_from_extra(offer_source_tx);
crypto::public_key related_tx_offer_pub_key = bc_services::get_offer_secure_key_by_index_from_tx(offer_source_tx, offer_tx_index);
currency::keypair ephemeral = AUTO_VAL_INIT(ephemeral);
bool r = currency::derive_ephemeral_key_helper(offer_owner, related_tx_pub_key, offer_tx_index, ephemeral);
CHECK_AND_ASSERT_MES(r, false, "derive_ephemeral_key_helper failed");
CHECK_AND_ASSERT_MES(ephemeral.pub == related_tx_offer_pub_key, false, "ephemeral.pub == related_tx_offer_pub_key");
crypto::generate_signature(crypto::cn_fast_hash(blob_for_sig.data(), blob_for_sig.size()), ephemeral.pub, ephemeral.sec, sig);
return true;
}
//------------------------------------------------------------------------------
bool fill_default_offer(bc_services::offer_details& od)
{
od.offer_type = OFFER_TYPE_PRIMARY_TO_TARGET;
od.amount_primary = 1000000000;
od.amount_target = 22222222;
od.target = "USD";
od.location_country = "US";
od.location_city = "New York City";
od.contacts = "skype: zina; icq: 12313212; email: zina@zina.com; mobile: +621234567834";
od.comment = "The best ever rate in NYC!!!";
od.payment_types = "BTC;BANK;CASH";
od.expiration_time = 10;
return true;
}
offers_tests::offers_tests()
{
REGISTER_CALLBACK_METHOD(offers_tests, configure_core);
REGISTER_CALLBACK_METHOD(offers_tests, check_offers_1);
REGISTER_CALLBACK_METHOD(offers_tests, check_offers_updated_1);
REGISTER_CALLBACK_METHOD(offers_tests, check_offers_updated_2);
}
#define FIRST_UPDATED_LOCATION "Washington"
#define SECOND_UPDATED_LOCATION "LA"
bool offers_tests::generate(std::vector<test_event_entry>& events) const
{
uint64_t ts_start = 1338224400;
GENERATE_ACCOUNT(miner_account);
MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
MAKE_ACCOUNT(events, third_acc);
DO_CALLBACK(events, "configure_core");
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_account);
REWIND_BLOCKS_N_WITH_TIME(events, blk_11, blk_1, miner_account, 10);
//push first offers
std::vector<currency::attachment_v> attachments;
bc_services::offer_details od = AUTO_VAL_INIT(od);
fill_default_offer(od);
bc_services::put_offer_into_attachment(od, attachments);
MAKE_TX_LIST_START_WITH_ATTACHS(events, txs_blk, miner_account, miner_account, MK_TEST_COINS(1), blk_11, attachments);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_12, blk_11, miner_account, txs_blk);
//push second offer
std::vector<currency::attachment_v> attachments2;
bc_services::offer_details od2 = AUTO_VAL_INIT(od2);
fill_default_offer(od2);
bc_services::put_offer_into_attachment(od2, attachments2);
MAKE_TX_LIST_START_WITH_ATTACHS(events, txs_blk2, miner_account, miner_account, MK_TEST_COINS(1), blk_12, attachments2);
//crypto::secret_key offer_secret_key = generator.last_tx_generated_secret_key;
currency::transaction tx = txs_blk2.back();
MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_12, miner_account, txs_blk2);
// Both offers has timestamp of correspoging blocks which is greather then blk_11.
// However, "now" is close to blk_11.timestamp because there was no commands after it in event queue to adjust the time.
// This condition helps to check rear case, when offers marked with future timestamp should not be filtered out.
DO_CALLBACK(events, "check_offers_1");
//now update offer
std::vector<currency::attachment_v> attachments3;
bc_services::update_offer uo = AUTO_VAL_INIT(uo);
fill_default_offer(uo.of);
uo.of.location_city = "Washington";
uo.offer_index = 0;
uo.tx_id = currency::get_transaction_hash(tx);
crypto::public_key related_tx_pub_key_1 = get_tx_pub_key_from_extra(tx);
crypto::public_key related_tx_offer_pub_key_1 = bc_services::get_offer_secure_key_by_index_from_tx(tx, 0);
currency::keypair ephemeral_1;
bool r = currency::derive_ephemeral_key_helper(miner_account.get_keys(), related_tx_pub_key_1, 0, ephemeral_1);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to derive_ephemeral_key_helper");
CHECK_AND_ASSERT_THROW_MES(ephemeral_1.pub == related_tx_offer_pub_key_1, "Failed to derive_ephemeral_key_helper(pub keys missmatch)");
blobdata bl_for_sig = bc_services::make_offer_sig_blob(uo);
crypto::generate_signature(crypto::cn_fast_hash(bl_for_sig.data(), bl_for_sig.size()), ephemeral_1.pub, ephemeral_1.sec, uo.sig);
bc_services::put_offer_into_attachment(uo, attachments3);
//blobdata bl_for_sig = currency::make_offer_sig_blob(uo);
//crypto::generate_signature(crypto::cn_fast_hash(bl_for_sig.data(), bl_for_sig.size()), currency::get_tx_pub_key_from_extra(tx), offer_secret_key, uo.sig);
MAKE_TX_LIST_START_WITH_ATTACHS(events, txs_blk3, miner_account, miner_account, MK_TEST_COINS(1), blk_13, attachments3);
//offer_secret_key = generator.last_tx_generated_secret_key;
tx = txs_blk3.back();
tx_id_1 = currency::get_transaction_hash(tx);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_14, blk_13, miner_account, txs_blk3);
DO_CALLBACK(events, "check_offers_updated_1");
//and update this offer once again
std::vector<currency::attachment_v> attachments4;
bc_services::update_offer uo2 = AUTO_VAL_INIT(uo2);
fill_default_offer(uo2.of);
uo2.of.location_city = "LA";
uo2.offer_index = 0;
uo2.tx_id = currency::get_transaction_hash(tx);
//---------------------------
crypto::public_key related_tx_pub_key = get_tx_pub_key_from_extra(tx);
crypto::public_key related_tx_offer_pub_key = bc_services::get_offer_secure_key_by_index_from_tx(tx, 0);
currency::keypair ephemeral;
r = currency::derive_ephemeral_key_helper(miner_account.get_keys(), related_tx_pub_key, 0, ephemeral);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to derive_ephemeral_key_helper");
CHECK_AND_ASSERT_THROW_MES(ephemeral.pub == related_tx_offer_pub_key, "Failed to derive_ephemeral_key_helper(pub keys missmatch)");
bl_for_sig = bc_services::make_offer_sig_blob(uo2);
crypto::generate_signature(crypto::cn_fast_hash(bl_for_sig.data(), bl_for_sig.size()), ephemeral.pub, ephemeral.sec, uo2.sig);
bc_services::put_offer_into_attachment(uo2, attachments4);
MAKE_TX_LIST_START_WITH_ATTACHS(events, txs_blk4, miner_account, miner_account, MK_TEST_COINS(1), blk_14, attachments4);
//offer_secret_key = generator.last_tx_generated_secret_key;
tx_id_2 = currency::get_transaction_hash(txs_blk4.back());
MAKE_NEXT_BLOCK_TX_LIST(events, blk_15, blk_14, miner_account, txs_blk4);
DO_CALLBACK(events, "check_offers_updated_2");
MAKE_NEXT_BLOCK(events, blk_16, blk_15, miner_account);
return true;
}
bool offers_tests::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; //four blocks
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH; //four blocks
c.get_blockchain_storage().set_core_runtime_config(pc);
return true;
}
bool get_of_by_hash(crypto::hash& id, const std::list<bc_services::offer_details_ex>& of_list, bc_services::offer_details_ex& od)
{
for (auto& of : of_list)
{
if (of.tx_hash == id)
{
od = of;
return true;
}
}
return false;
}
bool offers_tests::check_offers_1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
std::list<bc_services::offer_details_ex> offers;
get_all_offers(c, offers);
CHECK_EQ(2, offers.size());
return true;
}
bool offers_tests::check_offers_updated_1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
std::list<bc_services::offer_details_ex> offers;
get_all_offers(c, offers);
CHECK_EQ(2, offers.size());
bc_services::offer_details_ex target_offer;
bool r = get_of_by_hash(tx_id_1, offers, target_offer);
CHECK_TEST_CONDITION(r);
CHECK_EQ(target_offer.location_city, FIRST_UPDATED_LOCATION);
return true;
}
bool offers_tests::check_offers_updated_2(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
std::list<bc_services::offer_details_ex> offers;
get_all_offers(c, offers);
CHECK_EQ(2, offers.size());
bc_services::offer_details_ex target_offer;
bool r = get_of_by_hash(tx_id_1, offers, target_offer);
CHECK_TEST_CONDITION(!r);
r = get_of_by_hash(tx_id_2, offers, target_offer);
CHECK_TEST_CONDITION(r);
CHECK_EQ(target_offer.location_city, SECOND_UPDATED_LOCATION);
return true;
}
//------------------------------------------------------------------------------
bool construct_block_gentime_with_timestamp(test_generator& generator, const currency::block& prev_block, const currency::account_base& acc, uint64_t timestamp, currency::block& b)
{
bool r = false;
crypto::hash prev_id = get_block_hash(prev_block);
uint64_t already_generated_coins = generator.get_already_generated_coins(prev_block);
std::vector<size_t> block_sizes;
generator.get_last_n_block_sizes(block_sizes, prev_id, CURRENCY_REWARD_BLOCKS_WINDOW);
size_t height = get_block_height(prev_block) + 1;
r = generator.construct_block(b, height, prev_id, acc, timestamp, already_generated_coins, block_sizes, std::list<transaction>());
CHECK_AND_ASSERT_MES(r, false, "construct_block_manually failed");
return true;
}
offers_expiration_test::offers_expiration_test()
: m_offers_ts(0)
{
REGISTER_CALLBACK_METHOD(offers_expiration_test, c1);
}
bool offers_expiration_test::generate(std::vector<test_event_entry>& events) const
{
// Makes sure that offers are correctly removed from blockchain storage when they're expired by specified time or by general time limit (two weeks for now).
// Test outline:
// 1. Create four txs with expiration time set to 0 (max), 1, 2 and 3 days.
// 2. Rewind time by 2 days, make sure only 2 offers are expired.
// 3. Rewind time by OFFER_MAXIMUM_LIFE_TIME - 2 days more (to be OFFER_MAXIMUM_LIFE_TIME in total), make sure all offers are expired.
GENERATE_ACCOUNT(miner_acc);
GENERATE_ACCOUNT(alice_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
std::vector<currency::attachment_v> attachment;
m_offer = AUTO_VAL_INIT(m_offer);
fill_test_offer(m_offer);
bc_services::offer_details od = m_offer;
od.expiration_time = 0;
attachment.clear();
bc_services::put_offer_into_attachment(od, attachment);
2019-04-25 23:37:43 +02:00
MAKE_TX_ATTACH(events, tx_0, miner_acc, alice_acc, TESTS_DEFAULT_FEE, blk_0r, attachment);
2018-12-27 18:50:45 +03:00
od.expiration_time = 1;
attachment.clear();
bc_services::put_offer_into_attachment(od, attachment);
2019-04-25 23:37:43 +02:00
MAKE_TX_ATTACH(events, tx_1, miner_acc, alice_acc, TESTS_DEFAULT_FEE, blk_0r, attachment);
2018-12-27 18:50:45 +03:00
od.expiration_time = 2;
attachment.clear();
bc_services::put_offer_into_attachment(od, attachment);
2019-04-25 23:37:43 +02:00
MAKE_TX_ATTACH(events, tx_2, miner_acc, alice_acc, TESTS_DEFAULT_FEE, blk_0r, attachment);
2018-12-27 18:50:45 +03:00
od.expiration_time = 3;
attachment.clear();
bc_services::put_offer_into_attachment(od, attachment);
2019-04-25 23:37:43 +02:00
MAKE_TX_ATTACH(events, tx_3, miner_acc, alice_acc, TESTS_DEFAULT_FEE, blk_0r, attachment);
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list<transaction>({ tx_0, tx_1, tx_2, tx_3 }));
m_offers_ts = blk_1.timestamp;
events.push_back(event_core_time(m_offers_ts));
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc);
// rewind time for 2 days
uint64_t offers_ts_plus_two_days = m_offers_ts + 60 * 60 * 24 * 2 + 1;
events.push_back(event_core_time(offers_ts_plus_two_days));
DO_CALLBACK(events, "c1");
return true;
}
bool offers_expiration_test::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bc_services::bc_offers_service* offers_service = dynamic_cast<bc_services::bc_offers_service*>(c.get_blockchain_storage().get_attachment_services_manager().get_service_by_id(BC_OFFERS_SERVICE_ID));
CHECK_AND_ASSERT_MES(offers_service != nullptr, false, "Offers service was not registered in attachment service manager!");
// don't need to trim_offers() here because get_all_offers() returns offers filtered by expiration_time
// offers_service->trim_offers();
std::list<bc_services::offer_details_ex> offers;
bool r = get_all_offers(c, offers);
CHECK_AND_ASSERT_MES(r, false, "get_all_offers failed");
CHECK_V_EQ_EXPECTED_AND_ASSERT(offers.size(), 2);
bc_services::offer_details_ex offer_0 = offers.front(), offer_3 = offers.back();
if (offers.front().expiration_time != 0)
{
offer_0 = offers.back();
offer_3 = offers.front();
}
CHECK_AND_ASSERT_MES(offer_0.expiration_time == 0 && offer_3.expiration_time == 3, false, "Incorrect offers expiration time left");
r = compare_offers(m_offer, offer_0, default_offer_skip_field_mask | offers_fields::offer_field_expiration_time);
CHECK_AND_ASSERT_MES(r, false, "offer_0 obtained via bc_service differs from original");
r = compare_offers(m_offer, offer_3, default_offer_skip_field_mask | offers_fields::offer_field_expiration_time);
CHECK_AND_ASSERT_MES(r, false, "offer_3 obtained via bc_service differs from original");
// rewind time very close to the offers' lifetime limit
test_core_time::adjust(m_offers_ts + OFFER_MAXIMUM_LIFE_TIME - 1);
offers_service->trim_offers();
// trim_offers should still has no effect as all offers' are within their allowed lifetime (OFFER_MAXIMUM_LIFE_TIME)
CHECK_V_EQ_EXPECTED_AND_ASSERT(offers_service->get_offers_container().size(), 4);
offers.clear();
r = get_all_offers(c, offers);
CHECK_AND_ASSERT_MES(r, false, "get_all_offers failed");
// get_all_offers should returns only 1 offer -- the one with 0 (max) expiration time
CHECK_V_EQ_EXPECTED_AND_ASSERT(offers.size(), 1);
CHECK_V_EQ_EXPECTED_AND_ASSERT(offers.front().expiration_time, 0);
// rewind time beyond the offers' lifetime limit
test_core_time::adjust(m_offers_ts + OFFER_MAXIMUM_LIFE_TIME + 1);
offers_service->trim_offers();
// no offers should left in the backend service
CHECK_V_EQ_EXPECTED_AND_ASSERT(offers_service->get_offers_container().size(), 0);
offers.clear();
r = get_all_offers(c, offers);
CHECK_AND_ASSERT_MES(r, false, "get_all_offers failed");
// no offers should be visible via get_all_offers()
CHECK_V_EQ_EXPECTED_AND_ASSERT(offers.size(), 0);
return true;
}
//------------------------------------------------------------------------------
offers_filtering_1::offers_filtering_1()
{
REGISTER_CALLBACK_METHOD(offers_filtering_1, c1);
test_gentime_settings s = test_generator::get_test_gentime_settings();
s.tx_max_out_amount = PREMINE_AMOUNT; // use very high max allowed output amount to avoid splitting premine to countless outputs and slowing down the test to the death
s.miner_tx_max_outs = 11; // limit genesis coinbase outs count for the same reason
test_generator::set_test_gentime_settings(s);
}
bool offers_filtering_1::generate(std::vector<test_event_entry>& events) const
{
GENERATE_ACCOUNT(preminer_acc);
GENERATE_ACCOUNT(miner_acc);
MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, test_core_time::get_time());
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4);
std::list<transaction> txs;
size_t count = 0;
for (; count < offers_count / 2; ++count)
{
bc_services::offer_details od = AUTO_VAL_INIT(od);
fill_test_offer(od);
std::vector<currency::attachment_v> attachment;
bc_services::put_offer_into_attachment(od, attachment);
2019-04-25 23:37:43 +02:00
MAKE_TX_LIST_ATTACH(events, txs, miner_acc, miner_acc, TESTS_DEFAULT_FEE, blk_0r, attachment);
2018-12-27 18:50:45 +03:00
}
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, txs);
txs.clear();
for (; count < offers_count; ++count)
{
bc_services::offer_details od = AUTO_VAL_INIT(od);
fill_test_offer(od);
std::vector<currency::attachment_v> attachment;
bc_services::put_offer_into_attachment(od, attachment);
2019-04-25 23:37:43 +02:00
MAKE_TX_LIST_ATTACH(events, txs, miner_acc, miner_acc, TESTS_DEFAULT_FEE, blk_1, attachment);
2018-12-27 18:50:45 +03:00
}
MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner_acc, txs);
DO_CALLBACK(events, "c1");
return true;
}
void _dbg_print_offer_list(const std::list<bc_services::offer_details_ex>& ol)
{
int i = 0;
for (auto o : ol)
{
LOG_PRINT_L0(
i++ << ENDL <<
" amount_primary: " << o.amount_primary << ENDL <<
" amount_target: " << o.amount_target << ENDL <<
" rate: " << static_cast<double>(o.amount_primary) / o.amount_target << ENDL <<
" timestamp: " << o.timestamp);
}
}
bool check_offers_sorting(bool reverse, uint64_t order_by, const char* field_name, const std::list<bc_services::offer_details_ex>& original_list, //field_t (*field_selector) (const bc_services::offer_details_ex&),
bool (*field_cmp) (const bc_services::offer_details_ex&, const bc_services::offer_details_ex&), currency::core& c)
{
std::list<bc_services::offer_details_ex> offers_sorted(original_list);
bc_services::core_offers_filter filter = AUTO_VAL_INIT(filter);
filter.limit = UINT64_MAX;
filter.order_by = order_by;
filter.reverse = reverse;
bool r = bc_services::filter_offers_list(offers_sorted, filter, c.get_blockchain_storage().get_core_runtime_config().get_core_time());
CHECK_AND_FORCE_ASSERT_MES(r, false, "filter_offers_list failed");
CHECK_AND_FORCE_ASSERT_MES(offers_sorted.size() == offers_filtering_1::offers_count, false, "filter_offers_list returned wrong offer list");
//_dbg_print_offer_list(original_list);
//_dbg_print_offer_list(offers_sorted);
const bc_services::offer_details_ex* prev_offer = nullptr;
for (const bc_services::offer_details_ex& o : offers_sorted)
{
CHECK_AND_ASSERT_MES(prev_offer == nullptr || field_cmp(*prev_offer, o), false, "Offers list was not sorted by " << field_name);
prev_offer = &o;
}
return true;
}
bool check_offers_limits(const std::list<bc_services::offer_details_ex>& original_list, uint64_t offset, uint64_t limit, uint64_t expect, currency::core& c)
{
std::list<bc_services::offer_details_ex> offers_sorted(original_list);
bc_services::core_offers_filter filter = AUTO_VAL_INIT(filter);
filter.offset = offset;
filter.limit = limit;
filter.order_by = ORDER_BY_TIMESTAMP;
filter.reverse = false;
bool r = bc_services::filter_offers_list(offers_sorted, filter, c.get_blockchain_storage().get_core_runtime_config().get_core_time());
CHECK_AND_FORCE_ASSERT_MES(r, false, "filter_offers_list failed");
CHECK_AND_FORCE_ASSERT_MES(offers_sorted.size() == expect, false, "filter_offers_list returned wrong size of offer list: " << offers_sorted.size() << " for offset: " << offset << ", limit: " << limit << ", expect: " << expect);
return true;
}
bool offers_filtering_1::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bc_services::bc_offers_service* offers_service = dynamic_cast<bc_services::bc_offers_service*>(c.get_blockchain_storage().get_attachment_services_manager().get_service_by_id(BC_OFFERS_SERVICE_ID));
CHECK_AND_ASSERT_MES(offers_service != nullptr, false, "Offers service was not registered in attachment service manager!");
std::list<bc_services::offer_details_ex> offers;
bool r = get_all_offers(c, offers);
CHECK_AND_FORCE_ASSERT_MES(r, false, "get_all_offers failed");
CHECK_AND_FORCE_ASSERT_MES(offers.size() == offers_count, false, "Incorrect offers count");
#define CHECK_SORTING(field, enum_val) \
r &= check_offers_sorting(false, enum_val, #field, offers, [](const bc_services::offer_details_ex& a, const bc_services::offer_details_ex& b)->bool { return a.field <= b.field; }, c); \
r &= check_offers_sorting(true, enum_val, #field, offers, [](const bc_services::offer_details_ex& a, const bc_services::offer_details_ex& b)->bool { return a.field >= b.field; }, c)
CHECK_SORTING(timestamp, ORDER_BY_TIMESTAMP);
CHECK_SORTING(amount_primary, ORDER_BY_AMOUNT_PRIMARY);
CHECK_SORTING(amount_target, ORDER_BY_AMOUNT_TARGET);
// amount_rate requires custom comparator
r &= check_offers_sorting(false, ORDER_BY_AMOUNT_RATE, "amount_rate", offers,
[](const bc_services::offer_details_ex& a, const bc_services::offer_details_ex& b)->bool { return bc_services::calculate_offer_rate(a) <= bc_services::calculate_offer_rate(b); },
c);
r &= check_offers_sorting(true, ORDER_BY_AMOUNT_RATE, "amount_rate", offers,
[](const bc_services::offer_details_ex& a, const bc_services::offer_details_ex& b)->bool { return bc_services::calculate_offer_rate(a) >= bc_services::calculate_offer_rate(b); },
c);
CHECK_SORTING(payment_types, ORDER_BY_PAYMENT_TYPES);
CHECK_SORTING(contacts, ORDER_BY_CONTACTS);
CHECK_SORTING(location_city, ORDER_BY_LOCATION);
r &= check_offers_sorting(false, ORDER_BY_NAME, "target", offers,
[](const bc_services::offer_details_ex& a, const bc_services::offer_details_ex& b)->bool { return utf8_to_lower(a.target) <= utf8_to_lower(b.target); },
c);
uint64_t oles[][3] =
// offset limit expect
{{0, offers_filtering_1::offers_count, offers_filtering_1::offers_count},
{1, offers_filtering_1::offers_count, offers_filtering_1::offers_count-1},
{offers_filtering_1::offers_count-1, offers_filtering_1::offers_count, 1},
{offers_filtering_1::offers_count, offers_filtering_1::offers_count, 0},
{offers_filtering_1::offers_count+1, offers_filtering_1::offers_count, 0},
{0, offers_filtering_1::offers_count+1, offers_filtering_1::offers_count},
{0, offers_filtering_1::offers_count-1, offers_filtering_1::offers_count-1},
{1, offers_filtering_1::offers_count-1, offers_filtering_1::offers_count-1},
{1, offers_filtering_1::offers_count-2, offers_filtering_1::offers_count-2},
{0, 0, 0}
};
for (auto& el : oles)
{
r &= check_offers_limits(offers, el[0], el[1], el[2], c);
}
return r;
}
//------------------------------------------------------------------------------
offers_handling_on_chain_switching::offers_handling_on_chain_switching()
{
REGISTER_CALLBACK_METHOD(offers_handling_on_chain_switching, c1);
}
bool offers_handling_on_chain_switching::generate(std::vector<test_event_entry>& events) const
{
m_accounts.resize(TOTAL_ACCS_COUNT);
auto& miner_acc = m_accounts[MINER_ACC_IDX];
miner_acc.generate();
auto& alice_acc = m_accounts[ALICE_ACC_IDX];
alice_acc.generate();
// event index
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); // 0
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // 2N (N == CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
2019-04-25 23:37:43 +02:00
MAKE_TX(events, tx_0, miner_acc, alice_acc, TESTS_DEFAULT_FEE * 70, blk_0r); // 2N+1
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); // 2N+2
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // 4N+2
bc_services::offer_details od = AUTO_VAL_INIT(od);
fill_test_offer(od);
std::vector<currency::attachment_v> attachment;
bc_services::put_offer_into_attachment(od, attachment);
2019-04-25 23:37:43 +02:00
MAKE_TX_ATTACH(events, tx_1, alice_acc, alice_acc, TESTS_DEFAULT_FEE, blk_1r, attachment); // 4N+3
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc); // 4N+4
//MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_1); // 4N+4
DO_CALLBACK(events, "c1"); // 4N+5
return true;
}
bool offers_handling_on_chain_switching::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false, bool_stub = false;
// there's one tx with an offer in the pool
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
CHECK_AND_ASSERT_MES(c.get_alternative_blocks_count() == 0, false, "Incorrect alt blocks count: " << c.get_alternative_blocks_count());
// check Alice's wallet against offers, there should not be a one
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]);
alice_wlt->refresh();
alice_wlt->scan_tx_pool(bool_stub);
std::list<bc_services::offer_details_ex> offers;
r = alice_wlt->get_actual_offers(offers);
CHECK_AND_ASSERT_MES(r, false, "get_actual_offers failed");
CHECK_AND_ASSERT_MES(offers.size() == 0, false, "incorrect offers.size() = " << offers.size());
// mine first alt block (no txs)
uint64_t blk_1r_height = c.get_current_blockchain_size() - 2;
crypto::hash blk_1r_id = c.get_block_id_by_height(blk_1r_height);
block blk_2a = AUTO_VAL_INIT(blk_2a);
2019-03-25 01:30:20 +01:00
r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector<transaction>(), blk_1r_id, blk_1r_height + 1, &blk_2a);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
CHECK_AND_ASSERT_MES(c.get_alternative_blocks_count() == 1, false, "Incorrect alt blocks count: " << c.get_alternative_blocks_count());
const transaction& tx_1 = boost::get<transaction>(events[4 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3]);
// mine second alt block (include offer tx) -- this should trigger chain switching
block blk_3a = AUTO_VAL_INIT(blk_3a);
2019-03-25 01:30:20 +01:00
r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector<transaction>({tx_1}), get_block_hash(blk_2a), blk_1r_height + 2, &blk_3a);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
CHECK_AND_ASSERT_MES(c.get_alternative_blocks_count() == 1, false, "Incorrect alt blocks count: " << c.get_alternative_blocks_count());
// check the wallet for offers, we should have an offer now
alice_wlt->refresh();
alice_wlt->scan_tx_pool(bool_stub);
offers.clear();
r = alice_wlt->get_actual_offers(offers);
CHECK_AND_ASSERT_MES(r, false, "get_actual_offers failed");
CHECK_AND_ASSERT_MES(offers.size() == 1, false, "incorrect offers.size() = " << offers.size());
return true;
}
//------------------------------------------------------------------------------
offer_removing_and_selected_output::offer_removing_and_selected_output()
{
REGISTER_CALLBACK_METHOD(offer_removing_and_selected_output, check_offers);
}
bool offer_removing_and_selected_output::generate(std::vector<test_event_entry>& events) const
{
// Test idea: remove two offers and make sure in both cases a transfer with minimal amount is used for that "free" operation
bool r = false;
m_accounts.resize(TOTAL_ACCS_COUNT);
auto& miner_acc = m_accounts[MINER_ACC_IDX];
miner_acc.generate();
auto& alice_acc = m_accounts[ALICE_ACC_IDX];
alice_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// prepare different outputs for Alice
transaction tx_0 = AUTO_VAL_INIT(tx_0);
std::vector<tx_destination_entry> destinations;
destinations.push_back(tx_destination_entry(MK_TEST_COINS(4), alice_acc.get_public_address()));
destinations.push_back(tx_destination_entry(MK_TEST_COINS(8), alice_acc.get_public_address()));
destinations.push_back(tx_destination_entry(MK_TEST_COINS(1) * 1.2, alice_acc.get_public_address())); // <- min #2
destinations.push_back(tx_destination_entry(MK_TEST_COINS(1) * 1.1, alice_acc.get_public_address())); // <- min #1
2018-12-27 18:50:45 +03:00
destinations.push_back(tx_destination_entry(MK_TEST_COINS(3), alice_acc.get_public_address()));
destinations.push_back(tx_destination_entry(MK_TEST_COINS(2), alice_acc.get_public_address()));
destinations.push_back(tx_destination_entry(MK_TEST_COINS(5), alice_acc.get_public_address()));
uint64_t destinations_amount = 0;
for(auto& d : destinations)
destinations_amount += d.amount;
std::vector<tx_source_entry> sources;
r = fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), destinations_amount + TESTS_DEFAULT_FEE, 0);
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
2024-12-27 07:27:43 +01:00
r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0, 0);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
events.push_back(tx_0);
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
uint64_t offer_cancel_tx_selected_amount = MK_TEST_COINS(1) * 11 / 10; // min #1
2018-12-27 18:50:45 +03:00
DO_CALLBACK_PARAMS(events, "check_offers", offer_cancel_tx_selected_amount);
offer_cancel_tx_selected_amount = MK_TEST_COINS(1) * 12 / 10; // min #2
2018-12-27 18:50:45 +03:00
DO_CALLBACK_PARAMS(events, "check_offers", offer_cancel_tx_selected_amount);
return true;
}
bool offer_removing_and_selected_output::check_offers(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
uint64_t offer_cancel_tx_selected_amount = 0;
r = epee::string_tools::hex_to_pod(boost::get<callback_entry>(events[ev_index]).callback_params, offer_cancel_tx_selected_amount);
CHECK_AND_ASSERT_MES(r && offer_cancel_tx_selected_amount > 0, false, "hex_to_pod failed");
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]);
alice_wlt->refresh();
LOG_PRINT_CYAN("Alice's transfers:" << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
uint64_t alice_start_balance = alice_wlt->balance();
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
bc_services::offer_details_ex od = AUTO_VAL_INIT(od);
fill_test_offer(od);
od.fee = TESTS_DEFAULT_FEE;
transaction create_offer_tx = AUTO_VAL_INIT(create_offer_tx);
LOG_PRINT_CYAN("%%%%% alice_wlt->push_offer()", LOG_LEVEL_0);
alice_wlt->push_offer(od, create_offer_tx);
crypto::hash create_offer_tx_id = get_transaction_hash(create_offer_tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
2019-03-25 01:30:20 +01:00
CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed");
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("offer's put into the blockchain", "Alice", alice_wlt, alice_start_balance - od.fee, true, 1), false, "");
2018-12-27 18:50:45 +03:00
// check offer, retured by get_actual_offers()
std::list<bc_services::offer_details_ex> offers;
r = alice_wlt->get_actual_offers(offers);
CHECK_AND_ASSERT_MES(r && offers.size() == 1, false, "alice_wlt->get_actual_offers failed, offers.size() == " << offers.size());
CHECK_AND_ASSERT_MES(compare_offers(od, offers.front()), false, "");
// cancel offer
transaction cancel_offer_tx = AUTO_VAL_INIT(cancel_offer_tx);
LOG_PRINT_CYAN("%%%%% alice_wlt->cancel_offer_by_id()", LOG_LEVEL_0);
uint64_t cancellation_fee = TESTS_DEFAULT_FEE * 11 / 10;
alice_wlt->cancel_offer_by_id(create_offer_tx_id, 0, cancellation_fee, cancel_offer_tx);
2018-12-27 18:50:45 +03:00
// make sure used input is the expected one
CHECK_AND_ASSERT_MES(cancel_offer_tx.vin.size() == 1, false, "cancel_offer_tx.vin.size() == " << cancel_offer_tx.vin.size());
CHECKED_GET_SPECIFIC_VARIANT(cancel_offer_tx.vin[0], txin_to_key, in, false);
CHECK_AND_ASSERT_MES(in.amount == offer_cancel_tx_selected_amount, false, "Offer's cancellation tx uses input with amount " << print_money_brief(in.amount) << ", while expected amount to be used is: " << print_money_brief(offer_cancel_tx_selected_amount));
// make sure offer's cancellation tx has correct fee
CHECK_AND_ASSERT_MES(get_tx_fee(cancel_offer_tx) == cancellation_fee, false, "get_tx_fee(cancel_offer_tx) = " << get_tx_fee(cancel_offer_tx));
2018-12-27 18:50:45 +03:00
// add it to the blockchain
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
2019-03-25 01:30:20 +01:00
CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed");
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
// Alice's banace should not change
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("offer has been cancelled, ", "Alice", alice_wlt, alice_start_balance - od.fee - cancellation_fee, true, 1), false, "");
2018-12-27 18:50:45 +03:00
// get_actual_offers should return empty list
offers.clear();
r = alice_wlt->get_actual_offers(offers);
CHECK_AND_ASSERT_MES(r && offers.size() == 0, false, "alice_wlt->get_actual_offers failed, offers.size() = " << offers.size());
return true;
}
//------------------------------------------------------------------------------
offers_and_stuck_txs::offers_and_stuck_txs()
{
REGISTER_CALLBACK_METHOD(offers_and_stuck_txs, c1);
REGISTER_CALLBACK_METHOD(offers_and_stuck_txs, check_offers);
}
bool offers_and_stuck_txs::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// add an offer -- tx_1
bc_services::offer_details od = AUTO_VAL_INIT(od);
fill_test_offer(od);
od.comment = "new";
std::vector<attachment_v> attachments;
bc_services::put_offer_into_attachment(od, attachments);
MAKE_TX_ATTACH(events, tx_1, miner_acc, miner_acc, TESTS_DEFAULT_FEE, blk_0r, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1);
// make tx deleting the offer -- tx_2, don't add it to the blockchain
bc_services::cancel_offer co = AUTO_VAL_INIT(co);
co.tx_id = get_transaction_hash(tx_1);
co.offer_index = 0;
r = sign_an_offer(tx_1, co.offer_index, miner_acc.get_keys(), bc_services::make_offer_sig_blob(co), co.sig);
CHECK_AND_ASSERT_MES(r, false, "sign_an_offer failed");
attachments.clear();
bc_services::put_offer_into_attachment(co, attachments);
transaction tx_2 = AUTO_VAL_INIT(tx_2);
uint64_t fee = 7 * TESTS_DEFAULT_FEE;
r = construct_tx_to_key(m_hardforks, events, tx_2, blk_1, miner_acc, miner_acc, TESTS_DEFAULT_FEE, fee, 0, 0, empty_extra, attachments);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "construct_tx_to_key failed");
events.push_back(tx_2);
CHECK_AND_ASSERT_MES(get_tx_fee(tx_2) == fee, false, "Incorrect fee: " << print_money_brief(get_tx_fee(tx_2)) << ", expected: " << print_money_brief(fee));
// don't include tx_2 with offer deletion yet
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc);
size_t expected_tx_count = 1;
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", expected_tx_count);
DO_CALLBACK(events, "print_tx_pool");
// make tx updating the offer
bc_services::update_offer uo = AUTO_VAL_INIT(uo);
uo.tx_id = get_transaction_hash(tx_1);
uo.offer_index = 0;
uo.of = od;
uo.of.comment = "update";
r = sign_an_offer(tx_1, co.offer_index, miner_acc.get_keys(), bc_services::make_offer_sig_blob(uo), uo.sig);
CHECK_AND_ASSERT_MES(r, false, "sign_an_offer failed");
attachments.clear();
bc_services::put_offer_into_attachment(uo, attachments);
transaction tx_3 = AUTO_VAL_INIT(tx_3);
fee = 90 * TESTS_DEFAULT_FEE;
r = construct_tx_to_key(m_hardforks, events, tx_3, blk_2, miner_acc, miner_acc, TESTS_DEFAULT_FEE, fee, 0, 0, empty_extra, attachments);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "construct_tx_to_key failed");
events.push_back(tx_3);
CHECK_AND_ASSERT_MES(get_tx_fee(tx_3) == fee, false, "Incorrect fee: " << print_money_brief(get_tx_fee(tx_3)) << ", expected: " << print_money_brief(fee));
expected_tx_count = 2;
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", expected_tx_count);
DO_CALLBACK(events, "print_tx_pool");
DO_CALLBACK(events, "c1");
return true;
}
bool offers_and_stuck_txs::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
return true;
}
bool offers_and_stuck_txs::check_offers(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
return true;
}
//------------------------------------------------------------------------------
offers_updating_hack::offers_updating_hack()
{
REGISTER_CALLBACK_METHOD(offers_updating_hack, update_foreign_offer);
REGISTER_CALLBACK_METHOD(offers_updating_hack, delete_foreign_offer);
}
bool offers_updating_hack::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
transaction tx_a = AUTO_VAL_INIT(tx_a);
r = construct_tx_with_many_outputs(m_hardforks, events, blk_0r, miner_acc.get_keys(), alice_acc.get_public_address(), TESTS_DEFAULT_FEE * 1000, 10, TESTS_DEFAULT_FEE, tx_a);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed");
events.push_back(tx_a);
transaction tx_b = AUTO_VAL_INIT(tx_b);
r = construct_tx_with_many_outputs(m_hardforks, events, blk_0r, miner_acc.get_keys(), bob_acc.get_public_address(), TESTS_DEFAULT_FEE * 1000, 10, TESTS_DEFAULT_FEE, tx_b);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed");
events.push_back(tx_b);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list<transaction>({ tx_a, tx_b }));
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
// Alice adds and offer
bc_services::offer_details od = AUTO_VAL_INIT(od);
fill_test_offer(od);
od.comment = "new";
std::vector<attachment_v> attachments;
bc_services::put_offer_into_attachment(od, attachments);
MAKE_TX_ATTACH(events, tx_1, alice_acc, alice_acc, TESTS_DEFAULT_FEE, blk_1r, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_1);
DO_CALLBACK(events, "check_tx_pool_empty");
// Alice updates the offer
bc_services::update_offer uo = AUTO_VAL_INIT(uo);
uo.tx_id = get_transaction_hash(tx_1);
uo.offer_index = 0;
uo.of = od;
uo.of.comment = "update by Alice";
r = sign_an_offer(tx_1, uo.offer_index, alice_acc.get_keys(), bc_services::make_offer_sig_blob(uo), uo.sig);
CHECK_AND_ASSERT_MES(r, false, "sign_an_offer failed");
attachments.clear();
bc_services::put_offer_into_attachment(uo, attachments);
transaction tx_2 = AUTO_VAL_INIT(tx_2);
uint64_t fee = 90 * TESTS_DEFAULT_FEE;
r = construct_tx_to_key(m_hardforks, events, tx_2, blk_2, alice_acc, alice_acc, TESTS_DEFAULT_FEE, fee, 0, 0, empty_extra, attachments);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "construct_tx_to_key failed");
events.push_back(tx_2);
CHECK_AND_ASSERT_MES(get_tx_fee(tx_2) == fee, false, "Incorrect fee: " << print_money_brief(get_tx_fee(tx_2)) << ", expected: " << print_money_brief(fee));
// don't add tx_2 to the blockchain yet
// ======= Case 1
DO_CALLBACK(events, "update_foreign_offer");
// ======= Prepare for case 2
// these block should cause chain switching
MAKE_NEXT_BLOCK(events, blk_3a, blk_2, miner_acc);
MAKE_NEXT_BLOCK(events, blk_4a, blk_3a, miner_acc);
MAKE_NEXT_BLOCK(events, blk_5a, blk_4a, miner_acc);
MAKE_NEXT_BLOCK(events, blk_6a, blk_5a, miner_acc);
DO_CALLBACK(events, "clear_tx_pool"); // remove alt txs
events.push_back(tx_2); // put tx_2 into the pool back
size_t expected_tx_count = 1;
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", expected_tx_count);
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_6a), get_block_hash(blk_6a)));
// ======= Case 2
DO_CALLBACK(events, "delete_foreign_offer");
return true;
}
bool offers_updating_hack::update_foreign_offer(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
bc_services::bc_offers_service* offers_service = dynamic_cast<bc_services::bc_offers_service*>(c.get_blockchain_storage().get_attachment_services_manager().get_service_by_id(BC_OFFERS_SERVICE_ID));
CHECK_AND_ASSERT_MES(offers_service != nullptr, false, "Offers service was not registered in attachment service manager!");
//
// Attacker's part -- modify Alice's offers without Alice's private keys
//
// get offer update tx from the pool (it's not added yet to the blockchain)
std::list<transaction> txs;
CHECK_AND_ASSERT_MES(c.get_pool_transactions(txs), false, "");
CHECK_AND_ASSERT_MES(txs.size() == 1, false, "Incorrect tx pool count: " << txs.size());
LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true));
const transaction& offer_update_tx = txs.back();
tx_service_attachment tsa = AUTO_VAL_INIT(tsa);
r = get_type_in_variant_container(offer_update_tx.attachment, tsa);
CHECK_AND_ASSERT_MES(r, false, "get_type_in_variant_container failed");
CHECK_AND_ASSERT_MES(tsa.service_id == BC_OFFERS_SERVICE_ID && tsa.instruction == BC_OFFERS_SERVICE_INSTRUCTION_UPD, false, "invalid tsa: " << tsa.service_id << ", " << tsa.instruction);
// unpack tsa with update offer
bc_services::update_offer uo = AUTO_VAL_INIT(uo);
std::string json_buff;
CHECK_AND_ASSERT_MES(epee::zlib_helper::unpack(tsa.body, json_buff), false, "");
CHECK_AND_ASSERT_MES(epee::serialization::load_t_from_json(uo, json_buff), false, "");
// Case 1: Bob modifies Alice's offer
// modify an offer and don't resign
uo.of.comment = "update by Bob";
// repack
std::vector<attachment_v> attachments;
bc_services::put_offer_into_attachment(uo, attachments);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]);
bob_wlt->refresh();
// make a tx with this attachment (note: tsa.security is signed using Bob's keys, can be resign later using Alice's public address)
transaction tx = AUTO_VAL_INIT(tx);
bob_wlt->transfer(std::vector<tx_destination_entry>({ tx_destination_entry(TESTS_DEFAULT_FEE * 3, m_accounts[BOB_ACC_IDX].get_public_address()) }), 0, 0, TESTS_DEFAULT_FEE * 81, empty_extra, attachments,
2019-04-03 17:53:49 +03:00
tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx, 0, true, 0, false);
2018-12-27 18:50:45 +03:00
// don't resign yet
// send to network
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
r = c.handle_incoming_tx(tx_to_blob(tx), tvc, false);
CHECK_AND_ASSERT_MES(r && tvc.m_added_to_pool, false, "handle_incoming_tx failed: r = " << r << ", tvc.m_added_to_pool = " << tvc.m_added_to_pool);
LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true));
// put in a block 'tx', leave Alice's tx in the pool
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
2019-03-25 01:30:20 +01:00
CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector<transaction>({ tx })), false, "mine_next_pow_block_in_playtime failed");
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true));
// check offers
std::list<bc_services::offer_details_ex> offers;
r = get_all_offers(c, offers);
CHECK_AND_ASSERT_MES(r, false, "get_all_offers failed");
CHECK_AND_ASSERT_MES(offers.size() == 1, false, "Incorrect offers count: " << offers.size());
bc_services::offer_details_ex offer_0 = offers.front();
LOG_PRINT_YELLOW("\n\n!!!!!!!!!!!! offer_0.comment: " << offer_0.comment << "\n\n", LOG_LEVEL_0);
return true;
}
bool offers_updating_hack::delete_foreign_offer(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
bc_services::bc_offers_service* offers_service = dynamic_cast<bc_services::bc_offers_service*>(c.get_blockchain_storage().get_attachment_services_manager().get_service_by_id(BC_OFFERS_SERVICE_ID));
CHECK_AND_ASSERT_MES(offers_service != nullptr, false, "Offers service was not registered in attachment service manager!");
//
// Attacker's part -- modify Alice's offers without Alice's private keys
//
// get offer update tx from the pool (it's not added yet to the blockchain)
std::list<transaction> txs;
CHECK_AND_ASSERT_MES(c.get_pool_transactions(txs), false, "");
CHECK_AND_ASSERT_MES(txs.size() == 1, false, "Incorrect tx pool count: " << txs.size());
LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true));
const transaction& offer_update_tx = txs.back();
tx_service_attachment tsa = AUTO_VAL_INIT(tsa);
r = get_type_in_variant_container(offer_update_tx.attachment, tsa);
CHECK_AND_ASSERT_MES(r, false, "get_type_in_variant_container failed");
CHECK_AND_ASSERT_MES(tsa.service_id == BC_OFFERS_SERVICE_ID && tsa.instruction == BC_OFFERS_SERVICE_INSTRUCTION_UPD, false, "invalid tsa: " << tsa.service_id << ", " << tsa.instruction);
// unpack tsa with update offer
bc_services::update_offer uo = AUTO_VAL_INIT(uo);
std::string json_buff;
CHECK_AND_ASSERT_MES(epee::zlib_helper::unpack(tsa.body, json_buff), false, "");
CHECK_AND_ASSERT_MES(epee::serialization::load_t_from_json(uo, json_buff), false, "");
// Case 2: Bob deletes Alice's offer
bc_services::cancel_offer co = AUTO_VAL_INIT(co);
co.tx_id = uo.tx_id;
co.offer_index = uo.offer_index;
co.sig = uo.sig;
std::vector<attachment_v> attachments;
bc_services::put_offer_into_attachment(co, attachments);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]);
bob_wlt->refresh();
// make a tx with this attachment (note: tsa.security is signed using Bob's keys, can be resign later using Alice's public address)
transaction tx_c = AUTO_VAL_INIT(tx_c);
bob_wlt->transfer(std::vector<tx_destination_entry>({ tx_destination_entry(TESTS_DEFAULT_FEE * 3, m_accounts[BOB_ACC_IDX].get_public_address()) }), 0, 0, TESTS_DEFAULT_FEE * 19, empty_extra, attachments,
2019-04-03 17:53:49 +03:00
tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx_c, 0, true, 0, true);
2018-12-27 18:50:45 +03:00
LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true));
// put in a block 'tx', leave Alice's tx in the pool
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
2019-03-25 01:30:20 +01:00
CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector<transaction>({ tx_c })), false, "mine_next_pow_block_in_playtime failed");
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true));
std::list<bc_services::offer_details_ex> offers;
r = get_all_offers(c, offers);
CHECK_AND_ASSERT_MES(r, false, "get_all_offers failed");
LOG_PRINT_YELLOW("\n\n!!!!!!!!!!!! offers.size(): " << offers.size() << "\n\n", LOG_LEVEL_0);
return true;
}
//------------------------------------------------------------------------------
bool offers_multiple_update::generate(std::vector<test_event_entry>& events) const
{
// Test idea: make an offer then update it twice (two very similar update requests). Make sure raw/normal offers' count is correct.
bool r = false;
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
// Miner adds and offer
bc_services::offer_details od = AUTO_VAL_INIT(od);
fill_test_offer(od);
od.comment = "new";
std::vector<attachment_v> attachments;
bc_services::put_offer_into_attachment(od, attachments);
MAKE_TX_ATTACH(events, tx_1, miner_acc, miner_acc, TESTS_DEFAULT_FEE, blk_1, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1, miner_acc, tx_1);
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(1, 1));
// Miner updates the offer
bc_services::update_offer uo = AUTO_VAL_INIT(uo);
uo.tx_id = get_transaction_hash(tx_1);
uo.offer_index = 0;
uo.of = od;
uo.of.comment = "update";
r = sign_an_offer(tx_1, uo.offer_index, miner_acc.get_keys(), bc_services::make_offer_sig_blob(uo), uo.sig);
CHECK_AND_ASSERT_MES(r, false, "sign_an_offer failed");
attachments.clear();
bc_services::put_offer_into_attachment(uo, attachments);
transaction tx_2 = AUTO_VAL_INIT(tx_2);
uint64_t fee = 14 * TESTS_DEFAULT_FEE;
r = construct_tx_to_key(m_hardforks, events, tx_2, blk_2, miner_acc, miner_acc, TESTS_DEFAULT_FEE, fee, 0, 0, empty_extra, attachments);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "construct_tx_to_key failed");
events.push_back(tx_2);
// Miner updates the same the offer once more
uo.of.comment = "update 2";
r = sign_an_offer(tx_1, uo.offer_index, miner_acc.get_keys(), bc_services::make_offer_sig_blob(uo), uo.sig);
CHECK_AND_ASSERT_MES(r, false, "sign_an_offer failed");
attachments.clear();
bc_services::put_offer_into_attachment(uo, attachments);
transaction tx_3 = AUTO_VAL_INIT(tx_3);
fee = 19 * TESTS_DEFAULT_FEE;
r = construct_tx_to_key(m_hardforks, events, tx_3, blk_2, miner_acc, miner_acc, TESTS_DEFAULT_FEE, fee, 0, 0, empty_extra, attachments);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "construct_tx_to_key failed");
events.push_back(tx_3);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2, miner_acc, std::list<transaction>({ tx_2, tx_3 }));
// raw count should increase by 1 (=2), normal cound should remain the same (=1)
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(1, 2));
return true;
}
//------------------------------------------------------------------------------
bool offer_sig_validity_in_update_and_cancel::generate(std::vector<test_event_entry>& events) const
{
// Test idea: check that changing any field of signed update_offer or cancel_offer made signature invalid
bool r = false;
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
// del offer: valid sig, change tx_id, change offer_index
// upd offer: valid sig, change tx_id, change offer_index, change of
// Miner adds two offers
bc_services::offer_details od_1 = AUTO_VAL_INIT(od_1);
fill_test_offer(od_1);
od_1.comment = "1";
std::vector<attachment_v> attachments;
bc_services::put_offer_into_attachment(od_1, attachments);
MAKE_TX_ATTACH(events, tx_offer_1, miner_acc, miner_acc, TESTS_DEFAULT_FEE, blk_1, attachments);
bc_services::offer_details od_2 = AUTO_VAL_INIT(od_2);
fill_test_offer(od_2);
od_2.comment = "2";
attachments.clear();
bc_services::put_offer_into_attachment(od_2, attachments);
MAKE_TX_ATTACH(events, tx_offer_2, miner_acc, miner_acc, TESTS_DEFAULT_FEE, blk_1, attachments);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner_acc, std::list<transaction>({ tx_offer_1, tx_offer_2 }));
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(2, 2));
// Miner updates the offer
bc_services::update_offer uo_good = AUTO_VAL_INIT(uo_good);
uo_good.tx_id = get_transaction_hash(tx_offer_1);
uo_good.offer_index = 0;
uo_good.of = od_1;
uo_good.of.comment = "update";
r = sign_an_offer(tx_offer_1, uo_good.offer_index, miner_acc.get_keys(), bc_services::make_offer_sig_blob(uo_good), uo_good.sig);
CHECK_AND_ASSERT_MES(r, false, "sign_an_offer failed");
// 1. update offer with wrong tx_id (same sig)
bc_services::update_offer uo_bad = uo_good;
uo_bad.tx_id = get_transaction_hash(tx_offer_2); // tx_id of valid but another offer
attachments.clear();
bc_services::put_offer_into_attachment(uo_bad, attachments);
MAKE_TX_ATTACH_FEE(events, tx_wrong_uo_1, miner_acc, miner_acc, TESTS_DEFAULT_FEE, 3 * TESTS_DEFAULT_FEE, blk_2, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_wrong_uo_1);
// offers count shoudn't change
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(2, 2));
// 2. update offer with wrong offer_index (same sig)
uo_bad = uo_good;
uo_bad.offer_index = 1;
attachments.clear();
bc_services::put_offer_into_attachment(uo_bad, attachments);
MAKE_TX_ATTACH_FEE(events, tx_wrong_uo_2, miner_acc, miner_acc, TESTS_DEFAULT_FEE, 4 * TESTS_DEFAULT_FEE, blk_3, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, tx_wrong_uo_2);
// offers count shoudn't change
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(2, 2));
// 3. update offer with wrong 'of' (same sig)
uo_bad = uo_good;
uo_bad.of.comment = "update bad";
attachments.clear();
bc_services::put_offer_into_attachment(uo_bad, attachments);
MAKE_TX_ATTACH_FEE(events, tx_wrong_uo_3, miner_acc, miner_acc, TESTS_DEFAULT_FEE, 5 * TESTS_DEFAULT_FEE, blk_4, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4, miner_acc, tx_wrong_uo_3);
//MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc);
// offers count shoudn't change
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(2, 2));
// 4. update offer with valid sig (sanity check)
attachments.clear();
bc_services::put_offer_into_attachment(uo_good, attachments);
MAKE_TX_ATTACH_FEE(events, tx_good_uo, miner_acc, miner_acc, TESTS_DEFAULT_FEE, 6 * TESTS_DEFAULT_FEE, blk_5, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_6, blk_5, miner_acc, tx_good_uo);
// offers raw count should change, normal count - not
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(2, 3));
// miner removes offer
bc_services::cancel_offer co_good = AUTO_VAL_INIT(co_good);
co_good.tx_id = get_transaction_hash(tx_good_uo);
co_good.offer_index = 0;
r = sign_an_offer(tx_good_uo, co_good.offer_index, miner_acc.get_keys(), bc_services::make_offer_sig_blob(co_good), co_good.sig);
CHECK_AND_ASSERT_MES(r, false, "sign_an_offer failed");
// 5. remove offer with invalid tx_id
bc_services::cancel_offer co_bad = co_good;
co_bad.tx_id = get_transaction_hash(tx_offer_2); // another tx
attachments.clear();
bc_services::put_offer_into_attachment(co_bad, attachments);
MAKE_TX_ATTACH_FEE(events, tx_wrong_co_1, miner_acc, miner_acc, TESTS_DEFAULT_FEE, 7 * TESTS_DEFAULT_FEE, blk_6, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_7, blk_6, miner_acc, tx_wrong_co_1);
// offers count shoudn't change
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(2, 3));
// 6. remove offer with invalid
co_bad = co_good;
co_bad.offer_index = 1;
attachments.clear();
bc_services::put_offer_into_attachment(co_bad, attachments);
MAKE_TX_ATTACH_FEE(events, tx_wrong_co_2, miner_acc, miner_acc, TESTS_DEFAULT_FEE, 8 * TESTS_DEFAULT_FEE, blk_7, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_8, blk_7, miner_acc, tx_wrong_co_2);
// offers count shoudn't change
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(2, 3));
// 7. remove offer normally (sanity check)
attachments.clear();
bc_services::put_offer_into_attachment(co_good, attachments);
MAKE_TX_ATTACH_FEE(events, tx_good_co, miner_acc, miner_acc, TESTS_DEFAULT_FEE, 9 * TESTS_DEFAULT_FEE, blk_8, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_9, blk_8, miner_acc, tx_good_co);
// offers raw count shoudn't change, normal count should decreased
DO_CALLBACK_PARAMS(events, "check_offers_count", offers_count_param(1, 3));
return true;
}
//------------------------------------------------------------------------------
offer_lifecycle_via_tx_pool::offer_lifecycle_via_tx_pool()
{
REGISTER_CALLBACK_METHOD(offer_lifecycle_via_tx_pool, c1);
}
bool offer_lifecycle_via_tx_pool::generate(std::vector<test_event_entry>& events) const
{
// Test idea: go though typical offer life cycle using wallet member functions. Each operation will put a tx into the pool, then a block will be mined to commit it into the blockchain.
GENERATE_ACCOUNT(preminer_acc);
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
DO_CALLBACK(events, "c1");
return true;
}
bool offer_lifecycle_via_tx_pool::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]);
miner_wlt->refresh();
account_base someone;
someone.generate();
account_public_address some_addr = someone.get_public_address(); // just random public address
uint64_t miner_start_balance = miner_wlt->balance();
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
bc_services::offer_details_ex od = AUTO_VAL_INIT(od);
fill_test_offer(od);
od.comment = "1";
2019-04-25 23:37:43 +02:00
od.fee = TESTS_DEFAULT_FEE * 3;
2018-12-27 18:50:45 +03:00
// create an offer
transaction tx_1 = AUTO_VAL_INIT(tx_1);
TRY_ENTRY()
miner_wlt->push_offer(od, tx_1);
CATCH_ENTRY2(false);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
2019-03-25 01:30:20 +01:00
r = mine_next_pow_block_in_playtime(some_addr, c);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("After putting offer push tx into the blockchain", "miner", miner_wlt, miner_start_balance - od.fee), false, "");
CHECK_AND_ASSERT_MES(check_offers_count(c, 0, std::vector<test_event_entry>({ callback_entry("", epee::string_tools::pod_to_hex(offers_count_param(1, 1))) })), false, "");
// update the offer
transaction tx_2 = AUTO_VAL_INIT(tx_2);
od.comment = "UPDATE";
TRY_ENTRY()
miner_wlt->update_offer_by_id(get_transaction_hash(tx_1), 0, od, tx_2);
CATCH_ENTRY2(false);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
2019-03-25 01:30:20 +01:00
r = mine_next_pow_block_in_playtime(some_addr, c);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("After updating offer push tx into the blockchain", "miner", miner_wlt, miner_start_balance - od.fee * 2), false, "");
CHECK_AND_ASSERT_MES(check_offers_count(c, 0, std::vector<test_event_entry>({ callback_entry("", epee::string_tools::pod_to_hex(offers_count_param(1, 2))) })), false, "");
// update the offer once again
transaction tx_3 = AUTO_VAL_INIT(tx_3);
od.comment = "UPDATE2";
TRY_ENTRY()
miner_wlt->update_offer_by_id(get_transaction_hash(tx_2), 0, od, tx_3);
CATCH_ENTRY2(false);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
2019-03-25 01:30:20 +01:00
r = mine_next_pow_block_in_playtime(some_addr, c);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("After second update offer push tx into the blockchain", "miner", miner_wlt, miner_start_balance - od.fee * 3), false, "");
CHECK_AND_ASSERT_MES(check_offers_count(c, 0, std::vector<test_event_entry>({ callback_entry("", epee::string_tools::pod_to_hex(offers_count_param(1, 3))) })), false, "");
// cancel the offer
transaction tx_4 = AUTO_VAL_INIT(tx_4);
TRY_ENTRY()
miner_wlt->cancel_offer_by_id(get_transaction_hash(tx_3), 0, TESTS_DEFAULT_FEE, tx_4);
2018-12-27 18:50:45 +03:00
CATCH_ENTRY2(false);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
2019-03-25 01:30:20 +01:00
r = mine_next_pow_block_in_playtime(some_addr, c);
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true));
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("After offer's cancellation push tx into the blockchain", "miner", miner_wlt, miner_start_balance - od.fee * 3 - TESTS_DEFAULT_FEE), false, "");
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES(check_offers_count(c, 0, std::vector<test_event_entry>({ callback_entry("", epee::string_tools::pod_to_hex(offers_count_param(0, 3))) })), false, "");
return true;
}
//------------------------------------------------------------------------------
offer_cancellation_with_zero_fee::offer_cancellation_with_zero_fee()
{
REGISTER_CALLBACK_METHOD(offer_cancellation_with_zero_fee, c1);
}
bool offer_cancellation_with_zero_fee::generate(std::vector<test_event_entry>& events) const
{
// Test idea: make sure that an offer cannot be cancelled using zero fee
GENERATE_ACCOUNT(preminer_acc);
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
DO_CALLBACK(events, "c1");
return true;
}
bool offer_cancellation_with_zero_fee::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]);
miner_wlt->refresh();
LOG_PRINT_CYAN("Miners's transfers:" << ENDL << miner_wlt->dump_trunsfers(), LOG_LEVEL_0);
uint64_t miner_start_balance = miner_wlt->balance();
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
bc_services::offer_details_ex od = AUTO_VAL_INIT(od);
fill_test_offer(od);
od.fee = TESTS_DEFAULT_FEE * 2;
transaction create_offer_tx = AUTO_VAL_INIT(create_offer_tx);
LOG_PRINT_CYAN("%%%%% miner_wlt->push_offer()", LOG_LEVEL_0);
miner_wlt->push_offer(od, create_offer_tx);
crypto::hash create_offer_tx_id = get_transaction_hash(create_offer_tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[ALICE_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("offer's put into the blockchain", "Miner", miner_wlt, miner_start_balance - od.fee, true, 1), false, "");
// check offer, retured by get_actual_offers()
std::list<bc_services::offer_details_ex> offers;
r = miner_wlt->get_actual_offers(offers);
CHECK_AND_ASSERT_MES(r && offers.size() == 1, false, "miner_wlt->get_actual_offers failed, offers.size() == " << offers.size());
CHECK_AND_ASSERT_MES(compare_offers(od, offers.front()), false, "");
// cancel offer
transaction cancel_offer_tx = AUTO_VAL_INIT(cancel_offer_tx);
bool exception_caught = false;
try
{
LOG_PRINT_CYAN("%%%%% miner_wlt->cancel_offer_by_id()", LOG_LEVEL_0);
miner_wlt->cancel_offer_by_id(create_offer_tx_id, 0, 0 /* <-- zero fee */, cancel_offer_tx);
}
catch (std::exception& e)
{
LOG_PRINT_L0("Caught an expected exception: " << e.what());
exception_caught = true;
}
CHECK_AND_ASSERT_MES(exception_caught, false, "An exception on calcel_offer_by_id() was not caught as expected");
// make sure no new txs in the pool
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
// Make sure balance was no chaged by incorrect offer cancellation
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("offer has been cancelled, ", "Miner", miner_wlt, miner_start_balance - od.fee, true, 0), false, "");
return true;
}