Electroneum
cryptonote_basic.h
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 #pragma once
33 
34 #include <boost/variant.hpp>
35 #include <boost/functional/hash/hash.hpp>
36 #include <vector>
37 #include <cstring> // memcmp
38 #include <sstream>
39 #include <atomic>
40 #include "serialization/variant.h"
41 #include "serialization/vector.h"
45 #include "serialization/crypto.h"
46 #include "serialization/keyvalue_serialization.h" // eepe named serialization
47 #include "cryptonote_config.h"
48 #include "crypto/crypto.h"
49 #include "crypto/hash.h"
50 #include "misc_language.h"
51 #include "ringct/rctTypes.h"
52 #include "device/device.hpp"
53 #include "common/base58.h"
54 
55 namespace cryptonote
56 {
57  typedef std::vector<crypto::signature> ring_signature;
58 
60  {
65  bool spent;
66  };
67 
68  struct address_txs
69  {
72  };
73 
75  {
78 
83 
88 
89  bool operator==(const account_public_address& rhs) const
90  {
91  return m_spend_public_key == rhs.m_spend_public_key &&
92  m_view_public_key == rhs.m_view_public_key;
93  }
94 
95  bool operator!=(const account_public_address& rhs) const
96  {
97  return !(*this == rhs);
98  }
99  };
100 
101  /* outputs */
102 
104  {
105  std::vector<crypto::public_key> keys;
106  std::vector<uint8_t> script;
107 
109  FIELD(keys)
110  FIELD(script)
111  END_SERIALIZE()
112  };
113 
115  {
117  };
118 
120  {
122  txout_to_key(const crypto::public_key &_key) : key(_key) { }
124  };
125 
127  {
130 
132 
134 
135  if (std::is_same<Archive<W>, json_archive<W>>())
136  {
137  std::stringstream ss;
138  binary_archive<true> ba(ss);
139  bool r = ::serialization::serialize(ba, const_cast<account_public_address&>(address));
140  std::string address_blob = ss.str();
141 
142  if(!r) return false;
143 
144  etn_address = tools::base58::encode_addr(m_address_prefix, address_blob);
145 
146  ar.tag("address");
147  ar.serialize_string(etn_address);
148  if (!ar.stream().good())
149  return false;
150 
151  } else {
152  VARINT_FIELD(m_address_prefix)
153  FIELD(address)
154  }
155  END_SERIALIZE()
156  };
157 
158  /* inputs */
159 
160  struct txin_gen
161  {
162  size_t height;
163 
166  END_SERIALIZE()
167  };
168 
170  {
172  size_t prevout;
173  std::vector<uint8_t> sigset;
174 
176  FIELD(prev)
177  VARINT_FIELD(prevout)
178  FIELD(sigset)
179  END_SERIALIZE()
180  };
181 
183  {
185  size_t prevout;
187  std::vector<uint8_t> sigset;
188 
190  FIELD(prev)
191  VARINT_FIELD(prevout)
192  FIELD(script)
193  FIELD(sigset)
194  END_SERIALIZE()
195  };
196 
197  struct txin_to_key
198  {
200  std::vector<uint64_t> key_offsets;
201  crypto::key_image k_image; // double spending protection
202 
204  VARINT_FIELD(amount)
205  FIELD(key_offsets)
206  FIELD(k_image)
207  END_SERIALIZE()
208  };
209 
211 {
215 
217  VARINT_FIELD(amount)
218  VARINT_FIELD(relative_offset)
219  FIELD(tx_hash)
220  END_SERIALIZE()
221 };
222 
224 
226 
227  //typedef std::pair<uint64_t, txout> out_t;
228 
229  struct tx_out
230  {
233 
235  VARINT_FIELD(amount)
236  FIELD(target)
237  END_SERIALIZE()
238 
239  };
240 
241  template<typename T> static inline unsigned int getpos(T &ar) { return 0; }
242  template<> inline unsigned int getpos(binary_archive<true> &ar) { return ar.stream().tellp(); }
243  template<> inline unsigned int getpos(binary_archive<false> &ar) { return ar.stream().tellg(); }
244 
245  struct validator_db {
247  std::vector<uint8_t> validators;
248 
250  VARINT_FIELD(expiration_date)
251  FIELD(validators)
252  END_SERIALIZE()
253  };
254 
256  {
257 
258  public:
259  // tx information
260  size_t version;
261  uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time
262 
263  std::vector<txin_v> vin;
264 
265  std::vector<tx_out> vout;
266  //extra
267  std::vector<uint8_t> extra;
268 
272  VARINT_FIELD(unlock_time)
273  FIELD(vin)
274  FIELD(vout)
275  FIELD(extra)
276  END_SERIALIZE()
277 
278  public:
279  transaction_prefix(){ set_null(); }
280  void set_null()
281  {
282  version = 1;
283  unlock_time = 0;
284  vin.clear();
285  vout.clear();
286  extra.clear();
287  }
289  {
290  unlock_time = 0;
291  vin.clear();
292  vout.clear();
293  extra.clear();
294  }
295  };
296 
298  {
299  private:
300  // hash cash
301  mutable std::atomic<bool> hash_valid;
302  mutable std::atomic<bool> blob_size_valid;
303 
304  public:
305  std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
307 
308  // hash cash
310  mutable size_t blob_size;
311 
312  bool pruned;
313 
314  std::atomic<unsigned int> unprunable_size;
315  std::atomic<unsigned int> prefix_size;
316 
317  transaction();
318  transaction(const transaction &t): transaction_prefix(t), hash_valid(false), blob_size_valid(false), signatures(t.signatures), rct_signatures(t.rct_signatures), pruned(t.pruned), unprunable_size(t.unprunable_size.load()), prefix_size(t.prefix_size.load()) { if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } }
319  transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } pruned = t.pruned; unprunable_size = t.unprunable_size.load(); prefix_size = t.prefix_size.load(); return *this; }
320  virtual ~transaction();
321  void set_null();
322  void invalidate_hashes();
323  bool is_hash_valid() const { return hash_valid.load(std::memory_order_acquire); }
324  void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); }
325  bool is_blob_size_valid() const { return blob_size_valid.load(std::memory_order_acquire); }
326  void set_blob_size_valid(bool v) const { blob_size_valid.store(v,std::memory_order_release); }
327  void set_hash(const crypto::hash &h) { hash = h; set_hash_valid(true); }
328  void set_blob_size(size_t sz) { blob_size = sz; set_blob_size_valid(true); }
329 
331  if (!typename Archive<W>::is_saving())
332  {
333  set_hash_valid(false);
334  set_blob_size_valid(false);
335  }
336 
337  const unsigned int start_pos = getpos(ar);
338 
339  FIELDS(*static_cast<transaction_prefix *>(this))
340 
341  if (std::is_same<Archive<W>, binary_archive<W>>())
342  {
343  prefix_size = getpos(ar) - start_pos;
344  unprunable_size = getpos(ar) - start_pos;
345  }
346 
347  ar.tag("signatures");
348  ar.begin_array();
349  PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
350  bool signatures_not_expected = signatures.empty();
351  if (!signatures_not_expected && vin.size() != signatures.size())
352  return false;
353 
354  if (!pruned) for (size_t i = 0; i < vin.size(); ++i)
355  {
356  size_t signature_size = get_signature_size(vin[i]);
357  if (signatures_not_expected)
358  {
359  if (0 == signature_size)
360  continue;
361  else
362  return false;
363  }
364 
365  PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]);
366  if (signature_size != signatures[i].size())
367  return false;
368 
369  FIELDS(signatures[i]);
370 
371  if (vin.size() - i > 1)
372  ar.delimit_array();
373  }
374  ar.end_array();
375 
376  if (!typename Archive<W>::is_saving())
377  pruned = false;
378  END_SERIALIZE()
379 
380  template<bool W, template <bool> class Archive>
381  bool serialize_base(Archive<W> &ar)
382  {
383  FIELDS(*static_cast<transaction_prefix *>(this))
384 
385  if (!typename Archive<W>::is_saving())
386  pruned = true;
387  return ar.stream().good();
388  }
389 
390  private:
391  static size_t get_signature_size(const txin_v& tx_in);
392  };
393 
394 
395  inline
397  {
398  set_null();
399  }
400 
401  inline
403  {
404  }
405 
406  inline
408  {
410  signatures.clear();
411  rct_signatures.type = rct::RCTTypeNull;
412  set_hash_valid(false);
413  set_blob_size_valid(false);
414  pruned = false;
415  unprunable_size = 0;
416  prefix_size = 0;
417  }
418 
419  inline
421  {
422  set_hash_valid(false);
423  set_blob_size_valid(false);
424  }
425 
426  inline
427  size_t transaction::get_signature_size(const txin_v& tx_in)
428  {
429  struct txin_signature_size_visitor : public boost::static_visitor<size_t>
430  {
431  size_t operator()(const txin_gen& txin) const{return 0;}
432  size_t operator()(const txin_to_script& txin) const{return 0;}
433  size_t operator()(const txin_to_scripthash& txin) const{return 0;}
434  size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();}
435  size_t operator()(const txin_to_key_public& txin) const {return 1;}
436  };
437 
438  return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
439  }
440 
441 
442 
443  /************************************************************************/
444  /* */
445  /************************************************************************/
447  {
449  uint8_t minor_version; // now used as a voting mechanism, rather than how this particular block is built
453 
455  VARINT_FIELD(major_version)
456  VARINT_FIELD(minor_version)
457  VARINT_FIELD(timestamp)
458  FIELD(prev_id)
459  FIELD(nonce)
460  END_SERIALIZE()
461  };
462 
463  struct block: public block_header
464  {
465  private:
466  // hash cash
467  mutable std::atomic<bool> hash_valid;
468 
469  public:
470  block(): block_header(), hash_valid(false) {}
471  block(const block &b): block_header(b), hash_valid(false), miner_tx(b.miner_tx), tx_hashes(b.tx_hashes), signature(b.signature), signatory(b.signatory) { if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } }
472  block &operator=(const block &b) { block_header::operator=(b); hash_valid = false; miner_tx = b.miner_tx; tx_hashes = b.tx_hashes; signature = b.signature; signatory = b.signatory; if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } return *this; }
473  void invalidate_hashes() { set_hash_valid(false); }
474  bool is_hash_valid() const { return hash_valid.load(std::memory_order_acquire); }
475  void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); }
476 
478  std::vector<crypto::hash> tx_hashes;
479 
480  mutable std::vector<uint8_t> signature;
481  mutable std::vector<uint8_t> signatory;
482 
483  // hash cash
485 
487  if (!typename Archive<W>::is_saving())
488  set_hash_valid(false);
489 
490  FIELDS(*static_cast<block_header *>(this))
491  FIELD(miner_tx)
492  FIELD(tx_hashes)
494  FIELD(signatory)
495 
496  if (tx_hashes.size() > CRYPTONOTE_MAX_TX_PER_BLOCK)
497  return false;
498 
499  END_SERIALIZE()
500  };
501 
502 
503  /************************************************************************/
504  /* */
505  /************************************************************************/
506 
507 
508  struct keypair
509  {
512 
513  static inline keypair generate(hw::device &hwdev)
514  {
515  keypair k;
516  hwdev.generate_keys(k.pub, k.sec);
517  return k;
518  }
519  };
520  //---------------------------------------------------------------
521 
522 }
523 
524 namespace std {
525  template <>
526  struct hash<cryptonote::account_public_address>
527  {
528  std::size_t operator()(const cryptonote::account_public_address& addr) const
529  {
530  // https://stackoverflow.com/a/17017281
531  size_t res = 17;
532  res = res * 31 + hash<crypto::public_key>()(addr.m_spend_public_key);
533  res = res * 31 + hash<crypto::public_key>()(addr.m_view_public_key);
534  return res;
535  }
536  };
537 }
538 
541 
553 
565 
const char * res
Definition: hmac_keccak.cpp:41
crypto::public_key pub
block & operator=(const block &b)
const uint32_t T[512]
std::vector< crypto::hash > tx_hashes
crypto::secret_key sec
stream_type & stream()
void set_blob_size(size_t sz)
::std::string string
Definition: gtest-port.h:1097
void set_hash(const crypto::hash &h)
std::vector< uint8_t > signatory
uint64_t height
Definition: blockchain.cpp:91
boost::variant< txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_to_key_public > txin_v
const char * key
Definition: hmac_keccak.cpp:39
STL namespace.
boost::variant< txout_to_script, txout_to_scripthash, txout_to_key, txout_to_key_public > txout_target_v
cryptonote::account_public_address address
transaction(const transaction &t)
std::vector< uint64_t > key_offsets
std::vector< uint8_t > validators
unsigned char uint8_t
Definition: stdint.h:124
uint8_t type
Definition: rctTypes.h:241
std::vector< crypto::signature > ring_signature
std::vector< uint8_t > extra
#define END_SERIALIZE()
self-explanatory
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
bool is_hash_valid() const
return true
std::vector< uint8_t > script
for dealing with variants
virtual crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key &recovery_key=crypto::secret_key(), bool recover=false)=0
void set_blob_size_valid(bool v) const
unsigned int uint32_t
Definition: stdint.h:126
void set_hash_valid(bool v) const
#define FIELDS(f)
does not add a tag to the serialized value
void serialize(Archive &a, unsigned_tx_set &x, const boost::serialization::version_type ver)
unsigned __int64 uint64_t
Definition: stdint.h:136
#define BEGIN_SERIALIZE_OBJECT()
begins the environment of the DSL for described the serialization of an object
std::string encode_addr(uint64_t tag, const std::string &data)
Definition: base58.cpp:228
void load(Archive &a, std::unordered_map< h_key, hval > &x, const boost::serialization::version_type ver)
#define false
Definition: stdbool.h:38
static keypair generate(hw::device &hwdev)
POD_CLASS public_key
Definition: crypto.h:76
version
Supported socks variants.
Definition: socks.h:57
BLOB_SERIALIZER(cryptonote::txout_to_key)
std::vector< std::vector< crypto::signature > > signatures
std::atomic< unsigned int > prefix_size
std::vector< uint8_t > sigset
POD_CLASS signature
Definition: crypto.h:108
std::vector< uint8_t > signature
crypto::public_key key
transaction & operator=(const transaction &t)
#define CRYPTONOTE_MAX_TX_PER_BLOCK
POD_CLASS key_image
Definition: crypto.h:102
#define VARINT_FIELD(f)
tags and serializes the varint f
VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff)
std::vector< uint8_t > sigset
txout_target_v target
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble)
crypto::key_image k_image
void set_hash_valid(bool v) const
block(const block &b)
#define BEGIN_SERIALIZE()
Begins the environment of the DSL for describing how to serialize an of an archive type...
connection< TProtocol > & operator=(const connection< TProtocol > &obj)
std::vector< crypto::public_key > keys
POD_CLASS hash
Definition: hash.h:50
JSON archive.
txout_to_key(const crypto::public_key &_key)
#define CURRENT_TRANSACTION_VERSION
const char * address
Definition: multisig.cpp:37
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec)
else if(0==res)
#define END_KV_SERIALIZE_MAP()
bool operator!=(const account_public_address &rhs) const
#define FIELD(f)
tags the field with the variable name and then serializes it
std::size_t operator()(const cryptonote::account_public_address &addr) const
#define BEGIN_KV_SERIALIZE_MAP()
std::atomic< unsigned int > unprunable_size
a archive using the JSON standard
Definition: json_archive.h:112
#define inline
Definition: inline_c.h:35