32 #include <unordered_set>
53 void classify_addresses(
const std::vector<tx_destination_entry> &destinations,
const boost::optional<cryptonote::account_public_address>& change_addr,
size_t &num_stdaddresses,
size_t &num_subaddresses,
account_public_address &single_dest_subaddress)
57 std::unordered_set<cryptonote::account_public_address> unique_dst_addresses;
60 if (change_addr && dst_entr.addr == change_addr)
62 if (unique_dst_addresses.count(dst_entr.addr) == 0)
64 unique_dst_addresses.insert(dst_entr.addr);
65 if (dst_entr.is_subaddress)
68 single_dest_subaddress = dst_entr.addr;
76 LOG_PRINT_L2(
"destinations include " << num_stdaddresses <<
" standard addresses and " << num_subaddresses <<
" subaddresses");
79 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,
network_type nettype) {
88 if(!
get_block_reward(median_weight, current_block_weight, already_generated_coins, block_reward, hard_fork_version,
height, nettype))
94 #if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
95 LOG_PRINT_L1(
"Creating block template: reward " << block_reward <<
106 if (hard_fork_version >= 2 && hard_fork_version < 4) {
110 std::vector<uint64_t> out_amounts;
112 [&out_amounts](
uint64_t a_chunk) { out_amounts.push_back(a_chunk); },
113 [&out_amounts](
uint64_t a_dust) { out_amounts.push_back(a_dust); });
116 if (
height == 0 || hard_fork_version >= 4)
119 while (max_outs < out_amounts.size())
123 out_amounts[1] += out_amounts[0];
124 for (
size_t n = 1; n < out_amounts.size(); ++n)
125 out_amounts[n - 1] = out_amounts[n];
126 out_amounts.pop_back();
137 for (
const auto out_amount : out_amounts)
145 summary_amounts += out.amount = out_amount;
147 tx.
vout.push_back(out);
156 if(!extra_nonce.empty())
162 for (
size_t no = 0; no < out_amounts.size(); no++)
173 tk.
key = out_eph_public_key;
176 summary_amounts += out.amount = out_amounts[no];
178 tx.
vout.push_back(out);
185 CHECK_AND_ASSERT_MES(summary_amounts == block_reward,
false,
"Failed to construct miner tx, summary_amounts = " << summary_amounts <<
" not equal block_reward = " << block_reward);
189 tx.
vin.push_back(in);
202 for (
const auto &i : destinations)
206 if (change_addr && i.addr == *change_addr)
215 if (
count == 0 && change_addr)
216 return change_addr->m_view_public_key;
220 bool construct_tx_with_tx_key(
const account_keys& sender_account_keys,
const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations,
const boost::optional<cryptonote::account_public_address>& change_addr,
const std::vector<uint8_t> &extra,
transaction& tx,
uint64_t unlock_time,
const crypto::secret_key &tx_key,
const std::vector<crypto::secret_key> &additional_tx_keys,
bool rct,
const rct::RCTConfig &rct_config,
rct::multisig_out *msout,
bool shuffle_outs,
const uint32_t account_major_offset,
const cryptonote::network_type nettype)
230 std::vector<rct::key> amount_keys;
245 std::vector<tx_extra_field> tx_extra_fields;
248 bool add_dummy_payment_id =
true;
256 LOG_PRINT_L2(
"Adding cleartext payment ID to extra nonce. Encrypted PIDs are now deprecated." << payment_id8);
260 memcpy(payment_id.data, payment_id8.data, 8);
261 memset(payment_id.data + 8, 0, 24);
267 LOG_ERROR(
"Failed to add payment id to tx extra");
271 add_dummy_payment_id =
false;
275 add_dummy_payment_id =
false;
280 if (destinations.size() > 2)
281 add_dummy_payment_id =
false;
283 if (add_dummy_payment_id)
291 LOG_ERROR(
"Failed to add dummy payment id to tx extra");
298 MWARNING(
"Failed to parse tx extra");
299 tx_extra_fields.clear();
302 struct input_generation_context_data
306 std::vector<input_generation_context_data> in_contexts;
315 if (src_entr.real_output >= src_entr.outputs.size()) {
316 LOG_ERROR(
"real_output index (" << src_entr.real_output <<
")bigger than output_keys.size()="
317 << src_entr.outputs.size());
320 summary_inputs_etn += src_entr.amount;
323 in_contexts.push_back(input_generation_context_data());
325 keypair &in_ephemeral = in_contexts.back().in_ephemeral;
327 const auto &out_key =
reinterpret_cast<const crypto::public_key &
>(src_entr.outputs[src_entr.real_output].second.dest);
329 src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index,
330 in_ephemeral, img, hwdev, account_major_offset)) {
331 LOG_ERROR(
"Key image generation failed!");
336 if (!msout && !(in_ephemeral.
pub == src_entr.outputs[src_entr.real_output].second.dest)) {
337 LOG_ERROR(
"derived public key mismatch with output public key at index "
338 << idx <<
", real out "
339 << src_entr.real_output <<
"! "
340 <<
ENDL <<
"derived_key:"
343 <<
"real output_public_key:"
346 LOG_ERROR(
"amount " << src_entr.amount <<
", rct " << src_entr.rct);
347 LOG_ERROR(
"tx pubkey " << src_entr.real_out_tx_key <<
", real_output_in_tx_index "
348 << src_entr.real_output_in_tx_index);
354 input_to_key.
amount = src_entr.amount;
355 input_to_key.
k_image = msout ? rct::rct2ki(src_entr.multisig_kLRki.ki) : img;
359 input_to_key.
key_offsets.push_back(out_entry.first);
362 tx.
vin.push_back(input_to_key);
366 std::vector<size_t> ins_order(sources.size());
367 for (
size_t n = 0; n < sources.size(); ++n)
369 std::sort(ins_order.begin(), ins_order.end(), [&](
const size_t i0,
const size_t i1) {
370 const txin_to_key &tk0 = boost::get<txin_to_key>(tx.vin[i0]);
371 const txin_to_key &tk1 = boost::get<txin_to_key>(tx.vin[i1]);
372 return memcmp(&tk0.k_image, &tk1.k_image, sizeof(tk0.k_image)) > 0;
375 std::swap(tx.
vin[i0], tx.
vin[i1]);
376 std::swap(in_contexts[i0], in_contexts[i1]);
377 std::swap(sources[i0], sources[i1]);
382 std::shuffle(destinations.begin(), destinations.end(), std::default_random_engine(crypto::rand<unsigned int>()));
387 summary_inputs_etn += src_entr.amount;
390 input.
amount = src_entr.amount;
391 input.
tx_hash = src_entr.tx_hash;
394 tx.
vin.push_back(input);
399 size_t num_stdaddresses = 0;
400 size_t num_subaddresses = 0;
402 classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress);
406 if (num_stdaddresses == 0 && num_subaddresses == 1)
412 txkey_pub = rct::rct2pk(hwdev.
scalarmultBase(rct::sk2rct(tx_key)));
417 std::vector<crypto::public_key> additional_tx_public_keys;
422 bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1);
423 if (need_additional_txkeys)
424 CHECK_AND_ASSERT_MES(destinations.size() == additional_tx_keys.size(),
false,
"Wrong amount of additional tx keys");
435 need_additional_txkeys, additional_tx_keys,
436 additional_tx_public_keys, amount_keys, out_eph_public_key);
439 out.amount = dst_entr.amount;
441 tk.
key = out_eph_public_key;
443 tx.
vout.push_back(out);
445 summary_outs_etn += dst_entr.
amount;
448 out.amount = dst_entr.amount;
456 tx.
vout.push_back(out);
458 summary_outs_etn += dst_entr.
amount;
462 CHECK_AND_ASSERT_MES(additional_tx_public_keys.size() == additional_tx_keys.size(),
false,
"Internal error creating additional public keys");
467 if (need_additional_txkeys)
470 for (
size_t i = 0; i < additional_tx_public_keys.size(); ++i)
479 if(summary_outs_etn > summary_inputs_etn )
481 LOG_ERROR(
"Transaction inputs ETN ("<< summary_inputs_etn <<
") less than outputs ETN (" << summary_outs_etn <<
")");
486 bool zero_secret_key =
true;
491 MDEBUG(
"Null secret key, skipping signatures");
498 std::stringstream ss_ring_s;
505 ss_ring_s <<
"pub_keys:" <<
ENDL;
506 std::vector<const crypto::public_key *> keys_ptrs;
507 std::vector<crypto::public_key> keys(src_entr.outputs.size());
510 keys[ii] = rct2pk(o.second.dest);
511 keys_ptrs.push_back(&keys[ii]);
512 ss_ring_s << o.second.dest <<
ENDL;
516 tx.
signatures.push_back(std::vector<crypto::signature>());
517 std::vector<crypto::signature> &sigs = tx.
signatures.back();
518 sigs.resize(src_entr.outputs.size());
519 if (!zero_secret_key)
521 in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
522 ss_ring_s <<
"signatures:" <<
ENDL;
523 std::for_each(sigs.begin(), sigs.end(), [&](
const crypto::signature &s) { ss_ring_s << s << ENDL; });
524 ss_ring_s <<
"prefix_hash:" << tx_prefix_hash <<
ENDL <<
"in_ephemeral_key: "
525 << in_contexts[i].in_ephemeral.sec <<
ENDL <<
"real_output: " << src_entr.real_output <<
ENDL;
537 std::vector<crypto::signature> signature_vec;
538 if (!zero_secret_key) {
544 if (input_subaddress_index.
major == 0 && input_subaddress_index.
minor == 0) {
549 input_subaddress_index);
551 private_spend_for_sig);
557 private_view_for_sig,
558 private_spend_for_sig,
575 bool construct_tx_and_get_tx_key(
const account_keys& sender_account_keys,
const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations,
const boost::optional<cryptonote::account_public_address>& change_addr,
const std::vector<uint8_t> &extra,
transaction& tx,
uint64_t unlock_time,
crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys,
bool rct,
const rct::RCTConfig &rct_config,
rct::multisig_out *msout,
const uint32_t account_major_offset,
const cryptonote::network_type nettype)
581 size_t num_stdaddresses = 0;
582 size_t num_subaddresses = 0;
584 classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress);
585 bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1);
586 if (need_additional_txkeys)
588 additional_tx_keys.clear();
589 for (
const auto &d: destinations)
590 additional_tx_keys.push_back(keypair::generate(sender_account_keys.
get_device()).sec);
593 bool r =
construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys,
rct, rct_config, msout,
true, account_major_offset, nettype);
603 bool construct_tx(
const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources,
const std::vector<tx_destination_entry>& destinations,
const boost::optional<cryptonote::account_public_address>& change_addr,
const std::vector<uint8_t> &extra,
transaction& tx,
uint64_t unlock_time)
605 std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
608 std::vector<crypto::secret_key> additional_tx_keys;
609 std::vector<tx_destination_entry> destinations_copy = destinations;
610 return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys,
false, {
rct::RangeProofBorromean, 0}, NULL);
620 bl = boost::value_initialized<block>();
624 std::vector<size_t> sz;
640 miner::find_nonce_for_given_block(bl, 1, 0);
void set_null_besides_version()
std::vector< uint8_t > extra
std::vector< txin_v > vin
std::vector< tx_out > vout
std::vector< std::vector< crypto::signature > > signatures
virtual crypto::secret_key get_subaddress_private_viewkey(const crypto::secret_key &main_wallet_sec_view, crypto::secret_key &subaddress_sec_spend)=0
virtual bool generate_output_ephemeral_keys(const size_t tx_version, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key, const cryptonote::tx_destination_entry &dst_entr, const boost::optional< cryptonote::account_public_address > &change_addr, const size_t output_index, const bool &need_additional_txkeys, const std::vector< crypto::secret_key > &additional_tx_keys, std::vector< crypto::public_key > &additional_tx_public_keys, std::vector< rct::key > &amount_keys, crypto::public_key &out_eph_public_key)=0
virtual bool get_transaction_prefix_hash(const cryptonote::transaction_prefix &tx, crypto::hash &tx_prefix_hash)=0
virtual bool scalarmultBase(rct::key &aG, const rct::key &a)=0
virtual bool open_tx(crypto::secret_key &tx_key)=0
virtual bool generate_ring_signature(const crypto::hash &prefix_hash, const crypto::key_image &image, const std::vector< const crypto::public_key * > &pubs, const crypto::secret_key &sec, std::size_t sec_index, crypto::signature *sig)=0
virtual crypto::secret_key get_subaddress_private_spendkey(const cryptonote::account_keys &keys, const cryptonote::subaddress_index &subaddr_index)=0
virtual bool generate_input_signature(const crypto::hash &prefix_hash, const uint32_t input_index, const crypto::secret_key sec_view, const crypto::secret_key sec_spend, crypto::signature &signature)=0
virtual bool close_tx(void)=0
virtual bool scalarmultKey(rct::key &aP, const rct::key &P, const rct::key &a)=0
#define HF_VERSION_PUBLIC_TX
#define CURRENT_BLOCK_MINOR_VERSION
#define ETN_MINED_ETN_UNLOCK_WINDOW_V8
#define CURRENT_BLOCK_MAJOR_VERSION
#define CRYPTONOTE_MINED_ETN_UNLOCK_WINDOW
void * memcpy(void *a, const void *b, size_t c)
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
uint64_t const DEFAULT_DUST_THRESHOLD
uint64_t const BASE_REWARD_CLAMP_THRESHOLD
const crypto::public_key null_pkey
bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation)
bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key)
Holds cryptonote related classes and helpers.
std::string obj_to_json_str(T &obj)
bool construct_tx_and_get_tx_key(const account_keys &sender_account_keys, const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, std::vector< tx_source_entry > &sources, std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr, const std::vector< uint8_t > &extra, transaction &tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector< crypto::secret_key > &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, const uint32_t account_major_offset, const cryptonote::network_type nettype)
void classify_addresses(const std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr, size_t &num_stdaddresses, size_t &num_subaddresses, account_public_address &single_dest_subaddress)
bool generate_key_image_helper(const account_keys &ack, const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, const crypto::public_key &out_key, const crypto::public_key &tx_public_key, const std::vector< crypto::public_key > &additional_tx_public_keys, size_t real_output_index, keypair &in_ephemeral, crypto::key_image &ki, hw::device &hwdev, const uint32_t account_major_offset)
bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version, uint64_t current_block_height, network_type nettype)
bool sort_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< uint8_t > &sorted_tx_extra, bool allow_partial)
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash8 &payment_id)
void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, const chunk_handler_t &chunk_handler, const dust_handler_t &dust_handler)
bool get_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash &payment_id)
void set_payment_id_to_tx_extra_nonce(blobdata &extra_nonce, const crypto::hash &payment_id)
crypto::public_key get_destination_view_key_pub(const std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr)
std::vector< uint64_t > absolute_output_offsets_to_relative(const std::vector< uint64_t > &off)
const config_t & get_config(network_type nettype)
bool add_tx_pub_key_to_extra(transaction &tx, const crypto::public_key &tx_pub_key)
crypto::hash get_transaction_hash(const transaction &t)
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
bool construct_tx(const account_keys &sender_account_keys, std::vector< tx_source_entry > &sources, const std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr, const std::vector< uint8_t > &extra, transaction &tx, uint64_t unlock_time)
bool construct_tx_with_tx_key(const account_keys &sender_account_keys, const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, std::vector< tx_source_entry > &sources, std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr, const std::vector< uint8_t > &extra, transaction &tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector< crypto::secret_key > &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, bool shuffle_outs, const uint32_t account_major_offset, const cryptonote::network_type nettype)
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, network_type nettype)
blobdata tx_to_blob(const transaction &tx)
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
bool add_additional_tx_pub_keys_to_extra(std::vector< uint8_t > &tx_extra, const std::vector< crypto::public_key > &additional_pub_keys)
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
bool remove_field_from_tx_extra(std::vector< uint8_t > &tx_extra, const std::type_info &type)
bool generate_genesis_block(block &bl, std::string const &genesis_tx, uint32_t nonce)
bool add_extra_nonce_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &extra_nonce)
device & get_device(const std::string &device_descriptor)
mdb_size_t count(MDB_cursor *cur)
unsigned __int64 uint64_t
crypto::secret_key m_view_secret_key
hw::device & get_device() const
crypto::secret_key m_spend_secret_key
account_public_address m_account_address
crypto::public_key m_view_public_key
crypto::public_key m_spend_public_key
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX
std::pair< uint64_t, rct::ctkey > output_entry
crypto::key_image k_image
std::vector< uint64_t > key_offsets
uint64_t m_address_prefix
cryptonote::account_public_address address