forked from lthn/blockchain
chainge: pos_block_builder
This commit is contained in:
parent
e1bec6cc2f
commit
d67dbd986f
1 changed files with 144 additions and 35 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue