diff --git a/cryptonote_basic/cryptonote_basic.h b/cryptonote_basic/cryptonote_basic.h index 6cd78c3..d4558ef 100644 --- a/cryptonote_basic/cryptonote_basic.h +++ b/cryptonote_basic/cryptonote_basic.h @@ -44,35 +44,380 @@ #include "serialization/crypto.h" #include "serialization/keyvalue_serialization.h" // eepe named serialization #include "cryptonote_config.h" -#include "crypto.h" -#include "hash.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" #include "misc_language.h" -//#include "tx_extra.h" -//#include "ringct/rctTypes.h" +#include "tx_extra.h" +#include "ringct/rctTypes.h" +#include "device/device.hpp" namespace cryptonote { + typedef std::vector ring_signature; + + /* outputs */ + + struct txout_to_script + { + std::vector keys; + std::vector script; + + BEGIN_SERIALIZE_OBJECT() + FIELD(keys) + FIELD(script) + END_SERIALIZE() + }; + + struct txout_to_scripthash + { + crypto::hash hash; + }; + + struct txout_to_key + { + txout_to_key() { } + txout_to_key(const crypto::public_key &_key) : key(_key) { } + crypto::public_key key; + }; + + + /* inputs */ + + struct txin_gen + { + size_t height; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(height) + END_SERIALIZE() + }; + + struct txin_to_script + { + crypto::hash prev; + size_t prevout; + std::vector sigset; + + BEGIN_SERIALIZE_OBJECT() + FIELD(prev) + VARINT_FIELD(prevout) + FIELD(sigset) + END_SERIALIZE() + }; + + struct txin_to_scripthash + { + crypto::hash prev; + size_t prevout; + txout_to_script script; + std::vector sigset; + + BEGIN_SERIALIZE_OBJECT() + FIELD(prev) + VARINT_FIELD(prevout) + FIELD(script) + FIELD(sigset) + END_SERIALIZE() + }; + + struct txin_to_key + { + uint64_t amount; + std::vector key_offsets; + crypto::key_image k_image; // double spending protection + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(amount) + FIELD(key_offsets) + FIELD(k_image) + END_SERIALIZE() + }; + + + typedef boost::variant txin_v; + + typedef boost::variant txout_target_v; + + //typedef std::pair out_t; + struct tx_out + { + uint64_t amount; + txout_target_v target; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(amount) + FIELD(target) + END_SERIALIZE() + + + }; + + class transaction_prefix + { + + public: + // tx information + size_t version; + uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time + + std::vector vin; + std::vector vout; + //extra + std::vector extra; + + BEGIN_SERIALIZE() + VARINT_FIELD(version) + if(version == 0 || CURRENT_TRANSACTION_VERSION < version) return false; + VARINT_FIELD(unlock_time) + FIELD(vin) + FIELD(vout) + FIELD(extra) + END_SERIALIZE() + + public: + transaction_prefix(){} + }; + + class transaction: public transaction_prefix + { + private: + // hash cash + mutable std::atomic hash_valid; + mutable std::atomic blob_size_valid; + + public: + std::vector > signatures; //count signatures always the same as inputs count + rct::rctSig rct_signatures; + + // hash cash + mutable crypto::hash hash; + mutable size_t blob_size; + + transaction(); + transaction(const transaction &t): transaction_prefix(t), hash_valid(false), 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); } } + 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); } return *this; } + virtual ~transaction(); + void set_null(); + void invalidate_hashes(); + bool is_hash_valid() const { return hash_valid.load(std::memory_order_acquire); } + void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); } + bool is_blob_size_valid() const { return blob_size_valid.load(std::memory_order_acquire); } + void set_blob_size_valid(bool v) const { blob_size_valid.store(v,std::memory_order_release); } + + BEGIN_SERIALIZE_OBJECT() + if (!typename Archive::is_saving()) + { + set_hash_valid(false); + set_blob_size_valid(false); + } + + FIELDS(*static_cast(this)) + + if (version == 1) + { + ar.tag("signatures"); + ar.begin_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures); + bool signatures_not_expected = signatures.empty(); + if (!signatures_not_expected && vin.size() != signatures.size()) + return false; + + for (size_t i = 0; i < vin.size(); ++i) + { + size_t signature_size = get_signature_size(vin[i]); + if (signatures_not_expected) + { + if (0 == signature_size) + continue; + else + return false; + } + + PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]); + if (signature_size != signatures[i].size()) + return false; + + FIELDS(signatures[i]); + + if (vin.size() - i > 1) + ar.delimit_array(); + } + ar.end_array(); + } + else + { + ar.tag("rct_signatures"); + if (!vin.empty()) + { + ar.begin_object(); + bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); + if (!r || !ar.stream().good()) return false; + ar.end_object(); + if (rct_signatures.type != rct::RCTTypeNull) + { + ar.tag("rctsig_prunable"); + ar.begin_object(); + r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(), + vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); + if (!r || !ar.stream().good()) return false; + ar.end_object(); + } + } + } + END_SERIALIZE() + + template class Archive> + bool serialize_base(Archive &ar) + { + FIELDS(*static_cast(this)) + + if (version == 1) + { + } + else + { + ar.tag("rct_signatures"); + if (!vin.empty()) + { + ar.begin_object(); + bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); + if (!r || !ar.stream().good()) return false; + ar.end_object(); + } + } + return true; + } + + private: + static size_t get_signature_size(const txin_v& tx_in); + }; + + + inline + transaction::transaction() + { + set_null(); + } + + inline + transaction::~transaction() + { + //set_null(); + } + + inline + void transaction::set_null() + { + version = 1; + unlock_time = 0; + vin.clear(); + vout.clear(); + extra.clear(); + signatures.clear(); + rct_signatures.type = rct::RCTTypeNull; + set_hash_valid(false); + set_blob_size_valid(false); + } + + inline + void transaction::invalidate_hashes() + { + set_hash_valid(false); + set_blob_size_valid(false); + } + + inline + size_t transaction::get_signature_size(const txin_v& tx_in) + { + struct txin_signature_size_visitor : public boost::static_visitor + { + size_t operator()(const txin_gen& txin) const{return 0;} + size_t operator()(const txin_to_script& txin) const{return 0;} + size_t operator()(const txin_to_scripthash& txin) const{return 0;} + size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();} + }; + + return boost::apply_visitor(txin_signature_size_visitor(), tx_in); + } + + + + /************************************************************************/ + /* */ + /************************************************************************/ + struct block_header + { + uint8_t major_version; + uint8_t minor_version; // now used as a voting mechanism, rather than how this particular block is built + uint64_t timestamp; + crypto::hash prev_id; + uint32_t nonce; + + BEGIN_SERIALIZE() + VARINT_FIELD(major_version) + VARINT_FIELD(minor_version) + VARINT_FIELD(timestamp) + FIELD(prev_id) + FIELD(nonce) + END_SERIALIZE() + }; + + struct block: public block_header + { + private: + // hash cash + mutable std::atomic hash_valid; + + public: + block(): block_header(), hash_valid(false) {} + block(const block &b): block_header(b), hash_valid(false), miner_tx(b.miner_tx), tx_hashes(b.tx_hashes) { if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } } + block &operator=(const block &b) { block_header::operator=(b); hash_valid = false; miner_tx = b.miner_tx; tx_hashes = b.tx_hashes; if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } return *this; } + void invalidate_hashes() { set_hash_valid(false); } + bool is_hash_valid() const { return hash_valid.load(std::memory_order_acquire); } + void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); } + + transaction miner_tx; + std::vector tx_hashes; + + // hash cash + mutable crypto::hash hash; + + BEGIN_SERIALIZE_OBJECT() + if (!typename Archive::is_saving()) + set_hash_valid(false); + + FIELDS(*static_cast(this)) + FIELD(miner_tx) + FIELD(tx_hashes) + END_SERIALIZE() + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ struct account_public_address { crypto::public_key m_spend_public_key; crypto::public_key m_view_public_key; - BEGIN_SERIALIZE_OBJECT() - FIELD(m_spend_public_key) - FIELD(m_view_public_key) - END_SERIALIZE() - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key) - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key) - END_KV_SERIALIZE_MAP() - + BEGIN_SERIALIZE_OBJECT() + FIELD(m_spend_public_key) + FIELD(m_view_public_key) + END_SERIALIZE() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key) + END_KV_SERIALIZE_MAP() + bool operator==(const account_public_address& rhs) const { return m_spend_public_key == rhs.m_spend_public_key && m_view_public_key == rhs.m_view_public_key; } + bool operator!=(const account_public_address& rhs) const { return !(*this == rhs); @@ -84,13 +429,14 @@ namespace cryptonote crypto::public_key pub; crypto::secret_key sec; -// static inline keypair generate(hw::device &hwdev) -// { -// keypair k; -// hwdev.generate_keys(k.pub, k.sec); -// return k; -// } + static inline keypair generate(hw::device &hwdev) + { + keypair k; + hwdev.generate_keys(k.pub, k.sec); + return k; + } }; + //--------------------------------------------------------------- } @@ -108,3 +454,36 @@ namespace std { } }; } + +BLOB_SERIALIZER(cryptonote::txout_to_key); +BLOB_SERIALIZER(cryptonote::txout_to_scripthash); + +VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff); +VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0); +VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1); +VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2); +VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0); +VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1); +VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2); +VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc); +VARIANT_TAG(binary_archive, cryptonote::block, 0xbb); + +VARIANT_TAG(json_archive, cryptonote::txin_gen, "gen"); +VARIANT_TAG(json_archive, cryptonote::txin_to_script, "script"); +VARIANT_TAG(json_archive, cryptonote::txin_to_scripthash, "scripthash"); +VARIANT_TAG(json_archive, cryptonote::txin_to_key, "key"); +VARIANT_TAG(json_archive, cryptonote::txout_to_script, "script"); +VARIANT_TAG(json_archive, cryptonote::txout_to_scripthash, "scripthash"); +VARIANT_TAG(json_archive, cryptonote::txout_to_key, "key"); +VARIANT_TAG(json_archive, cryptonote::transaction, "tx"); +VARIANT_TAG(json_archive, cryptonote::block, "block"); + +VARIANT_TAG(debug_archive, cryptonote::txin_gen, "gen"); +VARIANT_TAG(debug_archive, cryptonote::txin_to_script, "script"); +VARIANT_TAG(debug_archive, cryptonote::txin_to_scripthash, "scripthash"); +VARIANT_TAG(debug_archive, cryptonote::txin_to_key, "key"); +VARIANT_TAG(debug_archive, cryptonote::txout_to_script, "script"); +VARIANT_TAG(debug_archive, cryptonote::txout_to_scripthash, "scripthash"); +VARIANT_TAG(debug_archive, cryptonote::txout_to_key, "key"); +VARIANT_TAG(debug_archive, cryptonote::transaction, "tx"); +VARIANT_TAG(debug_archive, cryptonote::block, "block"); diff --git a/cryptonote_basic/cryptonote_basic_impl.cpp b/cryptonote_basic/cryptonote_basic_impl.cpp index 9be2b15..3a9bb29 100644 --- a/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/cryptonote_basic/cryptonote_basic_impl.cpp @@ -41,7 +41,7 @@ using namespace epee; #include "common/base58.h" #include "crypto/hash.h" #include "common/int-util.h" -// #include "common/dns_utils.h" +//#include "common/dns_utils.h" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" @@ -296,7 +296,7 @@ namespace cryptonote { return true; } -// //-------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------- // bool get_account_address_from_str_or_url( // address_parse_info& info // , network_type nettype diff --git a/cryptonote_basic/cryptonote_basic_impl.h b/cryptonote_basic/cryptonote_basic_impl.h index 81242a2..f597850 100644 --- a/cryptonote_basic/cryptonote_basic_impl.h +++ b/cryptonote_basic/cryptonote_basic_impl.h @@ -31,29 +31,50 @@ #pragma once #include "cryptonote_basic.h" -#include "crypto.h" -#include "hash.h" -#include "cryptonote_config.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" namespace cryptonote { + /************************************************************************/ + /* */ + /************************************************************************/ + template + struct array_hasher: std::unary_function + { + std::size_t operator()(const t_array& val) const + { + return boost::hash_range(&val.data[0], &val.data[sizeof(val.data)]); + } + }; + #pragma pack(push, 1) - struct public_address_outer_blob - { - uint8_t m_ver; - account_public_address m_address; - uint8_t check_sum; - }; - struct public_integrated_address_outer_blob - { - uint8_t m_ver; - account_public_address m_address; - crypto::hash8 payment_id; - uint8_t check_sum; - }; + struct public_address_outer_blob + { + uint8_t m_ver; + account_public_address m_address; + uint8_t check_sum; + }; + struct public_integrated_address_outer_blob + { + uint8_t m_ver; + account_public_address m_address; + crypto::hash8 payment_id; + uint8_t check_sum; + }; #pragma pack (pop) + namespace + { + inline std::string return_first_address(const std::string &url, const std::vector &addresses, bool dnssec_valid) + { + if (addresses.empty()) + return {}; + return addresses[0]; + } + } + struct address_parse_info { account_public_address address; @@ -62,23 +83,46 @@ namespace cryptonote { crypto::hash8 payment_id; }; - uint8_t get_account_address_checksum(const public_address_outer_blob& bl); - uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); + /************************************************************************/ + /* Cryptonote helper functions */ + /************************************************************************/ + size_t get_min_block_size(uint8_t version); + size_t get_max_block_size(); + size_t get_max_tx_size(); + bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); + uint8_t get_account_address_checksum(const public_address_outer_blob& bl); + uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl); - std::string get_account_integrated_address_as_str( - network_type nettype - , const account_public_address& adr - , const crypto::hash8& payment_id - ); - + std::string get_account_address_as_str( + network_type nettype + , bool subaddress + , const account_public_address& adr + ); + + std::string get_account_integrated_address_as_str( + network_type nettype + , const account_public_address& adr + , const crypto::hash8& payment_id + ); - bool get_account_address_from_str( address_parse_info& info , network_type nettype , const std::string& str ); + bool get_account_address_from_str_or_url( + address_parse_info& info + , network_type nettype + , const std::string& str_or_url + , std::function&, bool)> dns_confirm = return_first_address + ); + + bool is_coinbase(const transaction& tx); + + bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b); + bool operator ==(const cryptonote::block& a, const cryptonote::block& b); } +bool parse_hash256(const std::string str_hash, crypto::hash& hash);