|
|
@ -228,7 +228,7 @@ namespace cryptonote { |
|
|
|
info.has_payment_id = false; |
|
|
|
info.has_payment_id = false; |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << address_prefix |
|
|
|
LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << address_prefix |
|
|
|
<< " or " << integrated_address_prefix |
|
|
|
<< " or " << integrated_address_prefix |
|
|
|
<< " or " << subaddress_prefix); |
|
|
|
<< " or " << subaddress_prefix); |
|
|
|
return false; |
|
|
|
return false; |
|
|
@ -296,6 +296,7 @@ namespace cryptonote { |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#if 0 |
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
bool get_account_address_from_str_or_url( |
|
|
|
bool get_account_address_from_str_or_url( |
|
|
|
address_parse_info& info |
|
|
|
address_parse_info& info |
|
|
@ -311,6 +312,7 @@ namespace cryptonote { |
|
|
|
return !address_str.empty() && |
|
|
|
return !address_str.empty() && |
|
|
|
get_account_address_from_str(info, nettype, address_str); |
|
|
|
get_account_address_from_str(info, nettype, address_str); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) { |
|
|
|
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) { |
|
|
|
return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b); |
|
|
|
return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b); |
|
|
@ -319,6 +321,106 @@ namespace cryptonote { |
|
|
|
bool operator ==(const cryptonote::block& a, const cryptonote::block& b) { |
|
|
|
bool operator ==(const cryptonote::block& a, const cryptonote::block& b) { |
|
|
|
return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); |
|
|
|
return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
|
|
|
|
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { |
|
|
|
|
|
|
|
tx.vin.clear(); |
|
|
|
|
|
|
|
tx.vout.clear(); |
|
|
|
|
|
|
|
tx.extra.clear(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
keypair txkey = keypair::generate(hw::get_device("default")); |
|
|
|
|
|
|
|
add_tx_pub_key_to_extra(tx, txkey.pub); |
|
|
|
|
|
|
|
if(!extra_nonce.empty()) |
|
|
|
|
|
|
|
if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
txin_gen in; |
|
|
|
|
|
|
|
in.height = height; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t block_reward; |
|
|
|
|
|
|
|
if(!get_block_reward(median_weight, current_block_weight, already_generated_coins, block_reward, hard_fork_version)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LOG_PRINT_L0("Block is too big"); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) |
|
|
|
|
|
|
|
LOG_PRINT_L1("Creating block template: reward " << block_reward << |
|
|
|
|
|
|
|
", fee " << fee); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
block_reward += fee; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and
|
|
|
|
|
|
|
|
// keeps the paid amount almost the same. The unpaid remainder gets pushed back to the
|
|
|
|
|
|
|
|
// emission schedule
|
|
|
|
|
|
|
|
// from hard fork 4, we use a single "dusty" output. This makes the tx even smaller,
|
|
|
|
|
|
|
|
// and avoids the quantization. These outputs will be added as rct outputs with identity
|
|
|
|
|
|
|
|
// masks, to they can be used as rct inputs.
|
|
|
|
|
|
|
|
if (hard_fork_version >= 2 && hard_fork_version < 4) { |
|
|
|
|
|
|
|
block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<uint64_t> out_amounts; |
|
|
|
|
|
|
|
decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::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"); |
|
|
|
|
|
|
|
if (height == 0 || hard_fork_version >= 4) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// the genesis block was not decomposed, for unknown reasons
|
|
|
|
|
|
|
|
while (max_outs < out_amounts.size()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//out_amounts[out_amounts.size() - 2] += out_amounts.back();
|
|
|
|
|
|
|
|
//out_amounts.resize(out_amounts.size() - 1);
|
|
|
|
|
|
|
|
out_amounts[1] += out_amounts[0]; |
|
|
|
|
|
|
|
for (size_t n = 1; n < out_amounts.size(); ++n) |
|
|
|
|
|
|
|
out_amounts[n - 1] = out_amounts[n]; |
|
|
|
|
|
|
|
out_amounts.pop_back(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t summary_amounts = 0; |
|
|
|
|
|
|
|
for (size_t no = 0; no < out_amounts.size(); no++) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);; |
|
|
|
|
|
|
|
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); |
|
|
|
|
|
|
|
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation); |
|
|
|
|
|
|
|
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key); |
|
|
|
|
|
|
|
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
txout_to_key tk; |
|
|
|
|
|
|
|
tk.key = out_eph_public_key; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tx_out out; |
|
|
|
|
|
|
|
summary_amounts += out.amount = out_amounts[no]; |
|
|
|
|
|
|
|
out.target = tk; |
|
|
|
|
|
|
|
tx.vout.push_back(out); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (hard_fork_version >= 4) |
|
|
|
|
|
|
|
tx.version = 2; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
tx.version = 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//lock
|
|
|
|
|
|
|
|
tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; |
|
|
|
|
|
|
|
tx.vin.push_back(in); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tx.invalidate_hashes(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "(" << print_money(block_reward - fee) << "+" << print_money(fee)
|
|
|
|
|
|
|
|
// << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2);
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|