// Copyright (c) 2014-2018 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Boolberry developers // 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 "alias_tests.h" #include "tx_builder.h" #include "random_helper.h" using namespace epee; using namespace currency; #define FIRST_ALIAS_NAME "first--01234567890" #define SECOND_ALIAS_NAME "second--01234567890" #define THIRD_ALIAS_NAME "test-alias-via-tx-1--01234567890" #define FOURTH_NAME "fourth--01234567890" #define FIFTH_NAME "fifth--01234567890" #define SIX_NAME "sixsix-double--01234567890" bool put_alias_via_tx_to_list(const currency::hard_forks_descriptor& hf, std::vector& events, std::list& tx_set, const block& head_block, const std::string& alias_name, const account_base& miner_acc, const account_base& alias_acc, test_generator& generator) { currency::extra_alias_entry ai2 = AUTO_VAL_INIT(ai2); ai2.m_alias = alias_name; ai2.m_address = alias_acc.get_keys().account_address; ai2.m_text_comment = "ssdss"; return put_alias_via_tx_to_list(hf, events, tx_set, head_block, miner_acc, ai2, generator); } bool put_next_block_with_alias_in_tx(const currency::hard_forks_descriptor& hf, std::vector& events, block& b, const block& head_block, const account_base& miner_acc, const currency::extra_alias_entry& ai, test_generator& generator) { std::list txs_0; if (!put_alias_via_tx_to_list(hf, events, txs_0, head_block, miner_acc, ai, generator)) return false; MAKE_NEXT_BLOCK_TX_LIST(events, blk, head_block, miner_acc, txs_0); b = blk; return true; } bool put_next_block_with_alias_in_tx(const currency::hard_forks_descriptor& hf, std::vector& events, block& b, const block& head_block, const std::string& alias_name, const account_base& miner_acc, const account_base& alias_acc, test_generator& generator) { currency::extra_alias_entry ai2 = AUTO_VAL_INIT(ai2); ai2.m_alias = alias_name; ai2.m_address = alias_acc.get_keys().account_address; ai2.m_text_comment = "ssdss"; return put_next_block_with_alias_in_tx(hf, events, b, head_block, miner_acc, ai2, generator); } #define MAKE_BLOCK_WITH_ALIAS_IN_TX(EVENTS, NAME, HEAD, ALIAS_NAME) \ block NAME; \ put_next_block_with_alias_in_tx(m_hardforks, EVENTS, NAME, HEAD, ALIAS_NAME, miner_account, second_acc, generator) #define MAKE_BLOCK_WITH_ALIAS_INFO_IN_TX(EVENTS, NAME, HEAD, MINER_ACCOUNT, ALIAS_INFO) \ block NAME; \ put_next_block_with_alias_in_tx(m_hardforks, EVENTS, NAME, HEAD, MINER_ACCOUNT, ALIAS_INFO, generator) //------------------------------------------------------------------------------ gen_alias_tests::gen_alias_tests() : m_invalid_tx_index(std::numeric_limits::max()) , m_invalid_block_index(std::numeric_limits::max()) , m_h(0) { REGISTER_CALLBACK_METHOD(gen_alias_tests, mark_invalid_tx); REGISTER_CALLBACK_METHOD(gen_alias_tests, mark_invalid_block); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_first_alias_added); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_second_alias_added); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_aliases_removed); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_splitted_back); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_alias_changed); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_alias_not_changed); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_alias_added_in_tx); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_height_not_changed); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_height_changed); REGISTER_CALLBACK_METHOD(gen_alias_tests, check_too_many_aliases_registration); } bool gen_alias_tests::generate(std::vector& events) const { GENERATE_ACCOUNT(preminer_account); GENERATE_ACCOUNT(miner_account); // event index m_accounts.push_back(miner_account); MAKE_GENESIS_BLOCK(events, blk_0, preminer_account, test_core_time::get_time()); // 0 DO_CALLBACK(events, "configure_core"); // 1 MAKE_ACCOUNT(events, first_acc); // 2 MAKE_ACCOUNT(events, second_acc); // 3 MAKE_ACCOUNT(events, third_acc); // 4 REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_account, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // 2N+4 (N = CURRENCY_MINED_MONEY_UNLOCK_WINDOW) size_t small_outs_to_transfer = MAX_ALIAS_PER_BLOCK + 10; transaction tx_1 = AUTO_VAL_INIT(tx_1); bool r = construct_tx_with_many_outputs(m_hardforks, events, blk_0, preminer_account.get_keys(), miner_account.get_public_address(), small_outs_to_transfer * TESTS_DEFAULT_FEE * 11, small_outs_to_transfer, TESTS_DEFAULT_FEE, tx_1); CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed"); events.push_back(tx_1); // 2N+5 MAKE_NEXT_BLOCK_TX1(events, blk_a, blk_0r, miner_account, tx_1); // 2N+6 REWIND_BLOCKS_N_WITH_TIME(events, blk_ar, blk_a, miner_account, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // 4N+6 MAKE_NEXT_BLOCK(events, blk_1, blk_ar, miner_account); // 4N+7 currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = FIRST_ALIAS_NAME; ai.m_text_comment = "first@first.com blablabla"; ai.m_address = first_acc.get_keys().account_address; MAKE_BLOCK_WITH_ALIAS_INFO_IN_TX(events, blk_2, blk_1, miner_account, ai); // 4N+8,4N+9 DO_CALLBACK(events, "check_first_alias_added"); // 4N+10 ai.m_alias = SECOND_ALIAS_NAME; ai.m_text_comment = "second@second.com blablabla"; ai.m_address = second_acc.get_keys().account_address; MAKE_BLOCK_WITH_ALIAS_INFO_IN_TX(events, blk_3, blk_2, miner_account, ai); // 4N+11,4N+12 DO_CALLBACK(events, "check_second_alias_added"); // 4N+13 //check split with remove alias MAKE_NEXT_BLOCK(events, blk_2_split, blk_1, miner_account); // 4N+14 MAKE_NEXT_BLOCK(events, blk_3_split, blk_2_split, miner_account); // 4N+15 MAKE_NEXT_BLOCK(events, blk_4_split, blk_3_split, miner_account); // 4N+16 DO_CALLBACK(events, "check_aliases_removed"); // 4N+17 //make back split to original and try update alias MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_account); // 4N+18 MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_account); // 4N+19 DO_CALLBACK(events, "check_splitted_back"); // 4N+20 currency::extra_alias_entry ai_upd = AUTO_VAL_INIT(ai_upd); ai_upd.m_alias = FIRST_ALIAS_NAME; ai_upd.m_address =third_acc.get_keys().account_address; ai_upd.m_text_comment = "changed alias haha"; r = sign_extra_alias_entry(ai_upd, first_acc.get_keys().account_address.spend_public_key, first_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "failed to sign update_alias"); MAKE_BLOCK_WITH_ALIAS_INFO_IN_TX(events, blk_6, blk_5, miner_account, ai_upd); // 4N+21,N+22 DO_CALLBACK(events, "check_alias_changed"); // 4N+23 //try to make fake alias change currency::extra_alias_entry ai_upd_fake = AUTO_VAL_INIT(ai_upd_fake); ai_upd_fake.m_alias = SECOND_ALIAS_NAME; ai_upd_fake.m_address =third_acc.get_keys().account_address; ai_upd_fake.m_text_comment = "changed alias haha"; r = sign_extra_alias_entry(ai_upd_fake, second_acc.get_keys().account_address.spend_public_key, second_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "failed to sign update_alias"); ai_upd_fake.m_text_comment = "changed alias haha - fake"; // changed text, signature became wrong std::list tx_list; r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_6, miner_account, ai_upd_fake, generator); // 4N+24 CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list"); DO_CALLBACK(events, "mark_invalid_block"); // 4N+25 // EXPECTED: blk_7 is rejected as containing incorrect tx (wrong alias sig) MAKE_NEXT_BLOCK_TX_LIST(events, blk_7, blk_6, miner_account, tx_list); // 4N+26 DO_CALLBACK(events, "check_alias_not_changed"); // 4N+27 account_base someone; someone.generate(); block blk_8; r = put_next_block_with_alias_in_tx(m_hardforks, events, blk_8, blk_6, THIRD_ALIAS_NAME, miner_account, someone, generator); // 4N+28,4N+29 CHECK_AND_ASSERT_MES(r, false, "put_next_block_with_alias_in_tx failed"); MAKE_NEXT_BLOCK(events, blk_9, blk_8, miner_account); // 4N+30 DO_CALLBACK(events, "check_alias_added_in_tx"); // 4N+31 // lets try to register same name ai = AUTO_VAL_INIT(ai); ai.m_alias = THIRD_ALIAS_NAME; ai.m_address = miner_account.get_public_address(); tx_list.clear(); DO_CALLBACK(events, "mark_invalid_tx"); // 4N+32 // EXPECTED: tx is rejected, because alias is already registered r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_9, miner_account, ai, generator); // 4N+33 CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list"); DO_CALLBACK(events, "check_alias_not_changed"); // 4N+34 DO_CALLBACK(events, "check_height_not_changed"); // 4N+35 //check notmal tx in tx pool MAKE_TX_LIST_START(events, txs_0, miner_account, miner_account, MK_TEST_COINS(1), blk_9); // 4N+36 if (!put_alias_via_tx_to_list(m_hardforks, events, txs_0, blk_9, FOURTH_NAME, miner_account, miner_account, generator)) // 4N+37 return false; someone.generate(); if (!put_alias_via_tx_to_list(m_hardforks, events, txs_0, blk_9, FIFTH_NAME, miner_account, someone, generator)) // 4N+38 return false; MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_9, miner_account, txs_0); // 4N+39 DO_CALLBACK(events, "check_height_changed"); // 4N+40 // //check duplicate tx in tx pool MAKE_TX_LIST_START(events, txs_2, miner_account, miner_account, MK_TEST_COINS(1), blk_13); // 4N+41 someone.generate(); if (!put_alias_via_tx_to_list(m_hardforks, events, txs_2, blk_13, SIX_NAME, miner_account, someone, generator)) // 4N+42 return false; DO_CALLBACK(events, "mark_invalid_tx"); // 4N+43 // EXPECTED: the next tx is rejected, because alias is already registered if (!put_alias_via_tx_to_list(m_hardforks, events, txs_2, blk_13, SIX_NAME, miner_account, miner_account, generator)) // 4N+44 return false; DO_CALLBACK(events, "mark_invalid_block"); // 4N+45 // EXPECTED: block is rejected as containing invalid tx MAKE_NEXT_BLOCK_TX_LIST(events, blk_14, blk_13, miner_account, txs_2); // 4N+46 DO_CALLBACK(events, "check_height_not_changed"); // 4N+47 DO_CALLBACK(events, "clear_tx_pool"); // 4N+48 DO_CALLBACK(events, "check_too_many_aliases_registration"); // 4N+49 return true; } bool gen_alias_tests::check_first_alias_added(currency::core& c, size_t ev_index, const std::vector& events) { const currency::account_base& first_acc = boost::get(events[2]); currency::extra_alias_entry_base ai = AUTO_VAL_INIT(ai); bool r = c.get_blockchain_storage().get_alias_info(FIRST_ALIAS_NAME, ai); CHECK_AND_ASSERT_MES(r, false, "first alias name check failed"); CHECK_AND_ASSERT_MES(ai.m_address.spend_public_key == first_acc.get_keys().account_address.spend_public_key && ai.m_address.view_public_key == first_acc.get_keys().account_address.view_public_key, false, "first alias name check failed"); return true; } bool gen_alias_tests::check_second_alias_added(currency::core& c, size_t ev_index, const std::vector& events) { const currency::account_base& second_acc = boost::get(events[3]); currency::extra_alias_entry_base ai = AUTO_VAL_INIT(ai); bool r = c.get_blockchain_storage().get_alias_info(SECOND_ALIAS_NAME, ai); CHECK_AND_ASSERT_MES(r, false, "first alias name check failed"); CHECK_AND_ASSERT_MES(ai.m_address.spend_public_key == second_acc.get_keys().account_address.spend_public_key && ai.m_address.view_public_key == second_acc.get_keys().account_address.view_public_key, false, "second alias name check failed"); return true; } bool gen_alias_tests::check_aliases_removed(currency::core& c, size_t ev_index, const std::vector& events) { currency::extra_alias_entry_base ai = AUTO_VAL_INIT(ai); bool r = c.get_blockchain_storage().get_alias_info(FIRST_ALIAS_NAME, ai); CHECK_AND_ASSERT_MES(!r, false, "first alias name check failed"); r = c.get_blockchain_storage().get_alias_info(SECOND_ALIAS_NAME, ai); CHECK_AND_ASSERT_MES(!r, false, "second alias name check failed"); return true; } bool gen_alias_tests::check_alias_added_in_tx(currency::core& c, size_t ev_index, const std::vector& events) { currency::extra_alias_entry_base ai = AUTO_VAL_INIT(ai); bool r = c.get_blockchain_storage().get_alias_info(THIRD_ALIAS_NAME, ai); CHECK_AND_ASSERT_MES(r, false, "third alias name check failed"); m_h = c.get_blockchain_storage().get_current_blockchain_size(); return true; } bool gen_alias_tests::check_height_not_changed(currency::core& c, size_t ev_index, const std::vector& events) { uint64_t new_h = c.get_blockchain_storage().get_current_blockchain_size(); CHECK_AND_ASSERT_MES(new_h == m_h, false, "third alias name check failed"); return true; } bool gen_alias_tests::check_height_changed(currency::core& c, size_t ev_index, const std::vector& events) { uint64_t new_h = c.get_blockchain_storage().get_current_blockchain_size(); CHECK_AND_ASSERT_MES(new_h == m_h+1, false, "fifth alias name check failed"); currency::extra_alias_entry_base ai = AUTO_VAL_INIT(ai); bool r = c.get_blockchain_storage().get_alias_info(FOURTH_NAME, ai); CHECK_AND_ASSERT_MES(r, false, "FOURTH_NAME alias name check failed"); r = c.get_blockchain_storage().get_alias_info(FIFTH_NAME, ai); CHECK_AND_ASSERT_MES(r, false, "FIFTH_NAME alias name check failed"); m_h = c.get_blockchain_storage().get_current_blockchain_size(); return true; } bool gen_alias_tests::check_splitted_back(currency::core& c, size_t ev_index, const std::vector& events) { return check_first_alias_added(c, ev_index, events) && check_second_alias_added(c, ev_index, events); } bool gen_alias_tests::check_alias_changed(currency::core& c, size_t ev_index, const std::vector& events) { const currency::account_base& third_acc = boost::get(events[4]); currency::extra_alias_entry_base ai = AUTO_VAL_INIT(ai); bool r = c.get_blockchain_storage().get_alias_info(FIRST_ALIAS_NAME, ai); CHECK_AND_ASSERT_MES(r, false, "first alias name check failed"); CHECK_AND_ASSERT_MES(ai.m_address.spend_public_key == third_acc.get_keys().account_address.spend_public_key && ai.m_address.view_public_key == third_acc.get_keys().account_address.view_public_key, false, "first alias update name check failed"); return true; } bool gen_alias_tests::check_alias_not_changed(currency::core& c, size_t ev_index, const std::vector& events) { return check_second_alias_added(c, ev_index, events); } bool gen_alias_tests::check_too_many_aliases_registration(currency::core& c, size_t ev_index, const std::vector& events) { // register too many aliases std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX); miner_wlt->refresh(); uint64_t estimated_alias_cost = get_alias_coast_from_fee(std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'), c.get_blockchain_storage().get_tx_fee_median()); extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_address = m_accounts[MINER_ACC_IDX].get_public_address(); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count() << ", expected: 0"); // attempt to create block from block template, then check how many aliases it will contain currency::block b; wide_difficulty_type diff; uint64_t height; blobdata extra = AUTO_VAL_INIT(extra); bool r = c.get_block_template(b, ai.m_address, ai.m_address, diff, height, extra); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); CHECK_AND_ASSERT_MES(b.tx_hashes.empty(), false, "block template has some txs, expected--none"); account_base someone; const size_t total_alias_to_gen = MAX_ALIAS_PER_BLOCK + 2; try { log_level_scope_changer llsc(LOG_LEVEL_0); // eliminate all the mess in the log during alias registration, comment this out if case of debugging for (size_t i = 0; i < total_alias_to_gen; ++i) { LOG_PRINT_YELLOW("Generating alias #" << i << " of " << total_alias_to_gen << "...", LOG_LEVEL_0); someone.generate(); ai.m_address = someone.get_public_address(); ai.m_alias = gen_random_alias(random_in_range(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED + 20)); transaction alias_reg_tx = AUTO_VAL_INIT(alias_reg_tx); miner_wlt->request_alias_registration(ai, alias_reg_tx, TESTS_DEFAULT_FEE, estimated_alias_cost); b.tx_hashes.push_back(get_transaction_hash(alias_reg_tx)); // add this tx to block template } } catch (std::exception& e) { LOG_ERROR("Caught an exception while registering an alias: " << e.what()); return false; } CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == total_alias_to_gen, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count() << ", expected: " << total_alias_to_gen); // complete block template and try to process it r = miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); c.handle_incoming_block(t_serializable_object_to_blob(b), bvc); CHECK_AND_NO_ASSERT_MES(!bvc.m_added_to_main_chain, false, "block verification context check failed: m_added_to_main_chain"); CHECK_AND_NO_ASSERT_MES(bvc.m_verification_failed, false, "block verification context check failed: ! m_verification_failed "); return true; } //------------------------------------------------------------------------------ gen_alias_strange_data::gen_alias_strange_data() { m_alice.generate(); REGISTER_CALLBACK_METHOD(gen_alias_strange_data, check_alias_changed); } bool gen_alias_strange_data::generate(std::vector& events) const { uint64_t ts_start = 1450000000; GENERATE_ACCOUNT(miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts_start); set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); std::list tx_list; // empty comment currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_text_comment = ""; ai.m_address = m_alice.get_public_address(); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); // empty comment currency::extra_alias_entry ai_upd = AUTO_VAL_INIT(ai_upd); ai_upd.m_alias = ai.m_alias; ai_upd.m_address.spend_public_key = null_pkey; ai_upd.m_address.view_public_key = null_pkey; ai_upd.m_text_comment = ""; r = sign_extra_alias_entry(ai_upd, m_alice.get_public_address().spend_public_key, m_alice.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "failed to sign update_alias"); MAKE_BLOCK_WITH_ALIAS_INFO_IN_TX(events, blk_2, blk_1, miner_acc, ai_upd); DO_CALLBACK(events, "check_alias_changed"); // max length alias + comment + view key tx_list.clear(); ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(255, 'x'); ai.m_text_comment = std::string(255, 'c'); ai.m_address = m_alice.get_public_address(); ai.m_view_key.push_back(m_alice.get_keys().view_secret_key); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2, miner_acc, tx_list); tx_list.clear(); ai.m_text_comment = std::string(255, '\0'); r = sign_extra_alias_entry(ai, m_alice.get_public_address().spend_public_key, m_alice.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_4, blk_3, miner_acc, tx_list); return true; } bool gen_alias_strange_data::check_alias_changed(currency::core& c, size_t ev_index, const std::vector& events) { currency::extra_alias_entry ai; bool r = c.get_blockchain_storage().get_alias_info(std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'), ai); CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); CHECK_AND_ASSERT_MES(ai.m_address.spend_public_key == null_pkey && ai.m_address.view_public_key == null_pkey, false, "alias didn't change"); return true; } //------------------------------------------------------------------------------ gen_alias_concurrency_with_switch::gen_alias_concurrency_with_switch() { REGISTER_CALLBACK_METHOD(gen_alias_concurrency_with_switch, check_alias); } bool gen_alias_concurrency_with_switch::generate(std::vector& events) const { // make really invalid address from random bytes // uint8_t invalid_addr[sizeof currency::account_public_address] = { 57, 244, 75, 72, 186, 222, 255, 245, 157, 183, 255, 152, 163, 1, 13, 139, 165, 252, 186, 21, 170, 30, 79, 91, 87, 107, 69, 223, 130, 76, 104, 205, 109, 50, 39, 215, 73, 216, 246, 24, 122, 180, 205, 42, 162, 217, 58, 215, 42, 38, 27, 207, 92, 12, 211, 217, 203, 202, 65, 237, 49, 190, 244, 240 }; uint64_t ts = 2000000000; // welcome to the future! test_core_time::adjust(ts); GENERATE_ACCOUNT(miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // two txs with concurrent alias registration: 1st std::list tx_list; currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_text_comment = ""; ai.m_address = miner_acc.get_public_address(); //ai.m_address = *reinterpret_cast(invalid_addr); ai.m_view_key.push_back(miner_acc.get_keys().view_secret_key); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // 2nd std::list tx_list2; ai.m_address.spend_public_key = null_pkey, ai.m_address.view_public_key = null_pkey; DO_CALLBACK(events, "mark_invalid_tx"); // because tx with a duplicate alias request (?) r = put_alias_via_tx_to_list(m_hardforks, events, tx_list2, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // 0 .. 10 11 12 <- height // (0 )..(0r)- (1 ) // \- (2 )- (3 ) MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); // split the chain // simulate handling a block with that tx: handle tx like going with the block... events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true)); events.push_back(tx_list2.front()); events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false)); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_0r, miner_acc, tx_list2); MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); // reorganize MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc); // go ahead DO_CALLBACK(events, "check_alias"); return true; } bool gen_alias_concurrency_with_switch::check_alias(currency::core& c, size_t ev_index, const std::vector& events) { currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); bool r = c.get_blockchain_storage().get_alias_info(std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'), ai); CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); CHECK_AND_ASSERT_MES(ai.m_address.spend_public_key == null_pkey && ai.m_address.view_public_key == null_pkey, false, "wrong alias"); return true; } //------------------------------------------------------------------------------ bool gen_alias_same_alias_in_tx_pool::generate(std::vector& events) const { uint64_t ts = test_core_time::get_time(); test_core_time::adjust(ts); GENERATE_ACCOUNT(miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4); // 1. add to the tx pool two txs: 1) register an alias; 2) update it std::list tx_list; currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_address = miner_acc.get_public_address(); ai.m_view_key.push_back(miner_acc.get_keys().view_secret_key); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); ai.m_address.spend_public_key = null_pkey, ai.m_address.view_public_key = null_pkey; r = sign_extra_alias_entry(ai, miner_acc.get_public_address().spend_public_key, miner_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); DO_CALLBACK(events, "mark_invalid_tx"); // because tx with a duplicate alias request r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); tx_list.pop_back(); // 'cause it's invalid CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // add a block to clear the tx pool MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); // 2. add to the pool two txs: 1) update previously registered alias 2) update it once again tx_list.clear(); ai.m_address.spend_public_key = miner_acc.get_public_address().spend_public_key; r = sign_extra_alias_entry(ai, miner_acc.get_public_address().spend_public_key, miner_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); ai.m_text_comment = "Oops, I forgot a comment!"; r = sign_extra_alias_entry(ai, miner_acc.get_public_address().spend_public_key, miner_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); DO_CALLBACK(events, "mark_invalid_tx"); // because tx with a duplicate alias request r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); tx_list.pop_back(); // 'cause it's invalid // and put it to the block MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner_acc, tx_list); return true; } //------------------------------------------------------------------------------ gen_alias_switch_and_tx_pool::gen_alias_switch_and_tx_pool() { REGISTER_CALLBACK_METHOD(gen_alias_switch_and_tx_pool, check_alias); } bool gen_alias_switch_and_tx_pool::generate(std::vector& events) const { // Brief outline: // 1) add a tx, registering an alias, got it in a block; // 2) add a tx, updating an alias, got it in another block; // 3) make a chain split; // 4) trigger switching to an alt chain, this should push both txs to the pool; // 5) look how two txs referring the same alias will survive in the pool (should survive); // 6) to make things a little worse, add a tx registering the same alias in block, which triggers chain switch; // 7) after switching the alias should be registered with the tx in p. 6. uint64_t ts = test_core_time::get_time(); test_core_time::adjust(ts); GENERATE_ACCOUNT(alice); GENERATE_ACCOUNT(miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); events.push_back(alice); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // 0 ...10 11 12 13 <- height // +--- reg an alias in blk_1 // | +--- update the alias in blk_2 // (0 )- (0r)- (1 )- (2 ) // \- (3 )- (4 )- (5 ) // 1. register an alias std::list tx_list; currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_address = miner_acc.get_public_address(); ai.m_view_key.push_back(miner_acc.get_keys().view_secret_key); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // add a block to clear the tx pool MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); // 2. update the alias tx_list.clear(); ai.m_address.spend_public_key = null_pkey, ai.m_address.view_public_key = null_pkey; r = sign_extra_alias_entry(ai, miner_acc.get_public_address().spend_public_key, miner_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // add one more block to bring the tx to life (i.e. blockchain) MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner_acc, tx_list); // split the blockchain MAKE_NEXT_BLOCK(events, blk_3, blk_0r, miner_acc); MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc); // make a tx, registering the same alias, simulate tx handling tx_list.clear(); ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_address = alice.get_public_address(); ai.m_view_key.push_back(alice.get_keys().view_secret_key); DO_CALLBACK(events, "mark_invalid_tx"); // tx is rejected, because tx pool already has tx with reg/upd this alias r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_4, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // simulate handling a block with that tx: handle tx like going with the block... events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true)); events.push_back(tx_list.front()); // now tx should be accepted events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false)); // ... then handle the block itself, it should be accepted MAKE_NEXT_BLOCK_TX_LIST(events, blk_5, blk_4, miner_acc, tx_list); DO_CALLBACK_PARAMS_STR(events, "check_alias", ai.m_alias); return true; } bool gen_alias_switch_and_tx_pool::check_alias(currency::core& c, size_t ev_index, const std::vector& events) { const std::string& alias_name = boost::get(events[ev_index]).callback_params; const currency::account_base& alice = boost::get(events[2]); currency::extra_alias_entry_base ai; bool r = c.get_blockchain_storage().get_alias_info(alias_name, ai); CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); CHECK_AND_ASSERT_MES(ai.m_address == alice.get_public_address() && !ai.m_view_key.empty() && ai.m_view_key.front() == alice.get_keys().view_secret_key, false, "wrong alias"); return true; } //------------------------------------------------------------------------------ bool gen_alias_update_after_addr_changed::generate(std::vector& events) const { // Brief idea: make sure an alias can only update the one, who owns private key to alias' target address. uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(miner_acc); GENERATE_ACCOUNT(alice); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // register an alias on behalf of miner_acc with miner's address std::list tx_list; currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_address = miner_acc.get_public_address(); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); // change the address to alice, while signing still by miner tx_list.clear(); ai.m_text_comment = "upd1"; ai.m_address = alice.get_public_address(); r = sign_extra_alias_entry(ai, miner_acc.get_public_address().spend_public_key, miner_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_1, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner_acc, tx_list); // try to update the alias on behalf of miner (should fail because it must be alice who can sign it) tx_list.clear(); ai.m_text_comment = "upd2"; r = sign_extra_alias_entry(ai, miner_acc.get_public_address().spend_public_key, miner_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_2, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // the next block will be rejected as invalid, as cantaining tx with invalid alias sign DO_CALLBACK(events, "mark_invalid_block"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2i, blk_2, miner_acc, tx_list); // !!!!!! // TODO: last tx is invalid, but still in the pool - this is a problem, because nobody can update the alias until this tx will be removed from the pool // !!!!!! // try to update the alias on behalf of alice (should be ok) tx_list.clear(); ai.m_address = miner_acc.get_public_address(); r = sign_extra_alias_entry(ai, alice.get_public_address().spend_public_key, alice.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_2, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2, miner_acc, tx_list); // try to change the alias on behalf on alice again (should fail) tx_list.clear(); ai.m_text_comment = "upd3"; r = sign_extra_alias_entry(ai, alice.get_public_address().spend_public_key, alice.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_3, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // the next block will be rejected as invalid, as cantaining tx with invalid alias sign DO_CALLBACK(events, "mark_invalid_block"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_3i, blk_3, miner_acc, tx_list); return true; } //------------------------------------------------------------------------------ bool gen_alias_blocking_reg_by_invalid_tx::generate(std::vector& events) const { // 1. Attacker makes an invalid tx to update an alias // 2. No one can include it into a block // 3. No one can register this alias std::list tx_list; uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(preminer_acc); GENERATE_ACCOUNT(miner_acc); GENERATE_ACCOUNT(alice); GENERATE_ACCOUNT(attacker); MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, ts); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4); uint64_t miner_money = get_outs_money_amount(blk_0r.miner_tx) * 4; // alice and attacker get some money MAKE_TX_LIST(events, tx_list, miner_acc, alice, miner_money / 2, blk_0r); MAKE_TX_LIST(events, tx_list, miner_acc, attacker, get_outs_money_amount(blk_0r.miner_tx), blk_0r); MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); tx_list.clear(); // Attacker makes invalid tx extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = "sweet.name"; ai.m_address = attacker.get_public_address(); ai.m_sign.push_back(invalid_signature); // it's an invalid sign, so effectivly it's an update alias request std::vector ex(1, ai); MAKE_TX_FEE_MIX_ATTR_EXTRA(events, tx_0, attacker, attacker, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, 0, blk_1, CURRENCY_TO_KEY_OUT_RELAXED, ex, false); // No one can't include this tx into a block DO_CALLBACK(events, "mark_invalid_block"); MAKE_NEXT_BLOCK_TX1(events, blk_1i, blk_1, miner_acc, tx_0); // Someone tries to correctly register this alias, but failes ai = AUTO_VAL_INIT(ai); ai.m_alias = "sweet.name"; ai.m_address = alice.get_public_address(); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_1, alice, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner_acc, tx_list); tx_list.clear(); return true; } //------------------------------------------------------------------------------ bool gen_alias_blocking_update_by_invalid_tx::generate(std::vector& events) const { // 1. Register an alias. // 2. Attacker makes a tx to update this alias with fake sign. // 3. Nobody can add a block, including attacker's tx. // 4. Alias owner can't update his alias until attacker's tx is in the pool. std::list tx_list; uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(preminer_acc); GENERATE_ACCOUNT(miner_acc); GENERATE_ACCOUNT(alice); GENERATE_ACCOUNT(attacker); MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, ts); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4); uint64_t miner_money = get_outs_money_amount(blk_0r.miner_tx) * 4; // alice and attacker get some money MAKE_TX_LIST(events, tx_list, miner_acc, alice, miner_money / 2, blk_0r); MAKE_TX_LIST(events, tx_list, miner_acc, attacker, get_outs_money_amount(blk_0r.miner_tx), blk_0r); MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); tx_list.clear(); //REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // Alice registers an alias for herself extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = "sweet.name"; ai.m_address = alice.get_public_address(); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_1, alice, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner_acc, tx_list); tx_list.clear(); // Attacker makes fake update alias tx ai = AUTO_VAL_INIT(ai); ai.m_alias = "sweet.name"; ai.m_address = attacker.get_public_address(); ai.m_sign.push_back(invalid_signature); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_2, attacker, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); // Obviously, miner can't add it to his next block, because it turns out to be invalid. DO_CALLBACK(events, "mark_invalid_block"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2i, blk_2, miner_acc, tx_list); tx_list.clear(); // Alice tries to update her alias ai = AUTO_VAL_INIT(ai); ai.m_alias = "sweet.name"; ai.m_address = alice.get_public_address(); ai.m_text_comment = "alice@mail.com"; r = sign_extra_alias_entry(ai, alice.get_public_address().spend_public_key, alice.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_2, alice, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2, miner_acc, tx_list); tx_list.clear(); return true; } //------------------------------------------------------------------------------ bool gen_alias_reg_with_locked_money::generate(std::vector& events) const { // Make sure alias can't be paid with locked money std::list tx_list; uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(miner_acc); GENERATE_ACCOUNT(alice); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); DO_CALLBACK(events, "configure_core"); currency::block& prev_block = blk_0; // the following line unlocks money // REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); prev_block = blk_0r; extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_address = miner_acc.get_public_address(); currency::tx_source_entry se = AUTO_VAL_INIT(se); se.amount = boost::get(blk_0.miner_tx.vout[0]).amount; currency::tx_source_entry::output_entry oe = AUTO_VAL_INIT(oe); oe.out_reference = 0; oe.stealth_address = boost::get(boost::get(blk_0.miner_tx.vout[0]).target).key; se.outputs.push_back(oe); //se.outputs.push_back(make_serializable_pair(0, boost::get(boost::get(blk_0.miner_tx.vout[0]).target).key)); se.real_output = 0; se.real_output_in_tx_index = 0; se.real_out_tx_key = currency::get_tx_pub_key_from_extra(blk_0.miner_tx); std::vector sources(1, se); account_public_address null_addr = AUTO_VAL_INIT(null_addr); std::vector destinations; destinations.push_back(tx_destination_entry(get_alias_coast_from_fee(ai.m_alias, TESTS_DEFAULT_FEE), null_addr)); tx_builder tb; tb.step1_init(); tb.step2_fill_inputs(miner_acc.get_keys(), sources); tb.step3_fill_outputs(destinations); tb.m_tx.extra.push_back(ai); tb.step4_calc_hash(); tb.step5_sign(sources); DO_CALLBACK(events, "mark_invalid_tx"); events.push_back(tb.m_tx); DO_CALLBACK(events, "mark_invalid_block"); MAKE_NEXT_BLOCK_TX1(events, blk_2, prev_block, miner_acc, tb.m_tx); return true; } //------------------------------------------------------------------------------ gen_alias_too_much_reward::gen_alias_too_much_reward() { REGISTER_CALLBACK_METHOD(gen_alias_too_much_reward, check_alias); test_gentime_settings s = test_generator::get_test_gentime_settings(); s.miner_tx_max_outs = 11; // limit genesis outs for speed-up, as we going to spend all premine test_generator::set_test_gentime_settings(s); } bool gen_alias_too_much_reward::generate(std::vector& events) const { // pay for alias far too much and see, if it's ok uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(miner_acc); // event index MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); // 0 set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); // 1 events.push_back(miner_acc); // 2 REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // N+3 uint64_t premine = get_outs_money_amount(blk_0.miner_tx); extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_address = miner_acc.get_public_address(); ai.m_view_key.push_back(miner_acc.get_keys().view_secret_key); std::vector extra; extra.push_back(ai); account_base reward_acc; bool r = get_aliases_reward_account(const_cast(reward_acc.get_public_address())); CHECK_AND_ASSERT_MES(r, false, "get_aliases_reward_account failed"); MAKE_TX_FEE_MIX_ATTR_EXTRA(events, tx_0, miner_acc, reward_acc, premine, TESTS_DEFAULT_FEE, 0, blk_0r, CURRENCY_TO_KEY_OUT_RELAXED, extra, false); MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); DO_CALLBACK(events, "check_alias"); return true; } bool gen_alias_too_much_reward::check_alias(currency::core& c, size_t ev_index, const std::vector& events) { const currency::account_base& miner_acc = boost::get(events[2]); currency::extra_alias_entry_base ai; bool r = c.get_blockchain_storage().get_alias_info(std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'), ai); CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); CHECK_AND_ASSERT_MES(ai.m_address == miner_acc.get_public_address() && ai.m_view_key.size() == 1 && ai.m_view_key.front() == miner_acc.get_keys().view_secret_key, false, "wrong alias"); return true; } //------------------------------------------------------------------------------ #define ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY_TESTS "2aa4f4571d454462f4f1d426475235a9449b97dd1e3a7f44aa58a407a475e75c" #define ALIAS_SHORT_NAMES_VALIDATION_PRIV_KEY_TESTS "44c7a7727a24c3a69e2030c52d366b82934f4d690c07c5206b45edd119dc010d" struct alias_entry { char name[16]; account_public_address addr; }; account_public_address pub_addr_from_string(const char* str) { account_public_address r = AUTO_VAL_INIT(r); CHECK_AND_ASSERT_THROW_MES(get_account_address_from_str(r, str), "get_account_address_from_str failed for " << str); return r; } gen_alias_too_small_reward::gen_alias_too_small_reward() { REGISTER_CALLBACK_METHOD(gen_alias_too_small_reward, init_runtime_config); REGISTER_CALLBACK_METHOD(gen_alias_too_small_reward, check_alias); } bool gen_alias_too_small_reward::init_runtime_config(currency::core& c, size_t ev_index, const std::vector& events) { core_runtime_config crc = c.get_blockchain_storage().get_core_runtime_config(); bool r = epee::string_tools::hex_to_pod(ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY_TESTS, crc.alias_validation_pubkey); CHECK_AND_ASSERT_THROW_MES(r, "failed to parse alias_validation_pub_key"); c.get_blockchain_storage().set_core_runtime_config(crc); return true; } bool gen_alias_too_small_reward::generate(std::vector& events) const { // pay for alias too small and see, if it's ok const alias_entry aliases[] = { {"a", pub_addr_from_string("ZxD95C97dFqVBsuTMA1VKjFxx8Cc7by2YTA9kLhFc8JB3zJ3qKKXRm9Lu2YQsjPP5UKhCSfLLEqJr5ovyQNYYQWV1Pv98fRzt")}, {"bb", pub_addr_from_string("ZxDL9euTT4C9FUj28QY1RdWnreMHJiWfrPs39rXhrgai8H4pmaFzJ4vUUYRmHhNxToN64H1U5sMnaHuD3S4kVbyY1mKHnERVZ")}, {"ccc", pub_addr_from_string("ZxBrpHp3xrjLrMMSyJUg44YmyJVZjetouVFdtqLfxpHUMSxiEyyQ7iKSj4sr6gn7qwXrj6YSw7UjJZLyc1H37QtF2p96c2gAD")}, {"dddd", pub_addr_from_string("ZxDtT1pTwt6R2t3eGw9VD6N1heHCKNLKuCFUvqgHpXkAVnPkfai4KDYEjRSV8E42XKN3MJeaHJMaxa9hUmaXLyHm2nQ12aX93")}, {"eeeee", pub_addr_from_string("ZxCABdwUJpqHstWJUHQ21piADBwaSsXcAh5EPtpSr8xXderWqvDef566ReFGrRqBUrE2tCgZ3HE5XRuxoq8mNTrP2X4J35yQq")}, {"ffffff", pub_addr_from_string("ZxC34uAJJ2iW15GkvcqaQd4RKZdu16tpmf4ubmsirw7eFtKoLi2xswhNqy3Q4VacCq5mM7zuYyoWEW8AS5HGtoXr1m9RuTUuu")}, {"ggggggg", pub_addr_from_string("ZxDHxZizSe5MNQoRkC1unqTrhYUkh1ZG7iEXMzLatyZ5EHRPat4Ls4ZRnN4CYLvJLq5F5gxdDtu17Zrvur7dcqU52sv2pryn7")}, {"hhhhhhhh", pub_addr_from_string("ZxDXME4qrbh7mAbrqDmCbzGj14VQP1n9KLLi7fXBMNvDd5UUpcevCSXQ9zSkZcJtbzBS7u16NiykAiv3q9VkZySL2ySB6hTfL")}, {"iiiiiiiii", pub_addr_from_string("ZxDtpxbC2bN8yu3J49tsUYUSoPYTnAgjmBogzFviUg3t2fGfWzmZ2gbKNC1XKVdMEE2hoW5sULs2hAF5T3igoAVW2MsHUmaj4")}, {"jjjjjjjjjj", pub_addr_from_string("ZxCBLxnctYwB37YZi7MsJqBCujXzkBeJEh7wPbYrFUvMiqXiPLkyBRAh6ahQ6wre2tGR8FHesZwKn2zYPkTuibyu2648g2CGV")} }; const size_t aliases_count = sizeof aliases / sizeof aliases[0]; uint64_t ts = test_core_time::get_time(); 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, ts); set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); DO_CALLBACK(events, "init_runtime_config"); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); transaction tx_1 = AUTO_VAL_INIT(tx_1); r = construct_tx_with_many_outputs(m_hardforks, events, blk_0r, miner_acc.get_keys(), miner_acc.get_public_address(), 3 * aliases_count * TESTS_DEFAULT_FEE * 100, 3 * aliases_count, TESTS_DEFAULT_FEE, tx_1); CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed"); events.push_back(tx_1); MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1); std::vector used_sources; std::list txs; for (size_t i = 0; i < aliases_count; ++i) { uint64_t alias_reward = get_alias_coast_from_fee(aliases[i].name, TESTS_DEFAULT_FEE); transaction tx = AUTO_VAL_INIT(tx); DO_CALLBACK(events, "mark_invalid_tx"); // should be rejected, because it's paid TX_POOL_MINIMUM_FEE / 10 if (!make_tx_reg_alias(events, generator, blk_1, aliases[i].name, aliases[i].addr, ALIAS_VERY_INITAL_COAST / 10, miner_acc, tx, used_sources)) return false; // this block commented due to new fee median rules, TODO: review // DO_CALLBACK(events, "mark_invalid_tx"); // should be rejected, because it's paid TX_POOL_MINIMUM_FEE / 10 less then required // if (!make_tx_reg_alias(events, generator, blk_1, aliases[i].name, aliases[i].addr, alias_reward - TESTS_DEFAULT_FEE / 10, miner_acc, tx, used_sources)) // return false; // should be accepted if (!make_tx_reg_alias(events, generator, blk_1, aliases[i].name, aliases[i].addr, alias_reward, miner_acc, tx, used_sources)) return false; txs.push_back(tx); } // one alias per block to avoid the limits block prev_block = blk_1; for(auto& tx : txs) { MAKE_NEXT_BLOCK_TX1(events, blk_n, prev_block, miner_acc, tx); prev_block = blk_n; } for (size_t i = 0; i < sizeof aliases / sizeof aliases[0]; ++i) { DO_CALLBACK_PARAMS(events, "check_alias", aliases[i]); } return true; } bool gen_alias_too_small_reward::make_tx_reg_alias(std::vector& events, test_generator &generator, const currency::block& prev_block, const std::string& alias, const account_public_address& alias_addr, uint64_t alias_reward, const currency::account_base& miner_acc, currency::transaction &tx, std::vector& used_sources) const { extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = alias; ai.m_address = alias_addr; ai.m_view_key.push_back(miner_acc.get_keys().view_secret_key); if (alias.size() < ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED) { crypto::secret_key alias_secret_key = AUTO_VAL_INIT(alias_secret_key); bool r = epee::string_tools::hex_to_pod(ALIAS_SHORT_NAMES_VALIDATION_PRIV_KEY_TESTS, alias_secret_key); CHECK_AND_ASSERT_THROW_MES(r, "failed to parse alias_secret_key"); crypto::public_key alias_public_key = AUTO_VAL_INIT(alias_public_key); r = epee::string_tools::hex_to_pod(ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY_TESTS, alias_public_key); CHECK_AND_ASSERT_THROW_MES(r, "failed to parse alias_public_key"); r = currency::sign_extra_alias_entry(ai, alias_public_key, alias_secret_key); CHECK_AND_ASSERT_THROW_MES(r, "failed to sign_extra_alias_entry"); } std::vector extra; extra.push_back(ai); account_base reward_acc; bool r = get_aliases_reward_account(const_cast(reward_acc.get_public_address())); CHECK_AND_ASSERT_MES(r, false, "get_aliases_reward_account failed"); std::vector sources; uint64_t amount = alias_reward + TESTS_DEFAULT_FEE; r = fill_tx_sources(sources, events, prev_block, miner_acc.get_keys(), amount, 0, used_sources); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed, requested money: " << print_money_brief(amount)); std::vector destinations; destinations.push_back(tx_destination_entry(alias_reward, reward_acc.get_public_address())); uint64_t sources_amount = get_sources_total_amount(sources); if (sources_amount > alias_reward + TESTS_DEFAULT_FEE) destinations.push_back(tx_destination_entry(sources_amount - (alias_reward + TESTS_DEFAULT_FEE), miner_acc.get_public_address())); // change crypto::secret_key stub = AUTO_VAL_INIT(stub); uint64_t tx_version = get_tx_version(get_block_height(prev_block), m_hardforks); r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx, tx_version, stub, uint64_t(0)); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx); append_vector_by_another_vector(used_sources, sources); return true; } bool gen_alias_too_small_reward::check_alias(currency::core& c, size_t ev_index, const std::vector& events) { alias_entry ae = AUTO_VAL_INIT(ae); bool r = epee::string_tools::hex_to_pod(boost::get(events[ev_index]).callback_params, ae); CHECK_AND_ASSERT_MES(r, false, "hex_to_pod failed: " << boost::get(events[ev_index]).callback_params); const currency::account_base& miner_acc = m_accounts[MINER_ACC_IDX]; extra_alias_entry ai = AUTO_VAL_INIT(ai); r = c.get_blockchain_storage().get_alias_info(ae.name, ai); CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); CHECK_AND_ASSERT_MES(ai.m_address == ae.addr && ai.m_view_key.size() == 1 && ai.m_view_key.front() == miner_acc.get_keys().view_secret_key, false, "wrong alias registration: " << ae.name); return true; } //------------------------------------------------------------------------------ bool gen_alias_tx_no_outs::generate(std::vector& events) const { // pay for alias with tx, having no outs uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); DO_CALLBACK(events, "configure_core"); events.push_back(miner_acc); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = "abcdefg"; ai.m_address = miner_acc.get_public_address(); currency::tx_source_entry se = AUTO_VAL_INIT(se); se.amount = boost::get(blk_0.miner_tx.vout[0]).amount; se.outputs.push_back(currency::tx_source_entry::output_entry(0, boost::get(boost::get(blk_0.miner_tx.vout[0]).target).key)); se.real_output = 0; se.real_output_in_tx_index = 0; se.real_out_tx_key = currency::get_tx_pub_key_from_extra(blk_0.miner_tx); std::vector sources(1, se); account_public_address null_addr = AUTO_VAL_INIT(null_addr); std::vector destinations; tx_builder tb; tb.step1_init(); tb.step2_fill_inputs(miner_acc.get_keys(), sources); tb.step3_fill_outputs(destinations); tb.m_tx.extra.push_back(ai); tb.step4_calc_hash(); tb.step5_sign(sources); DO_CALLBACK(events, "mark_invalid_tx"); events.push_back(tb.m_tx); return true; } //------------------------------------------------------------------------------ gen_alias_switch_and_check_block_template::gen_alias_switch_and_check_block_template() { REGISTER_CALLBACK_METHOD(gen_alias_switch_and_check_block_template, add_block_from_template); } bool gen_alias_switch_and_check_block_template::generate(std::vector& events) const { // 1) reg an alias, put tx into a block; // 2) update an alias with tx with a bigger fee, put tx into a block; // 3) split the chain by adding few blocks; // 4) switch to altchain, so both registration and updating txs go to the pool; // 5) create a block from block template and add it. // 0 ...10 11 12 13 14 <- height // +--- reg an alias in blk_2 // | +--- update the alias in blk_3 // (0 )- (0r)- (1 )- (2 )- (3 ) // \- (4 )- (5 )- (6 ) std::list tx_list; uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(preminer_acc); GENERATE_ACCOUNT(miner_acc); GENERATE_ACCOUNT(alice); MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, ts); // 0 set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); // 1 events.push_back(alice); // 2 REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4); // 2N = CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2 uint64_t miner_amount = get_outs_money_amount(blk_0r.miner_tx) * 4; // alice get some money MAKE_TX_LIST(events, tx_list, miner_acc, alice, miner_amount / 2, blk_0r); // 2N+3 MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); // 2N+4 tx_list.clear(); // Alice registers an alias extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'x'); ai.m_address = alice.get_public_address(); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_1, alice, ai, generator); // 2N+5 CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner_acc, tx_list); // 2N+6 tx_list.clear(); // Alice updates her alias (paid by miner in order not to confuse and mix the inputs) ai.m_text_comment = "alice@mail.com"; r = sign_extra_alias_entry(ai, alice.get_public_address().spend_public_key, alice.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); std::vector extra(1, ai); MAKE_TX_FEE_MIX_ATTR_EXTRA(events, tx_0, miner_acc, miner_acc, 1, TESTS_DEFAULT_FEE, 0, blk_2, CURRENCY_TO_KEY_OUT_RELAXED, extra, true); // 2N+7 MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_0); // 2N+8 // split the chain MAKE_NEXT_BLOCK(events, blk_4, blk_1, miner_acc); // 2N+9 MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc); // 2N+10 // switch to altchain MAKE_NEXT_BLOCK(events, blk_6, blk_5, miner_acc); // 2N+11 // try to create and add block from template DO_CALLBACK_PARAMS_STR(events, "add_block_from_template", ai.m_alias); // 2N+12 return true; } bool gen_alias_switch_and_check_block_template::add_block_from_template(currency::core& c, size_t ev_index, const std::vector& events) { account_base acc; acc.generate(); currency::block b; wide_difficulty_type diff; uint64_t height; blobdata extra = AUTO_VAL_INIT(extra); bool r = c.get_block_template(b, acc.get_public_address(), acc.get_public_address(), diff, height, extra); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); r = miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); c.handle_incoming_block(t_serializable_object_to_blob(b), bvc); r = check_block_verification_context(bvc, ev_index, b); CHECK_AND_NO_ASSERT_MES(r, false, "block verification context check failed"); // check that alias was successfully registered const std::string& alias_name = boost::get(events[ev_index]).callback_params; const currency::account_base& alice_acc = boost::get(events[2]); extra_alias_entry ai = AUTO_VAL_INIT(ai); r = c.get_blockchain_storage().get_alias_info(alias_name, ai); CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); CHECK_AND_ASSERT_MES(ai.m_address == alice_acc.get_public_address(), false, "wrong alias registration: " << alias_name); return true; } //------------------------------------------------------------------------------ gen_alias_too_many_regs_in_block_template::gen_alias_too_many_regs_in_block_template() : m_estimated_alias_cost(0) , m_total_alias_to_gen(MAX_ALIAS_PER_BLOCK + 1) { REGISTER_CALLBACK_METHOD(gen_alias_too_many_regs_in_block_template, add_block_from_template); } bool gen_alias_too_many_regs_in_block_template::generate(std::vector& events) const { // 1) add lots of alias-registering txs to the pool; // 2) create block template and check it contains not too many such txs. bool r = false; uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(preminer_acc); m_accounts.resize(TOTAL_ACCS_COUNT); GENERATE_ACCOUNT(miner_acc); m_accounts[MINER_ACC_IDX] = miner_acc; GENERATE_ACCOUNT(alice_acc); m_accounts[ALICE_ACC_IDX] = alice_acc; MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, ts); // 0 REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); uint64_t fee_median = generator.get_last_n_blocks_fee_median(get_block_hash(blk_0r)); m_estimated_alias_cost = currency::get_alias_coast_from_fee(std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'), fee_median); std::vector sources; std::vector destinations; uint64_t total_alias_cost = 0; for(size_t i = 0; i < m_total_alias_to_gen; ++i) { destinations.push_back(tx_destination_entry(m_estimated_alias_cost + TESTS_DEFAULT_FEE, alice_acc.get_public_address())); total_alias_cost += m_estimated_alias_cost + TESTS_DEFAULT_FEE; } total_alias_cost += TESTS_DEFAULT_FEE; r = fill_tx_sources(sources, events, blk_0r, preminer_acc.get_keys(), total_alias_cost, 0); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); uint64_t sources_amount = get_sources_total_amount(sources); if (sources_amount > total_alias_cost) destinations.push_back(tx_destination_entry(sources_amount - total_alias_cost, preminer_acc.get_public_address())); // return the change in order to keep median_fee low transaction tx_1 = AUTO_VAL_INIT(tx_1); uint64_t tx_version = get_tx_version(get_block_height(blk_0r), m_hardforks); r = construct_tx(preminer_acc.get_keys(), sources, destinations, empty_attachment, tx_1, tx_version, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_1); MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1); REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); // rewind few block to made money unlocked in Alice's wallet DO_CALLBACK(events, "add_block_from_template"); return true; } bool gen_alias_too_many_regs_in_block_template::add_block_from_template(currency::core& c, size_t ev_index, const std::vector& events) { // register too many aliases std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); alice_wlt->refresh(); extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_address = m_accounts[ALICE_ACC_IDX].get_public_address(); account_base someone; try { log_level_scope_changer llsc(LOG_LEVEL_0); // eliminate all the mess in the log during alias registration, comment this out if case of debugging for (size_t i = 0; i < m_total_alias_to_gen; ++i) { LOG_PRINT_YELLOW("Generating alias #" << i << " of " << m_total_alias_to_gen << "...", LOG_LEVEL_0); someone.generate(); ai.m_address = someone.get_public_address(); ai.m_alias = gen_random_alias(random_in_range(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED + 20)); transaction alias_reg_tx = AUTO_VAL_INIT(alias_reg_tx); alice_wlt->request_alias_registration(ai, alias_reg_tx, TESTS_DEFAULT_FEE, m_estimated_alias_cost); } } catch (std::exception& e) { LOG_ERROR("Caught an exception while registering an alias: " << e.what()); return false; } CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == m_total_alias_to_gen, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count() << ", expected: " << m_total_alias_to_gen); // attempt to create block from block template, then check how many aliases it will contain account_base acc; acc.generate(); currency::block b; wide_difficulty_type diff; uint64_t height; blobdata extra = AUTO_VAL_INIT(extra); bool r = c.get_block_template(b, acc.get_public_address(), acc.get_public_address(), diff, height, extra); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); r = miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); c.handle_incoming_block(t_serializable_object_to_blob(b), bvc); r = check_block_verification_context(bvc, ev_index, b); CHECK_AND_NO_ASSERT_MES(r, false, "block verification context check failed"); return true; } //------------------------------------------------------------------------------ bool gen_alias_update_for_free::generate(std::vector& events) const { std::list tx_list; uint64_t ts = test_core_time::get_time(); GENERATE_ACCOUNT(miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); // 0 set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); // 1 REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // 2N+1, 2N = CURRENCY_MINED_MONEY_UNLOCK_WINDOW // registrate an alias - pay as usual extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = std::string(ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED, 'a'); ai.m_address = miner_acc.get_public_address(); bool r = put_alias_via_tx_to_list(m_hardforks, events, tx_list, blk_0r, miner_acc, ai, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); tx_list.clear(); // update the alias - pay nothing ai.m_text_comment = "miner@mail.com"; r = sign_extra_alias_entry(ai, miner_acc.get_public_address().spend_public_key, miner_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); std::vector extra(1, ai); // create a tx with chargeback, paying only the minimum required fee std::vector sources; std::vector destinations; r = fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), TESTS_DEFAULT_FEE, 0, true, true); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); uint64_t input_amount = 0; for (auto se : sources) input_amount += se.amount; if (input_amount > TESTS_DEFAULT_FEE) destinations.push_back(tx_destination_entry(input_amount - TESTS_DEFAULT_FEE, miner_acc.get_public_address())); tx_builder tb; tb.step1_init(); tb.step2_fill_inputs(miner_acc.get_keys(), sources); tb.step3_fill_outputs(destinations); tb.m_tx.extra.push_back(ai); tb.step4_calc_hash(); tb.step5_sign(sources); events.push_back(tb.m_tx); MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1, miner_acc, tb.m_tx); return true; } //------------------------------------------------------------------------------ gen_alias_in_coinbase::gen_alias_in_coinbase() { REGISTER_CALLBACK_METHOD(gen_alias_in_coinbase, check); } bool gen_alias_in_coinbase::generate(std::vector& events) const { // Test idea: make sure that alias can be registered and update via coinbase transaction as well as normal one. // This also checks that coinbase transacton can hold an arbitrary entity in it's extra. uint64_t ts = 145000000; GENERATE_ACCOUNT(miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); // reg an alias using coinbase extra_alias_entry ai = AUTO_VAL_INIT(ai); ai.m_alias = "emmanuel.goldstein"; // long enough alias to minimize it's cost ai.m_address = miner_acc.get_public_address(); block blk_1 = AUTO_VAL_INIT(blk_1); bool r = generator.construct_pow_block_with_alias_info_in_coinbase(miner_acc, blk_0, ai, blk_1); CHECK_AND_ASSERT_MES(r, false, "construct_block_gentime_with_coinbase_cb failed"); events.push_back(blk_1); DO_CALLBACK_PARAMS_STR(events, "check", t_serializable_object_to_blob(ai)); // update an alias using coinbase ai.m_text_comment = "A Party member is expected to have no private emotions and no respites from enthusiasm."; ai.m_view_key.push_back(miner_acc.get_keys().view_secret_key); r = sign_extra_alias_entry(ai, miner_acc.get_public_address().spend_public_key, miner_acc.get_keys().spend_secret_key); CHECK_AND_ASSERT_MES(r, false, "sign_extra_alias_entry failed"); block blk_2 = AUTO_VAL_INIT(blk_2); r = generator.construct_pow_block_with_alias_info_in_coinbase(miner_acc, blk_1, ai, blk_2); CHECK_AND_ASSERT_MES(r, false, "construct_block_gentime_with_coinbase_cb failed"); events.push_back(blk_2); DO_CALLBACK_PARAMS_STR(events, "check", t_serializable_object_to_blob(ai)); return true; } bool gen_alias_in_coinbase::check(currency::core& c, size_t ev_index, const std::vector& events) { extra_alias_entry param_ai = AUTO_VAL_INIT(param_ai); bool r = t_unserializable_object_from_blob(param_ai, boost::get(events[ev_index]).callback_params); CHECK_AND_ASSERT_MES(r, false, "Can't obtain event params."); currency::extra_alias_entry_base ai = AUTO_VAL_INIT(ai); r = c.get_blockchain_storage().get_alias_info(param_ai.m_alias, ai); CHECK_AND_ASSERT_MES(r, false, "blockchain has no info for alias: " << param_ai.m_alias); CHECK_AND_ASSERT_MES(ai.m_address == param_ai.m_address, false, "m_address are wrong"); CHECK_AND_ASSERT_MES(ai.m_sign == param_ai.m_sign, false, "m_sign are wrong"); CHECK_AND_ASSERT_MES(ai.m_text_comment == param_ai.m_text_comment, false, "m_text_comment are wrong"); CHECK_AND_ASSERT_MES(ai.m_view_key == param_ai.m_view_key, false, "m_view_key are wrong"); return true; }