2018-12-27 18:50:45 +03:00
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote 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 "chain_switch_1.h"
# include "random_helper.h"
using namespace epee ;
using namespace currency ;
# include "currency_core/currency_format_utils.h"
gen_chain_switch_1 : : gen_chain_switch_1 ( )
: m_miner_initial_amount ( 0 )
{
REGISTER_CALLBACK ( " check_split_not_switched " , gen_chain_switch_1 : : check_split_not_switched ) ;
REGISTER_CALLBACK ( " check_split_switched " , gen_chain_switch_1 : : check_split_switched ) ;
}
//-----------------------------------------------------------------------------------------------------
bool gen_chain_switch_1 : : generate ( std : : vector < test_event_entry > & events ) const
{
uint64_t ts_start = 1450000000 ;
/*
0 10. . .11 12. . .22 23 24 25 < - main blockchain height ( assuming unlock window is 10 blocks )
( 0 ) - ( 0 r ) - ( 1 ) - ( 2 ) - ( 2 r ) - ( 3 ) - ( 4 ) < - main chain , until 7 isn ' t connected
\ | - ( 5 ) - ( 6 ) | < - alt chain , until 7 isn ' t connected
( 0 ) - ( 0 r ) - ( 1 ) - ( 2 ) - ( 2 r ) - ( 5 ) - ( 6 ) - ( 7 ) < - main chain , after reorganize
\ | - ( 3 ) - ( 4 ) | < - alt chain , after reorganize
MAIN CHAIN ( 3 ) - ( 4 )
miner - 5 - 14 - 16 = - 35
acc_1 + 5 + 3 = + 8
acc_2 + 8 + 2 = + 10
acc_3 + 1 + 13 = + 14
acc_4 + 2 + 1 = + 3
ALT CHAIN ( 5 ) - ( 6 ) - ( 7 )
miner - 5 - 20 - 16 = - 41
acc_1 + 5 + 1 + 2 = + 8
acc_2 + 3 = + 3
acc_3 + 2 + 12 = + 14
acc_4 + 14 + 2 = + 16
transactions ( [ n ] - tx amount , ( m ) - block ) :
( 1 ) : miner - [ 5 ] - > account_1 ( + 5 in main chain , + 5 in alt chain )
( 3 ) : miner - [ 7 ] - > account_2 ( + 7 in main chain , + 0 in alt chain ) , tx will be in tx pool after switch
( 4 ) , ( 6 ) : miner - [ 11 ] - > account_3 ( + 11 in main chain , + 11 in alt chain )
( 5 ) : miner - [ 13 ] - > account_4 ( + 0 in main chain , + 13 in alt chain ) , tx will be in tx pool before switch
transactions orders ( [ n ] - tx amount , ( m ) - block ) :
miner - [ 1 ] , [ 2 ] - > account_1 : in main chain ( 3 ) , ( 3 ) , in alt chain ( 5 ) , ( 6 )
miner - [ 1 ] , [ 2 ] - > account_2 : in main chain ( 3 ) , ( 4 ) , in alt chain ( 5 ) , ( 5 )
miner - [ 1 ] , [ 2 ] - > account_3 : in main chain ( 3 ) , ( 4 ) , in alt chain ( 6 ) , ( 5 )
miner - [ 1 ] , [ 2 ] - > account_4 : in main chain ( 4 ) , ( 3 ) , in alt chain ( 5 ) , ( 6 )
*/
GENERATE_ACCOUNT ( miner_account ) ;
m_miner_account = miner_account ;
// events
MAKE_GENESIS_BLOCK ( events , blk_0 , miner_account , ts_start ) ; // 0
m_miner_initial_amount = get_outs_money_amount ( blk_0 . miner_tx ) ;
MAKE_ACCOUNT ( events , recipient_account_1 ) ; // 1
MAKE_ACCOUNT ( events , recipient_account_2 ) ; // 2
MAKE_ACCOUNT ( events , recipient_account_3 ) ; // 3
MAKE_ACCOUNT ( events , recipient_account_4 ) ; // 4
REWIND_BLOCKS ( events , blk_0r , blk_0 , miner_account ) // <N blocks>
MAKE_TX ( events , tx_00 , miner_account , recipient_account_1 , MK_TEST_COINS ( 5 ) , blk_0r ) ; // 5 + N
MAKE_NEXT_BLOCK_TX1 ( events , blk_1 , blk_0r , miner_account , tx_00 ) ; // 6 + N
MAKE_NEXT_BLOCK ( events , blk_2 , blk_1 , miner_account ) ; // 7 + N
REWIND_BLOCKS ( events , blk_2r , blk_2 , miner_account ) // <N blocks>
// Transactions to test account balances after switch
MAKE_TX_LIST_START ( events , txs_blk_3 , miner_account , recipient_account_2 , MK_TEST_COINS ( 7 ) , blk_2r ) ; // 8 + 2N
MAKE_TX_LIST_START ( events , txs_blk_4 , miner_account , recipient_account_3 , MK_TEST_COINS ( 11 ) , blk_2r ) ; // 9 + 2N
MAKE_TX_LIST_START ( events , txs_blk_5 , miner_account , recipient_account_4 , MK_TEST_COINS ( 13 ) , blk_2r ) ; // 10 + 2N
std : : list < transaction > txs_blk_6 ;
txs_blk_6 . push_back ( txs_blk_4 . front ( ) ) ;
// Transactions, that has different order in alt block chains
MAKE_TX_LIST ( events , txs_blk_3 , miner_account , recipient_account_1 , MK_TEST_COINS ( 1 ) , blk_2r ) ; // 11 + 2N
txs_blk_5 . push_back ( txs_blk_3 . back ( ) ) ;
MAKE_TX_LIST ( events , txs_blk_3 , miner_account , recipient_account_1 , MK_TEST_COINS ( 2 ) , blk_2r ) ; // 12 + 2N
txs_blk_6 . push_back ( txs_blk_3 . back ( ) ) ;
MAKE_TX_LIST ( events , txs_blk_3 , miner_account , recipient_account_2 , MK_TEST_COINS ( 1 ) , blk_2r ) ; // 13 + 2N
txs_blk_5 . push_back ( txs_blk_3 . back ( ) ) ;
MAKE_TX_LIST ( events , txs_blk_4 , miner_account , recipient_account_2 , MK_TEST_COINS ( 2 ) , blk_2r ) ; // 14 + 2N
txs_blk_5 . push_back ( txs_blk_4 . back ( ) ) ;
MAKE_TX_LIST ( events , txs_blk_3 , miner_account , recipient_account_3 , MK_TEST_COINS ( 1 ) , blk_2r ) ; // 15 + 2N
txs_blk_6 . push_back ( txs_blk_3 . back ( ) ) ;
MAKE_TX_LIST ( events , txs_blk_4 , miner_account , recipient_account_3 , MK_TEST_COINS ( 2 ) , blk_2r ) ; // 16 + 2N
txs_blk_5 . push_back ( txs_blk_4 . back ( ) ) ;
MAKE_TX_LIST ( events , txs_blk_4 , miner_account , recipient_account_4 , MK_TEST_COINS ( 1 ) , blk_2r ) ; // 17 + 2N
txs_blk_5 . push_back ( txs_blk_4 . back ( ) ) ;
MAKE_TX_LIST ( events , txs_blk_3 , miner_account , recipient_account_4 , MK_TEST_COINS ( 2 ) , blk_2r ) ; // 18 + 2N
txs_blk_6 . push_back ( txs_blk_3 . back ( ) ) ;
MAKE_NEXT_BLOCK_TX_LIST ( events , blk_3 , blk_2r , miner_account , txs_blk_3 ) ; // 19 + 2N
MAKE_NEXT_BLOCK_TX_LIST ( events , blk_4 , blk_3 , miner_account , txs_blk_4 ) ; // 20 + 2N
//split
MAKE_NEXT_BLOCK_TX_LIST ( events , blk_5 , blk_2r , miner_account , txs_blk_5 ) ; // 22 + 2N
MAKE_NEXT_BLOCK_TX_LIST ( events , blk_6 , blk_5 , miner_account , txs_blk_6 ) ; // 23 + 2N
DO_CALLBACK ( events , " check_split_not_switched " ) ; // 21 + 2N
MAKE_NEXT_BLOCK ( events , blk_7 , blk_6 , miner_account ) ; // 24 + 2N
DO_CALLBACK ( events , " check_split_switched " ) ; // 25 + 2N
return true ;
}
//-----------------------------------------------------------------------------------------------------
bool gen_chain_switch_1 : : check_split_not_switched ( currency : : core & c , size_t ev_index , const std : : vector < test_event_entry > & events )
{
m_recipient_account_1 = boost : : get < account_base > ( events [ 1 ] ) ;
m_recipient_account_2 = boost : : get < account_base > ( events [ 2 ] ) ;
m_recipient_account_3 = boost : : get < account_base > ( events [ 3 ] ) ;
m_recipient_account_4 = boost : : get < account_base > ( events [ 4 ] ) ;
std : : list < block > blocks ;
bool r = c . get_blocks ( 0 , 10000 , blocks ) ;
CHECK_TEST_CONDITION ( r ) ;
CHECK_EQ ( 5 + 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW , blocks . size ( ) ) ;
CHECK_TEST_CONDITION ( blocks . back ( ) = = boost : : get < block > ( events [ 20 + 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW ] ) ) ; // blk_4
CHECK_EQ ( 2 , c . get_alternative_blocks_count ( ) ) ;
std : : vector < currency : : block > chain ;
map_hash2tx_t mtx ;
r = find_block_chain ( events , chain , mtx , get_block_hash ( blocks . back ( ) ) ) ;
CHECK_TEST_CONDITION ( r ) ;
CHECK_EQ ( MK_TEST_COINS ( 8 ) , get_balance ( m_recipient_account_1 , chain , mtx ) ) ;
CHECK_EQ ( MK_TEST_COINS ( 10 ) , get_balance ( m_recipient_account_2 , chain , mtx ) ) ;
CHECK_EQ ( MK_TEST_COINS ( 14 ) , get_balance ( m_recipient_account_3 , chain , mtx ) ) ;
CHECK_EQ ( MK_TEST_COINS ( 3 ) , get_balance ( m_recipient_account_4 , chain , mtx ) ) ;
crypto : : hash genesis_block_hash = currency : : get_block_hash ( boost : : get < currency : : block > ( events [ 0 ] ) ) ;
uint64_t mined_after_genesis = 0 ;
BOOST_FOREACH ( currency : : block b , blocks )
{
if ( currency : : get_block_hash ( b ) ! = genesis_block_hash )
mined_after_genesis + = get_outs_money_amount ( b . miner_tx ) ;
}
const size_t tx_main_chain_count = 11 ;
uint64_t amount = m_miner_initial_amount + mined_after_genesis - MK_TEST_COINS ( 35 ) - TESTS_DEFAULT_FEE * tx_main_chain_count ;
uint64_t balance = get_balance ( m_miner_account , chain , mtx ) ;
CHECK_TEST_CONDITION ( amount > balance ? amount - balance : balance - amount < = DEFAULT_DUST_THRESHOLD ) ;
std : : list < transaction > tx_pool ;
r = c . get_pool_transactions ( tx_pool ) ;
CHECK_TEST_CONDITION ( r ) ;
CHECK_EQ ( 1 , tx_pool . size ( ) ) ;
2022-07-06 13:22:05 +02:00
std : : vector < wallet_out_info > tx_outs ;
2018-12-27 18:50:45 +03:00
uint64_t transfered ;
crypto : : key_derivation derivation = AUTO_VAL_INIT ( derivation ) ;
lookup_acc_outs ( m_recipient_account_4 . get_keys ( ) , tx_pool . front ( ) , get_tx_pub_key_from_extra ( tx_pool . front ( ) ) , tx_outs , transfered , derivation ) ;
CHECK_EQ ( MK_TEST_COINS ( 13 ) , transfered ) ;
m_chain_1 . swap ( blocks ) ;
m_tx_pool . swap ( tx_pool ) ;
return true ;
}
//-----------------------------------------------------------------------------------------------------
bool gen_chain_switch_1 : : check_split_switched ( currency : : core & c , size_t ev_index , const std : : vector < test_event_entry > & events )
{
std : : list < block > blocks ;
bool r = c . get_blocks ( 0 , 10000 , blocks ) ;
CHECK_TEST_CONDITION ( r ) ;
CHECK_EQ ( 6 + 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW , blocks . size ( ) ) ;
auto it = blocks . end ( ) ;
- - it ; - - it ; - - it ;
CHECK_TEST_CONDITION ( std : : equal ( blocks . begin ( ) , it , m_chain_1 . begin ( ) ) ) ;
CHECK_TEST_CONDITION ( blocks . back ( ) = = boost : : get < block > ( events [ 24 + 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW ] ) ) ; // blk_7
std : : list < block > alt_blocks ;
r = c . get_alternative_blocks ( alt_blocks ) ;
CHECK_TEST_CONDITION ( r ) ;
CHECK_EQ ( 2 , c . get_alternative_blocks_count ( ) ) ;
// Some blocks that were in main chain are in alt chain now
BOOST_FOREACH ( block b , alt_blocks )
{
CHECK_TEST_CONDITION ( m_chain_1 . end ( ) ! = std : : find ( m_chain_1 . begin ( ) , m_chain_1 . end ( ) , b ) ) ;
}
std : : vector < currency : : block > chain ;
map_hash2tx_t mtx ;
r = find_block_chain ( events , chain , mtx , get_block_hash ( blocks . back ( ) ) ) ;
CHECK_TEST_CONDITION ( r ) ;
CHECK_EQ ( MK_TEST_COINS ( 8 ) , get_balance ( m_recipient_account_1 , chain , mtx ) ) ;
CHECK_EQ ( MK_TEST_COINS ( 3 ) , get_balance ( m_recipient_account_2 , chain , mtx ) ) ;
CHECK_EQ ( MK_TEST_COINS ( 14 ) , get_balance ( m_recipient_account_3 , chain , mtx ) ) ;
CHECK_EQ ( MK_TEST_COINS ( 16 ) , get_balance ( m_recipient_account_4 , chain , mtx ) ) ;
crypto : : hash genesis_block_hash = currency : : get_block_hash ( boost : : get < currency : : block > ( events [ 0 ] ) ) ;
uint64_t mined_after_genesis = 0 ;
BOOST_FOREACH ( currency : : block b , blocks )
{
if ( currency : : get_block_hash ( b ) ! = genesis_block_hash )
mined_after_genesis + = get_outs_money_amount ( b . miner_tx ) ;
}
const size_t tx_alt_chain_count = 11 ;
uint64_t amount = m_miner_initial_amount + mined_after_genesis - MK_TEST_COINS ( 41 ) - TESTS_DEFAULT_FEE * tx_alt_chain_count ;
uint64_t balance = get_balance ( m_miner_account , chain , mtx ) ;
CHECK_TEST_CONDITION ( amount > balance ? amount - balance : balance - amount < = DEFAULT_DUST_THRESHOLD ) ;
std : : list < transaction > tx_pool ;
r = c . get_pool_transactions ( tx_pool ) ;
CHECK_TEST_CONDITION ( r ) ;
CHECK_EQ ( 1 , tx_pool . size ( ) ) ;
CHECK_TEST_CONDITION ( ! ( tx_pool . front ( ) = = m_tx_pool . front ( ) ) ) ;
2022-07-06 13:22:05 +02:00
std : : vector < wallet_out_info > tx_outs ;
2018-12-27 18:50:45 +03:00
uint64_t transfered ;
crypto : : key_derivation derivation = AUTO_VAL_INIT ( derivation ) ;
lookup_acc_outs ( m_recipient_account_2 . get_keys ( ) , tx_pool . front ( ) , tx_outs , transfered , derivation ) ;
CHECK_EQ ( MK_TEST_COINS ( 7 ) , transfered ) ;
return true ;
}
//-----------------------------------------------------------------------------------------------------
bad_chain_switching_with_rollback : : bad_chain_switching_with_rollback ( )
{
REGISTER_CALLBACK_METHOD ( bad_chain_switching_with_rollback , c1 ) ;
}
bool bad_chain_switching_with_rollback : : generate ( std : : vector < test_event_entry > & events ) const
{
GENERATE_ACCOUNT ( preminer_acc ) ;
GENERATE_ACCOUNT ( miner_acc ) ;
GENERATE_ACCOUNT ( alice_acc ) ;
GENERATE_ACCOUNT ( bob_acc ) ;
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 + 4 ) ;
2019-04-25 23:37:43 +02:00
MAKE_TX ( events , tx_1 , miner_acc , alice_acc , TESTS_DEFAULT_FEE * 2 , blk_0r ) ;
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK_TX1 ( events , blk_1 , blk_0r , miner_acc , tx_1 ) ;
MAKE_NEXT_BLOCK ( events , blk_2 , blk_1 , miner_acc ) ;
// make tx_2 referring to tx_1 output
2019-04-25 23:37:43 +02:00
MAKE_TX ( events , tx_2 , alice_acc , bob_acc , TESTS_DEFAULT_FEE , blk_2 ) ;
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK_TX1 ( events , blk_3 , blk_2 , miner_acc , tx_2 ) ;
// check balance at gentime
// Alice should have nothing
std : : shared_ptr < tools : : wallet2 > alice_wlt ;
generator . init_test_wallet ( alice_acc , get_block_hash ( blk_0 ) , alice_wlt ) ;
bool r = generator . refresh_test_wallet ( events , alice_wlt . get ( ) , get_block_hash ( blk_3 ) , CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4 + 3 ) ;
CHECK_AND_ASSERT_MES ( r , false , " refresh_test_wallet failed " ) ;
CHECK_AND_ASSERT_MES ( check_balance_via_wallet ( * alice_wlt . get ( ) , " Alice " , 0 , 0 , 0 , 0 , 0 ) , false , " " ) ;
2019-04-25 23:37:43 +02:00
// Bob should have TESTS_DEFAULT_FEE
2018-12-27 18:50:45 +03:00
std : : shared_ptr < tools : : wallet2 > bob_wlt ;
generator . init_test_wallet ( bob_acc , get_block_hash ( blk_0 ) , bob_wlt ) ;
r = generator . refresh_test_wallet ( events , bob_wlt . get ( ) , get_block_hash ( blk_3 ) , CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4 + 3 ) ;
CHECK_AND_ASSERT_MES ( r , false , " refresh_test_wallet failed " ) ;
2019-04-25 23:37:43 +02:00
CHECK_AND_ASSERT_MES ( check_balance_via_wallet ( * bob_wlt . get ( ) , " Bob " , TESTS_DEFAULT_FEE , 0 , 0 , 0 , 0 ) , false , " " ) ;
2018-12-27 18:50:45 +03:00
// start altchain from blk_0r, include tx_2 but NOT include tx_1
DO_CALLBACK ( events , " mark_invalid_block " ) ;
MAKE_NEXT_BLOCK_TX1 ( events , blk_1a , blk_0r , miner_acc , tx_2 ) ;
DO_CALLBACK ( events , " mark_orphan_block " ) ;
MAKE_NEXT_BLOCK ( events , blk_2a , blk_1a , miner_acc ) ;
// 0 ... 14 15 16 17 18 19 <- height
// (0 )- (0r)- (1 )- (2 )- (3 )- <- main chain
// | tx_1 tx_2 <- txs (tx_2 uses output of tx_1)
// | | |
// | +--<--<--<--+
// |
// \- !1a!- !2a!- <- alt chain
// tx_2 <- txs (tx_2 uses output of tx_1)
// top block should be the 8last block in the main chain -- blk_3
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_3 ) , get_block_hash ( blk_3 ) ) ) ;
m_invalid_block_hash_to_check = get_block_hash ( blk_1a ) ;
DO_CALLBACK ( events , " c1 " ) ;
return true ;
}
bool bad_chain_switching_with_rollback : : c1 ( currency : : core & c , size_t ev_index , const std : : vector < test_event_entry > & events )
{
// altblocks now are marked as invalid only if rollback was unsuccessfull, so don't check it here
// invalid block can be checked by have_block() but can't be retreived by get_block_by_hash
//bool r = c.get_blockchain_storage().have_block(m_invalid_block_hash_to_check);
//CHECK_AND_ASSERT_MES(r, false, "have_block failed when called with id = " << m_invalid_block_hash_to_check);
block b = AUTO_VAL_INIT ( b ) ;
bool r = c . get_blockchain_storage ( ) . get_block_by_hash ( m_invalid_block_hash_to_check , b ) ;
CHECK_AND_ASSERT_MES ( ! r , false , " get_block_extended_info_by_hash suceeded, but expected to fail " ) ;
return true ;
}
//-----------------------------------------------------------------------------------------------------
struct tx_in_pool_info
{
crypto : : hash hash ;
size_t blobsize ;
} ;
struct params_tx_pool
{
params_tx_pool ( ) { }
2019-02-20 20:04:11 +01:00
params_tx_pool ( crypto : : hash hash , size_t blobsize ) : txs { tx_in_pool_info { hash , blobsize } }
{ }
params_tx_pool ( crypto : : hash hash1 , size_t blobsize1 , crypto : : hash hash2 , size_t blobsize2 )
{
txs . push_back ( tx_in_pool_info { hash1 , blobsize1 } ) ;
txs . push_back ( tx_in_pool_info { hash2 , blobsize2 } ) ;
}
2018-12-27 18:50:45 +03:00
std : : vector < tx_in_pool_info > txs ;
BEGIN_KV_SERIALIZE_MAP ( )
KV_SERIALIZE_CONTAINER_POD_AS_BLOB ( txs )
END_KV_SERIALIZE_MAP ( )
} ;
chain_switching_and_tx_with_attachment_blobsize : : chain_switching_and_tx_with_attachment_blobsize ( )
{
REGISTER_CALLBACK_METHOD ( chain_switching_and_tx_with_attachment_blobsize , check_tx_pool_txs ) ;
}
bool chain_switching_and_tx_with_attachment_blobsize : : 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 ) ;
tx_comment comment_att = AUTO_VAL_INIT ( comment_att ) ;
comment_att . comment = get_random_text ( CURRENCY_MAX_TRANSACTION_BLOB_SIZE * 9 / 10 ) ; // this is necessary to push cummulative block size out of full reward zone, so block reward will be non-default
std : : vector < attachment_v > attachment ( { comment_att } ) ;
// create txs with attachment (and put it in the pool)
2019-04-25 23:37:43 +02:00
MAKE_TX_ATTACH ( events , tx_1 , miner_acc , miner_acc , TESTS_DEFAULT_FEE , blk_0r , attachment ) ;
MAKE_TX_ATTACH ( events , tx_2 , miner_acc , miner_acc , TESTS_DEFAULT_FEE , blk_0r , attachment ) ;
2018-12-27 18:50:45 +03:00
// make sure the pool has correct txs
DO_CALLBACK_PARAMS_STR ( events , " check_tx_pool_txs " , epee : : serialization : : store_t_to_json ( params_tx_pool ( get_transaction_hash ( tx_1 ) , get_object_blobsize ( tx_1 ) , get_transaction_hash ( tx_2 ) , get_object_blobsize ( tx_2 ) ) ) ) ;
MAKE_NEXT_BLOCK ( events , blk_1 , blk_0r , miner_acc ) ;
MAKE_NEXT_BLOCK_TX_LIST ( events , blk_2 , blk_1 , miner_acc , std : : list < transaction > ( { tx_1 , tx_2 } ) ) ;
// make sure tx pool is empty now
DO_CALLBACK ( events , " check_tx_pool_empty " ) ;
// make altchain and grow it till reorganization happens
MAKE_NEXT_BLOCK ( events , blk_1a , blk_0r , miner_acc ) ;
MAKE_NEXT_BLOCK ( events , blk_2a , blk_1a , miner_acc ) ;
MAKE_NEXT_BLOCK ( events , blk_3a , blk_2a , miner_acc ) ;
// make sure chain switching happened indeed
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_3a ) , get_block_hash ( blk_3a ) ) ) ;
// txs must have been added back to tx_pool, make sure they are
DO_CALLBACK_PARAMS_STR ( events , " check_tx_pool_txs " , epee : : serialization : : store_t_to_json ( params_tx_pool ( get_transaction_hash ( tx_1 ) , get_object_blobsize ( tx_1 ) , get_transaction_hash ( tx_2 ) , get_object_blobsize ( tx_2 ) ) ) ) ;
// put a block with txs
// (this step triggered invalid block reward calculation a.k.a. "coinbase transaction doesn't use full amount of block reward"
// in past due to invalid tx blob size calculations)
MAKE_NEXT_BLOCK_TX_LIST ( events , blk_4a , blk_3a , miner_acc , std : : list < transaction > ( { tx_1 , tx_2 } ) ) ;
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_4a ) , get_block_hash ( blk_4a ) ) ) ;
// make sure tx pool is empty now
DO_CALLBACK ( events , " check_tx_pool_empty " ) ;
return true ;
}
bool chain_switching_and_tx_with_attachment_blobsize : : check_tx_pool_txs ( currency : : core & c , size_t ev_index , const std : : vector < test_event_entry > & events )
{
params_tx_pool p = AUTO_VAL_INIT ( p ) ;
bool r = epee : : serialization : : load_t_from_json ( p , boost : : get < callback_entry > ( events [ ev_index ] ) . callback_params ) ;
CHECK_AND_ASSERT_MES ( r , false , " Can't obtain event params. Forgot to pass them? " ) ;
CHECK_AND_ASSERT_MES ( c . get_pool_transactions_count ( ) = = p . txs . size ( ) , false , " Tx pool has " < < c . get_pool_transactions_count ( ) < < " transactions, expected: " < < p . txs . size ( ) ) ;
for ( auto & te : p . txs )
{
transaction tx = AUTO_VAL_INIT ( tx ) ;
bool r = c . get_transaction ( te . hash , tx ) ;
CHECK_AND_ASSERT_MES ( r , false , " get_transaction failed for " < < te . hash ) ;
crypto : : hash hash = get_transaction_hash ( tx ) ;
CHECK_AND_ASSERT_MES ( te . hash = = hash , false , " Tx in the pool has incorrect hash: " < < hash < < " , while expected is " < < te . hash ) ;
size_t blobsize = get_object_blobsize ( tx ) ;
CHECK_AND_ASSERT_MES ( te . blobsize = = blobsize , false , " Tx in the pool has incorrect blobsize == " < < blobsize < < " , while excepted value is " < < te . blobsize ) ;
}
return true ;
}
//-----------------------------------------------------------------------------------------------------
bool chain_switching_when_gindex_spent_in_both_chains : : generate ( std : : vector < test_event_entry > & events ) const
{
GENERATE_ACCOUNT ( miner_acc ) ;
GENERATE_ACCOUNT ( alice_acc ) ;
MAKE_GENESIS_BLOCK ( events , blk_0 , miner_acc , test_core_time : : get_time ( ) ) ;
2024-06-01 21:20:58 +02:00
DO_CALLBACK ( events , " configure_core " ) ; // necessary to set m_hardforks
if ( m_hardforks . is_hardfork_active_for_height ( ZANO_HARDFORK_04_ZARCANUM , 2 ) )
{
// HF4 requires tests_random_split_strategy (for 2 outputs minimum)
test_gentime_settings tgts = generator . get_test_gentime_settings ( ) ;
tgts . split_strategy = tests_random_split_strategy ;
generator . set_test_gentime_settings ( tgts ) ;
}
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK ( events , blk_1 , blk_0 , alice_acc ) ;
REWIND_BLOCKS_N ( events , blk_1r , blk_1 , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ;
uint64_t amount = get_outs_money_amount ( blk_1 . miner_tx ) - TESTS_DEFAULT_FEE ;
MAKE_NEXT_BLOCK ( events , blk_2 , blk_1r , miner_acc ) ;
MAKE_TX_FEE ( events , tx_1 , alice_acc , alice_acc , amount , TESTS_DEFAULT_FEE , blk_2 ) ;
MAKE_NEXT_BLOCK_TX1 ( events , blk_3 , blk_2 , miner_acc , tx_1 ) ;
// 0 1 11 12 13 14 < height
// (0 )- (1 )...(1r)- (2 )- (3 )- < main chain
// ^ \ tx_1 < txs
2020-08-20 17:05:03 +03:00
// | \
2018-12-27 18:50:45 +03:00
// | \-(2a)- (3a)- (4a)- < alt chain
// + tx_1 < txs
MAKE_NEXT_BLOCK ( events , blk_2a , blk_1r , miner_acc ) ;
MAKE_NEXT_BLOCK_TX1 ( events , blk_3a , blk_2a , miner_acc , tx_1 ) ;
MAKE_NEXT_BLOCK ( events , blk_4a , blk_3a , miner_acc ) ;
DO_CALLBACK ( events , " check_tx_pool_empty " ) ;
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_4a ) , get_block_hash ( blk_4a ) ) ) ;
CREATE_TEST_WALLET ( alice_wlt , alice_acc , blk_0 ) ;
REFRESH_TEST_WALLET_AT_GEN_TIME ( events , alice_wlt , blk_4a , CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4 ) ;
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME ( alice_wlt , amount ) ;
return true ;
}
//-----------------------------------------------------------------------------------------------------
bool alt_chain_coins_pow_mined_then_spent : : generate ( std : : vector < test_event_entry > & events ) const
{
// test idea: in alt chain mine and then spent some coins, then trigger chain switching
GENERATE_ACCOUNT ( miner_acc ) ;
GENERATE_ACCOUNT ( alice_acc ) ;
MAKE_GENESIS_BLOCK ( events , blk_0 , miner_acc , test_core_time : : get_time ( ) ) ;
MAKE_NEXT_BLOCK ( events , blk_1 , blk_0 , miner_acc ) ;
REWIND_BLOCKS_N ( events , blk_1r , blk_1 , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 ) ;
MAKE_NEXT_BLOCK ( events , blk_2a , blk_1 , alice_acc ) ;
REWIND_BLOCKS_N ( events , blk_2ra , blk_2a , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ;
// 0 1 2 12 13
// (0 )- (1 )- . . . (1r)-
2020-08-20 17:05:03 +03:00
// \
2018-12-27 18:50:45 +03:00
// \- (2a)...(2ra)- (3a)-
// |
// +-------------tx_1 tx_1 spents 2a.miner_tx output
events . push_back ( event_visitor_settings ( event_visitor_settings : : set_txs_kept_by_block , true ) ) ; // simulate alt-block tx behaviour
2019-04-25 23:37:43 +02:00
MAKE_TX ( events , tx_1 , alice_acc , alice_acc , TESTS_DEFAULT_FEE , blk_2ra ) ;
2018-12-27 18:50:45 +03:00
events . push_back ( event_visitor_settings ( event_visitor_settings : : set_txs_kept_by_block , false ) ) ;
MAKE_NEXT_BLOCK_TX1 ( events , blk_3a , blk_2ra , miner_acc , tx_1 ) ;
DO_CALLBACK ( events , " check_tx_pool_empty " ) ;
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_3a ) , get_block_hash ( blk_3a ) ) ) ;
return true ;
} ;
//-----------------------------------------------------------------------------------------------------
bool alt_blocks_validation_and_same_new_amount_in_two_txs : : generate ( std : : vector < test_event_entry > & events ) const
{
// test idea: make an alt block with two txs, containing the same, but never seen before output amount
// Should be processed ok with no problems
GENERATE_ACCOUNT ( miner_acc ) ;
GENERATE_ACCOUNT ( alice_acc ) ;
MAKE_GENESIS_BLOCK ( events , blk_0 , miner_acc , test_core_time : : get_time ( ) ) ;
2024-06-01 21:20:58 +02:00
DO_CALLBACK ( events , " configure_core " ) ; // necessary to set m_hardforks
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK ( events , blk_1 , blk_0 , miner_acc ) ;
REWIND_BLOCKS_N ( events , blk_1r , blk_1 , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 ) ;
// find out an amount that is never seen
uint64_t stub , new_amount = 0 ;
bool r = calculate_amounts_many_outs_have_and_no_outs_have ( get_outs_money_amount ( blk_1 . miner_tx ) , stub , new_amount ) ;
CHECK_AND_ASSERT_MES ( r , false , " calculate_amounts_many_outs_have_and_no_outs_have failed " ) ;
// main chain
MAKE_NEXT_BLOCK ( events , blk_2 , blk_1r , miner_acc ) ;
MAKE_NEXT_BLOCK ( events , blk_3 , blk_2 , miner_acc ) ;
// alt chain
MAKE_NEXT_BLOCK ( events , blk_2a , blk_1r , miner_acc ) ;
// make two txs with one output (huge fee, probably - doesn't matter) with amount that is never seen before
std : : vector < tx_source_entry > sources ;
2024-06-01 21:20:58 +02:00
r = fill_tx_sources ( sources , events , blk_1r , miner_acc . get_keys ( ) , new_amount + 2 * TESTS_DEFAULT_FEE , 0 ) ;
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES ( r , false , " fill_tx_sources failed " ) ;
std : : vector < tx_destination_entry > destinations ;
2024-06-01 21:20:58 +02:00
destinations . push_back ( tx_destination_entry ( new_amount , miner_acc . get_public_address ( ) ) ) ;
destinations . push_back ( tx_destination_entry ( TESTS_DEFAULT_FEE , miner_acc . get_public_address ( ) ) ) ; //just to make two outputs (to please HF4 rules)
2024-12-27 07:27:43 +01:00
transaction tx_1 { } ;
size_t tx_hardfork_id { } ;
uint64_t tx_version = get_tx_version_and_hardfork_id ( get_block_height ( blk_3 ) , m_hardforks , tx_hardfork_id ) ;
r = construct_tx ( miner_acc . get_keys ( ) , sources , destinations , empty_attachment , tx_1 , tx_version , tx_hardfork_id , 0 ) ;
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES ( r , false , " construct_tx failed " ) ;
2024-06-01 21:20:58 +02:00
ADD_CUSTOM_EVENT ( events , tx_1 ) ;
2018-12-27 18:50:45 +03:00
// second tx
sources . clear ( ) ;
2024-06-01 21:20:58 +02:00
r = fill_tx_sources ( sources , events , blk_1r , miner_acc . get_keys ( ) , new_amount + 2 * TESTS_DEFAULT_FEE , 0 , sources ) ;
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES ( r , false , " fill_tx_sources failed " ) ;
transaction tx_2 = AUTO_VAL_INIT ( tx_2 ) ;
// use the same destinations
2024-12-27 07:27:43 +01:00
tx_version = get_tx_version_and_hardfork_id ( get_block_height ( blk_3 ) , m_hardforks , tx_hardfork_id ) ;
r = construct_tx ( miner_acc . get_keys ( ) , sources , destinations , empty_attachment , tx_2 , tx_version , tx_hardfork_id , 0 ) ;
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES ( r , false , " construct_tx failed " ) ;
2024-06-01 21:20:58 +02:00
ADD_CUSTOM_EVENT ( events , tx_2 ) ;
2018-12-27 18:50:45 +03:00
// make an alt block with these txs
MAKE_NEXT_BLOCK_TX_LIST ( events , blk_3a , blk_2a , miner_acc , std : : list < transaction > ( { tx_1 , tx_2 } ) ) ;
// 0 1 11 12 13
// (0 )- (1 )-...(1r)- (2 )- (3 )-
2020-08-20 17:05:03 +03:00
// \
2018-12-27 18:50:45 +03:00
// \- (2a)- (3a)-
// tx_1
// tx_2
MAKE_NEXT_BLOCK ( events , blk_4a , blk_3a , miner_acc ) ; // this should switch the chains
DO_CALLBACK ( events , " check_tx_pool_empty " ) ;
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_4a ) , get_block_hash ( blk_4a ) ) ) ;
return true ;
}
//-----------------------------------------------------------------------------------------------------
alt_blocks_with_the_same_txs : : alt_blocks_with_the_same_txs ( )
{
REGISTER_CALLBACK_METHOD ( alt_blocks_with_the_same_txs , check_tx_related_to_altblock ) ;
REGISTER_CALLBACK_METHOD ( alt_blocks_with_the_same_txs , check_tx_not_related_to_altblock ) ;
}
bool alt_blocks_with_the_same_txs : : generate ( std : : vector < test_event_entry > & events ) const
{
2024-06-01 21:20:58 +02:00
// Test idea: check that two alt blocks having the same tx are correctly handled with respect to is_tx_related_to_altblock()
2018-12-27 18:50:45 +03:00
GENERATE_ACCOUNT ( miner_acc ) ;
MAKE_GENESIS_BLOCK ( events , blk_0 , miner_acc , test_core_time : : get_time ( ) ) ;
2024-06-01 21:20:58 +02:00
DO_CALLBACK ( events , " configure_core " ) ; // necessary to set m_hardforks
if ( m_hardforks . is_hardfork_active_for_height ( ZANO_HARDFORK_04_ZARCANUM , 2 ) )
{
// HF4 requires tests_random_split_strategy (for 2 outputs minimum)
test_gentime_settings tgts = generator . get_test_gentime_settings ( ) ;
tgts . split_strategy = tests_random_split_strategy ;
generator . set_test_gentime_settings ( tgts ) ;
}
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK ( events , blk_1 , blk_0 , miner_acc ) ;
REWIND_BLOCKS_N ( events , blk_1r , blk_1 , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 ) ;
// 0 1 11 12 13 14
// (0 )- (1 )-...(1r)- (2 )- (3 )-
// \ tx_0
2020-08-20 17:05:03 +03:00
// \
2018-12-27 18:50:45 +03:00
// \- (2a)- (3a)- (4 )-
// tx_0
2019-04-25 23:37:43 +02:00
MAKE_TX ( events , tx_0 , miner_acc , miner_acc , TESTS_DEFAULT_FEE , blk_1r ) ;
2018-12-27 18:50:45 +03:00
MAKE_NEXT_BLOCK_TX1 ( events , blk_2 , blk_1r , miner_acc , tx_0 ) ;
MAKE_NEXT_BLOCK ( events , blk_3 , blk_2 , miner_acc ) ;
crypto : : hash tx_0_hash = get_transaction_hash ( tx_0 ) ;
DO_CALLBACK_PARAMS ( events , " check_tx_not_related_to_altblock " , tx_0_hash ) ;
MAKE_NEXT_BLOCK_TX1 ( events , blk_2a , blk_1r , miner_acc , tx_0 ) ;
MAKE_NEXT_BLOCK ( events , blk_3a , blk_2a , miner_acc ) ;
DO_CALLBACK_PARAMS ( events , " check_tx_related_to_altblock " , tx_0_hash ) ;
// this should trigger reorganize
MAKE_NEXT_BLOCK ( events , blk_4a , blk_3a , miner_acc ) ;
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_4a ) , get_block_hash ( blk_4a ) ) ) ;
DO_CALLBACK_PARAMS ( events , " check_tx_related_to_altblock " , tx_0_hash ) ;
return true ;
}
bool alt_blocks_with_the_same_txs : : check_tx_related_to_altblock ( currency : : core & c , size_t ev_index , const std : : vector < test_event_entry > & events )
{
crypto : : hash tx_0_hash = null_hash ;
epee : : string_tools : : hex_to_pod ( boost : : get < callback_entry > ( events [ ev_index ] ) . callback_params , tx_0_hash ) ;
bool r = c . get_blockchain_storage ( ) . is_tx_related_to_altblock ( tx_0_hash ) ;
CHECK_AND_ASSERT_MES ( r , false , " tx " < < tx_0_hash < < " is expected to be related to an altblock, but BCS returned false " ) ;
return true ;
}
bool alt_blocks_with_the_same_txs : : check_tx_not_related_to_altblock ( currency : : core & c , size_t ev_index , const std : : vector < test_event_entry > & events )
{
crypto : : hash tx_0_hash = null_hash ;
epee : : string_tools : : hex_to_pod ( boost : : get < callback_entry > ( events [ ev_index ] ) . callback_params , tx_0_hash ) ;
bool r = ! c . get_blockchain_storage ( ) . is_tx_related_to_altblock ( tx_0_hash ) ;
CHECK_AND_ASSERT_MES ( r , false , " tx " < < tx_0_hash < < " is expected to NOT be related to an altblock, but BCS returned true " ) ;
return true ;
}
2021-01-07 18:21:52 +03:00
//-----------------------------------------------------------------------------------------------------
bool chain_switching_when_out_spent_in_alt_chain_mixin : : generate ( std : : vector < test_event_entry > & events ) const
{
2021-01-08 23:54:01 +03:00
// Test idea: make sure a tx can spend an output with mixins from another tx when both txs are in an altchain.
2021-01-07 18:21:52 +03:00
bool r = false ;
GENERATE_ACCOUNT ( miner_acc ) ;
GENERATE_ACCOUNT ( alice_acc ) ;
GENERATE_ACCOUNT ( bob_acc ) ;
MAKE_GENESIS_BLOCK ( events , blk_0 , miner_acc , test_core_time : : get_time ( ) ) ;
2024-06-01 21:20:58 +02:00
DO_CALLBACK ( events , " configure_core " ) ; // necessary to set m_hardforks
if ( m_hardforks . is_hardfork_active_for_height ( ZANO_HARDFORK_04_ZARCANUM , 2 ) )
{
// HF4 requires tests_random_split_strategy (for 2 outputs minimum)
test_gentime_settings tgts = generator . get_test_gentime_settings ( ) ;
tgts . split_strategy = tests_random_split_strategy ;
generator . set_test_gentime_settings ( tgts ) ;
}
2021-01-07 18:21:52 +03:00
MAKE_NEXT_BLOCK ( events , blk_1 , blk_0 , miner_acc ) ;
REWIND_BLOCKS_N ( events , blk_1r , blk_1 , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ;
2024-06-01 21:20:58 +02:00
// 0 1 11 12 22 23 24
// (0 )- (1 )-...(1r)- (2 )-...(2r)- (3 )- <-- main chain
2021-01-07 18:21:52 +03:00
// \
// \
2024-06-01 21:20:58 +02:00
// \- (2a)-...(2ar)- (3a)- (4a)-
// tx_0 <-------- tx_1 // tx_1 spends output from tx_0
2021-01-07 18:21:52 +03:00
2021-01-08 02:24:43 +03:00
// send batch of 10 x 5 test coins to Alice for easier tx_1 construction (and to generate free decoys)
2021-01-07 18:21:52 +03:00
transaction tx_0 ;
2022-05-11 23:52:33 +02:00
r = construct_tx_with_many_outputs ( m_hardforks , events , blk_1r , miner_acc . get_keys ( ) , alice_acc . get_public_address ( ) , MK_TEST_COINS ( 50 ) , 10 ,
2021-01-07 18:21:52 +03:00
TESTS_DEFAULT_FEE , tx_0 ) ;
CHECK_AND_ASSERT_MES ( r , false , " construct_tx_with_many_outputs failed " ) ;
events . push_back ( tx_0 ) ;
MAKE_NEXT_BLOCK ( events , blk_2 , blk_1r , miner_acc ) ;
2024-06-01 21:20:58 +02:00
REWIND_BLOCKS_N ( events , blk_2r , blk_2 , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ; // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
MAKE_NEXT_BLOCK ( events , blk_3 , blk_2r , miner_acc ) ;
// altchain
2021-01-07 18:21:52 +03:00
MAKE_NEXT_BLOCK_TX1 ( events , blk_2a , blk_1r , miner_acc , tx_0 ) ;
2024-06-01 21:20:58 +02:00
REWIND_BLOCKS_N ( events , blk_2ar , blk_2a , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ; // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
2021-01-07 18:21:52 +03:00
// make sure Alice received exactly 50 test coins
CREATE_TEST_WALLET ( alice_wlt , alice_acc , blk_0 ) ;
2024-06-01 21:20:58 +02:00
REFRESH_TEST_WALLET_AT_GEN_TIME ( events , alice_wlt , blk_2ar , 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2 ) ;
2021-01-07 18:21:52 +03:00
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME ( alice_wlt , MK_TEST_COINS ( 50 ) ) ;
2021-01-08 02:24:43 +03:00
// Alice spends her 5 test coins received by tx_0
2024-06-01 21:20:58 +02:00
MAKE_TX_FEE_MIX ( events , tx_1 , alice_acc , bob_acc , MK_TEST_COINS ( 4 ) , TESTS_DEFAULT_FEE , 3 /* nmix */ , blk_2ar ) ;
2021-01-07 18:21:52 +03:00
events . pop_back ( ) ; // pop back tx_1 as it won't go into the tx pool normally because of alt 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_1 ) ;
events . push_back ( event_visitor_settings ( event_visitor_settings : : set_txs_kept_by_block , false ) ) ;
2024-06-01 21:20:58 +02:00
MAKE_NEXT_BLOCK_TX1 ( events , blk_3a , blk_2ar , miner_acc , tx_1 ) ;
2021-01-07 18:21:52 +03:00
MAKE_NEXT_BLOCK ( events , blk_4a , blk_3a , miner_acc ) ;
// make sure Alice has correct balance
REFRESH_TEST_WALLET_AT_GEN_TIME ( events , alice_wlt , blk_4a , 2 ) ;
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME ( alice_wlt , MK_TEST_COINS ( 45 ) ) ;
2021-01-08 23:54:01 +03:00
// make sure chain successfully switched
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_4a ) , get_block_hash ( blk_4a ) ) ) ;
2021-01-07 18:21:52 +03:00
2021-01-08 02:24:43 +03:00
return true ;
}
//-----------------------------------------------------------------------------------------------------
bool chain_switching_when_out_spent_in_alt_chain_ref_id : : generate ( std : : vector < test_event_entry > & events ) const
{
2024-06-01 21:20:58 +02:00
//random_state_test_restorer::reset_random(0); // to make the test deterministic
2021-02-04 21:28:53 +01:00
uint64_t ts = 1450000000 ;
test_core_time : : adjust ( ts ) ;
2021-01-08 23:54:01 +03:00
// Test idea: make sure tx can spend (using ref_by_id) an output from another tx when both txs are in an altchain.
2021-01-08 02:24:43 +03:00
bool r = false ;
2021-02-04 21:28:53 +01:00
GENERATE_ACCOUNT ( miner_acc ) ;
2021-01-08 02:24:43 +03:00
GENERATE_ACCOUNT ( alice_acc ) ;
GENERATE_ACCOUNT ( bob_acc ) ;
2021-02-04 21:28:53 +01:00
miner_acc . set_createtime ( ts ) ;
alice_acc . set_createtime ( ts ) ;
bob_acc . set_createtime ( ts ) ;
2021-01-08 02:24:43 +03:00
MAKE_GENESIS_BLOCK ( events , blk_0 , miner_acc , test_core_time : : get_time ( ) ) ;
2024-06-01 21:20:58 +02:00
DO_CALLBACK ( events , " configure_core " ) ; // necessary to set m_hardforks
if ( m_hardforks . is_hardfork_active_for_height ( ZANO_HARDFORK_04_ZARCANUM , 2 ) )
{
// HF4 requires tests_random_split_strategy (for 2 outputs minimum)
test_gentime_settings tgts = generator . get_test_gentime_settings ( ) ;
tgts . split_strategy = tests_random_split_strategy ;
generator . set_test_gentime_settings ( tgts ) ;
}
2021-01-08 02:24:43 +03:00
MAKE_NEXT_BLOCK ( events , blk_1 , blk_0 , miner_acc ) ;
REWIND_BLOCKS_N ( events , blk_1r , blk_1 , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ;
2024-06-01 21:20:58 +02:00
// 0 1 11 12 22 23 24
// (0 )- (1 )-...(1r)- (2 )-...(2r)- (3 )- <-- main chain
2021-01-08 02:24:43 +03:00
// \
// \
2024-06-01 21:20:58 +02:00
// \- (2a)-...(2ar)- (3a)- (4a)-
// tx_0 <-------- tx_1 // tx_1 spends an output from tx_0 using ref_by_id and mixins
2021-01-08 02:24:43 +03:00
// send batch of 10 x 5 test coins to Alice for easier tx_0 construction
transaction tx_0 ;
2022-05-11 23:52:33 +02:00
r = construct_tx_with_many_outputs ( m_hardforks , events , blk_1r , miner_acc . get_keys ( ) , alice_acc . get_public_address ( ) , MK_TEST_COINS ( 50 ) , 10 ,
2021-01-08 23:54:01 +03:00
TESTS_DEFAULT_FEE , tx_0 , true ) ;
CHECK_AND_ASSERT_MES ( r , false , " construct_tx_with_many_outputs failed " ) ;
2021-01-08 02:24:43 +03:00
// make sure tx_0 really use ref_by_id
size_t refs_count = 0 , gindex_count = 0 ;
count_ref_by_id_and_gindex_refs_for_tx_inputs ( tx_0 , refs_count , gindex_count ) ;
CHECK_AND_ASSERT_MES ( refs_count = = 1 & & gindex_count = = 0 , false , " incorrect input references: " < < refs_count < < " , " < < gindex_count ) ;
2024-06-01 21:20:58 +02:00
ADD_CUSTOM_EVENT ( events , tx_0 ) ;
2021-01-08 02:24:43 +03:00
MAKE_NEXT_BLOCK ( events , blk_2 , blk_1r , miner_acc ) ;
2024-06-01 21:20:58 +02:00
REWIND_BLOCKS_N ( events , blk_2r , blk_2 , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ; // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
MAKE_NEXT_BLOCK ( events , blk_3 , blk_2r , miner_acc ) ;
// altchain
2021-01-08 02:24:43 +03:00
MAKE_NEXT_BLOCK_TX1 ( events , blk_2a , blk_1r , miner_acc , tx_0 ) ;
2024-06-01 21:20:58 +02:00
REWIND_BLOCKS_N ( events , blk_2ar , blk_2a , miner_acc , CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ; // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
2021-01-08 02:24:43 +03:00
// make sure Alice received exactly 50 test coins
CREATE_TEST_WALLET ( alice_wlt , alice_acc , blk_0 ) ;
2024-06-01 21:20:58 +02:00
REFRESH_TEST_WALLET_AT_GEN_TIME ( events , alice_wlt , blk_2ar , 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2 ) ;
2021-01-08 02:24:43 +03:00
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME ( alice_wlt , MK_TEST_COINS ( 50 ) ) ;
// Alice spends her 5 test coins received by tx_0
transaction tx_1 ;
2021-01-08 23:54:01 +03:00
std : : vector < tx_destination_entry > destinations ;
2024-06-01 21:20:58 +02:00
destinations . push_back ( tx_destination_entry ( MK_TEST_COINS ( 3 ) , bob_acc . get_public_address ( ) ) ) ;
destinations . push_back ( tx_destination_entry ( MK_TEST_COINS ( 1 ) , bob_acc . get_public_address ( ) ) ) ;
2021-01-08 23:54:01 +03:00
size_t nmix = 3 ;
2024-06-01 21:20:58 +02:00
r = construct_tx_to_key ( m_hardforks , events , tx_1 , blk_2ar , alice_acc , destinations , TESTS_DEFAULT_FEE , nmix , 0 , empty_extra , empty_attachment , true , true , true /* use_ref_by_id */ ) ;
2021-01-08 02:24:43 +03:00
CHECK_AND_ASSERT_MES ( r , false , " construct_tx_to_key failed " ) ;
2021-01-08 23:54:01 +03:00
// make sure tx_1 really use ref_by_id
refs_count = 0 , gindex_count = 0 ;
count_ref_by_id_and_gindex_refs_for_tx_inputs ( tx_1 , refs_count , gindex_count ) ;
CHECK_AND_ASSERT_MES ( refs_count = = nmix + 1 & & gindex_count = = 0 , false , " incorrect input references: " < < refs_count < < " , " < < gindex_count ) ;
2021-01-08 02:24:43 +03:00
// simulate handling a block with that tx: handle tx like going with the block...
2024-06-01 21:20:58 +02:00
ADD_CUSTOM_EVENT ( events , event_visitor_settings ( event_visitor_settings : : set_txs_kept_by_block , true ) ) ;
ADD_CUSTOM_EVENT ( events , tx_1 ) ;
ADD_CUSTOM_EVENT ( events , event_visitor_settings ( event_visitor_settings : : set_txs_kept_by_block , false ) ) ;
2021-01-08 02:24:43 +03:00
2024-06-01 21:20:58 +02:00
MAKE_NEXT_BLOCK_TX1 ( events , blk_3a , blk_2ar , miner_acc , tx_1 ) ;
2021-01-08 02:24:43 +03:00
MAKE_NEXT_BLOCK ( events , blk_4a , blk_3a , miner_acc ) ;
// make sure Alice has correct balance
REFRESH_TEST_WALLET_AT_GEN_TIME ( events , alice_wlt , blk_4a , 2 ) ;
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME ( alice_wlt , MK_TEST_COINS ( 45 ) ) ;
2024-06-01 21:20:58 +02:00
// make sure Bob has correct balance
CREATE_TEST_WALLET ( bob_wlt , bob_acc , blk_0 ) ;
REFRESH_TEST_WALLET_AT_GEN_TIME ( events , bob_wlt , blk_4a , 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4 ) ;
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME ( bob_wlt , MK_TEST_COINS ( 4 ) ) ;
2021-01-08 23:54:01 +03:00
// make sure chain successfully switched
DO_CALLBACK_PARAMS ( events , " check_top_block " , params_top_block ( get_block_height ( blk_4a ) , get_block_hash ( blk_4a ) ) ) ;
2021-01-08 02:24:43 +03:00
2021-01-07 18:21:52 +03:00
return true ;
}
2024-09-17 01:13:49 +05:00
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 ) - . . . - ( 0 r ) - ( 1 ) - . . . - ( 1 r ) - ( 2 )
| main | \
| | [ tx_0 ]
| |
| | main
\ - ( 1 a ) \ - ( 2 a )
\
[ tx_1 ]
Chain with head blk_1 versus chain with head blk_1a : chain with head blk_1
is the main , because blocks 1 , 1 a are empty .
Chain with head blk_2 versus chain with head blk_2a : chain with head blk_2a
is the main , because blocks 2 , 2 a 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 ) - . . . - ( 0 r )
|
\ - ( 1 a )
*/
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 " ) ;
2024-12-27 07:27:43 +01:00
size_t tx_hardfork_id { } ;
tx_version = get_tx_version_and_hardfork_id ( get_block_height ( blk_1r ) , m_hardforks , tx_hardfork_id ) ;
2024-09-17 01:13:49 +05:00
2024-12-27 07:27:43 +01:00
success = construct_tx ( miner . get_keys ( ) , sources , destinations , empty_attachment , tx_0 , tx_version , tx_hardfork_id , 0 ) ;
2024-09-17 01:13:49 +05:00
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.
2024-12-27 07:27:43 +01:00
tx_version = get_tx_version_and_hardfork_id ( get_block_height ( blk_1r ) , m_hardforks , tx_hardfork_id ) ;
2024-09-17 01:13:49 +05:00
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 " ) ;
2024-12-27 07:27:43 +01:00
success = construct_tx ( miner . get_keys ( ) , sources , destinations , empty_attachment , tx_1 , tx_version , tx_hardfork_id , 0 ) ;
2024-09-17 01:13:49 +05:00
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 ) - . . . - ( 1 r )
|
|
|
\ - ( 2 a )
\
[ 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 ;
}