1
0
Fork 0
forked from lthn/blockchain

coretests: zarcanum_pos_block_math greatly improved to cover various zarcanum signature issues (now exposes a known bug)

This commit is contained in:
sowle 2022-11-17 22:20:33 +01:00
parent 35b3be92eb
commit 57acf4013d
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC

View file

@ -14,10 +14,51 @@
#define AMOUNT_TO_TRANSFER_ZARCANUM_BASIC (TESTS_DEFAULT_FEE*10)
using namespace currency;
//------------------------------------------------------------------------------
// helpers
void invalidate_CLSAG_GGXG_sig(crypto::CLSAG_GGXG_signature& sig)
{
sig.c = 7;
}
void invalidate_bppe_sig(crypto::bppe_signature& sig)
{
sig.delta_1.make_random();
}
void invalidate_pub_key(crypto::public_key& pk)
{
pk.data[5] = 0x33;
}
bool invalidate_zarcanum_sig(size_t n, zarcanum_sig& sig)
{
switch(n)
{
case 0: break;
case 1: invalidate_pub_key(sig.C); break;
case 2: sig.c.make_random(); break;
case 3: invalidate_CLSAG_GGXG_sig(sig.clsag_ggxg); break;
case 4: invalidate_pub_key(sig.C_prime); break;
case 5: sig.d.make_random(); break;
case 6: invalidate_pub_key(sig.E); break;
case 7: invalidate_bppe_sig(sig.E_range_proof); break;
case 8: invalidate_pub_key(sig.pseudo_out_amount_commitment); break;
case 9: sig.y0.make_random(); break;
case 10: sig.y1.make_random(); break;
case 11: sig.y2.make_random(); break;
case 12: sig.y3.make_random(); break;
case 13: sig.y4.make_random(); break;
default: return false;
}
return true;
}
//------------------------------------------------------------------------------
zarcanum_basic_test::zarcanum_basic_test()
{
@ -339,6 +380,48 @@ zarcanum_pos_block_math::zarcanum_pos_block_math()
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 0);
}
bool make_next_pos_block(test_generator& generator, std::vector<test_event_entry>& events, const block& prev_block, const account_base& stake_acc,
uint64_t amount_to_find, size_t nmix, block& result)
{
bool r = false;
std::vector<tx_source_entry> sources;
size_t height = get_block_height(prev_block) + 1;
crypto::hash prev_id = get_block_hash(prev_block);
r = fill_tx_sources(sources, events, prev_block, stake_acc.get_keys(), amount_to_find, nmix, true, true, false);
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
CHECK_AND_ASSERT_MES(shuffle_source_entries(sources), false, "");
auto it = std::max_element(sources.begin(), sources.end(), [&](const tx_source_entry& lhs, const tx_source_entry& rhs){ return lhs.amount < rhs.amount; });
const tx_source_entry& se = *it;
const tx_source_entry::output_entry& oe = se.outputs[se.real_output];
crypto::key_image stake_output_key_image {};
currency::keypair ephemeral_keys {};
r = generate_key_image_helper(stake_acc.get_keys(), se.real_out_tx_key, se.real_output_in_tx_index, ephemeral_keys, stake_output_key_image);
CHECK_AND_ASSERT_MES(r, false, "generate_key_image_helper failed");
uint64_t stake_output_gindex = boost::get<uint64_t>(oe.out_reference);
currency::wide_difficulty_type pos_diff{};
crypto::hash last_pow_block_hash{}, last_pos_block_kernel_hash{};
r = generator.get_params_for_next_pos_block(prev_id, pos_diff, last_pow_block_hash, last_pos_block_kernel_hash);
CHECK_AND_ASSERT_MES(r, false, "get_params_for_next_pos_block failed");
pos_block_builder pb;
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
pb.step2_set_txs(std::vector<transaction>());
pb.step3a(pos_diff, last_pow_block_hash, last_pos_block_kernel_hash);
pb.step3b(se.amount, stake_output_key_image, se.real_out_tx_key, se.real_output_in_tx_index, se.real_out_amount_blinding_mask, stake_acc.get_keys().view_secret_key,
stake_output_gindex, prev_block.timestamp, POS_SCAN_WINDOW, POS_SCAN_STEP);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), stake_acc.get_public_address());
pb.step5_sign(se, stake_acc.get_keys());
result = pb.m_block;
return true;
}
bool zarcanum_pos_block_math::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
@ -349,70 +432,37 @@ bool zarcanum_pos_block_math::generate(std::vector<test_event_entry>& events) co
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc);
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 10);
std::vector<tx_source_entry> sources;
block blk_1_pos;
// blocks with an invalid zarcanum sig
for(size_t i = 1; ; ++i)
{
const block& prev_block = blk_1r;
const account_base& stake_acc = miner_acc;
uint64_t amount_to_find = COIN;
size_t nmix = 10;
size_t height = get_block_height(prev_block) + 1;
crypto::hash prev_id = get_block_hash(prev_block);
r = fill_tx_sources(sources, events, prev_block, stake_acc.get_keys(), amount_to_find, nmix, true, true, false);
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
CHECK_AND_ASSERT_MES(shuffle_source_entries(sources), false, "");
auto it = std::max_element(sources.begin(), sources.end(), [&](const tx_source_entry& lhs, const tx_source_entry& rhs){ return lhs.amount < rhs.amount; });
const tx_source_entry& se = *it;
const tx_source_entry::output_entry& oe = se.outputs[se.real_output];
crypto::key_image stake_output_key_image {};
currency::keypair ephemeral_keys {};
r = generate_key_image_helper(stake_acc.get_keys(), se.real_out_tx_key, se.real_output_in_tx_index, ephemeral_keys, stake_output_key_image);
CHECK_AND_ASSERT_MES(r, false, "generate_key_image_helper failed");
uint64_t stake_output_gindex = boost::get<uint64_t>(oe.out_reference);
currency::wide_difficulty_type pos_diff{};
crypto::hash last_pow_block_hash{}, last_pos_block_kernel_hash{};
r = generator.get_params_for_next_pos_block(prev_id, pos_diff, last_pow_block_hash, last_pos_block_kernel_hash);
CHECK_AND_ASSERT_MES(r, false, "get_params_for_next_pos_block failed");
pos_block_builder pb;
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
pb.step2_set_txs(std::vector<transaction>());
pb.step3a(pos_diff, last_pow_block_hash, last_pos_block_kernel_hash);
pb.step3b(se.amount, stake_output_key_image, se.real_out_tx_key, se.real_output_in_tx_index, se.real_out_amount_blinding_mask, stake_acc.get_keys().view_secret_key,
stake_output_gindex, prev_block.timestamp, POS_SCAN_WINDOW, POS_SCAN_STEP);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), stake_acc.get_public_address());
pb.step5_sign(se, stake_acc.get_keys());
blk_1_pos = pb.m_block;
block blk_1_pos_bad;
CHECK_AND_ASSERT_MES(make_next_pos_block(generator, events, blk_1r, miner_acc, COIN, 10, blk_1_pos_bad), false, "");
LOG_PRINT_CYAN("i = " << i, LOG_LEVEL_0);
if (!invalidate_zarcanum_sig(i, boost::get<zarcanum_sig>(blk_1_pos_bad.miner_tx.signatures[0])))
break;
generator.add_block_info(blk_1_pos_bad, std::list<transaction>{});
DO_CALLBACK(events, "mark_invalid_block");
ADD_CUSTOM_EVENT(events, blk_1_pos_bad);
}
//CHECK_AND_ASSERT_MES(blk_1_pos.miner_tx.signatures.size() == 1, false, "unexpected signatures size");
//zarcanum_sig& sig = boost::get<zarcanum_sig>(blk_1_pos.miner_tx.signatures[0]);
//sig.y0 = 0; // invalidate sig
generator.add_block_info(blk_1_pos, std::list<transaction>{});
ADD_CUSTOM_EVENT(events, blk_1_pos);
// make a normal PoS block
std::list<currency::account_base> miner_stake_sources( {miner_acc} );
MAKE_NEXT_POS_BLOCK(events, blk_2, blk_1r, miner_acc, miner_stake_sources);
// ... and a PoW block
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
// make a PoS block and than change its nonce, so its hash also changes
// this block should fail
std::list<currency::account_base> miner_stake_sources( {miner_acc} );
MAKE_NEXT_POS_BLOCK(events, blk_2, blk_1_pos, miner_acc, miner_stake_sources);
generator.remove_block_info(blk_2);
MAKE_NEXT_POS_BLOCK(events, blk_4_bad, blk_3, miner_acc, miner_stake_sources);
generator.remove_block_info(blk_4_bad);
events.pop_back();
blk_2.nonce = 0xc0ffee; // this will change block's hash
generator.add_block_info(blk_2, std::list<transaction>{});
blk_4_bad.nonce = 0xc0ffee; // this will change block's hash
generator.add_block_info(blk_4_bad, std::list<transaction>{});
DO_CALLBACK(events, "mark_invalid_block");
ADD_CUSTOM_EVENT(events, blk_2);
ADD_CUSTOM_EVENT(events, blk_4_bad);
//MAKE_NEXT_POS_BLOCK(events, blk_3, blk_2, miner_acc, miner_stake_sources);
//MAKE_NEXT_POS_BLOCK(events, blk_4, blk_3, miner_acc, miner_stake_sources);
// finally, make a normal block
MAKE_NEXT_POS_BLOCK(events, blk_4, blk_3, miner_acc, miner_stake_sources);
return true;
}