1
0
Fork 0
forked from lthn/blockchain

coretests: alt_chain_and_block_tx_fee_median test (#456)

* coretests: alt_chain_and_block_tx_fee_median test

* Run test "alt_chain_and_block_tx_fee_median" on run core tests

* Edit the test preamble
This commit is contained in:
Stёpa Dolgorukov 2024-09-17 01:13:49 +05:00 committed by GitHub
parent a8adcc07b7
commit 35427f8381
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 257 additions and 1 deletions

View file

@ -817,3 +817,241 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector<te
return true;
}
alt_chain_and_block_tx_fee_median::alt_chain_and_block_tx_fee_median()
{
REGISTER_CALLBACK_METHOD(alt_chain_and_block_tx_fee_median, check_after_hf4);
REGISTER_CALLBACK_METHOD(alt_chain_and_block_tx_fee_median, check_before_hf4);
}
bool alt_chain_and_block_tx_fee_median::generate(
std::vector<test_event_entry>& events) const
{
/* Test idea: check chain switching rules.
Rules before and after HF4 for PoW blocks are different. There're only PoW
blocks in the test situation. If the last blocks contain transactions (non
empty blocks), then the chain with the largest this_block_tx_fee_median on its
head becomes the main.
0 10 11 21 22
(0 ) - ... - (0r) - (1 ) - ... - (1r) - (2 )
| main | \
| | [tx_0]
| |
| | main
\ - (1a) \ - (2a)
\
[tx_1]
Chain with head blk_1 versus chain with head blk_1a: chain with head blk_1
is the main, because blocks 1, 1a are empty.
Chain with head blk_2 versus chain with head blk_2a: chain with head blk_2a
is the main, because blocks 2, 2a aren't empty and the fee of tx_1 is larger
than the fee of tx_0.
*/
bool success{};
bool hf4_active{};
std::vector<tx_source_entry> sources{};
std::vector<tx_destination_entry> destinations{};
transaction tx_0{}, tx_1{};
uint64_t tx_version{};
crypto::hash top_block{};
GENERATE_ACCOUNT(miner);
MAKE_GENESIS_BLOCK(events,
blk_0,
miner,
test_core_time::get_time());
DO_CALLBACK(events, "configure_core");
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner,
CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner);
MAKE_NEXT_BLOCK(events, blk_1a, blk_0r, miner);
/* It is decided which chain will be the main: with the head blk_1 or with the
head blk_1a.
0 10 11
/ - (1 )
|
(0 ) - ... - (0r)
|
\ - (1a)
*/
CHECK_AND_ASSERT_EQ(is_pos_block(blk_1), false);
CHECK_AND_ASSERT_EQ(is_pos_block(blk_1a), false);
CHECK_AND_ASSERT_EQ(get_block_height(blk_1), 11);
CHECK_AND_ASSERT_EQ(get_block_height(blk_1), get_block_height(blk_1a));
/* Blocks blk_1, blk_1a do not contain transactions (they are empty blocks).
Switching to the alternative chain with head blk_1a will not occur. The main
chain is the chain with the head blk_1. */
DO_CALLBACK_PARAMS(events,
"check_top_block",
params_top_block(get_block_height(blk_1),
get_block_hash(blk_1)));
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner,
CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// Transaction tx_0 is constructed and placed in block blk_2.
success = fill_tx_sources_and_destinations(
events,
/* head = */ blk_1r,
/* from = */ miner.get_keys(),
/* to = */ miner.get_public_address(),
/* amount = */ MK_TEST_COINS(10),
/* fee = */ m_fee_tx_0_blk_2,
/* nmix = */ 0,
sources,
destinations);
CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations");
tx_version = get_tx_version(get_block_height(blk_1r),
m_hardforks);
success = construct_tx(miner.get_keys(),
sources,
destinations,
empty_attachment,
tx_0,
tx_version,
0);
CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_0");
ADD_CUSTOM_EVENT(events, tx_0);
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner, tx_0);
sources.clear();
destinations.clear();
// Transaction tx_1 is constructed and placed in block blk_2a.
tx_version = get_tx_version(get_block_height(blk_1r),
m_hardforks);
success = fill_tx_sources_and_destinations(
events,
/* head = */ blk_1r,
/* from = */ miner.get_keys(),
/* to = */ miner.get_public_address(),
/* amount = */ MK_TEST_COINS(10),
/* fee = */ m_fee_tx_1_blk_2a,
/* nmix = */ 0,
sources,
destinations);
CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations");
success = construct_tx(miner.get_keys(),
sources,
destinations,
empty_attachment,
tx_1,
tx_version,
0);
CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_1");
ADD_CUSTOM_EVENT(events, tx_1);
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner, tx_1);
/* It is decided which chain will be the main: with the head blk_2 or with the
head blk_2a.
0 21 22
/ - (2 )
| \
| [tx_0]
|
(0 ) - ... - (1r)
|
|
|
\ - (2a)
\
[tx_1]
*/
CHECK_AND_ASSERT_EQ(is_pos_block(blk_2), false);
CHECK_AND_ASSERT_EQ(is_pos_block(blk_2a), false);
CHECK_AND_ASSERT_GREATER(m_fee_tx_1_blk_2a, m_fee_tx_0_blk_2);
CHECK_AND_ASSERT_EQ(get_block_height(blk_2), 22);
CHECK_AND_ASSERT_EQ(get_block_height(blk_2), get_block_height(blk_2a));
hf4_active =
m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM,
get_block_height(blk_2) + 1);
if (hf4_active)
{
/* With HF4 active, the chain with head blk_2a wins because transaction tx_1
has a greater fee than transaction tx_0. The main chain is the chain with
the head blk_2a. */
DO_CALLBACK(events, "check_after_hf4");
top_block = get_block_hash(blk_2a);
}
else
{
/* The chains have the same commulative difficulty. Therefore, with HF4
inactive, switching to the chain with the blk_2a head will not occur. The
main chain is the chain with the head blk_2. */
DO_CALLBACK(events, "check_before_hf4");
top_block = get_block_hash(blk_2);
}
DO_CALLBACK_PARAMS(events,
"check_top_block",
params_top_block(/* height = */ 22, top_block));
return true;
}
bool alt_chain_and_block_tx_fee_median::check_after_hf4(
currency::core& c,
size_t ev_index,
const std::vector<test_event_entry>& events)
{
block_extended_info bei{};
const uint64_t height_block{22};
CHECK_AND_ASSERT_EQ(
m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM,
height_block),
true);
c.get_blockchain_storage().get_block_extended_info_by_height(height_block,
bei);
CHECK_AND_ASSERT_EQ(bei.this_block_tx_fee_median, m_fee_tx_1_blk_2a);
return true;
}
bool alt_chain_and_block_tx_fee_median::check_before_hf4(
currency::core& c,
size_t ev_index,
const std::vector<test_event_entry>& events)
{
block_extended_info bei{};
const uint64_t height_block{22};
CHECK_AND_ASSERT_EQ(
m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM,
height_block),
false);
c.get_blockchain_storage().get_block_extended_info_by_height(height_block,
bei);
CHECK_AND_ASSERT_EQ(bei.this_block_tx_fee_median, m_fee_tx_0_blk_2);
return true;
}

View file

@ -82,3 +82,21 @@ struct chain_switching_when_out_spent_in_alt_chain_ref_id : public test_chain_un
{
bool generate(std::vector<test_event_entry>& events) const;
};
struct alt_chain_and_block_tx_fee_median : public test_chain_unit_enchanced
{
alt_chain_and_block_tx_fee_median();
bool generate(std::vector<test_event_entry>& events) const;
bool check_after_hf4(currency::core& c,
size_t ev_index,
const std::vector<test_event_entry>& events);
bool check_before_hf4(currency::core& c,
size_t ev_index,
const std::vector<test_event_entry>& events);
private:
const uint64_t m_fee_tx_0_blk_2{TESTS_DEFAULT_FEE};
const uint64_t m_fee_tx_1_blk_2a{2 * m_fee_tx_0_blk_2};
};

View file

@ -1140,7 +1140,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY_HF(alt_blocks_with_the_same_txs, "3-*");
GENERATE_AND_PLAY_HF(chain_switching_when_out_spent_in_alt_chain_mixin, "3-*");
GENERATE_AND_PLAY_HF(chain_switching_when_out_spent_in_alt_chain_ref_id, "3-*");
GENERATE_AND_PLAY_HF(alt_chain_and_block_tx_fee_median, "3-*");
// miscellaneous tests
GENERATE_AND_PLAY(test_blockchain_vs_spent_keyimges);