diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 61641fb..a8a256e 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -49,12 +49,16 @@ namespace crypto { ec_scalar c, r; friend class crypto_ops; }; + + POD_CLASS view_tag { + char data; + }; #pragma pack(pop) static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 && sizeof(public_key) == 32 && sizeof(secret_key) == 32 && sizeof(key_derivation) == 32 && sizeof(key_image) == 32 && - sizeof(signature) == 64, "Invalid structure size"); + sizeof(signature) == 64 && sizeof(view_tag) == 1, "Invalid structure size"); class crypto_ops { crypto_ops(); @@ -184,3 +188,4 @@ namespace crypto { CRYPTO_MAKE_COMPARABLE(public_key) CRYPTO_MAKE_HASHABLE(key_image) CRYPTO_MAKE_COMPARABLE(signature) +CRYPTO_MAKE_COMPARABLE(view_tag) diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index 9a30fe5..d3a88bf 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -65,6 +65,7 @@ namespace cryptonote crypto::hash hash; }; + // outputs <= HF_VERSION_VIEW_TAGS struct txout_to_key { txout_to_key() { } @@ -72,6 +73,20 @@ namespace cryptonote crypto::public_key key; }; + // outputs >= HF_VERSION_VIEW_TAGS + struct txout_to_tagged_key + { + txout_to_tagged_key() { } + txout_to_tagged_key(const crypto::public_key &_key, const crypto::view_tag &_view_tag) : key(_key), view_tag(_view_tag) { } + crypto::public_key key; + crypto::view_tag view_tag; // optimization to reduce scanning time + + BEGIN_SERIALIZE_OBJECT() + FIELD(key) + FIELD(view_tag) + END_SERIALIZE() + }; + struct txout_offshore { txout_offshore() { } @@ -187,9 +202,9 @@ namespace cryptonote typedef boost::variant txin_v; - typedef boost::variant txout_target_v; + typedef boost::variant txout_target_v; + typedef boost::variant txout_xhv_target_v; - //typedef std::pair out_t; struct tx_out { uint64_t amount; @@ -201,6 +216,18 @@ namespace cryptonote END_SERIALIZE() }; + struct tx_out_xhv + { + uint64_t amount; + txout_xhv_target_v target; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(amount) + FIELD(target) + END_SERIALIZE() + }; + + enum loki_version { loki_version_0 = 0, @@ -221,6 +248,7 @@ namespace cryptonote std::vector vin; std::vector vout; + std::vector vout_xhv; //extra std::vector extra; // Block height to use PR from @@ -259,7 +287,10 @@ namespace cryptonote if (blob_type != BLOB_TYPE_CRYPTONOTE_XHV || version < POU_TRANSACTION_VERSION) VARINT_FIELD(unlock_time) FIELD(vin) - FIELD(vout) + if (blob_type != BLOB_TYPE_CRYPTONOTE_XHV) + FIELD(vout) + else + FIELD(vout_xhv) if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC) { if (version >= loki_version_3_per_output_unlock_times && vout.size() != output_unlock_times.size()) return false; @@ -278,7 +309,7 @@ namespace cryptonote { FIELD(output_unlock_times) } - if (version >= POU_TRANSACTION_VERSION && vout.size() != output_unlock_times.size()) return false; + if (version >= POU_TRANSACTION_VERSION && vout_xhv.size() != output_unlock_times.size()) return false; VARINT_FIELD(amount_burnt) VARINT_FIELD(amount_minted) } @@ -339,7 +370,7 @@ namespace cryptonote if (!vin.empty()) { ar.begin_object(); - bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); + bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? vout.size() : vout_xhv.size()); if (!r || !ar.stream().good()) return false; ar.end_object(); if (rct_signatures.type != rct::RCTTypeNull) @@ -350,7 +381,7 @@ namespace cryptonote r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(), vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); } else { - r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(), + r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout_xhv.size(), vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : vin.size() > 0 && vin[0].type() == typeid(txin_offshore) ? boost::get(vin[0]).key_offsets.size() - 1 : vin.size() > 0 && vin[0].type() == typeid(txin_onshore) ? boost::get(vin[0]).key_offsets.size() - 1 : @@ -387,6 +418,7 @@ namespace cryptonote unlock_time = 0; vin.clear(); vout.clear(); + vout_xhv.clear(); extra.clear(); signatures.clear(); pricing_record_height = 0; @@ -652,6 +684,7 @@ VARIANT_TAG(binary_archive, cryptonote::txin_xasset, 0x5); 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::txout_to_tagged_key, 0x3); VARIANT_TAG(binary_archive, cryptonote::txout_offshore, 0x3); VARIANT_TAG(binary_archive, cryptonote::txout_xasset, 0x5); VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc); diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 81e5fe3..44dfa62 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -56,86 +56,6 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki) - { - crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); - bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation); - CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); - - r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub); - CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spend_public_key << ")"); - - crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, in_ephemeral.sec); - - crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); - return true; - } - //--------------------------------------------------------------- - uint64_t power_integral(uint64_t a, uint64_t b) - { - if(b == 0) - return 1; - uint64_t total = a; - for(uint64_t i = 1; i != b; i++) - total *= a; - return total; - } - //--------------------------------------------------------------- - bool get_tx_fee(const transaction& tx, uint64_t & fee) - { - uint64_t amount_in = 0; - uint64_t amount_out = 0; - if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV) - { - // This is the correct way to get the fee for Haven, because outs may be in different currencies to ins - switch (tx.version) { - case 6: - case 5: - fee = tx.rct_signatures.txnFee + tx.rct_signatures.txnOffshoreFee; - break; - case 4: - case 3: - if (tx.vin[0].type() == typeid(txin_to_key)) { - fee = tx.rct_signatures.txnFee + tx.rct_signatures.txnOffshoreFee; - } else if (tx.vin[0].type() == typeid(txin_offshore)) { - fee = tx.rct_signatures.txnFee_usd + tx.rct_signatures.txnOffshoreFee_usd; - } else if (tx.vin[0].type() == typeid(txin_onshore)) { - fee = tx.rct_signatures.txnFee_usd + tx.rct_signatures.txnOffshoreFee_usd; - } else if (tx.vin[0].type() == typeid(txin_xasset)) { - fee = tx.rct_signatures.txnFee_xasset + tx.rct_signatures.txnOffshoreFee_xasset; - } else { - CHECK_AND_ASSERT_MES(false, false, "unexpected type id in transaction"); - return false; - } - break; - case 2: - case 1: - fee = tx.rct_signatures.txnFee; - break; - } - return true; - } - BOOST_FOREACH(auto& in, tx.vin) - { - CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), 0, "unexpected type id in transaction"); - amount_in += boost::get(in).amount; - } - BOOST_FOREACH(auto& o, tx.vout) - amount_out += o.amount; - - CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" <& tx_extra, std::vector& tx_extra_fields) { tx_extra_fields.clear(); @@ -280,121 +200,6 @@ namespace cryptonote } return true; } - //----------------------------------------------------------------------------------------------- - bool check_outs_valid(const transaction& tx) - { - if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.version >= POU_TRANSACTION_VERSION) - { - CHECK_AND_ASSERT_MES(tx.vout.size() == tx.output_unlock_times.size(), false, "tx version 6+ must have equal number of output unlock times and outputs"); - } - BOOST_FOREACH(const tx_out& out, tx.vout) - { - if (tx.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) { - CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key), false, "wrong variant type: " - << out.target.type().name() << ", expected " << typeid(txout_to_key).name() - << ", in transaction id=" << get_transaction_hash(tx)); - } else { - CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key) || - out.target.type() == typeid(txout_offshore) || - out.target.type() == typeid(txout_xasset), false, "wrong variant type: " - << out.target.type().name() << ", expected " << typeid(txout_to_key).name() - << "or " << typeid(txout_offshore).name() - << "or " << typeid(txout_xasset).name() - << ", in transaction id=" << get_transaction_hash(tx)); - } - - if (tx.version == 1) - { - CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount ouput in transaction id=" << get_transaction_hash(tx)); - } - - if (tx.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) { - if(!check_key(boost::get(out.target).key)) - return false; - } else { - if(!check_key(out.target.type() == typeid(txout_to_key) ? boost::get(out.target).key : - out.target.type() == typeid(txout_offshore) ? boost::get(out.target).key : - boost::get(out.target).key)) - return false; - } - } - return true; - } - //----------------------------------------------------------------------------------------------- - bool check_money_overflow(const transaction& tx) - { - return check_inputs_overflow(tx) && check_outs_overflow(tx); - } - //--------------------------------------------------------------- - bool check_inputs_overflow(const transaction& tx) - { - uint64_t money = 0; - BOOST_FOREACH(const auto& in, tx.vin) - { - if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_xasset)) { - CHECKED_GET_SPECIFIC_VARIANT(in, const txin_xasset, tokey_in, false); - if(money > tokey_in.amount + money) - return false; - money += tokey_in.amount; - } else if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_offshore)) { - CHECKED_GET_SPECIFIC_VARIANT(in, const txin_offshore, tokey_in, false); - if(money > tokey_in.amount + money) - return false; - money += tokey_in.amount; - } else if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_onshore)) { - CHECKED_GET_SPECIFIC_VARIANT(in, const txin_onshore, tokey_in, false); - if(money > tokey_in.amount + money) - return false; - money += tokey_in.amount; - } else { - CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); - if(money > tokey_in.amount + money) - return false; - money += tokey_in.amount; - } - } - return true; - } - //--------------------------------------------------------------- - bool check_outs_overflow(const transaction& tx) - { - uint64_t money = 0; - BOOST_FOREACH(const auto& o, tx.vout) - { - if(money > o.amount + money) - return false; - money += o.amount; - } - return true; - } - /* - //--------------------------------------------------------------- - uint64_t get_outs_money_amount(const transaction& tx) - { - uint64_t outputs_amount = 0; - BOOST_FOREACH(const auto& o, tx.vout) - outputs_amount += o.amount; - return outputs_amount; - } - */ - //--------------------------------------------------------------- - std::map get_outs_money_amount(const transaction& tx) - { - std::map outputs_amount; - for(const auto& o: tx.vout) { - std::string asset_type; - if (o.target.type() == typeid(txout_offshore)) { - asset_type = "XUSD"; - } else if (o.target.type() == typeid(txout_xasset)) {; - asset_type = boost::get(o.target).asset_type; - } else { - // this close covers miner tx and normal XHV ouputs. - asset_type = "XHV"; - } - outputs_amount[asset_type] += o.amount; - } - return outputs_amount; - } //--------------------------------------------------------------- std::string short_hash_str(const crypto::hash& h) { @@ -405,40 +210,6 @@ namespace cryptonote return res; } //--------------------------------------------------------------- - bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index) - { - crypto::key_derivation derivation; - generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation); - crypto::public_key pk; - derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk); - return pk == out_key.key; - } - //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered) - { - crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); - if(null_pkey == tx_pub_key) - return false; - return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered); - } - //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered) - { - money_transfered = 0; - size_t i = 0; - BOOST_FOREACH(const tx_out& o, tx.vout) - { - CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" ); - if(is_out_to_acc(acc, boost::get(o.target), tx_pub_key, i)) - { - outs.push_back(i); - money_transfered += o.amount; - } - i++; - } - return true; - } - //--------------------------------------------------------------- void get_blob_hash(const blobdata& blob, crypto::hash& res) { cn_fast_hash(blob.data(), blob.size(), res); @@ -488,7 +259,7 @@ namespace cryptonote std::stringstream ss; binary_archive ba(ss); const size_t inputs = t.vin.size(); - const size_t outputs = t.vout.size(); + const size_t outputs = t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? t.vout.size() : t.vout_xhv.size(); bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs); CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures base"); cryptonote::get_blob_hash(ss.str(), hashes[1]); @@ -504,7 +275,7 @@ namespace cryptonote std::stringstream ss; binary_archive ba(ss); const size_t inputs = t.vin.size(); - const size_t outputs = t.vout.size(); + const size_t outputs = t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? t.vout.size() : t.vout_xhv.size(); size_t mixin; if (t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) { mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get(t.vin[0]).key_offsets.size() - 1 : 0; diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 6ac24b9..fa86540 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -63,12 +63,6 @@ namespace cryptonote bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); bool append_mm_tag_to_extra(std::vector& tx_extra, const tx_extra_merge_mining_tag& mm_tag); bool get_mm_tag_from_extra(const std::vector& tx_extra, tx_extra_merge_mining_tag& mm_tag); - bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered); - bool get_tx_fee(const transaction& tx, uint64_t & fee); - uint64_t get_tx_fee(const transaction& tx); - bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki); void get_blob_hash(const blobdata& blob, crypto::hash& res); crypto::hash get_blob_hash(const blobdata& blob); std::string short_hash_str(const crypto::hash& h); @@ -85,14 +79,10 @@ namespace cryptonote bool get_bytecoin_block_longhash(const block& blk, crypto::hash& res); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); bool get_inputs_money_amount(const transaction& tx, uint64_t& money); - //uint64_t get_outs_money_amount(const transaction& tx); std::map get_outs_money_amount(const transaction& tx); bool check_inputs_types_supported(const transaction& tx); bool check_outs_valid(const transaction& tx); - bool check_money_overflow(const transaction& tx); - bool check_outs_overflow(const transaction& tx); - bool check_inputs_overflow(const transaction& tx); uint64_t get_block_height(const block& b); std::vector relative_output_offsets_to_absolute(const std::vector& off); std::vector absolute_output_offsets_to_relative(const std::vector& off); diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index 178725b..6fa5479 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -61,3 +61,4 @@ BLOB_SERIALIZER(crypto::secret_key); BLOB_SERIALIZER(crypto::key_derivation); BLOB_SERIALIZER(crypto::key_image); BLOB_SERIALIZER(crypto::signature); +BLOB_SERIALIZER(crypto::view_tag);