Electroneum
cryptonote_tx_utils.cpp
Go to the documentation of this file.
1 // Copyrights(c) 2017-2021, The Electroneum Project
2 // Copyrights(c) 2014-2019, The Monero Project
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without modification, are
7 // permitted provided that the following conditions are met:
8 //
9 // 1. Redistributions of source code must retain the above copyright notice, this list of
10 // conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 // of conditions and the following disclaimer in the documentation and/or other
14 // materials provided with the distribution.
15 //
16 // 3. Neither the name of the copyright holder nor the names of its contributors may be
17 // used to endorse or promote products derived from this software without specific
18 // prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31 
32 #include <unordered_set>
33 #include <random>
34 #include "include_base_utils.h"
35 #include "string_tools.h"
36 using namespace epee;
37 
39 #include "cryptonote_tx_utils.h"
40 #include "cryptonote_config.h"
41 #include "cryptonote_basic/miner.h"
43 #include "crypto/crypto.h"
44 #include "crypto/hash.h"
45 #include "ringct/rctSigs.h"
46 #include "multisig/multisig.h"
47 
48 using namespace crypto;
49 
50 namespace cryptonote
51 {
52  //---------------------------------------------------------------
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)
54  {
55  num_stdaddresses = 0;
56  num_subaddresses = 0;
57  std::unordered_set<cryptonote::account_public_address> unique_dst_addresses;
58  for(const tx_destination_entry& dst_entr: destinations)
59  {
60  if (change_addr && dst_entr.addr == change_addr)
61  continue;
62  if (unique_dst_addresses.count(dst_entr.addr) == 0)
63  {
64  unique_dst_addresses.insert(dst_entr.addr);
65  if (dst_entr.is_subaddress)
66  {
67  ++num_subaddresses;
68  single_dest_subaddress = dst_entr.addr;
69  }
70  else
71  {
72  ++num_stdaddresses;
73  }
74  }
75  }
76  LOG_PRINT_L2("destinations include " << num_stdaddresses << " standard addresses and " << num_subaddresses << " subaddresses");
77  }
78  //---------------------------------------------------------------
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) {
80  tx.vin.clear();
81  tx.vout.clear();
82  tx.extra.clear();
83 
84  txin_gen in;
85  in.height = height;
86 
87  uint64_t block_reward;
88  if(!get_block_reward(median_weight, current_block_weight, already_generated_coins, block_reward, hard_fork_version, height, nettype))
89  {
90  LOG_PRINT_L0("Block is too big");
91  return false;
92  }
93 
94 #if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
95  LOG_PRINT_L1("Creating block template: reward " << block_reward <<
96  ", fee " << fee);
97 #endif
98  block_reward += fee;
99 
100  // from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and
101  // keeps the paid amount almost the same. The unpaid remainder gets pushed back to the
102  // emission schedule
103  // from hard fork 4, we use a single "dusty" output. This makes the tx even smaller,
104  // and avoids the quantization. These outputs will be added as rct outputs with identity
105  // masks, to they can be used as rct inputs.
106  if (hard_fork_version >= 2 && hard_fork_version < 4) {
107  block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD;
108  }
109 
110  std::vector<uint64_t> out_amounts;
111  decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::DEFAULT_DUST_THRESHOLD,
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); });
114 
115  CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
116  if (height == 0 || hard_fork_version >= 4)
117  {
118  // the genesis block was not decomposed, for unknown reasons
119  while (max_outs < out_amounts.size())
120  {
121  //out_amounts[out_amounts.size() - 2] += out_amounts.back();
122  //out_amounts.resize(out_amounts.size() - 1);
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();
127  }
128  }
129  else
130  {
131  CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded");
132  }
133 
134  uint64_t summary_amounts = 0;
135  if (hard_fork_version >= HF_VERSION_PUBLIC_TX)
136  {
137  for (const auto out_amount : out_amounts)
138  {
140  tk.address.m_view_public_key = miner_address.m_view_public_key;
141  tk.address.m_spend_public_key = miner_address.m_spend_public_key;
143 
144  tx_out out;
145  summary_amounts += out.amount = out_amount;
146  out.target = tk;
147  tx.vout.push_back(out);
148  }
149 
150  tx.version = 3;
151  }
152  else
153  {
154  keypair txkey = keypair::generate(hw::get_device("default"));
155  add_tx_pub_key_to_extra(tx, txkey.pub);
156  if(!extra_nonce.empty())
157  if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
158  return false;
159  if (!sort_tx_extra(tx.extra, tx.extra))
160  return false;
161 
162  for (size_t no = 0; no < out_amounts.size(); no++)
163  {
164  crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);;
165  crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
166  bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
167  CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
168 
169  r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key);
170  CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")");
171 
172  txout_to_key tk;
173  tk.key = out_eph_public_key;
174 
175  tx_out out;
176  summary_amounts += out.amount = out_amounts[no];
177  out.target = tk;
178  tx.vout.push_back(out);
179  }
180 
181  tx.version = 1;
182  }
183 
184 
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);
186 
187  //lock
189  tx.vin.push_back(in);
190 
191  tx.invalidate_hashes();
192 
193  //LOG_PRINT("MINER_TX generated ok, block_reward=" << print_etn(block_reward) << "(" << print_etn(block_reward - fee) << "+" << print_etn(fee)
194  // << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2);
195  return true;
196  }
197  //---------------------------------------------------------------
198  crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr)
199  {
201  size_t count = 0;
202  for (const auto &i : destinations)
203  {
204  if (i.amount == 0)
205  continue;
206  if (change_addr && i.addr == *change_addr)
207  continue;
208  if (i.addr == addr)
209  continue;
210  if (count > 0)
211  return null_pkey;
212  addr = i.addr;
213  ++count;
214  }
215  if (count == 0 && change_addr)
216  return change_addr->m_view_public_key;
217  return addr.m_view_public_key;
218  }
219  //---------------------------------------------------------------
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)
221  {
222  hw::device &hwdev = sender_account_keys.get_device();
223 
224  if (sources.empty())
225  {
226  LOG_ERROR("Empty sources");
227  return false;
228  }
229 
230  std::vector<rct::key> amount_keys;
231  //test tx is sent through this scope TWICE, once as a test and once for real... therefore we set null before each run.
233  amount_keys.clear();
234  if (msout)
235  {
236  msout->c.clear();
237  }
238 
239  tx.unlock_time = unlock_time;
240 
241  tx.extra = extra;
242  crypto::public_key txkey_pub;
243 
244  // if we have a stealth payment id, find it and encrypt it with the tx key now
245  std::vector<tx_extra_field> tx_extra_fields;
246  if (parse_tx_extra(tx.extra, tx_extra_fields))
247  {
248  bool add_dummy_payment_id = true;
249  tx_extra_nonce extra_nonce;
250  if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
251  {
252  crypto::hash payment_id = null_hash;
253  crypto::hash8 payment_id8 = null_hash8;
254  if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
255  {
256  LOG_PRINT_L2("Adding cleartext payment ID to extra nonce. Encrypted PIDs are now deprecated." << payment_id8);
257 
258  std::string extra_nonce;
259 
260  memcpy(payment_id.data, payment_id8.data, 8); // convert short pid to regular
261  memset(payment_id.data + 8, 0, 24); // merely a sanity check
262 
263  set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
265  if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
266  {
267  LOG_ERROR("Failed to add payment id to tx extra");
268  return false;
269  }
270  LOG_PRINT_L1("Encrypted payment ID: " << payment_id8);
271  add_dummy_payment_id = false;
272  }
273  else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
274  {
275  add_dummy_payment_id = false;
276  }
277  }
278 
279  // we don't add one if we've got more than the usual 1 destination plus change
280  if (destinations.size() > 2)
281  add_dummy_payment_id = false;
282 
283  if (add_dummy_payment_id)
284  {
285  std::string extra_nonce;
286  crypto::hash payment_id = null_hash;
287 
288  set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
289  if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
290  {
291  LOG_ERROR("Failed to add dummy payment id to tx extra");
292  // continue anyway
293  }
294  }
295  }
296  else
297  {
298  MWARNING("Failed to parse tx extra");
299  tx_extra_fields.clear();
300  }
301 
302  struct input_generation_context_data
303  {
304  keypair in_ephemeral;
305  };
306  std::vector<input_generation_context_data> in_contexts;
307 
308  uint64_t summary_inputs_etn = 0;
309  //fill inputs
310  int idx = -1;
311 
312  if(tx.version < 3) {
313  for (const tx_source_entry &src_entr : sources) {
314  ++idx;
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());
318  return false;
319  }
320  summary_inputs_etn += src_entr.amount;
321 
322  //key_derivation recv_derivation;
323  in_contexts.push_back(input_generation_context_data());
324  // Tx output private key which gets its value assigned inside generate_key_image_helper
325  keypair &in_ephemeral = in_contexts.back().in_ephemeral;
326  crypto::key_image img;//
327  const auto &out_key = reinterpret_cast<const crypto::public_key &>(src_entr.outputs[src_entr.real_output].second.dest);
328  if (!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key,
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!");
332  return false;
333  }
334 
335  //check that derivated key is equal with real output key (if non multisig)
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:"
341  << string_tools::pod_to_hex(in_ephemeral.pub)
342  << ENDL
343  << "real output_public_key:"
344  << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second.dest));
345 
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);
349  return false;
350  }
351 
352  //put key image into tx input
353  txin_to_key input_to_key;
354  input_to_key.amount = src_entr.amount;
355  input_to_key.k_image = msout ? rct::rct2ki(src_entr.multisig_kLRki.ki) : img;
356 
357  //fill outputs array and use relative offsets
358  for (const tx_source_entry::output_entry &out_entry: src_entr.outputs)
359  input_to_key.key_offsets.push_back(out_entry.first);
360 
361  input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets);
362  tx.vin.push_back(input_to_key);
363  }
364 
365  // sort ins by their key image
366  std::vector<size_t> ins_order(sources.size());
367  for (size_t n = 0; n < sources.size(); ++n)
368  ins_order[n] = 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;
373  });
374  tools::apply_permutation(ins_order, [&] (size_t i0, size_t i1) {
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]);
378  });
379 
380  if (shuffle_outs)
381  {
382  std::shuffle(destinations.begin(), destinations.end(), std::default_random_engine(crypto::rand<unsigned int>()));
383  }
384  } else{ // tx v3 onwards
385  for (const tx_source_entry &src_entr : sources) {
386  ++idx;
387  summary_inputs_etn += src_entr.amount;
388 
389  txin_to_key_public input;
390  input.amount = src_entr.amount;
391  input.tx_hash = src_entr.tx_hash;
392  input.relative_offset = src_entr.real_output_in_tx_index;
393 
394  tx.vin.push_back(input);
395  }
396  } //END OF WORK WITH INPUTS
397 
398  // figure out if we need to make additional tx pubkeys
399  size_t num_stdaddresses = 0;
400  size_t num_subaddresses = 0;
401  account_public_address single_dest_subaddress;
402  classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress);
403 
404  // if this is a single-destination transfer to a subaddress, we set the tx pubkey to R=s*D
405  //todo: 4.0.0.0
406  if (num_stdaddresses == 0 && num_subaddresses == 1)
407  {
408  txkey_pub = rct::rct2pk(hwdev.scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key)));
409  }
410  else
411  {
412  txkey_pub = rct::rct2pk(hwdev.scalarmultBase(rct::sk2rct(tx_key)));
413  }
415  add_tx_pub_key_to_extra(tx, txkey_pub);
416 
417  std::vector<crypto::public_key> additional_tx_public_keys;
418 
419  // we don't need to include additional tx keys if:
420  // - all the destinations are standard addresses
421  // - there's only one destination which is a subaddress
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");
425 
426  uint64_t summary_outs_etn = 0;
427  //fill outputs
428  size_t output_index = 0;
429  for (const tx_destination_entry &dst_entr: destinations) {
430  if(tx.version == 1) {
431  crypto::public_key out_eph_public_key;
432 
433  hwdev.generate_output_ephemeral_keys(tx.version, sender_account_keys, txkey_pub, tx_key,
434  dst_entr, change_addr, output_index,
435  need_additional_txkeys, additional_tx_keys,
436  additional_tx_public_keys, amount_keys, out_eph_public_key);
437 
438  tx_out out;
439  out.amount = dst_entr.amount;
440  txout_to_key tk;
441  tk.key = out_eph_public_key;
442  out.target = tk;
443  tx.vout.push_back(out);
444  output_index++;
445  summary_outs_etn += dst_entr.amount;
446  }else{
447  tx_out out;
448  out.amount = dst_entr.amount;
450  tkp.address.m_view_public_key = dst_entr.addr.m_view_public_key;
451  tkp.address.m_spend_public_key = dst_entr.addr.m_spend_public_key;
452  tkp.m_address_prefix = dst_entr.is_subaddress ?
455  out.target = tkp;
456  tx.vout.push_back(out);
457  output_index++;
458  summary_outs_etn += dst_entr.amount;
459  }
460  }
461 
462  CHECK_AND_ASSERT_MES(additional_tx_public_keys.size() == additional_tx_keys.size(), false, "Internal error creating additional public keys");
463 
465 
466  LOG_PRINT_L2("tx pubkey: " << txkey_pub);
467  if (need_additional_txkeys)
468  {
469  LOG_PRINT_L2("additional tx pubkeys: ");
470  for (size_t i = 0; i < additional_tx_public_keys.size(); ++i)
471  LOG_PRINT_L2(additional_tx_public_keys[i]);
472  add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
473  }
474 
475  if (!sort_tx_extra(tx.extra, tx.extra))
476  return false;
477 
478  //check etn
479  if(summary_outs_etn > summary_inputs_etn )
480  {
481  LOG_ERROR("Transaction inputs ETN ("<< summary_inputs_etn << ") less than outputs ETN (" << summary_outs_etn << ")");
482  return false;
483  }
484 
485  // check for watch only wallet
486  bool zero_secret_key = true;
487  for (size_t i = 0; i < sizeof(sender_account_keys.m_spend_secret_key); ++i)
488  zero_secret_key &= (sender_account_keys.m_spend_secret_key.data[i] == 0);
489  if (zero_secret_key)
490  {
491  MDEBUG("Null secret key, skipping signatures");
492  }
493 
494  //generate ring signatures
495  crypto::hash tx_prefix_hash;
496  hwdev.get_transaction_prefix_hash(tx, tx_prefix_hash);
497 
498  std::stringstream ss_ring_s;
499  size_t i = 0;
500 
501  if(tx.version < 3)
502  {
503  for(const tx_source_entry& src_entr: sources)
504  {
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());
508  size_t ii = 0;
509  for (const tx_source_entry::output_entry &o: src_entr.outputs) {
510  keys[ii] = rct2pk(o.second.dest);
511  keys_ptrs.push_back(&keys[ii]);
512  ss_ring_s << o.second.dest << ENDL;
513  ++ii;
514  }
515 
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)
520  hwdev.generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs,
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;
526  i++;
527 
528  MCINFO("construct_tx",
529  "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL
530  << ss_ring_s.str());
531  }
532  }
533  else
534  { //new public signatures for v3 onwards
535  for(uint64_t i = 0; i< tx.vin.size(); i++) {
537  std::vector<crypto::signature> signature_vec;
538  if (!zero_secret_key) {
539 
540  subaddress_index input_subaddress_index = sources[i].subaddr_index;
541  crypto::secret_key private_view_for_sig;
542  crypto::secret_key private_spend_for_sig;
543 
544  if (input_subaddress_index.major == 0 && input_subaddress_index.minor == 0) {
545  private_view_for_sig = sender_account_keys.m_view_secret_key;
546  private_spend_for_sig = sender_account_keys.m_spend_secret_key;
547  } else {
548  private_spend_for_sig = hwdev.get_subaddress_private_spendkey(sender_account_keys,
549  input_subaddress_index);
550  private_view_for_sig = hwdev.get_subaddress_private_viewkey(sender_account_keys.m_view_secret_key,
551  private_spend_for_sig);
552  }
553 
555  tx_prefix_hash,
556  i,
557  private_view_for_sig,
558  private_spend_for_sig,
559  signature
560  );
561  }
562  signature_vec.push_back(signature);
563  tx.signatures.push_back(signature_vec);
564  }
565 
566  MCINFO("construct_tx",
567  "transaction_created (v3): " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx));
568  }
569 
570  tx.invalidate_hashes();
571 
572  return true;
573  }
574  //---------------------------------------------------------------
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)
576  {
577  hw::device &hwdev = sender_account_keys.get_device();
578  hwdev.open_tx(tx_key);
579  try {
580  // figure out if we need to make additional tx pubkeys
581  size_t num_stdaddresses = 0;
582  size_t num_subaddresses = 0;
583  account_public_address single_dest_subaddress;
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)
587  {
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);
591  }
592 
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);
594  hwdev.close_tx();
595  return r;
596  } catch(...) {
597  hwdev.close_tx();
598  throw;
599  }
600  }
601  //---------------------------------------------------------------
602  // called by tests only (use hf_version 1 for the time being)
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)
604  {
605  std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
606  subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
607  crypto::secret_key tx_key;
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);
611  }
612  //---------------------------------------------------------------
614  block& bl
615  , std::string const & genesis_tx
616  , uint32_t nonce
617  )
618  {
619  //genesis block
620  bl = boost::value_initialized<block>();
621 
622 
623  account_public_address ac = boost::value_initialized<account_public_address>();
624  std::vector<size_t> sz;
625  construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis
626  blobdata txb = tx_to_blob(bl.miner_tx);
627  std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb);
628 
629  std::string genesis_coinbase_tx_hex = genesis_tx;
630 
631  blobdata tx_bl;
632  bool r = string_tools::parse_hexstr_to_binbuff(genesis_tx, tx_bl);
633  CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
635  CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
638  bl.timestamp = 0;
639  bl.nonce = nonce;
640  miner::find_nonce_for_given_block(bl, 1, 0);
641  bl.invalidate_hashes();
642  return true;
643  }
644  //---------------------------------------------------------------
645 }
uint64_t height
Definition: blockchain.cpp:91
std::vector< uint8_t > extra
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 AUTO_VAL_INIT(v)
Definition: misc_language.h:53
#define MWARNING(x)
Definition: misc_log_ex.h:74
#define MDEBUG(x)
Definition: misc_log_ex.h:76
#define MCINFO(cat, x)
Definition: misc_log_ex.h:53
#define ENDL
Definition: misc_log_ex.h:149
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
#define LOG_PRINT_L2(x)
Definition: misc_log_ex.h:101
#define LOG_PRINT_L0(x)
Definition: misc_log_ex.h:99
uint64_t const DEFAULT_DUST_THRESHOLD
uint64_t const BASE_REWARD_CLAMP_THRESHOLD
crypto namespace.
Definition: crypto.cpp:58
const crypto::public_key null_pkey
Definition: crypto.cpp:72
POD_CLASS signature
Definition: crypto.h:108
POD_CLASS hash8
Definition: hash.h:53
POD_CLASS key_derivation
Definition: crypto.h:98
bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation)
Definition: crypto.h:270
POD_CLASS public_key
Definition: crypto.h:76
bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key)
Definition: crypto.h:273
POD_CLASS key_image
Definition: crypto.h:102
POD_CLASS hash
Definition: hash.h:50
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
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)
std::string blobdata
Definition: blobdatatype.h:39
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)
bool parse_hexstr_to_binbuff(const epee::span< const char > s, epee::span< char > &res)
Definition: string_tools.h:92
std::string pod_to_hex(const t_pod_type &s)
Definition: string_tools.h:317
std::string buff_to_hex_nodelimer(const std::string &src)
Definition: string_tools.h:87
device & get_device(const std::string &device_descriptor)
Definition: device.cpp:95
mdb_size_t count(MDB_cursor *cur)
@ RangeProofBorromean
Definition: rctTypes.h:235
::std::string string
Definition: gtest-port.h:1097
void apply_permutation(std::vector< size_t > permutation, const F &swap)
unsigned int uint32_t
Definition: stdint.h:126
unsigned char uint8_t
Definition: stdint.h:124
unsigned __int64 uint64_t
Definition: stdint.h:136
crypto::secret_key m_view_secret_key
Definition: account.h:45
hw::device & get_device() const
Definition: account.cpp:59
crypto::secret_key m_spend_secret_key
Definition: account.h:44
account_public_address m_account_address
Definition: account.h:43
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX
crypto::secret_key sec
crypto::public_key pub
std::pair< uint64_t, rct::ctkey > output_entry
crypto::key_image k_image
std::vector< uint64_t > key_offsets
cryptonote::account_public_address address
crypto::public_key key
uint64_t amount
Definition: chaingen.h:290
std::vector< key > c
Definition: rctTypes.h:112