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"
48 #include <boost/algorithm/hex.hpp>
49 
50 using namespace crypto;
51 
52 namespace cryptonote
53 {
54  //---------------------------------------------------------------
55  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)
56  {
57  num_stdaddresses = 0;
58  num_subaddresses = 0;
59  std::unordered_set<cryptonote::account_public_address> unique_dst_addresses;
60  for(const tx_destination_entry& dst_entr: destinations)
61  {
62  if (change_addr && dst_entr.addr == change_addr)
63  continue;
64  if (unique_dst_addresses.count(dst_entr.addr) == 0)
65  {
66  unique_dst_addresses.insert(dst_entr.addr);
67  if (dst_entr.is_subaddress)
68  {
69  ++num_subaddresses;
70  single_dest_subaddress = dst_entr.addr;
71  }
72  else
73  {
74  ++num_stdaddresses;
75  }
76  }
77  }
78  LOG_PRINT_L2("destinations include " << num_stdaddresses << " standard addresses and " << num_subaddresses << " subaddresses");
79  }
80  //---------------------------------------------------------------
81  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) {
82  tx.vin.clear();
83  tx.vout.clear();
84  tx.extra.clear();
85 
86  txin_gen in;
87  in.height = height;
88 
89  uint64_t block_reward;
90  if(!get_block_reward(median_weight, current_block_weight, already_generated_coins, block_reward, hard_fork_version, height, nettype))
91  {
92  LOG_PRINT_L0("Block is too big");
93  return false;
94  }
95 
96 #if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
97  LOG_PRINT_L1("Creating block template: reward " << block_reward <<
98  ", fee " << fee);
99 #endif
100  block_reward += fee;
101 
102  // from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and
103  // keeps the paid amount almost the same. The unpaid remainder gets pushed back to the
104  // emission schedule
105  // from hard fork 4, we use a single "dusty" output. This makes the tx even smaller,
106  // and avoids the quantization. These outputs will be added as rct outputs with identity
107  // masks, to they can be used as rct inputs.
108  if (hard_fork_version >= 2 && hard_fork_version < 4) {
109  block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD;
110  }
111 
112  std::vector<uint64_t> out_amounts;
113  decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::DEFAULT_DUST_THRESHOLD,
114  [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); },
115  [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
116 
117  CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
118  if (height == 0 || hard_fork_version >= 4)
119  {
120  // the genesis block was not decomposed, for unknown reasons
121  while (max_outs < out_amounts.size())
122  {
123  //out_amounts[out_amounts.size() - 2] += out_amounts.back();
124  //out_amounts.resize(out_amounts.size() - 1);
125  out_amounts[1] += out_amounts[0];
126  for (size_t n = 1; n < out_amounts.size(); ++n)
127  out_amounts[n - 1] = out_amounts[n];
128  out_amounts.pop_back();
129  }
130  }
131  else
132  {
133  CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded");
134  }
135 
136  uint64_t summary_amounts = 0;
137  if (hard_fork_version >= HF_VERSION_PUBLIC_TX)
138  {
139  for (const auto out_amount : out_amounts)
140  {
142  tk.address.m_view_public_key = miner_address.m_view_public_key;
143  tk.address.m_spend_public_key = miner_address.m_spend_public_key;
145 
146  tx_out out;
147  summary_amounts += out.amount = out_amount;
148  out.target = tk;
149  tx.vout.push_back(out);
150  }
151 
152  tx.version = 3;
153  }
154  else
155  {
156  keypair txkey = keypair::generate(hw::get_device("default"));
157  add_tx_pub_key_to_extra(tx, txkey.pub);
158  if(!extra_nonce.empty())
159  if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
160  return false;
161  if (!sort_tx_extra(tx.extra, tx.extra))
162  return false;
163 
164  for (size_t no = 0; no < out_amounts.size(); no++)
165  {
166  crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);;
167  crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
168  bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
169  CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
170 
171  r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key);
172  CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")");
173 
174  txout_to_key tk;
175  tk.key = out_eph_public_key;
176 
177  tx_out out;
178  summary_amounts += out.amount = out_amounts[no];
179  out.target = tk;
180  tx.vout.push_back(out);
181  }
182 
183  tx.version = 1;
184  }
185 
186 
187  CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward);
188 
189  //lock
191  tx.vin.push_back(in);
192 
193  tx.invalidate_hashes();
194 
195  //LOG_PRINT("MINER_TX generated ok, block_reward=" << print_etn(block_reward) << "(" << print_etn(block_reward - fee) << "+" << print_etn(fee)
196  // << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2);
197  return true;
198  }
199  //---------------------------------------------------------------
200  crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr)
201  {
203  size_t count = 0;
204  for (const auto &i : destinations)
205  {
206  if (i.amount == 0)
207  continue;
208  if (change_addr && i.addr == *change_addr)
209  continue;
210  if (i.addr == addr)
211  continue;
212  if (count > 0)
213  return null_pkey;
214  addr = i.addr;
215  ++count;
216  }
217  if (count == 0 && change_addr)
218  return change_addr->m_view_public_key;
219  return addr.m_view_public_key;
220  }
221  //---------------------------------------------------------------
222  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)
223  {
224  hw::device &hwdev = sender_account_keys.get_device();
225 
226  if (sources.empty())
227  {
228  LOG_ERROR("Empty sources");
229  return false;
230  }
231 
232  std::vector<rct::key> amount_keys;
233  //test tx is sent through this scope TWICE, once as a test and once for real... therefore we set null before each run.
235 
236  amount_keys.clear();
237  if (msout)
238  {
239  msout->c.clear();
240  }
241 
242  tx.unlock_time = unlock_time;
243 
244  tx.extra = extra;
245  crypto::public_key txkey_pub;
246 
247  // if we have a stealth payment id, find it and encrypt it with the tx key now
248  std::vector<tx_extra_field> tx_extra_fields;
249  if (parse_tx_extra(tx.extra, tx_extra_fields))
250  {
251  // IS TX GOING TO THE SMARTCHAIN BRIDGE? IF SO ADD THE ETN ADDRESS AND NEW SMARTCHAIN ADDRESS TO TX EXTRA:
252  // Portal address is derived from the genesis block hash of the mainnet so nobody knows the private key.
253  cryptonote::account_public_address portal_address;
254  crypto::hash h;
255  crypto::ec_point point;
256  if(nettype == MAINNET){
257  epee::string_tools::hex_to_pod("a2050dacd6a36b6fc71cd6447ee498fb2c42801b74e8fe921213f4fcbd95ddcc", h); // v9 fork
258  }else{
259  epee::string_tools::hex_to_pod("1c5da5c1e1420653825260b8ffc85499fdfb6457153a7df9720e659075b3ce76", h); // genesis hash hex ---> hash type --
260  }
261  crypto::hash_to_point(h, point); // generate curve point (burn address spendkey) deterministically in such a way that we can't recover the private key
262  crypto::public_key portal_address_spendkey;
263  std::copy(std::begin(point.data), std::end(point.data), std::begin(portal_address_spendkey.data)); // serialise point to pubkey type
264  std::string portal_address_spendkey_hex_str = epee::string_tools::pod_to_hex(portal_address_spendkey); // for testing only. pub spend =
265  std::string portal_address_viewkey_hex_str;
266  if(nettype == MAINNET){
267  portal_address_viewkey_hex_str = "2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375"; //private view is just e5c8af002654f38ec39ac80edbbcd0c03c9b483379d297af0c3ca15568c7300e -
268  }else{
269  portal_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000 -
270  }
271  portal_address.m_spend_public_key = portal_address_spendkey;
272  epee::string_tools::hex_to_pod(portal_address_viewkey_hex_str, portal_address.m_view_public_key);
273  cryptonote::account_public_address dest_address = destinations[0].addr;
274 
275  // Grab the full etnk.... address as a string, which we serialise to the extra as bytestring
276  // Also use secp256k1 library to take their electroneum private key (which will become their smartchain private key)
277  // and use it to create a secp256k1 public key... Then use the public key to
278  // generate their smartchain address 0xABC1D........ and put this in the tx extra in the same fashion
279  // NB the curve private key domain of ed25519 is a subset of that of secp256k1, and therefore no extra modulo
280  // operation is needed before generating the smartchain public key.
281  // This code uses generates an Ethereum address by taking the last 20 bytes of the Keccak-256 hash of the public key
282  // and adding the prefix "0x".
283  if(dest_address == portal_address){
284  LOG_PRINT_L1("Sending a migration transaction:");
285  crypto::secret_key k = sender_account_keys.m_spend_secret_key; // example private key (can hardcode): 5810ba5a47a45a256458dffe9be21b341a7d74c0b9a8b6a232c60474acbed203
286  std::string seckeystring = epee::string_tools::pod_to_hex(sender_account_keys.m_spend_secret_key); //debug purposes
287 
288  // SOURCE ADDRESS
289  std::string bridge_source_address = cryptonote::get_account_address_as_str(nettype, false, sender_account_keys.m_account_address); //OK
290  add_bridge_source_address_to_tx_extra(tx.extra, bridge_source_address); //OK
291  LOG_PRINT_L1("Source address: " << bridge_source_address);
292 
293  // SMARTCHAIN ADDRESS
294  unsigned char seckey1[32];
295  unsigned char public_key64[65];
296  size_t pk_len = 65;
297  secp256k1_pubkey pubkey1;
299  memcpy(seckey1, sender_account_keys.m_spend_secret_key.data, 32);
300  if(secp256k1_ec_seckey_verify(ctx, seckey1) == 0) { // sec key has an unrealistic chance of being invalid (10^-128) https://en.bitcoin.it/wiki/Private_key
301  LOG_ERROR("Invalid private key");
302  return false;
303  }
304 
305  // create the pubkey and serialise it
306  if(secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1) == 0) { // this format is not sufficient for hashing, hence serialisation
307  LOG_ERROR("Failed to create secp256k1 public key");
308  return false;
309  }
310  secp256k1_ec_pubkey_serialize(ctx, public_key64, &pk_len, &pubkey1, SECP256K1_EC_UNCOMPRESSED); // serialise pubkey1 into publickey_64
311  std::string long_public_key2 = epee::string_tools::pod_to_hex(public_key64); // debug purposes - can check against https://lab.miguelmota.com/ethereum-private-key-to-public-key/example/
312 
313  // Ethereum address generation: Take the last 20 bytes of the Keccak-256 hash of the public key
314  // keccak-1600() is not suitable, but keccak() with 24 rounds and mdlen (=size) of 32 is the same
315  // as keccak-256 with a 32 byte output. 24 rounds is the default in Monero for keccak()
316  // the first byte is the compression type so hash the 64 bytes after the first byte only
317  // I have put the 32 byte hash inside pubkey1.data just to save time
318  keccak(public_key64 + 1, 64, pubkey1.data, 32);
319  unsigned char address[20]; //smartchain address
320  memcpy(address, pubkey1.data + 12, 20); // take the last 20 bytes of the 32 byte array for the address
321  std::string hex_address = epee::string_tools::pod_to_hex(address); // should be 0x12ed7467c3852e6b2Bd3C22AF694be8DF7637B10.
322  std::string bridge_smartchain_address = "0x" + hex_address; //prefix address with 0x
323  LOG_PRINT_L1("Smartchain address: " << bridge_smartchain_address);
324 
326  add_bridge_smartchain_address_to_tx_extra(tx.extra, bridge_smartchain_address);
327  }
328 
329  bool add_dummy_payment_id = true;
330  tx_extra_nonce extra_nonce;
331  if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
332  {
333  crypto::hash payment_id = null_hash;
334  crypto::hash8 payment_id8 = null_hash8;
335  if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
336  {
337  LOG_PRINT_L2("Adding cleartext payment ID to extra nonce. Encrypted PIDs are now deprecated." << payment_id8);
338 
339  std::string extra_nonce;
340 
341  memcpy(payment_id.data, payment_id8.data, 8); // convert short pid to regular
342  memset(payment_id.data + 8, 0, 24); // merely a sanity check
343 
344  set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
346  if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
347  {
348  LOG_ERROR("Failed to add payment id to tx extra");
349  return false;
350  }
351  LOG_PRINT_L1("Encrypted payment ID: " << payment_id8);
352  add_dummy_payment_id = false;
353  }
354  else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
355  {
356  add_dummy_payment_id = false;
357  }
358  }
359 
360  // we don't add one if we've got more than the usual 1 destination plus change
361  if (destinations.size() > 2)
362  add_dummy_payment_id = false;
363 
364  if (add_dummy_payment_id)
365  {
366  std::string extra_nonce;
367  crypto::hash payment_id = null_hash;
368 
369  set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
370  if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
371  {
372  LOG_ERROR("Failed to add dummy payment id to tx extra");
373  // continue anyway
374  }
375  }
376  }
377  else
378  {
379  MWARNING("Failed to parse tx extra");
380  tx_extra_fields.clear();
381  }
382 
383  struct input_generation_context_data
384  {
385  keypair in_ephemeral;
386  };
387  std::vector<input_generation_context_data> in_contexts;
388 
389  uint64_t summary_inputs_etn = 0;
390  //fill inputs
391  int idx = -1;
392 
393  if(tx.version < 3) {
394  for (const tx_source_entry &src_entr : sources) {
395  ++idx;
396  if (src_entr.real_output >= src_entr.outputs.size()) {//
397  LOG_ERROR("real_output index (" << src_entr.real_output << ")bigger than output_keys.size()="
398  << src_entr.outputs.size());
399  return false;
400  }
401  summary_inputs_etn += src_entr.amount;
402 
403  //key_derivation recv_derivation;
404  in_contexts.push_back(input_generation_context_data());
405  // Tx output private key which gets its value assigned inside generate_key_image_helper
406  keypair &in_ephemeral = in_contexts.back().in_ephemeral;
407  crypto::key_image img;//
408  const auto &out_key = reinterpret_cast<const crypto::public_key &>(src_entr.outputs[src_entr.real_output].second.dest);
409  if (!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key,
410  src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index,
411  in_ephemeral, img, hwdev, account_major_offset)) {
412  LOG_ERROR("Key image generation failed!");
413  return false;
414  }
415 
416  //check that derivated key is equal with real output key (if non multisig)
417  if (!msout && !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest)) {
418  LOG_ERROR("derived public key mismatch with output public key at index "
419  << idx << ", real out "
420  << src_entr.real_output << "! "
421  << ENDL << "derived_key:"
422  << string_tools::pod_to_hex(in_ephemeral.pub)
423  << ENDL
424  << "real output_public_key:"
425  << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second.dest));
426 
427  LOG_ERROR("amount " << src_entr.amount << ", rct " << src_entr.rct);
428  LOG_ERROR("tx pubkey " << src_entr.real_out_tx_key << ", real_output_in_tx_index "
429  << src_entr.real_output_in_tx_index);
430  return false;
431  }
432 
433  //put key image into tx input
434  txin_to_key input_to_key;
435  input_to_key.amount = src_entr.amount;
436  input_to_key.k_image = msout ? rct::rct2ki(src_entr.multisig_kLRki.ki) : img;
437 
438  //fill outputs array and use relative offsets
439  for (const tx_source_entry::output_entry &out_entry: src_entr.outputs)
440  input_to_key.key_offsets.push_back(out_entry.first);
441 
442  input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets);
443  tx.vin.push_back(input_to_key);
444  }
445 
446  // sort ins by their key image
447  std::vector<size_t> ins_order(sources.size());
448  for (size_t n = 0; n < sources.size(); ++n)
449  ins_order[n] = n;
450  std::sort(ins_order.begin(), ins_order.end(), [&](const size_t i0, const size_t i1) {
451  const txin_to_key &tk0 = boost::get<txin_to_key>(tx.vin[i0]);
452  const txin_to_key &tk1 = boost::get<txin_to_key>(tx.vin[i1]);
453  return memcmp(&tk0.k_image, &tk1.k_image, sizeof(tk0.k_image)) > 0;
454  });
455  tools::apply_permutation(ins_order, [&] (size_t i0, size_t i1) {
456  std::swap(tx.vin[i0], tx.vin[i1]);
457  std::swap(in_contexts[i0], in_contexts[i1]);
458  std::swap(sources[i0], sources[i1]);
459  });
460 
461  if (shuffle_outs)
462  {
463  std::shuffle(destinations.begin(), destinations.end(), std::default_random_engine(crypto::rand<unsigned int>()));
464  }
465  } else{ // tx v3 onwards
466  for (const tx_source_entry &src_entr : sources) {
467  ++idx;
468  summary_inputs_etn += src_entr.amount;
469 
470  txin_to_key_public input;
471  input.amount = src_entr.amount;
472  input.tx_hash = src_entr.tx_hash;
473  input.relative_offset = src_entr.real_output_in_tx_index;
474 
475  tx.vin.push_back(input);
476  }
477  } //END OF WORK WITH INPUTS
478 
479  // figure out if we need to make additional tx pubkeys
480  size_t num_stdaddresses = 0;
481  size_t num_subaddresses = 0;
482  account_public_address single_dest_subaddress;
483  classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress);
484 
485  // if this is a single-destination transfer to a subaddress, we set the tx pubkey to R=s*D
486  //todo: 4.0.0.0
487  if (num_stdaddresses == 0 && num_subaddresses == 1)
488  {
489  txkey_pub = rct::rct2pk(hwdev.scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key)));
490  }
491  else
492  {
493  txkey_pub = rct::rct2pk(hwdev.scalarmultBase(rct::sk2rct(tx_key)));
494  }
496  add_tx_pub_key_to_extra(tx, txkey_pub);
497 
498  std::vector<crypto::public_key> additional_tx_public_keys;
499 
500  // we don't need to include additional tx keys if:
501  // - all the destinations are standard addresses
502  // - there's only one destination which is a subaddress
503  bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1);
504  if (need_additional_txkeys)
505  CHECK_AND_ASSERT_MES(destinations.size() == additional_tx_keys.size(), false, "Wrong amount of additional tx keys");
506 
507  uint64_t summary_outs_etn = 0;
508  //fill outputs
509  size_t output_index = 0;
510  for (const tx_destination_entry &dst_entr: destinations) {
511  if(tx.version == 1) {
512  crypto::public_key out_eph_public_key;
513 
514  hwdev.generate_output_ephemeral_keys(tx.version, sender_account_keys, txkey_pub, tx_key,
515  dst_entr, change_addr, output_index,
516  need_additional_txkeys, additional_tx_keys,
517  additional_tx_public_keys, amount_keys, out_eph_public_key);
518 
519  tx_out out;
520  out.amount = dst_entr.amount;
521  txout_to_key tk;
522  tk.key = out_eph_public_key;
523  out.target = tk;
524  tx.vout.push_back(out);
525  output_index++;
526  summary_outs_etn += dst_entr.amount;
527  }else{
528  tx_out out;
529  out.amount = dst_entr.amount;
531  tkp.address.m_view_public_key = dst_entr.addr.m_view_public_key;
532  tkp.address.m_spend_public_key = dst_entr.addr.m_spend_public_key;
533  tkp.m_address_prefix = dst_entr.is_subaddress ?
536  out.target = tkp;
537  tx.vout.push_back(out);
538  output_index++;
539  summary_outs_etn += dst_entr.amount;
540  }
541  }
542 
543  CHECK_AND_ASSERT_MES(additional_tx_public_keys.size() == additional_tx_keys.size(), false, "Internal error creating additional public keys");
544 
546 
547  LOG_PRINT_L2("tx pubkey: " << txkey_pub);
548  if (need_additional_txkeys)
549  {
550  LOG_PRINT_L2("additional tx pubkeys: ");
551  for (size_t i = 0; i < additional_tx_public_keys.size(); ++i)
552  LOG_PRINT_L2(additional_tx_public_keys[i]);
553  add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
554  }
555 
556  if (!sort_tx_extra(tx.extra, tx.extra))
557  return false;
558 
559  //check etn
560  if(summary_outs_etn > summary_inputs_etn )
561  {
562  LOG_ERROR("Transaction inputs ETN ("<< summary_inputs_etn << ") less than outputs ETN (" << summary_outs_etn << ")");
563  return false;
564  }
565 
566  // check for watch only wallet
567  bool zero_secret_key = true;
568  for (size_t i = 0; i < sizeof(sender_account_keys.m_spend_secret_key); ++i)
569  zero_secret_key &= (sender_account_keys.m_spend_secret_key.data[i] == 0);
570  if (zero_secret_key)
571  {
572  MDEBUG("Null secret key, skipping signatures");
573  }
574 
575  //generate ring signatures
576  crypto::hash tx_prefix_hash;
577  hwdev.get_transaction_prefix_hash(tx, tx_prefix_hash);
578 
579  std::stringstream ss_ring_s;
580  size_t i = 0;
581 
582  if(tx.version < 3)
583  {
584  for(const tx_source_entry& src_entr: sources)
585  {
586  ss_ring_s << "pub_keys:" << ENDL;
587  std::vector<const crypto::public_key *> keys_ptrs;
588  std::vector<crypto::public_key> keys(src_entr.outputs.size());
589  size_t ii = 0;
590  for (const tx_source_entry::output_entry &o: src_entr.outputs) {
591  keys[ii] = rct2pk(o.second.dest);
592  keys_ptrs.push_back(&keys[ii]);
593  ss_ring_s << o.second.dest << ENDL;
594  ++ii;
595  }
596 
597  tx.signatures.push_back(std::vector<crypto::signature>());
598  std::vector<crypto::signature> &sigs = tx.signatures.back();
599  sigs.resize(src_entr.outputs.size());
600  if (!zero_secret_key)
601  hwdev.generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs,
602  in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
603  ss_ring_s << "signatures:" << ENDL;
604  std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature &s) { ss_ring_s << s << ENDL; });
605  ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: "
606  << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
607  i++;
608 
609  MCINFO("construct_tx",
610  "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL
611  << ss_ring_s.str());
612  }
613  }
614  else
615  { //new public signatures for v3 onwards
616  for(uint64_t i = 0; i< tx.vin.size(); i++) {
618  std::vector<crypto::signature> signature_vec;
619  if (!zero_secret_key) {
620 
621  subaddress_index input_subaddress_index = sources[i].subaddr_index;
622  crypto::secret_key private_view_for_sig;
623  crypto::secret_key private_spend_for_sig;
624 
625  if (input_subaddress_index.major == 0 && input_subaddress_index.minor == 0) {
626  private_view_for_sig = sender_account_keys.m_view_secret_key;
627  private_spend_for_sig = sender_account_keys.m_spend_secret_key;
628  } else {
629  private_spend_for_sig = hwdev.get_subaddress_private_spendkey(sender_account_keys,
630  input_subaddress_index);
631  private_view_for_sig = hwdev.get_subaddress_private_viewkey(sender_account_keys.m_view_secret_key,
632  private_spend_for_sig);
633  }
634 
636  tx_prefix_hash,
637  i,
638  private_view_for_sig,
639  private_spend_for_sig,
640  signature
641  );
642  }
643  signature_vec.push_back(signature);
644  tx.signatures.push_back(signature_vec);
645  }
646 
647  MCINFO("construct_tx",
648  "transaction_created (v3): " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx));
649  }
650 
651  tx.invalidate_hashes();
652 
653  return true;
654  }
655  //---------------------------------------------------------------
656  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)
657  {
658  hw::device &hwdev = sender_account_keys.get_device();
659  hwdev.open_tx(tx_key);
660  try {
661  // figure out if we need to make additional tx pubkeys
662  size_t num_stdaddresses = 0;
663  size_t num_subaddresses = 0;
664  account_public_address single_dest_subaddress;
665  classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress);
666  bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1);
667  if (need_additional_txkeys)
668  {
669  additional_tx_keys.clear();
670  for (const auto &d: destinations)
671  additional_tx_keys.push_back(keypair::generate(sender_account_keys.get_device()).sec);
672  }
673 
674  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);
675  hwdev.close_tx();
676  return r;
677  } catch(...) {
678  hwdev.close_tx();
679  throw;
680  }
681  }
682  //---------------------------------------------------------------
683  // called by tests only (use hf_version 1 for the time being)
684  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)
685  {
686  std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
687  subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
688  crypto::secret_key tx_key;
689  std::vector<crypto::secret_key> additional_tx_keys;
690  std::vector<tx_destination_entry> destinations_copy = destinations;
691  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);
692  }
693  //---------------------------------------------------------------
695  block& bl
696  , std::string const & genesis_tx
697  , uint32_t nonce
698  )
699  {
700  //genesis block
701  bl = boost::value_initialized<block>();
702 
703 
704  account_public_address ac = boost::value_initialized<account_public_address>();
705  std::vector<size_t> sz;
706  construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis
707  blobdata txb = tx_to_blob(bl.miner_tx);
708  std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb);
709 
710  std::string genesis_coinbase_tx_hex = genesis_tx;
711 
712  blobdata tx_bl;
713  bool r = string_tools::parse_hexstr_to_binbuff(genesis_tx, tx_bl);
714  CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
716  CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
719  bl.timestamp = 0;
720  bl.nonce = nonce;
721  miner::find_nonce_for_given_block(bl, 1, 0);
722  bl.invalidate_hashes();
723  return true;
724  }
725  //---------------------------------------------------------------
726 }
crypto::public_key pub
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
#define CRYPTONOTE_MINED_ETN_UNLOCK_WINDOW
const config_t & get_config(network_type nettype)
virtual bool scalarmultKey(rct::key &aP, const rct::key &P, const rct::key &a)=0
POD_CLASS ec_point
Definition: crypto.h:70
#define LOG_PRINT_L2(x)
Definition: misc_log_ex.h:101
std::string get_account_address_as_str(network_type nettype, bool subaddress, account_public_address const &adr)
void apply_permutation(std::vector< size_t > permutation, const F &swap)
crypto::secret_key sec
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
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
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)
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX
::std::string string
Definition: gtest-port.h:1097
POD_CLASS key_derivation
Definition: crypto.h:98
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, const chunk_handler_t &chunk_handler, const dust_handler_t &dust_handler)
uint64_t height
Definition: blockchain.cpp:91
bool add_bridge_smartchain_address_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &bridge_smartchain_address)
bool add_bridge_source_address_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &bridge_source_address)
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)
#define LOG_PRINT_L0(x)
Definition: misc_log_ex.h:99
crypto namespace.
Definition: crypto.cpp:58
SECP256K1_API void secp256k1_context_destroy(secp256k1_context *ctx) SECP256K1_ARG_NONNULL(1)
SECP256K1_API int secp256k1_ec_pubkey_serialize(const secp256k1_context *ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey *pubkey, unsigned int flags) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
cryptonote::account_public_address address
std::vector< uint64_t > key_offsets
bool add_additional_tx_pub_keys_to_extra(std::vector< uint8_t > &tx_extra, const std::vector< crypto::public_key > &additional_pub_keys)
unsigned char uint8_t
Definition: stdint.h:124
#define SECP256K1_CONTEXT_SIGN
Definition: secp256k1.h:207
uint64_t amount
Definition: chaingen.h:290
void copy(key &AA, const key &A)
Definition: rctOps.h:79
bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation)
Definition: crypto.h:272
void hash_to_point(const crypto::hash &h, crypto::ec_point &res)
Definition: crypto.cpp:496
std::vector< uint8_t > extra
#define MDEBUG(x)
Definition: misc_log_ex.h:76
#define ETN_MINED_ETN_UNLOCK_WINDOW_V8
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
#define SECP256K1_EC_UNCOMPRESSED
Definition: secp256k1.h:214
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
struct secp256k1_context_struct secp256k1_context
Definition: secp256k1.h:50
blobdata tx_to_blob(const transaction &tx)
mdb_size_t count(MDB_cursor *cur)
bool add_tx_pub_key_to_extra(transaction &tx, const crypto::public_key &tx_pub_key)
std::string pod_to_hex(const t_pod_type &s)
Definition: string_tools.h:317
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(const secp256k1_context *ctx, const unsigned char *seckey) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
bool generate_genesis_block(block &bl, std::string const &genesis_tx, uint32_t nonce)
virtual crypto::secret_key get_subaddress_private_spendkey(const cryptonote::account_keys &keys, const cryptonote::subaddress_index &subaddr_index)=0
unsigned int uint32_t
Definition: stdint.h:126
const crypto::public_key null_pkey
Definition: crypto.cpp:72
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)
std::vector< uint64_t > absolute_output_offsets_to_relative(const std::vector< uint64_t > &off)
device & get_device(const std::string &device_descriptor)
Definition: device.cpp:95
std::string obj_to_json_str(T &obj)
unsigned __int64 uint64_t
Definition: stdint.h:136
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
bool get_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash &payment_id)
virtual bool open_tx(crypto::secret_key &tx_key)=0
bool hex_to_pod(const std::string &hex_str, t_pod_type &s)
Definition: string_tools.h:324
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 parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
virtual bool close_tx(void)=0
POD_CLASS public_key
Definition: crypto.h:76
#define MWARNING(x)
Definition: misc_log_ex.h:74
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash8 &payment_id)
crypto::secret_key m_view_secret_key
Definition: account.h:45
uint64_t const BASE_REWARD_CLAMP_THRESHOLD
std::vector< std::vector< crypto::signature > > signatures
std::string blobdata
Definition: blobdatatype.h:39
std::vector< key > c
Definition: rctTypes.h:112
unsigned char data[64]
Definition: secp256k1.h:75
account_public_address m_account_address
Definition: account.h:43
uint64_t const DEFAULT_DUST_THRESHOLD
POD_CLASS signature
Definition: crypto.h:108
POD_CLASS hash8
Definition: hash.h:53
crypto::public_key key
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
#define ENDL
Definition: misc_log_ex.h:149
bool sort_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< uint8_t > &sorted_tx_extra, bool allow_partial)
virtual bool scalarmultBase(rct::key &aG, const rct::key &a)=0
std::string buff_to_hex_nodelimer(const std::string &src)
Definition: string_tools.h:87
POD_CLASS key_image
Definition: crypto.h:102
crypto::public_key get_destination_view_key_pub(const std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr)
void * memcpy(void *a, const void *b, size_t c)
crypto::secret_key m_spend_secret_key
Definition: account.h:44
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX
bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key)
Definition: crypto.h:275
#define HF_VERSION_PUBLIC_TX
crypto::key_image k_image
crypto::hash get_transaction_hash(const transaction &t)
bool remove_field_from_tx_extra(std::vector< uint8_t > &tx_extra, const std::type_info &type)
bool add_extra_nonce_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &extra_nonce)
#define AUTO_VAL_INIT(v)
Definition: misc_language.h:53
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
#define CURRENT_BLOCK_MINOR_VERSION
virtual bool get_transaction_prefix_hash(const cryptonote::transaction_prefix &tx, crypto::hash &tx_prefix_hash)=0
POD_CLASS hash
Definition: hash.h:50
const char * address
Definition: multisig.cpp:37
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 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)
std::pair< uint64_t, rct::ctkey > output_entry
void set_payment_id_to_tx_extra_nonce(blobdata &extra_nonce, const crypto::hash &payment_id)
#define MCINFO(cat, x)
Definition: misc_log_ex.h:53
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)
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
hw::device & get_device() const
Definition: account.cpp:59
SECP256K1_API secp256k1_context * secp256k1_context_create(unsigned int flags) SECP256K1_WARN_UNUSED_RESULT
bool parse_hexstr_to_binbuff(const epee::span< const char > s, epee::span< char > &res)
Definition: string_tools.h:92
virtual crypto::secret_key get_subaddress_private_viewkey(const crypto::secret_key &main_wallet_sec_view, crypto::secret_key &subaddress_sec_spend)=0
#define CURRENT_BLOCK_MAJOR_VERSION