1
0
Fork 0
forked from lthn/blockchain

chainge: pos_block_builder

This commit is contained in:
sowle 2022-11-08 00:07:53 +01:00
parent e1bec6cc2f
commit d67dbd986f
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC

View file

@ -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<const crypto::public_key*> 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<currency::NLSAG_sig>(m_block.miner_tx.signatures[0]).s[0]);
if (m_context.zarcanum)
{
// Zarcanum
zarcanum_sig& sig = boost::get<zarcanum_sig>(m_block.miner_tx.signatures[0]);
txin_zc_input& stake_input = boost::get<txin_zc_input>(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<crypto::CLSAG_GGXG_input_ref_t> 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<crypto::zarcanum_proof&>(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<NLSAG_sig>(m_block.miner_tx.signatures[0]);
txin_to_key& stake_input = boost::get<txin_to_key>(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<const crypto::public_key*> 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<zarcanum_sig>(m_block.miner_tx.signatures[0]);
txin_zc_input& stake_input = boost::get<txin_zc_input>(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<crypto::CLSAG_GGXG_input_ref_t> 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<crypto::zarcanum_proof&>(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<NLSAG_sig>(m_block.miner_tx.signatures[0]);
txin_to_key& stake_input = boost::get<txin_to_key>(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<const crypto::public_key*> 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<transaction> 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<size_t> 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