1
0
Fork 0
forked from lthn/blockchain

1) refactored block template creation and construct_miner_tx to incorporate block reward, essential for Zarcanum PoS; 2) fixed a bug in Zarcanum PoS generation; zarcanum_block_with_txs test now passes successfully

This commit is contained in:
sowle 2023-06-09 01:19:37 +02:00
parent 13e8d0dfe3
commit e80e4a60cc
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
13 changed files with 47 additions and 25 deletions

View file

@ -1323,7 +1323,7 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms
{
CHECK_AND_ASSERT_MES(b.miner_tx.attachment.empty(), false, "coinbase transaction has attachments; attachments are not allowed for coinbase transactions.");
CHECK_AND_ASSERT_MES(b.miner_tx.proofs.size() == 3, false, "coinbase transaction has incorrect number of proofs (" << b.miner_tx.proofs.size() << "), expected 2");
CHECK_AND_ASSERT_MES(b.miner_tx.proofs.size() == 3, false, "coinbase transaction has incorrect number of proofs (" << b.miner_tx.proofs.size() << "), expected 3");
CHECK_AND_ASSERT_MES(b.miner_tx.proofs[0].type() == typeid(zc_asset_surjection_proof), false, "coinbase transaction has incorrect type of proof #0 (expected: zc_asset_surjection_proof)");
CHECK_AND_ASSERT_MES(b.miner_tx.proofs[1].type() == typeid(zc_outs_range_proof), false, "coinbase transaction has incorrect type of proof #1 (expected: zc_outs_range_proof)");
CHECK_AND_ASSERT_MES(b.miner_tx.proofs[2].type() == typeid(zc_balance_proof), false, "coinbase transaction has incorrect type of proof #2 (expected: zc_balance_proof)");
@ -1518,6 +1518,8 @@ bool blockchain_storage::create_block_template(const create_block_template_param
if (!block_filled)
return false;
resp.txs_fee = fee;
/*
instead of complicated two-phase template construction and adjustment of cumulative size with block reward we
use CURRENCY_COINBASE_BLOB_RESERVED_SIZE as penalty-free coinbase transaction reservation.
@ -1528,6 +1530,7 @@ bool blockchain_storage::create_block_template(const create_block_template_param
miner_address,
stakeholder_address,
b.miner_tx,
resp.block_reward_without_fee,
get_tx_version(height, m_core_runtime_config.hard_forks),
ex_nonce,
CURRENCY_MINER_TX_MAX_OUTS,

View file

@ -147,6 +147,8 @@ namespace currency
wide_difficulty_type diffic;
uint64_t height;
tx_generation_context miner_tx_tgc; // bad design, a lot of copying, consider redesign -- sowle
uint64_t block_reward_without_fee;
uint64_t txs_fee; // sum of transactions' fee if any
};
typedef std::unordered_map<crypto::hash, transaction> transactions_map;

View file

@ -357,24 +357,24 @@ namespace currency
const account_public_address &miner_address,
const account_public_address &stakeholder_address,
transaction& tx,
uint64_t& block_reward_without_fee,
uint64_t tx_version,
const blobdata& extra_nonce /* = blobdata() */,
size_t max_outs /* = CURRENCY_MINER_TX_MAX_OUTS */,
bool pos /* = false */,
const pos_entry& pe /* = pos_entry() */, // only pe.stake_unlock_time and pe.stake_amount are used now, TODO: consider refactoring -- sowle
tx_generation_context* ogc_ptr /* = nullptr */,
tx_generation_context* ogc_ptr /* = nullptr */,
const keypair* tx_one_time_key_to_use /* = nullptr */
)
{
bool r = false;
uint64_t block_reward = 0;
if (!get_block_reward(pos, median_size, current_block_size, already_generated_coins, block_reward, height))
if (!get_block_reward(pos, median_size, current_block_size, already_generated_coins, block_reward_without_fee, height))
{
LOG_ERROR("Block is too big");
return false;
}
block_reward += fee;
uint64_t block_reward = block_reward_without_fee + fee;
//
// prepare destinations

View file

@ -255,7 +255,8 @@ namespace currency
uint64_t fee,
const account_public_address &miner_address,
const account_public_address &stakeholder_address,
transaction& tx,
transaction& tx,
uint64_t& block_reward_without_fee,
uint64_t tx_version,
const blobdata& extra_nonce = blobdata(),
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,

View file

@ -912,6 +912,8 @@ namespace currency
res.prev_hash = string_tools::pod_to_hex(resp.b.prev_id);
res.miner_tx_tgc = resp.miner_tx_tgc;
res.height = resp.height;
res.block_reward_without_fee = resp.block_reward_without_fee;
res.txs_fee = resp.txs_fee;
//calculate epoch seed
res.seed = currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(res.height));

View file

@ -861,6 +861,8 @@ namespace currency
blobdata blocktemplate_blob;
std::string prev_hash;
tx_generation_context miner_tx_tgc;
uint64_t block_reward_without_fee;
uint64_t txs_fee;
std::string status;
BEGIN_KV_SERIALIZE_MAP()
@ -870,6 +872,8 @@ namespace currency
KV_SERIALIZE(blocktemplate_blob)
KV_SERIALIZE(prev_hash)
KV_SERIALIZE(miner_tx_tgc)
KV_SERIALIZE(block_reward_without_fee)
KV_SERIALIZE(txs_fee)
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};

View file

@ -3898,7 +3898,7 @@ bool wallet2::is_in_hardfork_zone(uint64_t hardfork_index) const
return m_core_runtime_config.is_hardfork_active_for_height(hardfork_index, get_blockchain_current_size());
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::block& b, const pos_entry& pe, currency::tx_generation_context& miner_tx_tgc) const
bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t full_block_reward, const currency::pos_entry& pe, currency::tx_generation_context& miner_tx_tgc, currency::block& b) const
{
bool r = false;
WLT_CHECK_AND_ASSERT_MES(pe.wallet_index < m_transfers.size(), false, "invalid pe.wallet_index: " << pe.wallet_index);
@ -4082,9 +4082,8 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl
b.miner_tx.proofs.emplace_back(std::move(range_proofs));
// balance proof
uint64_t block_reward = COIN; // TODO @#@# move it somewhere -- sowle
currency::zc_balance_proof balance_proof{};
r = generate_tx_balance_proof(b.miner_tx, miner_tx_id, miner_tx_tgc, block_reward, balance_proof);
r = generate_tx_balance_proof(b.miner_tx, miner_tx_id, miner_tx_tgc, full_block_reward, balance_proof);
WLT_CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
b.miner_tx.proofs.emplace_back(std::move(balance_proof));
@ -4243,7 +4242,8 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco
set_block_datetime(current_timestamp, b);
WLT_LOG_MAGENTA("Applying actual timestamp: " << current_timestamp, LOG_LEVEL_0);
res = prepare_and_sign_pos_block(cxt, b, tmpl_req.pe, tmpl_rsp.miner_tx_tgc);
uint64_t full_block_reward = tmpl_rsp.block_reward_without_fee + tmpl_rsp.txs_fee;
res = prepare_and_sign_pos_block(cxt, full_block_reward, tmpl_req.pe, tmpl_rsp.miner_tx_tgc, b);
WLT_CHECK_AND_ASSERT_MES(res, false, "Failed to prepare_and_sign_pos_block");
crypto::hash block_hash = get_block_hash(b);

View file

@ -883,7 +883,7 @@ namespace tools
//next functions in public area only becausce of test_generator
//TODO: Need refactoring - remove it back to private zone
void set_genesis(const crypto::hash& genesis_hash);
bool prepare_and_sign_pos_block(const mining_context& cxt, currency::block& b, const currency::pos_entry& pe, currency::tx_generation_context& miner_tx_tgc) const;
bool prepare_and_sign_pos_block(const mining_context& cxt, uint64_t full_block_reward, const currency::pos_entry& pe, currency::tx_generation_context& miner_tx_tgc, currency::block& b) const;
void process_new_blockchain_entry(const currency::block& b,
const currency::block_direct_data_entry& bche,
const crypto::hash& bl_id,

View file

@ -299,6 +299,7 @@ bool test_generator::construct_block(currency::block& blk,
blk.miner_tx = AUTO_VAL_INIT(blk.miner_tx);
size_t target_block_size = txs_size + 0; // zero means no cost for ordinary coinbase
tx_generation_context miner_tx_tgc{};
uint64_t block_reward_without_fee = 0;
while (true)
{
r = construct_miner_tx(height, misc_utils::median(block_sizes),
@ -308,6 +309,7 @@ bool test_generator::construct_block(currency::block& blk,
miner_acc.get_keys().account_address,
miner_acc.get_keys().account_address,
blk.miner_tx,
block_reward_without_fee,
get_tx_version(height, m_hardforks),
blobdata(),
test_generator::get_test_gentime_settings().miner_tx_max_outs,
@ -354,7 +356,7 @@ bool test_generator::construct_block(currency::block& blk,
else
{
//need to build pos block
r = sign_block(wallets[won_walled_index].mining_context, pe, *wallets[won_walled_index].wallet, miner_tx_tgc, blk);
r = sign_block(wallets[won_walled_index].mining_context, pe, block_reward_without_fee + total_fee, *wallets[won_walled_index].wallet, miner_tx_tgc, blk);
CHECK_AND_ASSERT_MES(r, false, "Failed to find_kernel_and_sign()");
}
@ -373,11 +375,12 @@ bool test_generator::construct_block(currency::block& blk,
bool test_generator::sign_block(const tools::wallet2::mining_context& mining_context,
const pos_entry& pe,
uint64_t full_block_reward,
const tools::wallet2& w,
tx_generation_context& miner_tx_tgc,
currency::block& b)
{
bool r = w.prepare_and_sign_pos_block(mining_context, b, pe, miner_tx_tgc);
bool r = w.prepare_and_sign_pos_block(mining_context, full_block_reward, pe, miner_tx_tgc, b);
CHECK_AND_ASSERT_MES(r, false, "prepare_and_sign_pos_block failed");
return true;
}
@ -933,9 +936,10 @@ bool test_generator::construct_block(int64_t manual_timestamp_adjustment,
}
else
{
uint64_t base_block_reward = 0;
size_t current_block_size = txs_sizes + get_object_blobsize(blk.miner_tx);
// TODO: This will work, until size of constructed block is less then CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE
if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, miner_acc.get_public_address(), miner_acc.get_public_address(), blk.miner_tx, get_tx_version(height, m_hardforks), blobdata(), 1))
if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, miner_acc.get_public_address(), miner_acc.get_public_address(), blk.miner_tx, base_block_reward, get_tx_version(height, m_hardforks), blobdata(), 1))
return false;
}

View file

@ -488,6 +488,7 @@ public:
bool sign_block(const tools::wallet2::mining_context& mining_context,
const currency::pos_entry& pe,
uint64_t full_block_reward,
const tools::wallet2& w,
currency::tx_generation_context& miner_tx_tgc,
currency::block& b);
@ -951,7 +952,9 @@ bool test_generator::construct_block_gentime_with_coinbase_cb(const currency::bl
size_t height = get_block_height(prev_block) + 1;
//size_t current_block_size = get_object_blobsize(miner_tx);
r = construct_miner_tx(height, epee::misc_utils::median(block_sizes), already_generated_coins, 0 /* current_block_size !HACK! */, 0, acc.get_public_address(), acc.get_public_address(), miner_tx, get_tx_version(height, m_hardforks), currency::blobdata(), 1);
uint64_t block_reward_without_fee = 0;
r = construct_miner_tx(height, epee::misc_utils::median(block_sizes), already_generated_coins, 0 /* current_block_size !HACK! */, 0, acc.get_public_address(), acc.get_public_address(), miner_tx, block_reward_without_fee, get_tx_version(height, m_hardforks), currency::blobdata(), 1);
CHECK_AND_ASSERT_MES(r, false, "construct_miner_tx failed");
if (!cb(miner_tx))

View file

@ -166,9 +166,10 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
pe.amount = m_context.stake_amount;
// generate miner tx using incorrect current_block_size only for size estimation
uint64_t block_reward_without_fee = 0;
size_t estimated_block_size = m_txs_total_size;
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_miner_tx_tgc, tx_one_time_key_to_use);
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, 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);
@ -176,7 +177,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
for (size_t try_count = 0; try_count != 10; ++try_count)
{
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_miner_tx_tgc, tx_one_time_key_to_use);
reward_receiver_address, stakeholder_address, m_block.miner_tx, estimated_block_size, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, 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);

View file

@ -34,23 +34,24 @@ bool test_transaction_generation_and_ring_signature()
std::string add_str = miner_acc3.get_public_address_str();
uint64_t block_reward_without_fee = 0;
account_base rv_acc;
rv_acc.generate();
account_base rv_acc2;
rv_acc2.generate();
transaction tx_mine_1;
construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().account_address, miner_acc1.get_keys().account_address, tx_mine_1, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().account_address, miner_acc1.get_keys().account_address, tx_mine_1, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_2;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc2.get_keys().account_address, miner_acc2.get_keys().account_address, tx_mine_2, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc2.get_keys().account_address, miner_acc2.get_keys().account_address, tx_mine_2, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_3;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc3.get_keys().account_address, miner_acc3.get_keys().account_address, tx_mine_3, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc3.get_keys().account_address, miner_acc3.get_keys().account_address, tx_mine_3, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_4;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc4.get_keys().account_address, miner_acc4.get_keys().account_address, tx_mine_4, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc4.get_keys().account_address, miner_acc4.get_keys().account_address, tx_mine_4, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_5;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc5.get_keys().account_address, miner_acc5.get_keys().account_address, tx_mine_5, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc5.get_keys().account_address, miner_acc5.get_keys().account_address, tx_mine_5, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_6;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc6.get_keys().account_address, miner_acc6.get_keys().account_address, tx_mine_6, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc6.get_keys().account_address, miner_acc6.get_keys().account_address, tx_mine_6, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
//fill inputs entry
typedef tx_source_entry::output_entry tx_output_entry;
@ -134,8 +135,9 @@ bool test_block_creation()
account_public_address adr;
bool r = get_account_address_from_str(adr, "ZxDLGBGXbjo5w51tJkvxEPHFRr7Xft4hf33N8EkJPndoGCqocQF1mzpZqYwXByx5gMbfQuPAAB9vj79EFR6Jwkgu1o3aMQPwJ");
CHECK_AND_ASSERT_MES(r, false, "failed to import");
uint64_t block_reward_without_fee = 0;
block b;
r = construct_miner_tx(90, epee::misc_utils::median(szs), 3553616528562147, 33094, 10000000, adr, adr, b.miner_tx, TRANSACTION_VERSION_PRE_HF4);
r = construct_miner_tx(90, epee::misc_utils::median(szs), 3553616528562147, 33094, 10000000, adr, adr, b.miner_tx, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
return r;
}

View file

@ -807,7 +807,7 @@ bool zarcanum_block_with_txs::generate(std::vector<test_event_entry>& events) co
// make sure Alice received both block reward and the fee
uint64_t mined_amount_2 = COIN + fee;
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, m_alice_balance + mined_amount_2, 0, mined_amount + mined_amount_2, 0, 0));
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, m_alice_balance + mined_amount_2, UINT64_MAX, mined_amount + mined_amount_2, 0, 0));
m_alice_balance += mined_amount_2;