Electroneum
cryptonote_format_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 <atomic>
33 #include <boost/algorithm/string.hpp>
34 #include "wipeable_string.h"
35 #include "string_tools.h"
36 #include "serialization/string.h"
38 #include "cryptonote_config.h"
39 #include "crypto/crypto.h"
40 #include "crypto/hash.h"
41 #include "ringct/rctSigs.h"
42 
43 using namespace epee;
44 
45 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
46 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "cn"
47 
48 #define ENCRYPTED_PAYMENT_ID_TAIL 0x8d
49 
50 // #define ENABLE_HASH_CASH_INTEGRITY_CHECK
51 
52 using namespace crypto;
53 
54 static const uint64_t valid_decomposed_outputs[] = {
55  (uint64_t)1, (uint64_t)2, (uint64_t)3, (uint64_t)4, (uint64_t)5, (uint64_t)6, (uint64_t)7, (uint64_t)8, (uint64_t)9,
56  (uint64_t)10, (uint64_t)20, (uint64_t)30, (uint64_t)40, (uint64_t)50, (uint64_t)60, (uint64_t)70, (uint64_t)80, (uint64_t)90,
57  (uint64_t)100, (uint64_t)200, (uint64_t)300, (uint64_t)400, (uint64_t)500, (uint64_t)600, (uint64_t)700, (uint64_t)800, (uint64_t)900, // 100 = 1 Electroneum
58  (uint64_t)1000, (uint64_t)2000, (uint64_t)3000, (uint64_t)4000, (uint64_t)5000, (uint64_t)6000, (uint64_t)7000, (uint64_t)8000, (uint64_t)9000,
59  (uint64_t)10000, (uint64_t)20000, (uint64_t)30000, (uint64_t)40000, (uint64_t)50000, (uint64_t)60000, (uint64_t)70000, (uint64_t)80000, (uint64_t)90000,
60  (uint64_t)100000, (uint64_t)200000, (uint64_t)300000, (uint64_t)400000, (uint64_t)500000, (uint64_t)600000, (uint64_t)700000, (uint64_t)800000, (uint64_t)900000,
61  (uint64_t)1000000, (uint64_t)2000000, (uint64_t)3000000, (uint64_t)4000000, (uint64_t)5000000, (uint64_t)6000000, (uint64_t)7000000, (uint64_t)8000000, (uint64_t)9000000,
62  (uint64_t)10000000, (uint64_t)20000000, (uint64_t)30000000, (uint64_t)40000000, (uint64_t)50000000, (uint64_t)60000000, (uint64_t)70000000, (uint64_t)80000000, (uint64_t)90000000,
63  (uint64_t)100000000, (uint64_t)200000000, (uint64_t)300000000, (uint64_t)400000000, (uint64_t)500000000, (uint64_t)600000000, (uint64_t)700000000, (uint64_t)800000000, (uint64_t)900000000,
64  (uint64_t)1000000000, (uint64_t)2000000000, (uint64_t)3000000000, (uint64_t)4000000000, (uint64_t)5000000000, (uint64_t)6000000000, (uint64_t)7000000000, (uint64_t)8000000000, (uint64_t)9000000000,
65  (uint64_t)10000000000, (uint64_t)20000000000, (uint64_t)30000000000, (uint64_t)40000000000, (uint64_t)50000000000, (uint64_t)60000000000, (uint64_t)70000000000, (uint64_t)80000000000, (uint64_t)90000000000,
66  (uint64_t)100000000000, (uint64_t)200000000000, (uint64_t)300000000000, (uint64_t)400000000000, (uint64_t)500000000000, (uint64_t)600000000000, (uint64_t)700000000000, (uint64_t)800000000000, (uint64_t)900000000000,
67  (uint64_t)1000000000000, (uint64_t)2000000000000, (uint64_t)3000000000000, (uint64_t)4000000000000, (uint64_t)5000000000000, (uint64_t)6000000000000, (uint64_t)7000000000000, (uint64_t)8000000000000, (uint64_t)9000000000000,
68  (uint64_t)10000000000000, (uint64_t)20000000000000, (uint64_t)30000000000000, (uint64_t)40000000000000, (uint64_t)50000000000000, (uint64_t)60000000000000, (uint64_t)70000000000000, (uint64_t)80000000000000, (uint64_t)90000000000000,
69  (uint64_t)100000000000000, (uint64_t)200000000000000, (uint64_t)300000000000000, (uint64_t)400000000000000, (uint64_t)500000000000000, (uint64_t)600000000000000, (uint64_t)700000000000000, (uint64_t)800000000000000, (uint64_t)900000000000000,
70  (uint64_t)1000000000000000, (uint64_t)2000000000000000, (uint64_t)3000000000000000, (uint64_t)4000000000000000, (uint64_t)5000000000000000, (uint64_t)6000000000000000, (uint64_t)7000000000000000, (uint64_t)8000000000000000, (uint64_t)9000000000000000,
71  (uint64_t)10000000000000000, (uint64_t)20000000000000000, (uint64_t)30000000000000000, (uint64_t)40000000000000000, (uint64_t)50000000000000000, (uint64_t)60000000000000000, (uint64_t)70000000000000000, (uint64_t)80000000000000000, (uint64_t)90000000000000000,
72  (uint64_t)100000000000000000, (uint64_t)200000000000000000, (uint64_t)300000000000000000, (uint64_t)400000000000000000, (uint64_t)500000000000000000, (uint64_t)600000000000000000, (uint64_t)700000000000000000, (uint64_t)800000000000000000, (uint64_t)900000000000000000,
73  (uint64_t)1000000000000000000, (uint64_t)2000000000000000000, (uint64_t)3000000000000000000, (uint64_t)4000000000000000000, (uint64_t)5000000000000000000, (uint64_t)6000000000000000000, (uint64_t)7000000000000000000, (uint64_t)8000000000000000000, (uint64_t)9000000000000000000,
74  (uint64_t)10000000000000000000ull
75 };
76 
77 static std::atomic<unsigned int> default_decimal_point(CRYPTONOTE_DISPLAY_DECIMAL_POINT);
78 
79 static std::atomic<uint64_t> tx_hashes_calculated_count(0);
80 static std::atomic<uint64_t> tx_hashes_cached_count(0);
81 static std::atomic<uint64_t> block_hashes_calculated_count(0);
82 static std::atomic<uint64_t> block_hashes_cached_count(0);
83 
84 #define CHECK_AND_ASSERT_THROW_MES_L1(expr, message) {if(!(expr)) {MWARNING(message); throw std::runtime_error(message);}}
85 
86 namespace cryptonote
87 {
88  static inline unsigned char *operator &(ec_point &point) {
89  return &reinterpret_cast<unsigned char &>(point);
90  }
91  static inline const unsigned char *operator &(const ec_point &point) {
92  return &reinterpret_cast<const unsigned char &>(point);
93  }
94 
95  // a copy of rct::addKeys, since we can't link to libringct to avoid circular dependencies
96  static void add_public_key(crypto::public_key &AB, const crypto::public_key &A, const crypto::public_key &B) {
97  ge_p3 B2, A2;
98  CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&B2, &B) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
99  CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A2, &A) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
100  ge_cached tmp2;
101  ge_p3_to_cached(&tmp2, &B2);
102  ge_p1p1 tmp3;
103  ge_add(&tmp3, &A2, &tmp2);
104  ge_p1p1_to_p3(&A2, &tmp3);
105  ge_p3_tobytes(&AB, &A2);
106  }
107 }
108 
109 namespace cryptonote
110 {
111  //---------------------------------------------------------------
113  {
114  std::ostringstream s;
117 
118  crypto::cn_fast_hash(s.str().data(), s.str().size(), h);
119  }
120  //---------------------------------------------------------------
122  {
123  crypto::hash h = null_hash;
125  return h;
126  }
127  //---------------------------------------------------------------
128  bool expand_transaction_1(transaction &tx, bool base_only)
129  {
130  return true;
131  }
132  //---------------------------------------------------------------
134  {
135  std::stringstream ss;
136  ss << tx_blob;
137  binary_archive<false> ba(ss);
138  bool r = ::serialization::serialize(ba, tx);
139  CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
140  CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data");
141  tx.invalidate_hashes();
142  tx.set_blob_size(tx_blob.size());
143  return true;
144  }
145  //---------------------------------------------------------------
147  {
148  std::stringstream ss;
149  ss << tx_blob;
150  binary_archive<false> ba(ss);
151  bool r = tx.serialize_base(ba);
152  CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
153  CHECK_AND_ASSERT_MES(expand_transaction_1(tx, true), false, "Failed to expand transaction data");
154  tx.invalidate_hashes();
155  return true;
156  }
157  //---------------------------------------------------------------
159  {
160  std::stringstream ss;
161  ss << tx_blob;
162  binary_archive<false> ba(ss);
163  bool r = ::serialization::serialize_noeof(ba, tx);
164  CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction prefix from blob");
165  return true;
166  }
167  //---------------------------------------------------------------
169  {
170  std::stringstream ss;
171  ss << tx_blob;
172  binary_archive<false> ba(ss);
173  bool r = ::serialization::serialize(ba, tx);
174  CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
175  CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data");
176  tx.invalidate_hashes();
177  //TODO: validate tx
178 
179  return get_transaction_hash(tx, tx_hash);
180  }
181  //---------------------------------------------------------------
182  bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
183  {
184  if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash))
185  return false;
186  get_transaction_prefix_hash(tx, tx_prefix_hash);
187  return true;
188  }
189  //---------------------------------------------------------------
190  bool is_v1_tx(const blobdata_ref& tx_blob)
191  {
192  //TODO: Public - assure return true. Build logic for prunable v2/v3 tx data later.
193  return true;
194 
196  const char* begin = static_cast<const char*>(tx_blob.data());
197  const char* end = begin + tx_blob.size();
198  int read = tools::read_varint(begin, end, version);
199  if (read <= 0)
200  throw std::runtime_error("Internal error getting transaction version");
201  }
202  //---------------------------------------------------------------
203  bool is_v1_tx(const blobdata& tx_blob)
204  {
205  return is_v1_tx(blobdata_ref{tx_blob.data(), tx_blob.size()});
206  }
207  //---------------------------------------------------------------
208  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)
209  {
210  crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
211  bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
212  if (!r)
213  {
214  MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
215  memcpy(&recv_derivation, rct::identity().bytes, sizeof(recv_derivation));
216  }
217 
218  std::vector<crypto::key_derivation> additional_recv_derivations;
219  for (size_t i = 0; i < additional_tx_public_keys.size(); ++i)
220  {
221  crypto::key_derivation additional_recv_derivation = AUTO_VAL_INIT(additional_recv_derivation);
222  r = hwdev.generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation);
223  if (!r)
224  {
225  MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")");
226  }
227  else
228  {
229  additional_recv_derivations.push_back(additional_recv_derivation);
230  }
231  }
232 
233  boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev);
234  CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address");
235 
236  return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev, account_major_offset);
237  }
238  //---------------------------------------------------------------
239  bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const uint32_t account_major_offset)
240  {
241  uint32_t major_index_offset_based = received_index.major + (received_index.major != 0 ? account_major_offset : 0);
242  cryptonote::subaddress_index recv_index = {major_index_offset_based, received_index.minor};
243 
244  if (hwdev.compute_key_image(ack, out_key, recv_derivation, real_output_index, recv_index, in_ephemeral, ki))
245  {
246  return true;
247  }
248 
250  {
251  // for watch-only wallet, simply copy the known output pubkey
252  in_ephemeral.pub = out_key;
253  in_ephemeral.sec = crypto::null_skey;
254  }
255  else
256  {
257  // derive secret key with subaddress - step 1: original CN derivation
258  crypto::secret_key scalar_step1;
259  hwdev.derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1); // computes Hs(a*R || idx) + b
260 
261  // step 2: add Hs(a || index_major || index_minor)
262  crypto::secret_key subaddr_sk;
263  crypto::secret_key scalar_step2;
264  if (recv_index.is_zero())
265  {
266  scalar_step2 = scalar_step1; // treat index=(0,0) as a special case representing the main address
267  }
268  else
269  {
270  subaddr_sk = hwdev.get_subaddress_secret_key(ack.m_view_secret_key, recv_index);
271  hwdev.sc_secret_add(scalar_step2, scalar_step1,subaddr_sk);
272  }
273 
274  in_ephemeral.sec = scalar_step2;
275 
276  if (ack.m_multisig_keys.empty())
277  {
278  // when not in multisig, we know the full spend secret key, so the output pubkey can be obtained by scalarmultBase
279  CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive public key");
280  }
281  else
282  {
283  // when in multisig, we only know the partial spend secret key. but we do know the full spend public key, so the output pubkey can be obtained by using the standard CN key derivation
284  CHECK_AND_ASSERT_MES(hwdev.derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub), false, "Failed to derive public key");
285  // and don't forget to add the contribution from the subaddress part
286  if (!recv_index.is_zero())
287  {
288  crypto::public_key subaddr_pk;
289  CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(subaddr_sk, subaddr_pk), false, "Failed to derive public key");
290  add_public_key(in_ephemeral.pub, in_ephemeral.pub, subaddr_pk);
291  }
292  }
293 
294  CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_key,
295  false, "key image helper precomp: given output pubkey doesn't match the derived one");
296  }
297 
298  hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
299  return true;
300  }
301  //---------------------------------------------------------------
303  {
304  if(b == 0)
305  return 1;
306  uint64_t total = a;
307  for(uint64_t i = 1; i != b; i++)
308  total *= a;
309  return total;
310  }
311  //---------------------------------------------------------------
312  bool parse_amount(uint64_t& amount, const std::string& str_amount_)
313  {
314  std::string str_amount = str_amount_;
315  boost::algorithm::trim(str_amount);
316 
317  size_t point_index = str_amount.find_first_of('.');
318  size_t fraction_size;
319  if (std::string::npos != point_index)
320  {
321  fraction_size = str_amount.size() - point_index - 1;
322  while (default_decimal_point < fraction_size && '0' == str_amount.back())
323  {
324  str_amount.erase(str_amount.size() - 1, 1);
325  --fraction_size;
326  }
327  if (default_decimal_point < fraction_size)
328  return false;
329  str_amount.erase(point_index, 1);
330  }
331  else
332  {
333  fraction_size = 0;
334  }
335 
336  if (str_amount.empty())
337  return false;
338 
339  if (fraction_size < default_decimal_point)
340  {
341  str_amount.append(default_decimal_point - fraction_size, '0');
342  }
343 
344  return string_tools::get_xtype_from_string(amount, str_amount);
345  }
346  //---------------------------------------------------------------
347  uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
348  {
349  return blob_size;
350  }
351  //---------------------------------------------------------------
353  {
354  size_t blob_size;
355  if (tx.is_blob_size_valid())
356  {
357  blob_size = tx.blob_size;
358  }
359  else
360  {
361  std::ostringstream s;
363  ::serialization::serialize(a, const_cast<transaction&>(tx));
364  blob_size = s.str().size();
365  }
366  return get_transaction_weight(tx, blob_size);
367  }
368  //---------------------------------------------------------------
369  bool get_tx_fee(const transaction& tx, uint64_t & fee)
370  {
371  uint64_t amount_in = 0;
372  uint64_t amount_out = 0;
373  for(auto& in: tx.vin)
374  {
375  CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_to_key_public), 0, "unexpected type id in transaction");
376 
377  if(tx.version == 1 || tx.version == 2)
378  {
379  amount_in += boost::get<txin_to_key>(in).amount;
380  }
381  else
382  {
383  amount_in += boost::get<txin_to_key_public>(in).amount;
384  }
385  }
386  for(auto& o: tx.vout)
387  amount_out += o.amount;
388 
389  CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" <<amount_in << ") more than it has (" << amount_out << ")");
390  fee = amount_in - amount_out;
391  return true;
392  }
393  //---------------------------------------------------------------
395  {
396  uint64_t r = 0;
397  if(!get_tx_fee(tx, r))
398  return 0;
399  return r;
400  }
401  //---------------------------------------------------------------
402  bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields)
403  {
404  tx_extra_fields.clear();
405 
406  if(tx_extra.empty())
407  return true;
408 
409  std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
410  std::istringstream iss(extra_str);
411  binary_archive<false> ar(iss);
412 
413  bool eof = false;
414  while (!eof)
415  {
416  tx_extra_field field;
417  bool r = ::do_serialize(ar, field);
418  CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
419  tx_extra_fields.push_back(field);
420 
421  std::ios_base::iostate state = iss.rdstate();
422  eof = (EOF == iss.peek());
423  iss.clear(state);
424  }
425  CHECK_AND_NO_ASSERT_MES_L1(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
426 
427  return true;
428  }
429  //---------------------------------------------------------------
430  template<typename T>
431  static bool pick(binary_archive<true> &ar, std::vector<tx_extra_field> &fields, uint8_t tag)
432  {
433  std::vector<tx_extra_field>::iterator it;
434  while ((it = std::find_if(fields.begin(), fields.end(), [](const tx_extra_field &f) { return f.type() == typeid(T); })) != fields.end())
435  {
436  bool r = ::do_serialize(ar, tag);
437  CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra field");
438  r = ::do_serialize(ar, boost::get<T>(*it));
439  CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra field");
440  fields.erase(it);
441  }
442  return true;
443  }
444  //---------------------------------------------------------------
445  bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t> &sorted_tx_extra, bool allow_partial)
446  {
447  std::vector<tx_extra_field> tx_extra_fields;
448 
449  if(tx_extra.empty())
450  {
451  sorted_tx_extra.clear();
452  return true;
453  }
454 
455  std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
456  std::istringstream iss(extra_str);
457  binary_archive<false> ar(iss);
458 
459  bool eof = false;
460  size_t processed = 0;
461  while (!eof)
462  {
463  tx_extra_field field;
464  bool r = ::do_serialize(ar, field);
465  if (!r)
466  {
467  MWARNING("failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
468  if (!allow_partial)
469  return false;
470  break;
471  }
472  tx_extra_fields.push_back(field);
473  processed = iss.tellg();
474 
475  std::ios_base::iostate state = iss.rdstate();
476  eof = (EOF == iss.peek());
477  iss.clear(state);
478  }
480  {
481  MWARNING("failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
482  if (!allow_partial)
483  return false;
484  }
485  MTRACE("Sorted " << processed << "/" << tx_extra.size());
486 
487  std::ostringstream oss;
488  binary_archive<true> nar(oss);
489 
490  // sort by:
491  if (!pick<tx_extra_pub_key>(nar, tx_extra_fields, TX_EXTRA_TAG_PUBKEY)) return false;
492  if (!pick<tx_extra_additional_pub_keys>(nar, tx_extra_fields, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS)) return false;
493  if (!pick<tx_extra_nonce>(nar, tx_extra_fields, TX_EXTRA_NONCE)) return false;
494  if (!pick<tx_extra_merge_mining_tag>(nar, tx_extra_fields, TX_EXTRA_MERGE_MINING_TAG)) return false;
495  if (!pick<tx_extra_mysterious_minergate>(nar, tx_extra_fields, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG)) return false;
496  if (!pick<tx_extra_padding>(nar, tx_extra_fields, TX_EXTRA_TAG_PADDING)) return false;
497 
498  // if not empty, someone added a new type and did not add a case above
499  if (!tx_extra_fields.empty())
500  {
501  MERROR("tx_extra_fields not empty after sorting, someone forgot to add a case above");
502  return false;
503  }
504 
505  std::string oss_str = oss.str();
506  if (allow_partial && processed < tx_extra.size())
507  {
508  MDEBUG("Appending unparsed data");
509  oss_str += std::string((const char*)tx_extra.data() + processed, tx_extra.size() - processed);
510  }
511  sorted_tx_extra = std::vector<uint8_t>(oss_str.begin(), oss_str.end());
512  return true;
513  }
514  //---------------------------------------------------------------
515  crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index)
516  {
517  std::vector<tx_extra_field> tx_extra_fields;
518  parse_tx_extra(tx_extra, tx_extra_fields);
519 
520  tx_extra_pub_key pub_key_field;
521  if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index))
522  return null_pkey;
523 
524  return pub_key_field.pub_key;
525  }
526  //---------------------------------------------------------------
528  {
529  return get_tx_pub_key_from_extra(tx_prefix.extra, pk_index);
530  }
531  //---------------------------------------------------------------
533  {
534  return get_tx_pub_key_from_extra(tx.extra, pk_index);
535  }
536  //---------------------------------------------------------------
538  {
539  return add_tx_pub_key_to_extra(tx.extra, tx_pub_key);
540  }
541  //---------------------------------------------------------------
543  {
544  return add_tx_pub_key_to_extra(tx.extra, tx_pub_key);
545  }
546  //---------------------------------------------------------------
547  bool add_tx_pub_key_to_extra(std::vector<uint8_t>& tx_extra, const crypto::public_key& tx_pub_key)
548  {
549  tx_extra.resize(tx_extra.size() + 1 + sizeof(crypto::public_key));
550  tx_extra[tx_extra.size() - 1 - sizeof(crypto::public_key)] = TX_EXTRA_TAG_PUBKEY;
551  *reinterpret_cast<crypto::public_key*>(&tx_extra[tx_extra.size() - sizeof(crypto::public_key)]) = tx_pub_key;
552  return true;
553  }
554  //---------------------------------------------------------------
555  std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const std::vector<uint8_t>& tx_extra)
556  {
557  // parse
558  std::vector<tx_extra_field> tx_extra_fields;
559  parse_tx_extra(tx_extra, tx_extra_fields);
560  // find corresponding field
561  tx_extra_additional_pub_keys additional_pub_keys;
562  if(!find_tx_extra_field_by_type(tx_extra_fields, additional_pub_keys))
563  return {};
564  return additional_pub_keys.data;
565  }
566  //---------------------------------------------------------------
567  std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx)
568  {
570  }
571  //---------------------------------------------------------------
572  bool add_additional_tx_pub_keys_to_extra(std::vector<uint8_t>& tx_extra, const std::vector<crypto::public_key>& additional_pub_keys)
573  {
574  // convert to variant
575  tx_extra_field field = tx_extra_additional_pub_keys{ additional_pub_keys };
576  // serialize
577  std::ostringstream oss;
578  binary_archive<true> ar(oss);
579  bool r = ::do_serialize(ar, field);
580  CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra additional tx pub keys");
581  // append
582  std::string tx_extra_str = oss.str();
583  size_t pos = tx_extra.size();
584  tx_extra.resize(tx_extra.size() + tx_extra_str.size());
585  memcpy(&tx_extra[pos], tx_extra_str.data(), tx_extra_str.size());
586  return true;
587  }
588  //---------------------------------------------------------------
589  bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce)
590  {
591  CHECK_AND_ASSERT_MES(extra_nonce.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max");
592  size_t start_pos = tx_extra.size();
593  tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size());
594  //write tag
595  tx_extra[start_pos] = TX_EXTRA_NONCE;
596  //write len
597  ++start_pos;
598  tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
599  //write data
600  ++start_pos;
601  memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size());
602  return true;
603  }
604  //---------------------------------------------------------------
605  bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type)
606  {
607  if (tx_extra.empty())
608  return true;
609  std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
610  std::istringstream iss(extra_str);
611  binary_archive<false> ar(iss);
612  std::ostringstream oss;
613  binary_archive<true> newar(oss);
614 
615  bool eof = false;
616  while (!eof)
617  {
618  tx_extra_field field;
619  bool r = ::do_serialize(ar, field);
620  CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
621  if (field.type() != type)
622  ::do_serialize(newar, field);
623 
624  std::ios_base::iostate state = iss.rdstate();
625  eof = (EOF == iss.peek());
626  iss.clear(state);
627  }
628  CHECK_AND_NO_ASSERT_MES_L1(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
629  tx_extra.clear();
630  std::string s = oss.str();
631  tx_extra.reserve(s.size());
632  std::copy(s.begin(), s.end(), std::back_inserter(tx_extra));
633  return true;
634  }
635  //---------------------------------------------------------------
636  void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id)
637  {
638  extra_nonce.clear();
639  extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID);
640  const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
641  std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
642  }
643  //---------------------------------------------------------------
645  {
646  extra_nonce.clear();
647  extra_nonce.push_back(TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID);
648  const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
649  std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
650  }
651  //---------------------------------------------------------------
652  bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id)
653  {
654  if(sizeof(crypto::hash) + 1 != extra_nonce.size())
655  return false;
656  if(TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0])
657  return false;
658  payment_id = *reinterpret_cast<const crypto::hash*>(extra_nonce.data() + 1);
659  return true;
660  }
661  //---------------------------------------------------------------
663  {
664  if(sizeof(crypto::hash8) + 1 != extra_nonce.size())
665  return false;
666  if (TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID != extra_nonce[0])
667  return false;
668  payment_id = *reinterpret_cast<const crypto::hash8*>(extra_nonce.data() + 1);
669  return true;
670  }
671  //---------------------------------------------------------------
673  {
674  etn = 0;
675  if(tx.version == 1 || tx.version == 2) {
676  for(const auto& in: tx.vin)
677  {
678  CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
679  etn += tokey_in.amount;
680  }
681  }
682  else //tx.version >= 3 (public transactions: can spend only new inputs)
683  {
684  for(const auto& in: tx.vin)
685  {
686  CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key_public, tokey_in, false);
687  etn += tokey_in.amount;
688  }
689  }
690 
691  return true;
692  }
693  //---------------------------------------------------------------
695  {
696  CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1");
697  CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], const txin_gen, coinbase_in, 0);
698  return coinbase_in.height;
699  }
700  //---------------------------------------------------------------
702  {
703  for(const auto& in: tx.vin)
704  {
705  if (tx.version == 1 || tx.version == 2)
706  {
707  CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: "
708  << in.type().name() << ", expected " << typeid(txin_to_key).name()
709  << ", in transaction id=" << get_transaction_hash(tx));
710  }
711  else //tx.version >= 3 (public transactions: can spend only new inputs)
712  {
713  CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key_public), false, "wrong variant type: "
714  << in.type().name() << ", expected " << typeid(txin_to_key_public).name()
715  << ", in transaction id=" << get_transaction_hash(tx));
716  }
717  }
718  return true;
719  }
720  //-----------------------------------------------------------------------------------------------
722  {
723  for(const tx_out& out: tx.vout)
724  {
725  if (tx.version == 1)
726  {
727  CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key), false, "wrong variant type: "
728  << out.target.type().name() << ", expected " << typeid(txout_to_key).name()
729  << ", in transaction id=" << get_transaction_hash(tx));
730 
731  CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx));
732 
733  if(!check_key(boost::get<txout_to_key>(out.target).key))
734  return false;
735  }
736  else //tx.version >= 2 (public transactions: only new public outputs are allowed)
737  {
738  CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key_public), false, "wrong variant type: "
739  << out.target.type().name() << ", expected " << typeid(txout_to_key_public).name()
740  << ", in transaction id=" << get_transaction_hash(tx));
741 
742  CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx));
743 
744  if(!check_key(boost::get<txout_to_key_public>(out.target).address.m_spend_public_key) ||
745  !check_key(boost::get<txout_to_key_public>(out.target).address.m_view_public_key))
746  return false;
747  }
748 
749  }
750  return true;
751  }
752  //-----------------------------------------------------------------------------------------------
754  {
755  return check_inputs_overflow(tx) && check_outs_overflow(tx);
756  }
757  //---------------------------------------------------------------
759  {
760  uint64_t etn = 0;
761  if(tx.version >= 3)
762  {
763  for(const auto& in: tx.vin)
764  {
765  CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key_public, tokey_in, false);
766  if(etn > tokey_in.amount + etn)
767  return false;
768  etn += tokey_in.amount;
769  }
770  return true;
771  }
772 
773  for(const auto& in: tx.vin)
774  {
775  CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
776  if(etn > tokey_in.amount + etn)
777  return false;
778  etn += tokey_in.amount;
779  }
780  return true;
781  }
782  //---------------------------------------------------------------
784  {
785  uint64_t etn = 0;
786  for(const auto& o: tx.vout)
787  {
788  if(etn > o.amount + etn)
789  return false;
790  etn += o.amount;
791  }
792  return true;
793  }
794  //---------------------------------------------------------------
796  {
797  uint64_t outputs_amount = 0;
798  for(const auto& o: tx.vout)
799  outputs_amount += o.amount;
800  return outputs_amount;
801  }
802  //---------------------------------------------------------------
804  {
806  CHECK_AND_ASSERT_MES(res.size() == 64, res, "wrong hash256 with string_tools::pod_to_hex conversion");
807  auto erased_pos = res.erase(8, 48);
808  res.insert(8, "....");
809  return res;
810  }
811  //---------------------------------------------------------------
812  bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_pub_keys, size_t output_index)
813  {
814  crypto::key_derivation derivation;
815  bool r = acc.get_device().generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
816  CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation");
819  CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key");
820  if (pk == out_key.key)
821  return true;
822  // try additional tx pubkeys if available
823  if (!additional_tx_pub_keys.empty())
824  {
825  CHECK_AND_ASSERT_MES(output_index < additional_tx_pub_keys.size(), false, "wrong number of additional tx pubkeys");
826  r = acc.get_device().generate_key_derivation(additional_tx_pub_keys[output_index], acc.m_view_secret_key, derivation);
827  CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation");
829  CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key");
830  return pk == out_key.key;
831  }
832  return false;
833  }
834  //---------------------------------------------------------------
835  boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index, hw::device &hwdev)
836  {
837  // try the shared tx pubkey
838  crypto::public_key subaddress_spendkey;
839  hwdev.derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey);
840  auto found = subaddresses.find(subaddress_spendkey);
841  if (found != subaddresses.end())
842  return subaddress_receive_info{ found->second, derivation };
843  // try additional tx pubkeys if available
844  if (!additional_derivations.empty())
845  {
846  CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations");
847  hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey);
848  found = subaddresses.find(subaddress_spendkey);
849  if (found != subaddresses.end())
850  return subaddress_receive_info{ found->second, additional_derivations[output_index] };
851  }
852  return boost::none;
853  }
854  //---------------------------------------------------------------
855  boost::optional<subaddress_receive_info> is_out_to_acc_precomp_public(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const cryptonote::account_public_address output_address)
856  {
857  crypto::public_key subaddress_spendkey = output_address.m_spend_public_key;
858  auto found = subaddresses.find(subaddress_spendkey);
859  if (found != subaddresses.end()){
860  return subaddress_receive_info{found->second, {}};
861  }
862  return boost::none;
863  }
864  //---------------------------------------------------------------
865  bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& etn_transfered)
866  {
868  if(null_pkey == tx_pub_key)
869  return false;
870  std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
871  return lookup_acc_outs(acc, tx, tx_pub_key, additional_tx_pub_keys, outs, etn_transfered);
872  }
873  //---------------------------------------------------------------
874  bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_pub_keys, std::vector<size_t>& outs, uint64_t& etn_transfered)
875  {
876  CHECK_AND_ASSERT_MES(additional_tx_pub_keys.empty() || additional_tx_pub_keys.size() == tx.vout.size(), false, "wrong number of additional pubkeys" );
877  etn_transfered = 0;
878  size_t i = 0;
879  for(const tx_out& o: tx.vout)
880  {
881  CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" );
882  if(is_out_to_acc(acc, boost::get<txout_to_key>(o.target), tx_pub_key, additional_tx_pub_keys, i))
883  {
884  outs.push_back(i);
885  etn_transfered += o.amount;
886  }
887  i++;
888  }
889  return true;
890  }
891  //---------------------------------------------------------------
893  {
894  cn_fast_hash(blob.data(), blob.size(), res);
895  }
896  //---------------------------------------------------------------
898  {
899  cn_fast_hash(blob.data(), blob.size(), res);
900  }
901  //---------------------------------------------------------------
902  void set_default_decimal_point(unsigned int decimal_point)
903  {
904  switch (decimal_point)
905  {
906  case 2:
907  default_decimal_point = decimal_point;
908  break;
909  default:
910  ASSERT_MES_AND_THROW("Invalid decimal point specification: " << decimal_point);
911  }
912  }
913  //---------------------------------------------------------------
915  {
916  return default_decimal_point;
917  }
918  //---------------------------------------------------------------
919  std::string get_unit(unsigned int decimal_point)
920  {
921  if (decimal_point == (unsigned int)-1)
922  decimal_point = default_decimal_point;
923  switch (decimal_point)
924  {
925  case 2:
926  return "electroneum";
927  case 0:
928  return "ecent";
929  default:
930  ASSERT_MES_AND_THROW("Invalid decimal point specification: " << decimal_point);
931  }
932  }
933  //---------------------------------------------------------------
934  std::string print_etn(uint64_t amount, unsigned int decimal_point)
935  {
936  if (decimal_point == (unsigned int)-1)
937  decimal_point = default_decimal_point;
938  std::string s = std::to_string(amount);
939  if(s.size() < decimal_point+1)
940  {
941  s.insert(0, decimal_point+1 - s.size(), '0');
942  }
943  if (decimal_point > 0)
944  s.insert(s.size() - decimal_point, ".");
945  return s;
946  }
947  //---------------------------------------------------------------
949  {
950  crypto::hash h = null_hash;
951  get_blob_hash(blob, h);
952  return h;
953  }
954  //---------------------------------------------------------------
956  {
957  crypto::hash h = null_hash;
958  get_blob_hash(blob, h);
959  return h;
960  }
961  //---------------------------------------------------------------
963  {
964  crypto::hash h = null_hash;
965  get_transaction_hash(t, h, NULL);
966  CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(t, h, NULL), "Failed to calculate transaction hash");
967  return h;
968  }
969  //---------------------------------------------------------------
971  {
972  return get_transaction_hash(t, res, NULL);
973  }
974  //---------------------------------------------------------------
976  {
977  if (t.version == 1)
978  return false;
979  const unsigned int unprunable_size = t.unprunable_size;
980  if (blob && unprunable_size)
981  {
982  CHECK_AND_ASSERT_MES(unprunable_size <= blob->size(), false, "Inconsistent transaction unprunable and blob sizes");
983  cryptonote::get_blob_hash(epee::span<const char>(blob->data() + unprunable_size, blob->size() - unprunable_size), res);
984  }
985  else
986  {
987  transaction &tt = const_cast<transaction&>(t);
988  std::stringstream ss;
989  binary_archive<true> ba(ss);
990  const size_t inputs = t.vin.size();
991  const size_t outputs = t.vout.size();
992  const size_t mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 : 0;
993  bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin);
994  CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable");
995  cryptonote::get_blob_hash(ss.str(), res);
996  }
997  return true;
998  }
999  //---------------------------------------------------------------
1001  {
1002  crypto::hash res;
1003  CHECK_AND_ASSERT_THROW_MES(calculate_transaction_prunable_hash(t, blobdata, res), "Failed to calculate tx prunable hash");
1004  return res;
1005  }
1006  //---------------------------------------------------------------
1008  {
1009  // v1 transactions hash the entire blob
1010  CHECK_AND_ASSERT_THROW_MES(t.version > 1, "Hash for pruned v1 tx cannot be calculated");
1011 
1012  // v2 transactions hash different parts together, than hash the set of those hashes
1013  crypto::hash hashes[3];
1014 
1015  // prefix
1017 
1018  transaction &tt = const_cast<transaction&>(t);
1019 
1020  // base rct
1021  {
1022  std::stringstream ss;
1023  binary_archive<true> ba(ss);
1024  const size_t inputs = t.vin.size();
1025  const size_t outputs = t.vout.size();
1026  bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs);
1027  CHECK_AND_ASSERT_THROW_MES(r, "Failed to serialize rct signatures base");
1028  cryptonote::get_blob_hash(ss.str(), hashes[1]);
1029  }
1030 
1031  // prunable rct
1033  hashes[2] = crypto::null_hash;
1034  else
1035  hashes[2] = pruned_data_hash;
1036 
1037  // the tx hash is the hash of the 3 hashes
1039  return res;
1040  }
1041  //---------------------------------------------------------------
1042  bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
1043  {
1044  // v1 transactions hash the entire blob
1045  if (t.version == 1)
1046  {
1047  size_t ignored_blob_size, &blob_size_ref = blob_size ? *blob_size : ignored_blob_size;
1048  return get_object_hash(t, res, blob_size_ref);
1049  }
1050 
1051  // v2 transactions hash different parts together, than hash the set of those hashes
1052  crypto::hash hashes[3];
1053 
1054  // prefix
1056 
1057  const blobdata blob = tx_to_blob(t);
1058  const unsigned int unprunable_size = t.unprunable_size;
1059  const unsigned int prefix_size = t.prefix_size;
1060 
1061  // base rct
1062  CHECK_AND_ASSERT_MES(prefix_size <= unprunable_size && unprunable_size <= blob.size(), false, "Inconsistent transaction prefix, unprunable and blob sizes");
1063  cryptonote::get_blob_hash(epee::span<const char>(blob.data() + prefix_size, unprunable_size - prefix_size), hashes[1]);
1064 
1065  // prunable rct
1067  {
1068  hashes[2] = crypto::null_hash;
1069  }
1070  else
1071  {
1072  CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, &blob, hashes[2]), false, "Failed to get tx prunable hash");
1073  }
1074 
1075  // the tx hash is the hash of the 3 hashes
1076  res = cn_fast_hash(hashes, sizeof(hashes));
1077 
1078  // we still need the size
1079  if (blob_size)
1080  {
1081  if (!t.is_blob_size_valid())
1082  {
1083  t.blob_size = blob.size();
1084  t.set_blob_size_valid(true);
1085  }
1086  *blob_size = t.blob_size;
1087  }
1088 
1089  return true;
1090  }
1091  //---------------------------------------------------------------
1092  bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
1093  {
1094  if (t.is_hash_valid())
1095  {
1096 #ifdef ENABLE_HASH_CASH_INTEGRITY_CHECK
1097  CHECK_AND_ASSERT_THROW_MES(!calculate_transaction_hash(t, res, blob_size) || t.hash == res, "tx hash cash integrity failure");
1098 #endif
1099  res = t.hash;
1100  if (blob_size)
1101  {
1102  if (!t.is_blob_size_valid())
1103  {
1105  t.set_blob_size_valid(true);
1106  }
1107  *blob_size = t.blob_size;
1108  }
1109  ++tx_hashes_cached_count;
1110  return true;
1111  }
1112  ++tx_hashes_calculated_count;
1113  bool ret = calculate_transaction_hash(t, res, blob_size);
1114  if (!ret)
1115  return false;
1116  t.hash = res;
1117  t.set_hash_valid(true);
1118  if (blob_size)
1119  {
1120  t.blob_size = *blob_size;
1121  t.set_blob_size_valid(true);
1122  }
1123  return true;
1124  }
1125  //---------------------------------------------------------------
1126  bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size)
1127  {
1128  return get_transaction_hash(t, res, &blob_size);
1129  }
1130  //---------------------------------------------------------------
1132  {
1133  blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
1134  crypto::hash tree_root_hash = get_tx_tree_hash(b);
1135  blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
1136  blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
1137  return blob;
1138  }
1139  //---------------------------------------------------------------
1140  bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob)
1141  {
1143  }
1144  //---------------------------------------------------------------
1146  {
1147  if (b.is_hash_valid())
1148  {
1149 #ifdef ENABLE_HASH_CASH_INTEGRITY_CHECK
1150  CHECK_AND_ASSERT_THROW_MES(!calculate_block_hash(b, res) || b.hash == res, "block hash cash integrity failure");
1151 #endif
1152  res = b.hash;
1153  ++block_hashes_cached_count;
1154  return true;
1155  }
1156  ++block_hashes_calculated_count;
1157  bool ret = calculate_block_hash(b, res);
1158  if (!ret)
1159  return false;
1160  b.hash = res;
1161  b.set_hash_valid(true);
1162  return true;
1163  }
1164  //---------------------------------------------------------------
1166  {
1167  crypto::hash p = null_hash;
1168  get_block_hash(b, p);
1169  return p;
1170  }
1171  //---------------------------------------------------------------
1173  {
1175  const int cn_variant = b.major_version == 6 ? b.major_version - 5 : 0; // Emergency HF so anti-asic is only if HF 6
1176  crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant);
1177  return true;
1178  }
1179  //---------------------------------------------------------------
1180  std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off)
1181  {
1182  std::vector<uint64_t> res = off;
1183  for(size_t i = 1; i < res.size(); i++)
1184  res[i] += res[i-1];
1185  return res;
1186  }
1187  //---------------------------------------------------------------
1188  std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off)
1189  {
1190  std::vector<uint64_t> res = off;
1191  if(!off.size())
1192  return res;
1193  std::sort(res.begin(), res.end());//just to be sure, actually it is already should be sorted
1194  for(size_t i = res.size()-1; i != 0; i--)
1195  res[i] -= res[i-1];
1196 
1197  return res;
1198  }
1199  //---------------------------------------------------------------
1201  {
1202  crypto::hash p = null_hash;
1203  get_block_longhash(b, p, height);
1204  return p;
1205  }
1206  //---------------------------------------------------------------
1207  bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash)
1208  {
1209  std::stringstream ss;
1210  ss << b_blob;
1211  binary_archive<false> ba(ss);
1212  bool r = ::serialization::serialize(ba, b);
1213  CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob");
1214  b.invalidate_hashes();
1216  if (block_hash)
1217  {
1218  calculate_block_hash(b, *block_hash, &b_blob);
1219  ++block_hashes_calculated_count;
1220  b.hash = *block_hash;
1221  b.set_hash_valid(true);
1222  }
1223  return true;
1224  }
1225  //---------------------------------------------------------------
1227  {
1228  return parse_and_validate_block_from_blob(b_blob, b, NULL);
1229  }
1230  //---------------------------------------------------------------
1231  bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash)
1232  {
1233  return parse_and_validate_block_from_blob(b_blob, b, &block_hash);
1234  }
1235  //---------------------------------------------------------------
1237  {
1239  }
1240  //---------------------------------------------------------------
1241  bool block_to_blob(const block& b, blobdata& b_blob)
1242  {
1243  return t_serializable_object_to_blob(b, b_blob);
1244  }
1245  //---------------------------------------------------------------
1247  {
1248  return t_serializable_object_to_blob(tx);
1249  }
1250  //---------------------------------------------------------------
1251  bool tx_to_blob(const transaction& tx, blobdata& b_blob)
1252  {
1253  return t_serializable_object_to_blob(tx, b_blob);
1254  }
1255  //---------------------------------------------------------------
1256  void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h)
1257  {
1258  tree_hash(tx_hashes.data(), tx_hashes.size(), h);
1259  }
1260  //---------------------------------------------------------------
1261  crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes)
1262  {
1263  crypto::hash h = null_hash;
1264  get_tx_tree_hash(tx_hashes, h);
1265  return h;
1266  }
1267  //---------------------------------------------------------------
1269  {
1270  std::vector<crypto::hash> txs_ids;
1271  txs_ids.reserve(1 + b.tx_hashes.size());
1272  crypto::hash h = null_hash;
1273  size_t bl_sz = 0;
1274  CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(b.miner_tx, h, bl_sz), "Failed to calculate transaction hash");
1275  txs_ids.push_back(h);
1276  for(auto& th: b.tx_hashes)
1277  txs_ids.push_back(th);
1278  return get_tx_tree_hash(txs_ids);
1279  }
1280  //---------------------------------------------------------------
1282  {
1283  const uint64_t *begin = valid_decomposed_outputs;
1284  const uint64_t *end = valid_decomposed_outputs + sizeof(valid_decomposed_outputs) / sizeof(valid_decomposed_outputs[0]);
1285  return std::binary_search(begin, end, amount);
1286  }
1287  //---------------------------------------------------------------
1288  void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached)
1289  {
1290  tx_hashes_calculated = tx_hashes_calculated_count;
1291  tx_hashes_cached = tx_hashes_cached_count;
1292  block_hashes_calculated = block_hashes_calculated_count;
1293  block_hashes_cached = block_hashes_cached_count;
1294  }
1295  //---------------------------------------------------------------
1297  {
1299  crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash);
1300  sc_add((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data);
1301  return key;
1302  }
1303  //---------------------------------------------------------------
1305  {
1307  crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash);
1308  sc_sub((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data);
1309  return key;
1310  }
1311 }
uint64_t height
Definition: blockchain.cpp:91
std::vector< uint8_t > extra
std::atomic< unsigned int > unprunable_size
std::atomic< unsigned int > prefix_size
void set_blob_size(size_t sz)
void set_hash_valid(bool v) const
void set_blob_size_valid(bool v) const
Non-owning sequence of data. Does not deep copy.
Definition: span.h:57
constexpr std::size_t size() const noexcept
Definition: span.h:111
constexpr pointer data() const noexcept
Definition: span.h:110
const char * data() const noexcept
size_t size() const noexcept
virtual bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b)=0
virtual bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image)=0
virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation)=0
virtual bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub)=0
virtual crypto::secret_key get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index)=0
virtual bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub)=0
virtual bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec)=0
virtual bool compute_key_image(const cryptonote::account_keys &ack, const crypto::public_key &out_key, const crypto::key_derivation &recv_derivation, size_t real_output_index, const cryptonote::subaddress_index &received_index, cryptonote::keypair &in_ephemeral, crypto::key_image &ki)
Definition: device.hpp:246
virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub)=0
int ge_frombytes_vartime(ge_p3 *, const unsigned char *)
void sc_sub(unsigned char *, const unsigned char *, const unsigned char *)
void sc_add(unsigned char *, const unsigned char *, const unsigned char *)
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT
#define CHECK_AND_ASSERT_THROW_MES_L1(expr, message)
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val)
void * memcpy(void *a, const void *b, size_t c)
void cn_fast_hash(const void *data, size_t length, char *hash)
void tree_hash(const char(*hashes)[HASH_SIZE], size_t count, char *root_hash)
const char * res
Definition: hmac_keccak.cpp:41
const char * key
Definition: hmac_keccak.cpp:39
#define AUTO_VAL_INIT(v)
Definition: misc_language.h:53
#define MERROR(x)
Definition: misc_log_ex.h:73
#define MWARNING(x)
Definition: misc_log_ex.h:74
#define MDEBUG(x)
Definition: misc_log_ex.h:76
#define CHECK_AND_NO_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:189
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
Definition: misc_log_ex.h:173
#define MTRACE(x)
Definition: misc_log_ex.h:77
#define CHECK_AND_NO_ASSERT_MES_L1(expr, fail_ret_val, message)
Definition: misc_log_ex.h:193
#define ASSERT_MES_AND_THROW(message)
Definition: misc_log_ex.h:172
void do_serialize(boost::mpl::false_, Archive &a, epee::net_utils::network_address &na)
crypto namespace.
Definition: crypto.cpp:58
const crypto::public_key null_pkey
Definition: crypto.cpp:72
void cn_fast_hash(const void *data, std::size_t length, hash &hash)
Definition: hash.h:69
bool check_key(const public_key &key)
Definition: crypto.h:254
POD_CLASS ec_point
Definition: crypto.h:70
const crypto::secret_key null_skey
Definition: crypto.cpp:73
POD_CLASS hash8
Definition: hash.h:53
POD_CLASS key_derivation
Definition: crypto.h:98
POD_CLASS public_key
Definition: crypto.h:76
POD_CLASS key_image
Definition: crypto.h:102
POD_CLASS hash
Definition: hash.h:50
void cn_slow_hash(const void *data, std::size_t length, hash &hash, int variant=0, uint64_t height=0)
Definition: hash.h:79
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
bool is_v1_tx(const blobdata &tx_blob)
void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t &block_hashes_cached)
void get_blob_hash(const epee::span< const char > &blob, crypto::hash &res)
bool is_valid_decomposed_amount(uint64_t amount)
void set_encrypted_payment_id_to_tx_extra_nonce(blobdata &extra_nonce, const crypto::hash8 &payment_id)
crypto::hash get_blob_hash(const epee::span< const char > &blob)
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::string short_hash_str(const crypto::hash &h)
bool get_object_hash(const t_object &o, crypto::hash &res)
uint64_t get_outs_etn_amount(const transaction &tx)
bool calculate_transaction_hash(const transaction &t, crypto::hash &res, size_t *blob_size)
bool sort_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< uint8_t > &sorted_tx_extra, bool allow_partial)
bool calculate_transaction_prunable_hash(const transaction &t, const cryptonote::blobdata *blob, crypto::hash &res)
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash8 &payment_id)
bool check_inputs_overflow(const transaction &tx)
blobdata get_block_hashing_blob(const block &b)
bool is_out_to_acc(const account_keys &acc, const txout_to_key &out_key, const crypto::public_key &tx_pub_key, const std::vector< crypto::public_key > &additional_tx_pub_keys, size_t output_index)
uint64_t power_integral(uint64_t a, uint64_t b)
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)
unsigned int get_default_decimal_point()
uint64_t get_transaction_weight(const transaction &tx)
boost::variant< tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag, tx_extra_additional_pub_keys, tx_extra_mysterious_minergate > tx_extra_field
Definition: tx_extra.h:187
crypto::hash get_transaction_prunable_hash(const transaction &t, const cryptonote::blobdata *blobdata)
bool expand_transaction_1(transaction &tx, bool base_only)
std::vector< uint64_t > absolute_output_offsets_to_relative(const std::vector< uint64_t > &off)
crypto::public_key get_tx_pub_key_from_extra(const transaction &tx, size_t pk_index)
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
crypto::hash get_block_longhash(const block &b, uint64_t height)
crypto::secret_key encrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase)
uint64_t get_block_height(const block &b)
bool calculate_block_hash(const block &b, crypto::hash &res, const blobdata *blob)
boost::optional< subaddress_receive_info > is_out_to_acc_precomp(const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, const crypto::public_key &out_key, const crypto::key_derivation &derivation, const std::vector< crypto::key_derivation > &additional_derivations, size_t output_index, hw::device &hwdev)
bool tx_to_blob(const transaction &tx, blobdata &b_blob)
bool lookup_acc_outs(const account_keys &acc, const transaction &tx, const crypto::public_key &tx_pub_key, const std::vector< crypto::public_key > &additional_tx_pub_keys, std::vector< size_t > &outs, uint64_t &etn_transfered)
bool check_outs_valid(const transaction &tx)
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
bool get_transaction_hash(const transaction &t, crypto::hash &res, size_t &blob_size)
crypto::secret_key decrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase)
bool check_outs_overflow(const transaction &tx)
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefix_hash)
void set_default_decimal_point(unsigned int decimal_point)
uint64_t get_tx_fee(const transaction &tx)
bool check_etn_overflow(const transaction &tx)
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
crypto::hash get_transaction_prefix_hash(const transaction_prefix &tx)
std::string blobdata
Definition: blobdatatype.h:39
bool block_to_blob(const block &b, blobdata &b_blob)
bool add_additional_tx_pub_keys_to_extra(std::vector< uint8_t > &tx_extra, const std::vector< crypto::public_key > &additional_pub_keys)
size_t get_object_blobsize(const t_object &o)
bool parse_amount(uint64_t &amount, const std::string &str_amount_)
bool get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash &block_hash)
bool parse_and_validate_tx_prefix_from_blob(const blobdata &tx_blob, transaction_prefix &tx)
bool remove_field_from_tx_extra(std::vector< uint8_t > &tx_extra, const std::type_info &type)
crypto::hash get_tx_tree_hash(const block &b)
bool check_inputs_types_supported(const transaction &tx)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
crypto::hash get_pruned_transaction_hash(const transaction &t, const crypto::hash &pruned_data_hash)
boost::optional< subaddress_receive_info > is_out_to_acc_precomp_public(const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, const cryptonote::account_public_address output_address)
std::string get_unit(unsigned int decimal_point)
bool generate_key_image_helper_precomp(const account_keys &ack, const crypto::public_key &out_key, const crypto::key_derivation &recv_derivation, size_t real_output_index, const subaddress_index &received_index, keypair &in_ephemeral, crypto::key_image &ki, hw::device &hwdev, const uint32_t account_major_offset)
bool add_tx_pub_key_to_extra(std::vector< uint8_t > &tx_extra, const crypto::public_key &tx_pub_key)
bool parse_and_validate_tx_base_from_blob(const blobdata &tx_blob, transaction &tx)
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
std::vector< crypto::public_key > get_additional_tx_pub_keys_from_extra(const transaction_prefix &tx)
bool add_extra_nonce_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &extra_nonce)
std::string to_string(t_connection_type type)
std::string pod_to_hex(const t_pod_type &s)
Definition: string_tools.h:317
std::string & trim(std::string &str)
Definition: string_tools.h:288
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
Definition: string_tools.h:125
std::string buff_to_hex_nodelimer(const std::string &src)
Definition: string_tools.h:87
version
Supported socks variants.
Definition: socks.h:58
@ RCTTypeNull
Definition: rctTypes.h:229
void copy(key &AA, const key &A)
Definition: rctOps.h:79
key identity()
Definition: rctOps.h:73
bool serialize_noeof(Archive &ar, T &v)
bool check_stream_state(Archive &ar, bool noeof=false)
::std::string string
Definition: gtest-port.h:1097
Matcher< T > A()
std::string get_varint_data(const T &v)
Returns the string that represents the varint.
Definition: varint.h:85
crypto::hash get_block_hash(uint64_t height)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
#define ge_p1p1_to_p3
Definition: ge.h:63
#define ge_p3_tobytes
Definition: ge.h:55
#define ge_p3_to_cached
Definition: ge.h:61
#define ge_add
Definition: ge.h:69
void serialize(Archive &a, unsigned_tx_set &x, const boost::serialization::version_type ver)
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
std::vector< crypto::secret_key > m_multisig_keys
Definition: account.h:46
account_public_address m_account_address
Definition: account.h:43
bool is_hash_valid() const
void set_hash_valid(bool v) const
std::vector< crypto::hash > tx_hashes
crypto::secret_key sec
crypto::public_key pub
std::vector< crypto::public_key > data
Definition: tx_extra.h:167
crypto::public_key pub_key
Definition: tx_extra.h:99
txout_target_v target
crypto::public_key key
uint8_t type
Definition: rctTypes.h:241
bool serialize_rctsig_base(Archive< W > &ar, size_t inputs, size_t outputs)
Definition: rctTypes.h:251
rctSigPrunable p
Definition: rctTypes.h:437
bool serialize_rctsig_prunable(Archive< W > &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
Definition: rctTypes.h:325
Definition: blake256.h:37
struct hash_func hashes[]
#define TX_EXTRA_NONCE_MAX_COUNT
Definition: tx_extra.h:36
#define TX_EXTRA_NONCE_PAYMENT_ID
Definition: tx_extra.h:45
#define TX_EXTRA_TAG_PADDING
Definition: tx_extra.h:38
#define TX_EXTRA_TAG_PUBKEY
Definition: tx_extra.h:39
#define TX_EXTRA_NONCE
Definition: tx_extra.h:40
#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID
Definition: tx_extra.h:46
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG
Definition: tx_extra.h:43
#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS
Definition: tx_extra.h:42
#define TX_EXTRA_MERGE_MINING_TAG
Definition: tx_extra.h:41