diff options
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 32 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.cpp | 14 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.h | 3 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_tx_utils.cpp | 35 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_tx_utils.h | 10 |
5 files changed, 62 insertions, 32 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 5f9db676c..0b6a3abf3 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1341,6 +1341,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: // one input, of type txin_gen, with height set to the block's height // correct miner tx unlock time // a non-overflowing tx amount (dubious necessity on this check) +// valid output types bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, uint8_t hf_version) { LOG_PRINT_L3("Blockchain::" << __func__); @@ -1369,6 +1370,8 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, return false; } + CHECK_AND_ASSERT_MES(check_output_types(b.miner_tx, hf_version), false, "miner transaction has invalid output type(s) in block " << get_block_hash(b)); + return true; } //------------------------------------------------------------------ @@ -3044,12 +3047,14 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context // from v4, forbid invalid pubkeys if (hf_version >= 4) { for (const auto &o: tx.vout) { - if (o.target.type() == typeid(txout_to_key)) { - const txout_to_key& out_to_key = boost::get<txout_to_key>(o.target); - if (!crypto::check_key(out_to_key.key)) { - tvc.m_invalid_output = true; - return false; - } + crypto::public_key output_public_key; + if (!get_output_public_key(o, output_public_key)) { + tvc.m_invalid_output = true; + return false; + } + if (!crypto::check_key(output_public_key)) { + tvc.m_invalid_output = true; + return false; } } } @@ -3166,6 +3171,13 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context } } + // from v15, require view tags on outputs + if (!check_output_types(tx, hf_version)) + { + tvc.m_invalid_output = true; + return false; + } + return true; } //------------------------------------------------------------------ @@ -3977,9 +3989,11 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons } // The original code includes a check for the output corresponding to this input - // to be a txout_to_key. This is removed, as the database does not store this info, - // but only txout_to_key outputs are stored in the DB in the first place, done in - // Blockchain*::add_output + // to be a txout_to_key. This is removed, as the database does not store this info. + // Only txout_to_key (and since HF_VERSION_VIEW_TAGS, txout_to_tagged_key) + // outputs are stored in the DB in the first place, done in Blockchain*::add_output. + // Additional type checks on outputs were also added via cryptonote::check_output_types + // and cryptonote::get_output_public_key (see Blockchain::check_tx_outputs). m_output_keys.push_back(rct::ctkey({rct::pk2rct(pubkey), commitment})); return true; diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 2d2b1cbcf..a78f5d673 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1177,7 +1177,8 @@ namespace cryptonote return false; } - if (!check_tx_inputs_ring_members_diff(tx)) + const uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version(); + if (!check_tx_inputs_ring_members_diff(tx, hf_version)) { MERROR_VER("tx uses duplicate ring members"); return false; @@ -1189,6 +1190,12 @@ namespace cryptonote return false; } + if (!check_output_types(tx, hf_version)) + { + MERROR_VER("tx does not use valid output type(s)"); + return false; + } + return true; } //----------------------------------------------------------------------------------------------- @@ -1295,10 +1302,9 @@ namespace cryptonote return true; } //----------------------------------------------------------------------------------------------- - bool core::check_tx_inputs_ring_members_diff(const transaction& tx) const + bool core::check_tx_inputs_ring_members_diff(const transaction& tx, const uint8_t hf_version) const { - const uint8_t version = m_blockchain_storage.get_current_hard_fork_version(); - if (version >= 6) + if (hf_version >= 6) { for(const auto& in: tx.vin) { diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 2e5248c5d..0b36730b6 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -1012,10 +1012,11 @@ namespace cryptonote * @brief verify that each ring uses distinct members * * @param tx the transaction to check + * @param hf_version the hard fork version rules to use * * @return false if any ring uses duplicate members, true otherwise */ - bool check_tx_inputs_ring_members_diff(const transaction& tx) const; + bool check_tx_inputs_ring_members_diff(const transaction& tx, const uint8_t hf_version) const; /** * @brief verify that each input key image in a transaction is in diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 76192be5d..1d2024a05 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -149,12 +149,17 @@ namespace cryptonote r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")"); - txout_to_key tk; - tk.key = out_eph_public_key; + uint64_t amount = out_amounts[no]; + summary_amounts += amount; + + bool use_view_tags = hard_fork_version >= HF_VERSION_VIEW_TAGS; + crypto::view_tag view_tag; + if (use_view_tags) + crypto::derive_view_tag(derivation, no, view_tag); tx_out out; - summary_amounts += out.amount = out_amounts[no]; - out.target = tk; + cryptonote::set_tx_out(amount, out_eph_public_key, use_view_tags, view_tag, out); + tx.vout.push_back(out); } @@ -198,7 +203,7 @@ namespace cryptonote return addr.m_view_public_key; } //--------------------------------------------------------------- - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, bool shuffle_outs) + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, bool shuffle_outs, bool use_view_tags) { hw::device &hwdev = sender_account_keys.get_device(); @@ -406,17 +411,16 @@ namespace cryptonote { CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount); crypto::public_key out_eph_public_key; + crypto::view_tag view_tag; hwdev.generate_output_ephemeral_keys(tx.version,sender_account_keys, txkey_pub, tx_key, dst_entr, change_addr, output_index, need_additional_txkeys, additional_tx_keys, - additional_tx_public_keys, amount_keys, out_eph_public_key); + additional_tx_public_keys, amount_keys, out_eph_public_key, + use_view_tags, view_tag); tx_out out; - out.amount = dst_entr.amount; - txout_to_key tk; - tk.key = out_eph_public_key; - out.target = tk; + cryptonote::set_tx_out(dst_entr.amount, out_eph_public_key, use_view_tags, view_tag, out); tx.vout.push_back(out); output_index++; summary_outs_money += dst_entr.amount; @@ -546,7 +550,9 @@ namespace cryptonote } for (size_t i = 0; i < tx.vout.size(); ++i) { - destinations.push_back(rct::pk2rct(boost::get<txout_to_key>(tx.vout[i].target).key)); + crypto::public_key output_public_key; + get_output_public_key(tx.vout[i], output_public_key); + destinations.push_back(rct::pk2rct(output_public_key)); outamounts.push_back(tx.vout[i].amount); amount_out += tx.vout[i].amount; } @@ -607,7 +613,7 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout) + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, bool use_view_tags) { hw::device &hwdev = sender_account_keys.get_device(); hwdev.open_tx(tx_key); @@ -627,7 +633,8 @@ namespace cryptonote } } - bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, msout); + bool shuffle_outs = true; + bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, msout, shuffle_outs, use_view_tags); hwdev.close_tx(); return r; } catch(...) { @@ -643,7 +650,7 @@ namespace cryptonote crypto::secret_key tx_key; std::vector<crypto::secret_key> additional_tx_keys; std::vector<tx_destination_entry> destinations_copy = destinations; - return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0}, NULL); + return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0}, NULL, false); } //--------------------------------------------------------------- bool generate_genesis_block( diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index be6a6d946..f4ffb98ff 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -119,21 +119,23 @@ namespace cryptonote //--------------------------------------------------------------- crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr); bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time); - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, rct::multisig_out *msout = NULL, bool shuffle_outs = true); - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, rct::multisig_out *msout = NULL); + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, rct::multisig_out *msout = NULL, bool shuffle_outs = true, bool use_view_tags = false); + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, rct::multisig_out *msout = NULL, bool use_view_tags = false); bool generate_output_ephemeral_keys(const size_t tx_version, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key, const cryptonote::tx_destination_entry &dst_entr, const boost::optional<cryptonote::account_public_address> &change_addr, const size_t output_index, const bool &need_additional_txkeys, const std::vector<crypto::secret_key> &additional_tx_keys, std::vector<crypto::public_key> &additional_tx_public_keys, std::vector<rct::key> &amount_keys, - crypto::public_key &out_eph_public_key) ; + crypto::public_key &out_eph_public_key, + const bool use_view_tags, crypto::view_tag &view_tag) ; bool generate_output_ephemeral_keys(const size_t tx_version, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key, const cryptonote::tx_destination_entry &dst_entr, const boost::optional<cryptonote::account_public_address> &change_addr, const size_t output_index, const bool &need_additional_txkeys, const std::vector<crypto::secret_key> &additional_tx_keys, std::vector<crypto::public_key> &additional_tx_public_keys, std::vector<rct::key> &amount_keys, - crypto::public_key &out_eph_public_key) ; + crypto::public_key &out_eph_public_key, + const bool use_view_tags, crypto::view_tag &view_tag) ; bool generate_genesis_block( block& bl |