initial implementation of multisig wallet / TX support

This commit is contained in:
Some Random Crypto Guy
2024-09-27 16:15:42 +01:00
parent 7abf28d87c
commit acb3af43f0
9 changed files with 321 additions and 85 deletions
+38 -17
View File
@@ -2750,9 +2750,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_asset_type(tx.vout[o], asset_type), error::wallet_internal_error, "failed to get output_asset_type");
m_transfers.push_back(transfer_details{});
if (m_transfers_indices.count(asset_type) == 0) {
m_transfers_indices[asset_type] = std::vector<size_t>{};
m_transfers_indices[asset_type] = std::set<size_t>{};
}
m_transfers_indices[asset_type].push_back(m_transfers.size()-1);
m_transfers_indices[asset_type].insert(m_transfers.size()-1);
transfer_details& td = m_transfers.back();
td.m_block_height = height;
td.m_internal_output_index = o;
@@ -8329,6 +8329,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
not multisig_tx_builder.init(
m_account.get_keys(),
ptx.construction_data.extra,
ptx.tx.type,
ptx.construction_data.unlock_time,
ptx.construction_data.subaddr_account,
ptx.construction_data.subaddr_indices,
@@ -10139,9 +10140,12 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
for (size_t idx: selected_transfers) {
subaddr_minor_indices.insert(m_transfers[idx].m_subaddr_index.minor);
}
// Store the TX type
tx.type = tx_type;
THROW_WALLET_EXCEPTION_IF(
not multisig_tx_builder.init(m_account.get_keys(),
extra,
tx_type,
unlock_time,
subaddr_account,
subaddr_minor_indices,
@@ -10320,7 +10324,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
}
// try to find a rct input of enough size
for (size_t& i: m_transfers_indices[asset_type])
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)
@@ -10340,25 +10344,28 @@ 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_indices[asset_type].size(); i++)
for (auto i=m_transfers_indices[asset_type].begin(); i!= m_transfers_indices[asset_type].end(); ++i)
{
size_t idx = m_transfers_indices[asset_type][i];
const transfer_details& td = m_transfers[i];
size_t idx = *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_indices[asset_type].size(); ++j)
LOG_PRINT_L2("Considering input " << idx << ", " << print_money(td.amount()));
if (i == m_transfers_indices[asset_type].end()) continue;
auto j = i;
std::advance(j, 1);
for (; j!=m_transfers_indices[asset_type].end(); ++j)
{
size_t idx2 = m_transfers_indices[asset_type][j];
size_t idx2 = *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)
@@ -10367,16 +10374,16 @@ 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
// if they're unrelated. If they are related, we'll end up returning
// them if we find nothing better
picks.clear();
picks.push_back(i);
picks.push_back(j);
LOG_PRINT_L0("we could use " << i << " and " << j);
picks.push_back(idx);
picks.push_back(idx2);
LOG_PRINT_L0("we could use " << idx << " and " << idx2);
if (relatedness == 0.0f)
return picks;
current_output_relatdness = relatedness;
@@ -10693,7 +10700,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// 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])
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)
@@ -14438,7 +14445,21 @@ crypto::key_image wallet2::get_multisig_composite_key_image(size_t n) const
for (const auto &info: td.m_multisig_info)
for (const auto &pki: info.m_partial_key_images)
pkis.push_back(pki);
bool r = multisig::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki);
// SRCG: work out if we have origin data to use
bool use_origin_data = false;
cryptonote::origin_data origin_tx_data;
if (td.m_td_origin_idx != (uint64_t)-1) {
// Flag to indicate this is a TX that uses a return_address
const transfer_details& td_origin = get_transfer_details(td.m_td_origin_idx);
origin_tx_data.tx_pub_key = get_tx_pub_key_from_extra(td_origin.m_tx);
origin_tx_data.output_index = td_origin.m_internal_output_index;
origin_tx_data.tx_type = td_origin.m_tx.type;
use_origin_data = true;
}
bool r = multisig::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki, use_origin_data, origin_tx_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
return ki;
}
+1 -1
View File
@@ -625,7 +625,7 @@ private:
};
typedef std::vector<transfer_details> transfer_container;
typedef serializable_unordered_map<std::string, std::vector<size_t>> transfer_details_indices;
typedef serializable_unordered_map<std::string, std::set<size_t>> transfer_details_indices;
typedef serializable_unordered_multimap<crypto::hash, payment_details> payment_container;
typedef std::set<uint32_t> unique_index_container;