this code is a hot mess of confusion with transfer_details and public_keys being scattered to the four winds. this code is NOT safe to use in its current format
This commit is contained in:
@@ -1074,6 +1074,8 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::BURN) {
|
||||
|
||||
/*
|
||||
// Conversion TX - update our records
|
||||
circ_supply cs;
|
||||
cs.tx_hash = tx_hash;
|
||||
@@ -1085,12 +1087,12 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
result = mdb_cursor_put(m_cur_circ_supply, &val_tx_id, &val_circ_supply, MDB_APPEND);
|
||||
if (result)
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx circulating supply to db transaction: ", result).c_str() ));
|
||||
|
||||
*/
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cs.asset_type);
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - cs.amount_burnt;
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - tx.amount_burnt;
|
||||
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
|
||||
if (source_tally == 0 && result == MDB_NOTFOUND) {
|
||||
if (tx.source_asset_type == "FULM") {
|
||||
@@ -1114,19 +1116,20 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
bool ok = cryptonote::get_output_asset_type(out, asset_type);
|
||||
if (!ok)
|
||||
throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)"));
|
||||
|
||||
/*
|
||||
circ_supply cs;
|
||||
cs.tx_hash = tx_hash;
|
||||
cs.asset_type = cryptonote::asset_id_from_type(asset_type);
|
||||
cs.amount_burnt = 0;
|
||||
cs.amount_minted = out.amount;
|
||||
|
||||
minted_amounts[cs.asset_type] += out.amount;
|
||||
|
||||
*/
|
||||
minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount;
|
||||
/*
|
||||
MDB_val_set(val_circ_supply, cs);
|
||||
result = mdb_cursor_put(m_cur_circ_supply, &val_tx_id, &val_circ_supply, MDB_APPEND);
|
||||
result = mdb_cursor_put(m_cur_circ_supply, &val_tx_id, &val_circ_supply, MDB_APPENDDUP);
|
||||
if (result)
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx circulating supply to db transaction: ", result).c_str() ));
|
||||
*/
|
||||
}
|
||||
|
||||
// Now update the overall tally entries
|
||||
@@ -1273,7 +1276,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before undoing mint =" << source_tally.str() << "\n\tTally after undoing mint =" << final_source_tally.str());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Update the circ_supply table by deleting all entries for this TX
|
||||
if ((result = mdb_cursor_get(m_cur_circ_supply, &val_tx_id, NULL, MDB_SET))) {
|
||||
if (result == MDB_NOTFOUND) {
|
||||
@@ -1286,6 +1289,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
if (result)
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of circulating supply to db transaction: ", result).c_str()));
|
||||
}
|
||||
*/
|
||||
remove_tx_outputs(tip->data.tx_id, tx);
|
||||
|
||||
result = mdb_cursor_get(m_cur_tx_outputs, &val_tx_id, NULL, MDB_SET);
|
||||
@@ -1818,6 +1822,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
mdb_set_compare(txn, m_properties, compare_string);
|
||||
|
||||
mdb_set_compare(txn, m_circ_supply, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_circ_supply, compare_uint64);
|
||||
mdb_set_compare(txn, m_circ_supply_tally, compare_uint64);
|
||||
|
||||
mdb_set_dupsort(txn, m_yield_txs, compare_uint64);
|
||||
|
||||
@@ -212,6 +212,7 @@ namespace crypto {
|
||||
tools::write_varint(end, output_index);
|
||||
assert(end <= buf.output_index + sizeof buf.output_index);
|
||||
hash_to_scalar(&buf, end - reinterpret_cast<char *>(&buf), res);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
bool crypto_ops::derive_public_key(const key_derivation &derivation, size_t output_index,
|
||||
|
||||
@@ -314,7 +314,7 @@ namespace cryptonote
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, uniqueness,hwdev);
|
||||
CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address");
|
||||
|
||||
return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, uniqueness, subaddr_recv_info->index, in_ephemeral, ki, hwdev);
|
||||
|
||||
@@ -99,6 +99,7 @@ namespace cryptonote
|
||||
crypto::key_derivation derivation;
|
||||
};
|
||||
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, const boost::optional<crypto::view_tag>& view_tag_opt = boost::optional<crypto::view_tag>());
|
||||
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, const crypto::hash& uniqueness, hw::device &hwdev, const boost::optional<crypto::view_tag>& view_tag_opt = boost::optional<crypto::view_tag>());
|
||||
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, const crypto::key_image& ki, hw::device &hwdev, const boost::optional<crypto::view_tag>& view_tag_opt = boost::optional<crypto::view_tag>());
|
||||
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_public_keys, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
|
||||
@@ -260,8 +260,8 @@ namespace config
|
||||
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10
|
||||
} }; // Bender's nightmare
|
||||
|
||||
std::string const GENESIS_TX = "023c01ff000180c09e90acbb1402ba4fcfcff0d4a91441c87615e514be3938e173179ac34a7fc98c0286e7320fdc0446554c4d3c0000000000000021019e809607ceda9ae7ae6755e05bcdc9c555acc8e95dcaede402eca1166a032e1a0100000000000000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
||||
//std::string const GENESIS_TX = "023c01ff000180c09e90acbb1402ba4fcfcff0d4a91441c87615e514be3938e173179ac34a7fc98c0286e7320fdc0446554c4d3c0000000000000021019e809607ceda9ae7ae6755e05bcdc9c555acc8e95dcaede402eca1166a032e1a0100000000000000000000000000000000000000000000000000000000000000000000000000";
|
||||
std::string const GENESIS_TX = "023c01ff000180c09e90acbb1402ae6cfc932cab508d92455942efbb2ec5a8632e33ff6bcac04a8e31be271efb8c0446554c4d3c0000000000000021015a71ac0441d4ee3f321df5ffd4bd3d0f04755152e7e6485a3b6c965356cb92ed0100000000000000000000000000000000000000000000000000000000000000000000000000";
|
||||
uint32_t const GENESIS_NONCE = 10000;
|
||||
|
||||
// Hash domain separators
|
||||
|
||||
@@ -1386,7 +1386,6 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height,
|
||||
return false;
|
||||
}
|
||||
MDEBUG("Miner tx hash: " << get_transaction_hash(b.miner_tx));
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.unlock_time == height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "coinbase transaction transaction has the wrong unlock time=" << b.miner_tx.unlock_time << ", expected " << height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
//check outs overflow
|
||||
if(!check_outs_overflow(b.miner_tx))
|
||||
@@ -2483,6 +2482,36 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA
|
||||
res.outs.clear();
|
||||
res.outs.reserve(req.outputs.size());
|
||||
|
||||
// if an asset type is provided in the request, most indexes provided in the request are asset type output id's.
|
||||
// need to use the asset type output id's provided to retrieve the respective global output id's
|
||||
std::map<uint64_t, uint64_t> global_outs_by_asset_type_output_id;
|
||||
if (!req.asset_type.empty())
|
||||
{
|
||||
std::vector<uint64_t> asset_type_output_indices;
|
||||
for (const auto &i: req.outputs)
|
||||
{
|
||||
// some inputs in the request have already been used in attempted rings in the past. These inputs will
|
||||
// have the is_global_out flag set to true, since they already have the global output id saved
|
||||
if (!i.is_global_out)
|
||||
asset_type_output_indices.push_back(i.index);
|
||||
}
|
||||
|
||||
std::vector<uint64_t> global_out_ids;
|
||||
global_out_ids.reserve(asset_type_output_indices.size());
|
||||
|
||||
m_db->get_output_id_from_asset_type_output_index(req.asset_type, asset_type_output_indices, global_out_ids);
|
||||
|
||||
uint64_t global_outs = 0;
|
||||
for (const auto &i: req.outputs)
|
||||
{
|
||||
if (!i.is_global_out)
|
||||
{
|
||||
global_outs_by_asset_type_output_id[i.index] = global_out_ids[global_outs];
|
||||
++global_outs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<cryptonote::output_data_t> data;
|
||||
try
|
||||
{
|
||||
@@ -2492,7 +2521,11 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA
|
||||
for (const auto &i: req.outputs)
|
||||
{
|
||||
amounts.push_back(i.amount);
|
||||
// if no asset type provided, the offsets provided are already global output id's unless specifically set
|
||||
if (req.asset_type.empty() || i.is_global_out)
|
||||
offsets.push_back(i.index);
|
||||
else
|
||||
offsets.push_back(global_outs_by_asset_type_output_id[i.index]);
|
||||
}
|
||||
m_db->get_output_key(epee::span<const uint64_t>(amounts.data(), amounts.size()), offsets, data);
|
||||
if (data.size() != req.outputs.size())
|
||||
@@ -2512,6 +2545,11 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA
|
||||
res.outs[i].txid = toi.first;
|
||||
}
|
||||
}
|
||||
if (!req.asset_type.empty())
|
||||
{
|
||||
for (size_t i = 0; i < req.outputs.size(); ++i)
|
||||
res.outs[i].output_id = offsets[i];
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
|
||||
@@ -316,7 +316,7 @@ namespace cryptonote
|
||||
tx.version = 2;
|
||||
|
||||
//lock
|
||||
tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
tx.unlock_time = 0;//height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
tx.vin.push_back(in);
|
||||
|
||||
tx.invalidate_hashes();
|
||||
@@ -436,7 +436,7 @@ namespace cryptonote
|
||||
} else {
|
||||
tx.version = 2;
|
||||
}
|
||||
tx.unlock_time = unlock_time;
|
||||
tx.unlock_time = 0;//unlock_time;
|
||||
|
||||
tx.extra = extra;
|
||||
crypto::public_key txkey_pub;
|
||||
@@ -552,7 +552,7 @@ namespace cryptonote
|
||||
crypto::hash uniqueness = cn_fast_hash(reinterpret_cast<void*>(&output_index_wrapper), sizeof(size_t));
|
||||
|
||||
const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
|
||||
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, uniqueness, in_ephemeral,img, hwdev))
|
||||
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, src_entr.uniqueness, in_ephemeral,img, hwdev))
|
||||
{
|
||||
LOG_ERROR("Key image generation failed!");
|
||||
return false;
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace cryptonote
|
||||
rct::multisig_kLRki multisig_kLRki; //multisig info
|
||||
oracle::pricing_record pr;
|
||||
std::string asset_type;
|
||||
crypto::hash uniqueness; //the uniqueness needed to prove ownership of the consumed output
|
||||
|
||||
void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); }
|
||||
|
||||
|
||||
@@ -847,6 +847,7 @@ namespace cryptonote
|
||||
cryptonote::COMMAND_RPC_GET_OUTPUTS_BIN::request req_bin;
|
||||
req_bin.outputs = req.outputs;
|
||||
req_bin.get_txid = req.get_txid;
|
||||
req_bin.asset_type = req.asset_type;
|
||||
cryptonote::COMMAND_RPC_GET_OUTPUTS_BIN::response res_bin;
|
||||
if(!m_core.get_outs(req_bin, res_bin))
|
||||
{
|
||||
|
||||
+127
-42
@@ -1799,6 +1799,7 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
|
||||
if(tx_scan_info.received)
|
||||
{
|
||||
tx_scan_info.money_transfered = o.amount; // may be 0 for ringct outputs
|
||||
tx_scan_info.uniqueness = cn_fast_hash(reinterpret_cast<void*>(&i), sizeof(size_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4126,6 +4127,7 @@ bool wallet2::clear()
|
||||
{
|
||||
m_blockchain.clear();
|
||||
m_transfers.clear();
|
||||
m_transfers_indices.clear();
|
||||
m_key_images.clear();
|
||||
m_pub_keys.clear();
|
||||
m_unconfirmed_txs.clear();
|
||||
@@ -4148,6 +4150,7 @@ void wallet2::clear_soft(bool keep_key_images)
|
||||
{
|
||||
m_blockchain.clear();
|
||||
m_transfers.clear();
|
||||
m_transfers_indices.clear();
|
||||
if (!keep_key_images)
|
||||
m_key_images.clear();
|
||||
m_pub_keys.clear();
|
||||
@@ -6585,21 +6588,9 @@ bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_heig
|
||||
if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
|
||||
{
|
||||
//interpret as block index
|
||||
if(get_blockchain_current_height()-1 + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS >= unlock_time)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
//interpret as time
|
||||
uint64_t adjusted_time;
|
||||
try { adjusted_time = get_daemon_adjusted_time(); }
|
||||
catch(...) { adjusted_time = time(NULL); } // use local time if no daemon to report blockchain time
|
||||
// XXX: this needs to be fast, so we'd need to get the starting heights
|
||||
// from the daemon to be correct once voting kicks in
|
||||
uint64_t v2height = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827;
|
||||
uint64_t leeway = block_height < v2height ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2;
|
||||
if(adjusted_time + leeway >= unlock_time)
|
||||
uint64_t min_unlock_blocks = CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
|
||||
uint64_t unlock_height = block_height + std::max(min_unlock_blocks, unlock_time);
|
||||
if(get_blockchain_current_height()-1 + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS >= unlock_height)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@@ -6853,7 +6844,7 @@ void wallet2::commit_tx(pending_tx& ptx)
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error,
|
||||
"Bad output index in selected transfers: " + boost::lexical_cast<std::string>(idx));
|
||||
THROW_WALLET_EXCEPTION_IF(m_transfers[idx].asset_type >= source_asset, error::wallet_internal_error,
|
||||
THROW_WALLET_EXCEPTION_IF(m_transfers[idx].asset_type != source_asset, error::wallet_internal_error,
|
||||
"Bad output asset_type in selected transfers: " + boost::lexical_cast<std::string>(idx));
|
||||
}
|
||||
}
|
||||
@@ -8449,6 +8440,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||
req_t.amounts.resize(std::distance(req_t.amounts.begin(), end));
|
||||
req_t.from_height = std::max<uint64_t>(segregation_fork_height, RECENT_OUTPUT_BLOCKS) - RECENT_OUTPUT_BLOCKS;
|
||||
req_t.to_height = segregation_fork_height + 1;
|
||||
req_t.rct_asset_type = rct_asset_type;
|
||||
req_t.cumulative = true;
|
||||
req_t.binary = true;
|
||||
|
||||
@@ -8836,6 +8828,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||
COMMAND_RPC_GET_OUTPUTS_BIN::request chunk_req = AUTO_VAL_INIT(chunk_req);
|
||||
COMMAND_RPC_GET_OUTPUTS_BIN::response chunk_daemon_resp = AUTO_VAL_INIT(chunk_daemon_resp);
|
||||
chunk_req.get_txid = false;
|
||||
chunk_req.asset_type = rct_asset_type;
|
||||
const size_t this_chunk_size = std::min<size_t>(req.outputs.size() - offset, chunk_size);
|
||||
chunk_req.outputs.reserve(this_chunk_size);
|
||||
for (size_t i = 0; i < this_chunk_size; ++i)
|
||||
@@ -8893,7 +8886,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||
for (size_t n = 0; n < requested_outputs_count; ++n)
|
||||
{
|
||||
size_t i = base + n;
|
||||
if (req.outputs[i].index == td.m_global_output_index)
|
||||
if (daemon_resp.outs[i].output_id == td.m_global_output_index)
|
||||
if (daemon_resp.outs[i].key == td.get_public_key())
|
||||
if (daemon_resp.outs[i].mask == mask)
|
||||
if (daemon_resp.outs[i].unlocked)
|
||||
@@ -9080,6 +9073,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||
src.real_output = it_to_replace - src.outputs.begin();
|
||||
src.real_output_in_tx_index = td.m_internal_output_index;
|
||||
src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()});
|
||||
|
||||
detail::print_source_entry(src);
|
||||
++out_index;
|
||||
}
|
||||
@@ -9298,6 +9292,42 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
src.amount = td.amount();
|
||||
src.rct = td.is_rct();
|
||||
src.asset_type = td.asset_type;
|
||||
|
||||
// check to see if the tx_source_entry was a payout from a protocol_tx
|
||||
if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
|
||||
// Parse the uniqueness from the originating TX key image
|
||||
crypto::public_key output_public_key = td.get_public_key();
|
||||
auto search = m_protocol_txs.find(output_public_key);
|
||||
THROW_WALLET_EXCEPTION_IF(search == m_protocol_txs.end(), error::wallet_internal_error, "failed to locate protocol_tx entry to permit source usage");
|
||||
size_t idx = search->second;
|
||||
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers");
|
||||
const transfer_details& td2 = get_transfer_details(idx);
|
||||
THROW_WALLET_EXCEPTION_IF(td2.m_tx.type != cryptonote::transaction_type::CONVERT && td2.m_tx.type != cryptonote::transaction_type::YIELD, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers");
|
||||
|
||||
// We now have access to the sorted tx.vin vector - we need the key_image from the first entry to decode the public_key
|
||||
THROW_WALLET_EXCEPTION_IF(td2.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "incorrect TX vin[0] type for protocol_tx origin in m_transfers");
|
||||
|
||||
const txin_to_key &in = boost::get<txin_to_key>(td2.m_tx.vin[0]);
|
||||
crypto::key_image ki = in.k_image;
|
||||
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(td2.m_tx);
|
||||
THROW_WALLET_EXCEPTION_IF(tx_pub_key == null_pkey, error::wallet_internal_error, "Tx pubkey was not found");
|
||||
|
||||
// Generate a derivation using the _correct_ TX pubkey
|
||||
crypto::key_derivation convert_tx_derivation;
|
||||
THROW_WALLET_EXCEPTION_IF(!generate_key_derivation(tx_pub_key, get_account().get_keys().m_view_secret_key, convert_tx_derivation), error::wallet_internal_error, "Failed to generate a derivation image");
|
||||
|
||||
// Derive a public key now, using the information we have
|
||||
crypto::hash uniqueness = cn_fast_hash(&ki.data[0], 32);
|
||||
crypto::public_key pk = crypto::null_pkey;
|
||||
THROW_WALLET_EXCEPTION_IF(!m_account.get_device().derive_public_key(convert_tx_derivation, uniqueness, get_account().get_keys().m_account_address.m_spend_public_key, pk), error::wallet_internal_error, "Failed to derive a public key given the necessary key image");
|
||||
THROW_WALLET_EXCEPTION_IF(pk != output_public_key, error::wallet_internal_error, "public key derived from CONVERT_TX uniqueness does not match");
|
||||
src.uniqueness = uniqueness;
|
||||
} else {
|
||||
size_t output_index_wrapper = td.m_internal_output_index;
|
||||
src.uniqueness = cn_fast_hash(reinterpret_cast<void*>(&output_index_wrapper), sizeof(size_t));
|
||||
}
|
||||
//paste mixin transaction
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(outs.size() < out_index + 1 , error::wallet_internal_error, "outs.size() < out_index + 1");
|
||||
@@ -9337,6 +9367,23 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
src.multisig_kLRki = {.k = {}, .L = {}, .R = {}, .ki = rct::ki2rct(td.m_key_image)};
|
||||
else
|
||||
src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()});
|
||||
|
||||
if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
|
||||
LOG_ERROR("****************************** TD IS FROM A PROTOCOL_TX ******************************");
|
||||
|
||||
// Get the necessary information from the originating CONVERT / YIELD tx
|
||||
auto search = m_protocol_txs.find(td.get_public_key());
|
||||
THROW_WALLET_EXCEPTION_IF(search == m_protocol_txs.end(), error::wallet_internal_error, "failed to locate protocol_tx entry to permit source usage");
|
||||
size_t idx = search->second;
|
||||
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers");
|
||||
const transfer_details& td2 = get_transfer_details(idx);
|
||||
THROW_WALLET_EXCEPTION_IF(td2.m_tx.type != cryptonote::transaction_type::CONVERT && td2.m_tx.type != cryptonote::transaction_type::YIELD, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers");
|
||||
real_oe.second.dest = rct::pk2rct(td2.get_public_key());
|
||||
src.real_out_tx_key = get_tx_pub_key_from_extra(td2.m_tx, td.m_pk_index);
|
||||
src.real_out_additional_tx_keys = get_additional_tx_pub_keys_from_extra(td2.m_tx);
|
||||
}
|
||||
|
||||
detail::print_source_entry(src);
|
||||
++out_index;
|
||||
}
|
||||
@@ -9346,6 +9393,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
std::vector<cryptonote::tx_destination_entry> splitted_dsts = dsts;
|
||||
cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
|
||||
change_dts.amount = found_money - needed_money;
|
||||
change_dts.asset_type = source_asset;
|
||||
change_dts.is_change = true;
|
||||
if (change_dts.amount == 0)
|
||||
{
|
||||
@@ -9549,15 +9597,21 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
LOG_PRINT_L2("transfer_selected_rct done");
|
||||
}
|
||||
|
||||
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices)
|
||||
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices, const std::string& asset_type)
|
||||
{
|
||||
std::vector<size_t> picks;
|
||||
float current_output_relatdness = 1.0f;
|
||||
|
||||
LOG_PRINT_L2("pick_preferred_rct_inputs: needed_money " << print_money(needed_money));
|
||||
LOG_PRINT_L2("pick_preferred_rct_inputs: needed_money " << print_money(needed_money) << " " << asset_type);
|
||||
|
||||
// Make sure we have transfer indices for the specified asset_type
|
||||
if (m_transfers_indices.count(asset_type) == 0) {
|
||||
LOG_ERROR("Failed to find list of indices for '" << asset_type << "' - aborting");
|
||||
return picks;
|
||||
}
|
||||
|
||||
// try to find a rct input of enough size
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
for (size_t& i: m_transfers_indices[asset_type])
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
if (!is_spent(td, false) && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
|
||||
@@ -9577,23 +9631,25 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
|
||||
// this could be made better by picking one of the outputs to be a small one, since those
|
||||
// are less useful since often below the needed money, so if one can be used in a pair,
|
||||
// it gets rid of it for the future
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
for (size_t i = 0; i < m_transfers_indices[asset_type].size(); i++)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
size_t idx = m_transfers_indices[asset_type][i];
|
||||
const transfer_details& td = m_transfers[idx];
|
||||
if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
|
||||
{
|
||||
if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below)
|
||||
{
|
||||
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
|
||||
MDEBUG("Ignoring output " << idx << " of amount " << print_money(td.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
|
||||
continue;
|
||||
}
|
||||
LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount()));
|
||||
for (size_t j = i + 1; j < m_transfers.size(); ++j)
|
||||
LOG_PRINT_L2("Considering input " << idx << ", " << print_money(td.amount()));
|
||||
for (size_t j = i + 1; j < m_transfers_indices[asset_type].size(); ++j)
|
||||
{
|
||||
const transfer_details& td2 = m_transfers[j];
|
||||
size_t idx2 = m_transfers_indices[asset_type][j];
|
||||
const transfer_details& td2 = m_transfers[idx2];
|
||||
if (td2.amount() > m_ignore_outputs_above || td2.amount() < m_ignore_outputs_below)
|
||||
{
|
||||
MDEBUG("Ignoring output " << j << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
|
||||
MDEBUG("Ignoring output " << idx2 << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
|
||||
continue;
|
||||
}
|
||||
if (!is_spent(td2, false) && !td2.m_frozen && !td2.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
|
||||
@@ -9602,7 +9658,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
|
||||
// already found. If the same, don't update, and oldest suitable outputs
|
||||
// will be used in preference.
|
||||
float relatedness = get_output_relatedness(td, td2);
|
||||
LOG_PRINT_L2(" with input " << j << ", " << print_money(td2.amount()) << ", relatedness " << relatedness);
|
||||
LOG_PRINT_L2(" with input " << idx2 << ", " << print_money(td2.amount()) << ", relatedness " << relatedness);
|
||||
if (relatedness < current_output_relatdness)
|
||||
{
|
||||
// reset the current picks with those, and return them directly
|
||||
@@ -9611,7 +9667,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
|
||||
picks.clear();
|
||||
picks.push_back(i);
|
||||
picks.push_back(j);
|
||||
LOG_PRINT_L0("we could use " << i << " and " << j);
|
||||
LOG_PRINT_L0("we could use " << idx << " and " << idx2);
|
||||
if (relatedness == 0.0f)
|
||||
return picks;
|
||||
current_output_relatdness = relatedness;
|
||||
@@ -9866,7 +9922,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(
|
||||
// gather all dust and non-dust outputs belonging to specified subaddresses
|
||||
size_t num_nondust_outputs = 0;
|
||||
size_t num_dust_outputs = 0;
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
|
||||
// Verify that we have outputs in our wallet for the correct asset_type
|
||||
THROW_WALLET_EXCEPTION_IF(!m_transfers_indices.count(source_asset), error::wallet_internal_error, "Cannot find outputs with correct asset_type to pay for TX");
|
||||
|
||||
for (size_t& i: m_transfers_indices[source_asset])
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
|
||||
@@ -9953,7 +10013,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(
|
||||
// this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which
|
||||
// will get us a known fee.
|
||||
uint64_t estimated_fee = estimate_fee(use_per_byte_fee, use_rct, 2, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags, base_fee, fee_quantization_mask);
|
||||
preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices);
|
||||
preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices, source_asset);
|
||||
if (!preferred_inputs.empty())
|
||||
{
|
||||
string s;
|
||||
@@ -10371,13 +10431,13 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
{
|
||||
std::vector<size_t> unused_transfers_indices;
|
||||
std::vector<size_t> unused_dust_indices;
|
||||
const bool use_rct = use_fork_rules(4, 0);
|
||||
|
||||
// determine threshold for fractional amount
|
||||
const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
|
||||
const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
|
||||
const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0);
|
||||
const bool clsag = use_fork_rules(get_clsag_fork(), 0);
|
||||
const bool use_per_byte_fee = true;
|
||||
const bool use_rct = true;
|
||||
const bool bulletproof = true;
|
||||
const bool bulletproof_plus = true;
|
||||
const bool clsag = true;
|
||||
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
|
||||
const uint64_t base_fee = get_base_fee(priority);
|
||||
const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags);
|
||||
@@ -10391,6 +10451,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
|
||||
std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr;
|
||||
|
||||
// Verify that we have outputs in our wallet for the correct asset_type
|
||||
THROW_WALLET_EXCEPTION_IF(!m_transfers_indices.count(asset_type), error::wallet_internal_error, "Cannot find outputs with correct asset_type to pay for TX");
|
||||
|
||||
// gather all dust and non-dust outputs of specified subaddress (if any) and below specified threshold (if any)
|
||||
bool fund_found = false;
|
||||
for (size_t& i: m_transfers_indices[asset_type])
|
||||
@@ -10446,6 +10509,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
|
||||
std::vector<size_t> unused_dust_indices;
|
||||
const bool use_rct = use_fork_rules(4, 0);
|
||||
std::string asset_type = "FULM";
|
||||
|
||||
// Verify that we have outputs in our wallet for the correct asset_type
|
||||
THROW_WALLET_EXCEPTION_IF(!m_transfers_indices.count(asset_type), error::wallet_internal_error, "Cannot find outputs with correct asset_type to pay for TX");
|
||||
|
||||
// find output with the given key image
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
@@ -10488,11 +10555,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit();
|
||||
std::vector<std::vector<get_outs_entry>> outs;
|
||||
|
||||
const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE);
|
||||
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
|
||||
const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
|
||||
const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0);
|
||||
const bool clsag = use_fork_rules(get_clsag_fork(), 0);
|
||||
const bool use_per_byte_fee = true;
|
||||
const bool use_rct = true;
|
||||
const bool bulletproof = true;
|
||||
const bool bulletproof_plus = true;
|
||||
const bool clsag = true;
|
||||
const rct::RCTConfig rct_config {
|
||||
rct::RangeProofPaddedBulletproof,
|
||||
bulletproof_plus ? 4 : 3
|
||||
@@ -11413,7 +11480,8 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
|
||||
else
|
||||
{
|
||||
crypto::secret_key scalar1;
|
||||
crypto::derivation_to_scalar(found_derivation, n, scalar1);
|
||||
crypto::hash uniqueness = cn_fast_hash(reinterpret_cast<void*>(&n), sizeof(size_t));
|
||||
crypto::derivation_to_scalar(found_derivation, uniqueness, scalar1);
|
||||
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
|
||||
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus);
|
||||
const rct::key C = tx.rct_signatures.outPk[n].mask;
|
||||
@@ -11503,6 +11571,7 @@ bool wallet2::is_out_to_acc(const cryptonote::account_public_address &address, c
|
||||
// first run quick check if output has matching view tag, otherwise output should not belong to account
|
||||
if (out_can_be_to_acc(view_tag_opt, derivation, output_index))
|
||||
{
|
||||
/*
|
||||
// if view tag match, run slower check deriving output pub key and comparing to expected
|
||||
r = crypto::derive_public_key(derivation, output_index, address.m_spend_public_key, derived_out_key);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key");
|
||||
@@ -11511,6 +11580,22 @@ bool wallet2::is_out_to_acc(const cryptonote::account_public_address &address, c
|
||||
found = true;
|
||||
found_derivation = derivation;
|
||||
}
|
||||
*/
|
||||
if (!found) {
|
||||
// SRCG: We KNOW it's a txin_to_key, so it's an RCT transaction, NOT a PROTOCOL transaction.
|
||||
// The uniqueness value will therefore ALWAYS be a hash of the output_index
|
||||
size_t output_index_wrapper = output_index;
|
||||
crypto::hash uniqueness = cn_fast_hash(reinterpret_cast<void*>(&output_index_wrapper), sizeof(size_t));
|
||||
|
||||
// if view tag match, run slower check deriving output pub key and comparing to expected
|
||||
r = crypto::derive_public_key(derivation, uniqueness, address.m_spend_public_key, derived_out_key);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key");
|
||||
if (out_key == derived_out_key)
|
||||
{
|
||||
found = true;
|
||||
found_derivation = derivation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !additional_derivations.empty())
|
||||
|
||||
@@ -602,7 +602,7 @@ private:
|
||||
};
|
||||
|
||||
typedef std::vector<transfer_details> transfer_container;
|
||||
typedef std::map<std::string, std::vector<size_t>> transfer_details_indices;
|
||||
typedef serializable_unordered_map<std::string, std::vector<size_t>> transfer_details_indices;
|
||||
typedef serializable_unordered_multimap<crypto::hash, payment_details> payment_container;
|
||||
|
||||
struct multisig_sig
|
||||
@@ -1265,6 +1265,7 @@ private:
|
||||
VERSION_FIELD(1)
|
||||
FIELD(m_blockchain)
|
||||
FIELD(m_transfers)
|
||||
FIELD(m_transfers_indices)
|
||||
FIELD(m_account_public_address)
|
||||
FIELD(m_key_images)
|
||||
FIELD(m_unconfirmed_txs)
|
||||
@@ -1733,7 +1734,7 @@ private:
|
||||
std::vector<uint64_t> get_unspent_amounts_vector(bool strict);
|
||||
uint64_t get_dynamic_base_fee_estimate();
|
||||
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
|
||||
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices);
|
||||
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices, const std::string& asset_type);
|
||||
void set_spent(size_t idx, uint64_t height);
|
||||
void set_unspent(size_t idx);
|
||||
bool is_spent(const transfer_details &td, bool strict = true) const;
|
||||
|
||||
Reference in New Issue
Block a user