Electroneum
Loading...
Searching...
No Matches
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"
38#include "cryptonote_config.h"
39#include "crypto/crypto.h"
40#include "crypto/hash.h"
41#include "ringct/rctSigs.h"
42
43using 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
52using namespace crypto;
53
54static 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
77static std::atomic<unsigned int> default_decimal_point(CRYPTONOTE_DISPLAY_DECIMAL_POINT);
78
79static std::atomic<uint64_t> tx_hashes_calculated_count(0);
80static std::atomic<uint64_t> tx_hashes_cached_count(0);
81static std::atomic<uint64_t> block_hashes_calculated_count(0);
82static 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
86namespace 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
109namespace 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;
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");
142 tx.set_blob_size(tx_blob.size());
143 return true;
144 }
145 //---------------------------------------------------------------
147 {
148 std::stringstream ss;
149 ss << tx_blob;
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");
155 return true;
156 }
157 //---------------------------------------------------------------
159 {
160 std::stringstream ss;
161 ss << tx_blob;
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;
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");
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_bridge_source_address>(nar, tx_extra_fields, TX_EXTRA_TAG_BRIDGE_SOURCE_ADDRESS)) return false;
496 if (!pick<tx_extra_bridge_smartchain_address>(nar, tx_extra_fields, TX_EXTRA_TAG_BRIDGE_SMARTCHAIN_ADDRESS)) return false;
497 if (!pick<tx_extra_bridge_ownership_sig>(nar, tx_extra_fields, TX_EXTRA_TAG_BRIDGE_OWNERSHIP_SIG)) return false;
498 if (!pick<tx_extra_mysterious_minergate>(nar, tx_extra_fields, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG)) return false;
499 if (!pick<tx_extra_padding>(nar, tx_extra_fields, TX_EXTRA_TAG_PADDING)) return false;
500
501 // if not empty, someone added a new type and did not add a case above
502 if (!tx_extra_fields.empty())
503 {
504 MERROR("tx_extra_fields not empty after sorting, someone forgot to add a case above");
505 return false;
506 }
507
508 std::string oss_str = oss.str();
509 if (allow_partial && processed < tx_extra.size())
510 {
511 MDEBUG("Appending unparsed data");
512 oss_str += std::string((const char*)tx_extra.data() + processed, tx_extra.size() - processed);
513 }
514 sorted_tx_extra = std::vector<uint8_t>(oss_str.begin(), oss_str.end());
515 return true;
516 }
517 //---------------------------------------------------------------
518 crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index)
519 {
520 std::vector<tx_extra_field> tx_extra_fields;
521 parse_tx_extra(tx_extra, tx_extra_fields);
522
523 tx_extra_pub_key pub_key_field;
524 if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index))
525 return null_pkey;
526
527 return pub_key_field.pub_key;
528 }
529 //---------------------------------------------------------------
531 {
532 return get_tx_pub_key_from_extra(tx_prefix.extra, pk_index);
533 }
534 //---------------------------------------------------------------
536 {
537 return get_tx_pub_key_from_extra(tx.extra, pk_index);
538 }
539 //---------------------------------------------------------------
541 {
542 return add_tx_pub_key_to_extra(tx.extra, tx_pub_key);
543 }
544 //---------------------------------------------------------------
546 {
547 return add_tx_pub_key_to_extra(tx.extra, tx_pub_key);
548 }
549 //---------------------------------------------------------------
550 bool add_tx_pub_key_to_extra(std::vector<uint8_t>& tx_extra, const crypto::public_key& tx_pub_key)
551 {
552 tx_extra.resize(tx_extra.size() + 1 + sizeof(crypto::public_key));
553 tx_extra[tx_extra.size() - 1 - sizeof(crypto::public_key)] = TX_EXTRA_TAG_PUBKEY;
554 *reinterpret_cast<crypto::public_key*>(&tx_extra[tx_extra.size() - sizeof(crypto::public_key)]) = tx_pub_key;
555 return true;
556 }
557 //---------------------------------------------------------------
558 std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const std::vector<uint8_t>& tx_extra)
559 {
560 // parse
561 std::vector<tx_extra_field> tx_extra_fields;
562 parse_tx_extra(tx_extra, tx_extra_fields);
563 // find corresponding field
564 tx_extra_additional_pub_keys additional_pub_keys;
565 if(!find_tx_extra_field_by_type(tx_extra_fields, additional_pub_keys))
566 return {};
567 return additional_pub_keys.data;
568 }
569 //---------------------------------------------------------------
570 std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx)
571 {
573 }
574 //---------------------------------------------------------------
575 bool add_additional_tx_pub_keys_to_extra(std::vector<uint8_t>& tx_extra, const std::vector<crypto::public_key>& additional_pub_keys)
576 {
577 // convert to variant
578 tx_extra_field field = tx_extra_additional_pub_keys{ additional_pub_keys };
579 // serialize
580 std::ostringstream oss;
581 binary_archive<true> ar(oss);
582 bool r = ::do_serialize(ar, field);
583 CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra additional tx pub keys");
584 // append
585 std::string tx_extra_str = oss.str();
586 size_t pos = tx_extra.size();
587 tx_extra.resize(tx_extra.size() + tx_extra_str.size());
588 memcpy(&tx_extra[pos], tx_extra_str.data(), tx_extra_str.size());
589 return true;
590 }
591 //---------------------------------------------------------------
592 bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce)
593 {
594 CHECK_AND_ASSERT_MES(extra_nonce.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max");
595 size_t start_pos = tx_extra.size();
596 tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size());
597 //write tag
598 tx_extra[start_pos] = TX_EXTRA_NONCE;
599 //write len
600 ++start_pos;
601 tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
602 //write data
603 ++start_pos;
604 memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size());
605 return true;
606 }
607 //---------------------------------------------------------------
608 bool add_bridge_source_address_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& bridge_source_address)
609 {
610 //CHECK_AND_ASSERT_MES(bridge_source_address.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max");
611 size_t start_pos = tx_extra.size();
612 tx_extra.resize(tx_extra.size() + 2 + bridge_source_address.size());
613 //write tag
614 tx_extra[start_pos] = TX_EXTRA_TAG_BRIDGE_SOURCE_ADDRESS;
615 //write len
616 ++start_pos;
617 tx_extra[start_pos] = static_cast<uint8_t>(bridge_source_address.size());
618 //write data
619 ++start_pos;
620 memcpy(&tx_extra[start_pos], bridge_source_address.data(), bridge_source_address.size());
621 return true;
622 }
623 //---------------------------------------------------------------
624 bool add_bridge_smartchain_address_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& bridge_smartchain_address)
625 {
626 //CHECK_AND_ASSERT_MES(bridge_smartchain_address.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max");
627 size_t start_pos = tx_extra.size();
628 tx_extra.resize(tx_extra.size() + 2 + bridge_smartchain_address.size());
629 //write tag
630 tx_extra[start_pos] = TX_EXTRA_TAG_BRIDGE_SMARTCHAIN_ADDRESS;
631 //write len
632 ++start_pos;
633 tx_extra[start_pos] = static_cast<uint8_t>(bridge_smartchain_address.size());
634 //write data
635 ++start_pos;
636 memcpy(&tx_extra[start_pos], bridge_smartchain_address.data(), bridge_smartchain_address.size());
637 return true;
638 }
639 //---------------------------------------------------------------
640 bool add_bridge_ownership_sig_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::signature& sig)
641 {
642 size_t start_pos = tx_extra.size();
643 tx_extra.resize(tx_extra.size() + 2 + sizeof(crypto::signature));
644 //write tag
645 tx_extra[start_pos] = TX_EXTRA_TAG_BRIDGE_OWNERSHIP_SIG;
646 //write len
647 ++start_pos;
648 tx_extra[start_pos] = static_cast<uint8_t>(sizeof(crypto::signature));
649 //write data
650 ++start_pos;
651 memcpy(&tx_extra[start_pos], &sig, sizeof(crypto::signature));
652 return true;
653 }
654 //---------------------------------------------------------------
655 bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type)
656 {
657 if (tx_extra.empty())
658 return true;
659 std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
660 std::istringstream iss(extra_str);
661 binary_archive<false> ar(iss);
662 std::ostringstream oss;
663 binary_archive<true> newar(oss);
664
665 bool eof = false;
666 while (!eof)
667 {
668 tx_extra_field field;
669 bool r = ::do_serialize(ar, field);
670 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())));
671 if (field.type() != type)
672 ::do_serialize(newar, field);
673
674 std::ios_base::iostate state = iss.rdstate();
675 eof = (EOF == iss.peek());
676 iss.clear(state);
677 }
678 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())));
679 tx_extra.clear();
680 std::string s = oss.str();
681 tx_extra.reserve(s.size());
682 std::copy(s.begin(), s.end(), std::back_inserter(tx_extra));
683 return true;
684 }
685 //---------------------------------------------------------------
686 void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id)
687 {
688 extra_nonce.clear();
689 extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID);
690 const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
691 std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
692 }
693 //---------------------------------------------------------------
695 {
696 extra_nonce.clear();
697 extra_nonce.push_back(TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID);
698 const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
699 std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
700 }
701 //---------------------------------------------------------------
702 bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id)
703 {
704 if(sizeof(crypto::hash) + 1 != extra_nonce.size())
705 return false;
706 if(TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0])
707 return false;
708 payment_id = *reinterpret_cast<const crypto::hash*>(extra_nonce.data() + 1);
709 return true;
710 }
711 //---------------------------------------------------------------
713 {
714 if(sizeof(crypto::hash8) + 1 != extra_nonce.size())
715 return false;
716 if (TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID != extra_nonce[0])
717 return false;
718 payment_id = *reinterpret_cast<const crypto::hash8*>(extra_nonce.data() + 1);
719 return true;
720 }
721 //---------------------------------------------------------------
723 {
724 etn = 0;
725 if(tx.version == 1 || tx.version == 2) {
726 for(const auto& in: tx.vin)
727 {
728 CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
729 etn += tokey_in.amount;
730 }
731 }
732 else //tx.version >= 3 (public transactions: can spend only new inputs)
733 {
734 for(const auto& in: tx.vin)
735 {
736 CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key_public, tokey_in, false);
737 etn += tokey_in.amount;
738 }
739 }
740
741 return true;
742 }
743 //---------------------------------------------------------------
745 {
746 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");
747 CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], const txin_gen, coinbase_in, 0);
748 return coinbase_in.height;
749 }
750 //---------------------------------------------------------------
752 {
753 for(const auto& in: tx.vin)
754 {
755 if (tx.version == 1 || tx.version == 2)
756 {
757 CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: "
758 << in.type().name() << ", expected " << typeid(txin_to_key).name()
759 << ", in transaction id=" << get_transaction_hash(tx));
760 }
761 else //tx.version >= 3 (public transactions: can spend only new inputs)
762 {
763 CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key_public), false, "wrong variant type: "
764 << in.type().name() << ", expected " << typeid(txin_to_key_public).name()
765 << ", in transaction id=" << get_transaction_hash(tx));
766 }
767 }
768 return true;
769 }
770 //-----------------------------------------------------------------------------------------------
772 {
773 for(const tx_out& out: tx.vout)
774 {
775 if (tx.version == 1)
776 {
777 CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key), false, "wrong variant type: "
778 << out.target.type().name() << ", expected " << typeid(txout_to_key).name()
779 << ", in transaction id=" << get_transaction_hash(tx));
780
781 CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx));
782
783 if(!check_key(boost::get<txout_to_key>(out.target).key))
784 return false;
785 }
786 else //tx.version >= 2 (public transactions: only new public outputs are allowed)
787 {
788 CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key_public), false, "wrong variant type: "
789 << out.target.type().name() << ", expected " << typeid(txout_to_key_public).name()
790 << ", in transaction id=" << get_transaction_hash(tx));
791
792 CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx));
793
794 if(!check_key(boost::get<txout_to_key_public>(out.target).address.m_spend_public_key) ||
795 !check_key(boost::get<txout_to_key_public>(out.target).address.m_view_public_key))
796 return false;
797 }
798
799 }
800 return true;
801 }
802 //-----------------------------------------------------------------------------------------------
804 {
806 }
807 //---------------------------------------------------------------
809 {
810 uint64_t etn = 0;
811 if(tx.version >= 3)
812 {
813 for(const auto& in: tx.vin)
814 {
815 CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key_public, tokey_in, false);
816 if(etn > tokey_in.amount + etn)
817 return false;
818 etn += tokey_in.amount;
819 }
820 return true;
821 }
822
823 for(const auto& in: tx.vin)
824 {
825 CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
826 if(etn > tokey_in.amount + etn)
827 return false;
828 etn += tokey_in.amount;
829 }
830 return true;
831 }
832 //---------------------------------------------------------------
834 {
835 uint64_t etn = 0;
836 for(const auto& o: tx.vout)
837 {
838 if(etn > o.amount + etn)
839 return false;
840 etn += o.amount;
841 }
842 return true;
843 }
844 //---------------------------------------------------------------
846 {
847 uint64_t outputs_amount = 0;
848 for(const auto& o: tx.vout)
849 outputs_amount += o.amount;
850 return outputs_amount;
851 }
852 //---------------------------------------------------------------
853 std::string short_hash_str(const crypto::hash& h)
854 {
855 std::string res = string_tools::pod_to_hex(h);
856 CHECK_AND_ASSERT_MES(res.size() == 64, res, "wrong hash256 with string_tools::pod_to_hex conversion");
857 auto erased_pos = res.erase(8, 48);
858 res.insert(8, "....");
859 return res;
860 }
861 //---------------------------------------------------------------
862 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)
863 {
864 crypto::key_derivation derivation;
865 bool r = acc.get_device().generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
866 CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation");
869 CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key");
870 if (pk == out_key.key)
871 return true;
872 // try additional tx pubkeys if available
873 if (!additional_tx_pub_keys.empty())
874 {
875 CHECK_AND_ASSERT_MES(output_index < additional_tx_pub_keys.size(), false, "wrong number of additional tx pubkeys");
876 r = acc.get_device().generate_key_derivation(additional_tx_pub_keys[output_index], acc.m_view_secret_key, derivation);
877 CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation");
879 CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key");
880 return pk == out_key.key;
881 }
882 return false;
883 }
884 //---------------------------------------------------------------
885 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)
886 {
887 // try the shared tx pubkey
888 crypto::public_key subaddress_spendkey;
889 hwdev.derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey);
890 auto found = subaddresses.find(subaddress_spendkey);
891 if (found != subaddresses.end())
892 return subaddress_receive_info{ found->second, derivation };
893 // try additional tx pubkeys if available
894 if (!additional_derivations.empty())
895 {
896 CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations");
897 hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey);
898 found = subaddresses.find(subaddress_spendkey);
899 if (found != subaddresses.end())
900 return subaddress_receive_info{ found->second, additional_derivations[output_index] };
901 }
902 return boost::none;
903 }
904 //---------------------------------------------------------------
905 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)
906 {
907 crypto::public_key subaddress_spendkey = output_address.m_spend_public_key;
908 auto found = subaddresses.find(subaddress_spendkey);
909 if (found != subaddresses.end()){
910 return subaddress_receive_info{found->second, {}};
911 }
912 return boost::none;
913 }
914 //---------------------------------------------------------------
915 bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& etn_transfered)
916 {
918 if(null_pkey == tx_pub_key)
919 return false;
920 std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
921 return lookup_acc_outs(acc, tx, tx_pub_key, additional_tx_pub_keys, outs, etn_transfered);
922 }
923 //---------------------------------------------------------------
924 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)
925 {
926 CHECK_AND_ASSERT_MES(additional_tx_pub_keys.empty() || additional_tx_pub_keys.size() == tx.vout.size(), false, "wrong number of additional pubkeys" );
927 etn_transfered = 0;
928 size_t i = 0;
929 for(const tx_out& o: tx.vout)
930 {
931 CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" );
932 if(is_out_to_acc(acc, boost::get<txout_to_key>(o.target), tx_pub_key, additional_tx_pub_keys, i))
933 {
934 outs.push_back(i);
935 etn_transfered += o.amount;
936 }
937 i++;
938 }
939 return true;
940 }
941 //---------------------------------------------------------------
943 {
944 cn_fast_hash(blob.data(), blob.size(), res);
945 }
946 //---------------------------------------------------------------
948 {
949 cn_fast_hash(blob.data(), blob.size(), res);
950 }
951 //---------------------------------------------------------------
952 void set_default_decimal_point(unsigned int decimal_point)
953 {
954 switch (decimal_point)
955 {
956 case 2:
957 default_decimal_point = decimal_point;
958 break;
959 default:
960 ASSERT_MES_AND_THROW("Invalid decimal point specification: " << decimal_point);
961 }
962 }
963 //---------------------------------------------------------------
965 {
966 return default_decimal_point;
967 }
968 //---------------------------------------------------------------
969 std::string get_unit(unsigned int decimal_point)
970 {
971 if (decimal_point == (unsigned int)-1)
972 decimal_point = default_decimal_point;
973 switch (decimal_point)
974 {
975 case 2:
976 return "electroneum";
977 case 0:
978 return "ecent";
979 default:
980 ASSERT_MES_AND_THROW("Invalid decimal point specification: " << decimal_point);
981 }
982 }
983 //---------------------------------------------------------------
984 std::string print_etn(uint64_t amount, unsigned int decimal_point)
985 {
986 if (decimal_point == (unsigned int)-1)
987 decimal_point = default_decimal_point;
988 std::string s = std::to_string(amount);
989 if(s.size() < decimal_point+1)
990 {
991 s.insert(0, decimal_point+1 - s.size(), '0');
992 }
993 if (decimal_point > 0)
994 s.insert(s.size() - decimal_point, ".");
995 return s;
996 }
997 //---------------------------------------------------------------
999 {
1000 crypto::hash h = null_hash;
1001 get_blob_hash(blob, h);
1002 return h;
1003 }
1004 //---------------------------------------------------------------
1006 {
1007 crypto::hash h = null_hash;
1008 get_blob_hash(blob, h);
1009 return h;
1010 }
1011 //---------------------------------------------------------------
1013 {
1014 crypto::hash h = null_hash;
1015 get_transaction_hash(t, h, NULL);
1016 CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(t, h, NULL), "Failed to calculate transaction hash");
1017 return h;
1018 }
1019 //---------------------------------------------------------------
1021 {
1022 return get_transaction_hash(t, res, NULL);
1023 }
1024 //---------------------------------------------------------------
1026 {
1027 if (t.version == 1)
1028 return false;
1029 const unsigned int unprunable_size = t.unprunable_size;
1030 if (blob && unprunable_size)
1031 {
1032 CHECK_AND_ASSERT_MES(unprunable_size <= blob->size(), false, "Inconsistent transaction unprunable and blob sizes");
1033 cryptonote::get_blob_hash(epee::span<const char>(blob->data() + unprunable_size, blob->size() - unprunable_size), res);
1034 }
1035 else
1036 {
1037 transaction &tt = const_cast<transaction&>(t);
1038 std::stringstream ss;
1039 binary_archive<true> ba(ss);
1040 const size_t inputs = t.vin.size();
1041 const size_t outputs = t.vout.size();
1042 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;
1043 bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin);
1044 CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable");
1045 cryptonote::get_blob_hash(ss.str(), res);
1046 }
1047 return true;
1048 }
1049 //---------------------------------------------------------------
1056 //---------------------------------------------------------------
1058 {
1059 // v1 transactions hash the entire blob
1060 CHECK_AND_ASSERT_THROW_MES(t.version > 1, "Hash for pruned v1 tx cannot be calculated");
1061
1062 // v2 transactions hash different parts together, than hash the set of those hashes
1064
1065 // prefix
1067
1068 transaction &tt = const_cast<transaction&>(t);
1069
1070 // base rct
1071 {
1072 std::stringstream ss;
1073 binary_archive<true> ba(ss);
1074 const size_t inputs = t.vin.size();
1075 const size_t outputs = t.vout.size();
1076 bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs);
1077 CHECK_AND_ASSERT_THROW_MES(r, "Failed to serialize rct signatures base");
1078 cryptonote::get_blob_hash(ss.str(), hashes[1]);
1079 }
1080
1081 // prunable rct
1083 hashes[2] = crypto::null_hash;
1084 else
1085 hashes[2] = pruned_data_hash;
1086
1087 // the tx hash is the hash of the 3 hashes
1089 return res;
1090 }
1091 //---------------------------------------------------------------
1092 bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
1093 {
1094 // v1 transactions hash the entire blob
1095 if (t.version == 1)
1096 {
1097 size_t ignored_blob_size, &blob_size_ref = blob_size ? *blob_size : ignored_blob_size;
1098 return get_object_hash(t, res, blob_size_ref);
1099 }
1100
1101 // v2 transactions hash different parts together, than hash the set of those hashes
1103
1104 // prefix
1106
1107 const blobdata blob = tx_to_blob(t);
1108 const unsigned int unprunable_size = t.unprunable_size;
1109 const unsigned int prefix_size = t.prefix_size;
1110
1111 // base rct
1112 CHECK_AND_ASSERT_MES(prefix_size <= unprunable_size && unprunable_size <= blob.size(), false, "Inconsistent transaction prefix, unprunable and blob sizes");
1113 cryptonote::get_blob_hash(epee::span<const char>(blob.data() + prefix_size, unprunable_size - prefix_size), hashes[1]);
1114
1115 // prunable rct
1117 {
1118 hashes[2] = crypto::null_hash;
1119 }
1120 else
1121 {
1122 CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, &blob, hashes[2]), false, "Failed to get tx prunable hash");
1123 }
1124
1125 // the tx hash is the hash of the 3 hashes
1126 res = cn_fast_hash(hashes, sizeof(hashes));
1127
1128 // we still need the size
1129 if (blob_size)
1130 {
1131 if (!t.is_blob_size_valid())
1132 {
1133 t.blob_size = blob.size();
1134 t.set_blob_size_valid(true);
1135 }
1136 *blob_size = t.blob_size;
1137 }
1138
1139 return true;
1140 }
1141 //---------------------------------------------------------------
1142 bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
1143 {
1144 if (t.is_hash_valid())
1145 {
1146#ifdef ENABLE_HASH_CASH_INTEGRITY_CHECK
1147 CHECK_AND_ASSERT_THROW_MES(!calculate_transaction_hash(t, res, blob_size) || t.hash == res, "tx hash cash integrity failure");
1148#endif
1149 res = t.hash;
1150 if (blob_size)
1151 {
1152 if (!t.is_blob_size_valid())
1153 {
1155 t.set_blob_size_valid(true);
1156 }
1157 *blob_size = t.blob_size;
1158 }
1159 ++tx_hashes_cached_count;
1160 return true;
1161 }
1162 ++tx_hashes_calculated_count;
1163 bool ret = calculate_transaction_hash(t, res, blob_size);
1164 if (!ret)
1165 return false;
1166 t.hash = res;
1167 t.set_hash_valid(true);
1168 if (blob_size)
1169 {
1170 t.blob_size = *blob_size;
1171 t.set_blob_size_valid(true);
1172 }
1173 return true;
1174 }
1175 //---------------------------------------------------------------
1176 bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size)
1177 {
1178 return get_transaction_hash(t, res, &blob_size);
1179 }
1180 //---------------------------------------------------------------
1182 {
1183 blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
1184 crypto::hash tree_root_hash = get_tx_tree_hash(b);
1185 blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
1186 blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
1187 return blob;
1188 }
1189 //---------------------------------------------------------------
1191 {
1193 }
1194 //---------------------------------------------------------------
1196 {
1197 if (b.is_hash_valid())
1198 {
1199#ifdef ENABLE_HASH_CASH_INTEGRITY_CHECK
1200 CHECK_AND_ASSERT_THROW_MES(!calculate_block_hash(b, res) || b.hash == res, "block hash cash integrity failure");
1201#endif
1202 res = b.hash;
1203 ++block_hashes_cached_count;
1204 return true;
1205 }
1206 ++block_hashes_calculated_count;
1207 bool ret = calculate_block_hash(b, res);
1208 if (!ret)
1209 return false;
1210 b.hash = res;
1211 b.set_hash_valid(true);
1212 return true;
1213 }
1214 //---------------------------------------------------------------
1216 {
1217 crypto::hash p = null_hash;
1218 get_block_hash(b, p);
1219 return p;
1220 }
1221 //---------------------------------------------------------------
1223 {
1225 const int cn_variant = b.major_version == 6 ? b.major_version - 5 : 0; // Emergency HF so anti-asic is only if HF 6
1226 crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant);
1227 return true;
1228 }
1229 //---------------------------------------------------------------
1230 std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off)
1231 {
1232 std::vector<uint64_t> res = off;
1233 for(size_t i = 1; i < res.size(); i++)
1234 res[i] += res[i-1];
1235 return res;
1236 }
1237 //---------------------------------------------------------------
1238 std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off)
1239 {
1240 std::vector<uint64_t> res = off;
1241 if(!off.size())
1242 return res;
1243 std::sort(res.begin(), res.end());//just to be sure, actually it is already should be sorted
1244 for(size_t i = res.size()-1; i != 0; i--)
1245 res[i] -= res[i-1];
1246
1247 return res;
1248 }
1249 //---------------------------------------------------------------
1251 {
1252 crypto::hash p = null_hash;
1254 return p;
1255 }
1256 //---------------------------------------------------------------
1258 {
1259 std::stringstream ss;
1260 ss << b_blob;
1261 binary_archive<false> ba(ss);
1262 bool r = ::serialization::serialize(ba, b);
1263 CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob");
1266 if (block_hash)
1267 {
1268 calculate_block_hash(b, *block_hash, &b_blob);
1269 ++block_hashes_calculated_count;
1270 b.hash = *block_hash;
1271 b.set_hash_valid(true);
1272 }
1273 return true;
1274 }
1275 //---------------------------------------------------------------
1277 {
1278 return parse_and_validate_block_from_blob(b_blob, b, NULL);
1279 }
1280 //---------------------------------------------------------------
1282 {
1283 return parse_and_validate_block_from_blob(b_blob, b, &block_hash);
1284 }
1285 //---------------------------------------------------------------
1287 {
1289 }
1290 //---------------------------------------------------------------
1291 bool block_to_blob(const block& b, blobdata& b_blob)
1292 {
1293 return t_serializable_object_to_blob(b, b_blob);
1294 }
1295 //---------------------------------------------------------------
1297 {
1299 }
1300 //---------------------------------------------------------------
1301 bool tx_to_blob(const transaction& tx, blobdata& b_blob)
1302 {
1303 return t_serializable_object_to_blob(tx, b_blob);
1304 }
1305 //---------------------------------------------------------------
1306 void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h)
1307 {
1308 tree_hash(tx_hashes.data(), tx_hashes.size(), h);
1309 }
1310 //---------------------------------------------------------------
1311 crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes)
1312 {
1313 crypto::hash h = null_hash;
1314 get_tx_tree_hash(tx_hashes, h);
1315 return h;
1316 }
1317 //---------------------------------------------------------------
1319 {
1320 std::vector<crypto::hash> txs_ids;
1321 txs_ids.reserve(1 + b.tx_hashes.size());
1322 crypto::hash h = null_hash;
1323 size_t bl_sz = 0;
1324 CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(b.miner_tx, h, bl_sz), "Failed to calculate transaction hash");
1325 txs_ids.push_back(h);
1326 for(auto& th: b.tx_hashes)
1327 txs_ids.push_back(th);
1328 return get_tx_tree_hash(txs_ids);
1329 }
1330 //---------------------------------------------------------------
1332 {
1333 const uint64_t *begin = valid_decomposed_outputs;
1334 const uint64_t *end = valid_decomposed_outputs + sizeof(valid_decomposed_outputs) / sizeof(valid_decomposed_outputs[0]);
1335 return std::binary_search(begin, end, amount);
1336 }
1337 //---------------------------------------------------------------
1338 void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached)
1339 {
1340 tx_hashes_calculated = tx_hashes_calculated_count;
1341 tx_hashes_cached = tx_hashes_cached_count;
1342 block_hashes_calculated = block_hashes_calculated_count;
1343 block_hashes_cached = block_hashes_cached_count;
1344 }
1345 //---------------------------------------------------------------
1347 {
1349 crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash);
1350 sc_add((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data);
1351 return key;
1352 }
1353 //---------------------------------------------------------------
1355 {
1357 crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash);
1358 sc_sub((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data);
1359 return key;
1360 }
1361}
uint64_t height
uint8_t version
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
const char * key
#define AUTO_VAL_INIT(v)
#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)
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
#define MTRACE(x)
Definition misc_log_ex.h:77
#define CHECK_AND_NO_ASSERT_MES_L1(expr, fail_ret_val, message)
#define ASSERT_MES_AND_THROW(message)
crypto namespace.
Definition crypto.cpp:58
const crypto::public_key null_pkey
Definition crypto.cpp:72
bool check_key(const public_key &key)
Definition crypto.h:256
POD_CLASS ec_point
Definition crypto.h:70
POD_CLASS signature
Definition crypto.h:108
const crypto::secret_key null_skey
Definition crypto.cpp:73
epee::mlocked< tools::scrubbed< ec_scalar > > secret_key
Definition crypto.h:82
void cn_fast_hash(const void *data, size_t length, char *hash)
POD_CLASS hash8
Definition hash.h:53
POD_CLASS key_derivation
Definition crypto.h:101
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, uint64_t height)
POD_CLASS public_key
Definition crypto.h:79
POD_CLASS key_image
Definition crypto.h:105
POD_CLASS hash
Definition hash.h:50
bool do_serialize(Archive &ar, T &v)
just calls the serialize function defined for ar and v...
Definition hash.h:124
Holds cryptonote related classes and helpers.
Definition ban.cpp:40
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)
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 add_bridge_ownership_sig_to_tx_extra(std::vector< uint8_t > &tx_extra, const crypto::signature &sig)
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)
std::vector< crypto::public_key > get_additional_tx_pub_keys_from_extra(const std::vector< uint8_t > &tx_extra)
bool get_tx_fee(const transaction &tx, uint64_t &fee)
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)
void get_transaction_prefix_hash(const transaction_prefix &tx, crypto::hash &h)
unsigned int get_default_decimal_point()
crypto::hash get_transaction_prunable_hash(const transaction &t, const cryptonote::blobdata *blobdata)
bool expand_transaction_1(transaction &tx, bool base_only)
void get_tx_tree_hash(const std::vector< crypto::hash > &tx_hashes, crypto::hash &h)
std::vector< uint64_t > absolute_output_offsets_to_relative(const std::vector< uint64_t > &off)
epee::span< const char > blobdata_ref
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
bool get_block_hash(const block &b, crypto::hash &res)
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
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)
crypto::public_key get_tx_pub_key_from_extra(const std::vector< uint8_t > &tx_extra, size_t pk_index)
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 add_bridge_smartchain_address_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &bridge_smartchain_address)
bool add_tx_pub_key_to_extra(transaction &tx, const crypto::public_key &tx_pub_key)
crypto::hash get_transaction_hash(const transaction &t)
bool 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)
blobdata block_to_blob(const block &b)
crypto::secret_key decrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase)
bool lookup_acc_outs(const account_keys &acc, const transaction &tx, std::vector< size_t > &outs, uint64_t &etn_transfered)
bool check_outs_overflow(const transaction &tx)
bool get_block_longhash(const block &b, crypto::hash &res, uint64_t height)
void set_default_decimal_point(unsigned int decimal_point)
bool check_etn_overflow(const transaction &tx)
blobdata tx_to_blob(const transaction &tx)
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
std::string blobdata
boost::variant< tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag, tx_extra_additional_pub_keys, tx_extra_bridge_source_address, tx_extra_bridge_smartchain_address, tx_extra_bridge_ownership_sig, tx_extra_mysterious_minergate > tx_extra_field
Definition tx_extra.h:217
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 parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
bool get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
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)
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_bridge_source_address_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &bridge_source_address)
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)
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
bool add_extra_nonce_to_tx_extra(std::vector< uint8_t > &tx_extra, const blobdata &extra_nonce)
std::string pod_to_hex(const t_pod_type &s)
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
std::string buff_to_hex_nodelimer(const std::string &src)
@ RCTTypeNull
Definition rctTypes.h:229
key identity()
Definition rctOps.h:73
bool serialize_noeof(Archive &ar, T &v)
bool check_stream_state(Archive &ar, bool noeof=false)
bool serialize(Archive &ar, T &v)
std::enable_if< std::is_integral< T >::value &&std::is_unsigned< T >::value &&0<=bits &&bits<=std::numeric_limits< T >::digits, int >::type read_varint(InputIt &&first, InputIt &&last, T &write)
reads in the varint that is pointed to by InputIt into write
Definition varint.h:95
std::string get_varint_data(const T &v)
Returns the string that represents the varint.
Definition varint.h:85
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
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:170
crypto::public_key pub_key
Definition tx_extra.h:102
txout_target_v target
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
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:48
#define TX_EXTRA_TAG_PADDING
Definition tx_extra.h:38
#define TX_EXTRA_TAG_PUBKEY
Definition tx_extra.h:39
#define TX_EXTRA_TAG_BRIDGE_SMARTCHAIN_ADDRESS
Definition tx_extra.h:44
#define TX_EXTRA_NONCE
Definition tx_extra.h:40
#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID
Definition tx_extra.h:49
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG
Definition tx_extra.h:46
#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS
Definition tx_extra.h:42
#define TX_EXTRA_TAG_BRIDGE_SOURCE_ADDRESS
Definition tx_extra.h:43
#define TX_EXTRA_MERGE_MINING_TAG
Definition tx_extra.h:41
#define TX_EXTRA_TAG_BRIDGE_OWNERSHIP_SIG
Definition tx_extra.h:45