From d67dbd986fe4fe26b12e5b0e2dc4b3c3684d1043 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 8 Nov 2022 00:07:53 +0100 Subject: [PATCH] chainge: pos_block_builder --- tests/core_tests/pos_block_builder.cpp | 179 ++++++++++++++++++++----- 1 file changed, 144 insertions(+), 35 deletions(-) diff --git a/tests/core_tests/pos_block_builder.cpp b/tests/core_tests/pos_block_builder.cpp index 167725c9..99769aae 100644 --- a/tests/core_tests/pos_block_builder.cpp +++ b/tests/core_tests/pos_block_builder.cpp @@ -146,9 +146,9 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, const account_public_address &reward_and_stake_receiver_address, const blobdata& extra_nonce, size_t max_outs, - keypair tx_one_time_key) + const keypair* tx_one_time_key_to_use) { - step4_generate_coinbase_tx(median_size, already_generated_coins, reward_and_stake_receiver_address, reward_and_stake_receiver_address, extra_nonce, max_outs, tx_one_time_key); + step4_generate_coinbase_tx(median_size, already_generated_coins, reward_and_stake_receiver_address, reward_and_stake_receiver_address, extra_nonce, max_outs, tx_one_time_key_to_use); } @@ -158,22 +158,27 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, const account_public_address &stakeholder_address, const blobdata& extra_nonce, size_t max_outs, - keypair tx_one_time_key) + const keypair* tx_one_time_key_to_use) { CHECK_AND_ASSERT_THROW_MES(m_step == 3, "pos_block_builder: incorrect step sequence"); + uint64_t tx_version = m_context.zarcanum ? TRANSACTION_VERSION_POST_HF4 : TRANSACTION_VERSION_PRE_HF4; + pos_entry pe{}; + pe.stake_unlock_time = 0; // TODO + pe.amount = m_context.stake_amount; + // generate miner tx using incorrect current_block_size only for size estimation size_t estimated_block_size = m_txs_total_size; - bool r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_context.stake_amount, m_context.sk.kimage, - m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key); - CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed"); + bool r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, + reward_receiver_address, stakeholder_address, m_block.miner_tx, tx_version, extra_nonce, max_outs, true, pe, &m_blinding_masks_sum, tx_one_time_key_to_use); + CHECK_AND_ASSERT_THROW_MES(r, "construct_miner_tx failed"); estimated_block_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx); size_t cumulative_size = 0; for (size_t try_count = 0; try_count != 10; ++try_count) { - r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_context.stake_amount, m_context.sk.kimage, - m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key); + r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, + reward_receiver_address, stakeholder_address, m_block.miner_tx, tx_version, extra_nonce, max_outs, true, pe, &m_blinding_masks_sum, tx_one_time_key_to_use); CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed"); cumulative_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx); @@ -194,27 +199,118 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, } -void pos_block_builder::step5_sign(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const crypto::public_key& stake_tx_out_pub_key, const currency::account_base& stakeholder_account) +void pos_block_builder::step5_sign(const currency::tx_source_entry& se, const currency::account_keys& stakeholder_keys) { + bool r = false; CHECK_AND_ASSERT_THROW_MES(m_step == 4, "pos_block_builder: incorrect step sequence"); - if (m_context.zarcanum) { LOG_PRINT_YELLOW("pos_block_builder::step5_sign() is called for seemingly zarcanum block", LOG_LEVEL_0); } - crypto::key_derivation pos_coin_derivation = AUTO_VAL_INIT(pos_coin_derivation); - bool r = crypto::generate_key_derivation(stake_tx_pub_key, stakeholder_account.get_keys().view_secret_key, pos_coin_derivation); // v * 8 * R + // calculate stake_out_derivation and secret_x (derived ephemeral secret key) + crypto::key_derivation stake_out_derivation = AUTO_VAL_INIT(stake_out_derivation); + r = crypto::generate_key_derivation(se.real_out_tx_key, stakeholder_keys.view_secret_key, stake_out_derivation); // d = 8 * v * R CHECK_AND_ASSERT_THROW_MES(r, "generate_key_derivation failed"); - crypto::secret_key secret_x = AUTO_VAL_INIT(secret_x); - crypto::derive_secret_key(pos_coin_derivation, stake_tx_out_index, stakeholder_account.get_keys().spend_secret_key, secret_x); // x = s + Hs(v * 8 * R, i) + crypto::derive_secret_key(stake_out_derivation, se.real_output_in_tx_index, stakeholder_keys.spend_secret_key, secret_x); // x = Hs(8 * v * R, i) + s - // sign block actually in coinbase transaction - crypto::hash block_hash = currency::get_block_hash(m_block); - std::vector keys_ptrs(1, &stake_tx_out_pub_key); - crypto::generate_ring_signature(block_hash, m_context.sk.kimage, keys_ptrs, secret_x, 0, &boost::get(m_block.miner_tx.signatures[0]).s[0]); + if (m_context.zarcanum) + { + // Zarcanum + zarcanum_sig& sig = boost::get(m_block.miner_tx.signatures[0]); + txin_zc_input& stake_input = boost::get(m_block.miner_tx.vin[1]); + + stake_input.k_image = m_context.sk.kimage; + + for(const auto& oe : se.outputs) + { + //oe. + } + + + stake_input.key_offsets.push_back(m_pos_stake_output_gindex); // TODO: support decoys + + crypto::hash tx_hash_for_sig = get_transaction_hash(m_block.miner_tx); // TODO @#@# change to block hash after the corresponding test is made + + std::vector ring; + uint64_t secret_index = 0; // index of the real stake output + + uint8_t err = 0; + r = crypto::zarcanum_generate_proof(tx_hash_for_sig, m_context.kernel_hash, ring, m_context.last_pow_block_id_hashed, m_context.sk.kimage, + secret_x, m_context.secret_q, secret_index, m_blinding_masks_sum, m_context.stake_amount, m_context.stake_out_blinding_mask, + static_cast(sig), &err); + CHECK_AND_ASSERT_THROW_MES(r, "zarcanum_generate_proof failed, err: " << (int)err); + } + else + { + // old PoS with non-hidden amounts + NLSAG_sig& sig = boost::get(m_block.miner_tx.signatures[0]); + txin_to_key& stake_input = boost::get(m_block.miner_tx.vin[1]); + + stake_input.k_image = m_context.sk.kimage; + stake_input.amount = m_context.stake_amount; + stake_input.key_offsets.push_back(m_pos_stake_output_gindex); + + crypto::hash block_hash = currency::get_block_hash(m_block); + std::vector keys_ptrs(1, &se.outputs.front().stealth_address); + sig.s.resize(1); + crypto::generate_ring_signature(block_hash, m_context.sk.kimage, keys_ptrs, secret_x, 0, sig.s.data()); + } m_step = 5; } +void pos_block_builder::step5_sign(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const crypto::public_key& stake_tx_out_pub_key, + const currency::account_base& stakeholder_account) +{ + bool r = false; + CHECK_AND_ASSERT_THROW_MES(m_step == 4, "pos_block_builder: incorrect step sequence"); + + // calculate stake_out_derivation and secret_x (derived ephemeral secret key) + crypto::key_derivation stake_out_derivation = AUTO_VAL_INIT(stake_out_derivation); + r = crypto::generate_key_derivation(stake_tx_pub_key, stakeholder_account.get_keys().view_secret_key, stake_out_derivation); // d = 8 * v * R + CHECK_AND_ASSERT_THROW_MES(r, "generate_key_derivation failed"); + crypto::secret_key secret_x = AUTO_VAL_INIT(secret_x); + crypto::derive_secret_key(stake_out_derivation, stake_tx_out_index, stakeholder_account.get_keys().spend_secret_key, secret_x); // x = Hs(8 * v * R, i) + s + + if (m_context.zarcanum) + { + // Zarcanum + zarcanum_sig& sig = boost::get(m_block.miner_tx.signatures[0]); + txin_zc_input& stake_input = boost::get(m_block.miner_tx.vin[1]); + + stake_input.k_image = m_context.sk.kimage; + stake_input.key_offsets.push_back(m_pos_stake_output_gindex); // TODO: support decoys + + crypto::hash tx_hash_for_sig = get_transaction_hash(m_block.miner_tx); // TODO @#@# change to block hash after the corresponding test is made + + std::vector ring; + uint64_t secret_index = 0; // index of the real stake output + + uint8_t err = 0; + r = crypto::zarcanum_generate_proof(tx_hash_for_sig, m_context.kernel_hash, ring, m_context.last_pow_block_id_hashed, m_context.sk.kimage, + secret_x, m_context.secret_q, secret_index, m_blinding_masks_sum, m_context.stake_amount, m_context.stake_out_blinding_mask, + static_cast(sig), &err); + CHECK_AND_ASSERT_THROW_MES(r, "zarcanum_generate_proof failed, err: " << (int)err); + } + else + { + // old PoS with non-hidden amounts + NLSAG_sig& sig = boost::get(m_block.miner_tx.signatures[0]); + txin_to_key& stake_input = boost::get(m_block.miner_tx.vin[1]); + + stake_input.k_image = m_context.sk.kimage; + stake_input.amount = m_context.stake_amount; + stake_input.key_offsets.push_back(m_pos_stake_output_gindex); + + crypto::hash block_hash = currency::get_block_hash(m_block); + std::vector keys_ptrs(1, &stake_tx_out_pub_key); + sig.s.resize(1); + crypto::generate_ring_signature(block_hash, m_context.sk.kimage, keys_ptrs, secret_x, 0, sig.s.data()); + } + + m_step = 5; +} + +/* void pos_block_builder::step5_sign_zarcanum(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const currency::account_base& stakeholder_account) { CHECK_AND_ASSERT_THROW_MES(m_step == 4, "pos_block_builder: incorrect step sequence"); @@ -243,10 +339,11 @@ void pos_block_builder::step5_sign_zarcanum(const crypto::public_key& stake_tx_p m_step = 5; } +*/ - -bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, +/* +bool construct_homemade_pos_miner_tx(bool zarcanum, size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t current_block_size, uint64_t fee, uint64_t pos_stake_amount, @@ -255,33 +352,45 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo const account_public_address &reward_receiving_address, const account_public_address &stakeholder_address, transaction& tx, - const blobdata& extra_nonce /*= blobdata()*/, - size_t max_outs /*= CURRENCY_MINER_TX_MAX_OUTS*/, - keypair tx_one_time_key /*= keypair::generate()*/) + const blobdata& extra_nonce, //= blobdata(), + size_t max_outs, //= CURRENCY_MINER_TX_MAX_OUTS, + keypair tx_one_time_key, //= keypair::generate()) { - boost::value_initialized new_tx; - tx = new_tx; + tx = transaction{}; - tx.version = TRANSACTION_VERSION_PRE_HF4; + tx.version = zarcanum ? TRANSACTION_VERSION_POST_HF4 : TRANSACTION_VERSION_PRE_HF4; set_tx_unlock_time(tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // calculate block reward uint64_t block_reward; bool r = get_block_reward(true, median_size, current_block_size, already_generated_coins, block_reward, height); - CHECK_AND_ASSERT_MES(r, false, "Block is too big"); + CHECK_AND_ASSERT_MES(r, false, "get_block_reward failed"); block_reward += fee; - // decompose reward into outputs and populate tx.vout + // + // prepare destinations + // + // 1. split block_reward into out_amounts std::vector out_amounts; - decompose_amount_into_digits(block_reward, DEFAULT_DUST_THRESHOLD, - [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, - [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); - CHECK_AND_ASSERT_MES(2 <= max_outs, false, "max_out must be greather than 1"); - while (out_amounts.size() + 1 > max_outs) + if (tx.version > TRANSACTION_VERSION_PRE_HF4) { - out_amounts[out_amounts.size() - 2] += out_amounts.back(); - out_amounts.resize(out_amounts.size() - 1); + // randomly split into CURRENCY_TX_MIN_ALLOWED_OUTS outputs + decompose_amount_randomly(block_reward, [&](uint64_t a){ out_amounts.push_back(a); }, CURRENCY_TX_MIN_ALLOWED_OUTS); + } + else + { + // non-hidden outs: split into digits + decompose_amount_into_digits(block_reward, DEFAULT_DUST_THRESHOLD, + [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, + [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); + + CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); + while (max_outs < out_amounts.size()) + { + out_amounts[out_amounts.size() - 2] += out_amounts.back(); + out_amounts.resize(out_amounts.size() - 1); + } } // reward