aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/wallet2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/wallet2.cpp')
-rw-r--r--src/wallet/wallet2.cpp239
1 files changed, 211 insertions, 28 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 63b17e20f..6e38e5c38 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -226,7 +226,7 @@ struct options {
const command_line::arg_descriptor<std::string> tx_notify = { "tx-notify" , "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" , "" };
};
-void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file)
+void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file)
{
keys_file = file_path;
wallet_file = file_path;
@@ -238,6 +238,7 @@ void do_prepare_file_names(const std::string& file_path, std::string& keys_file,
{//provided wallet file name
keys_file += ".keys";
}
+ mms_file = file_path + ".mms";
}
uint64_t calculate_fee(uint64_t fee_per_kb, size_t bytes, uint64_t fee_multiplier)
@@ -330,6 +331,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
wallet->init(std::move(daemon_address), std::move(login), 0, false, *trusted_daemon);
boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir);
wallet->set_ring_database(ringdb_path.string());
+ wallet->get_message_store().set_options(vm);
wallet->device_name(device_name);
wallet->device_derivation_path(device_derivation_path);
@@ -892,6 +894,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_key_reuse_mitigation2(true),
m_segregation_height(0),
m_ignore_fractional_outputs(true),
+ m_track_uses(false),
m_is_initialized(false),
m_kdf_rounds(kdf_rounds),
is_old_file_format(false),
@@ -899,6 +902,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_multisig(false),
m_multisig_threshold(0),
m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex),
+ m_account_public_address{crypto::null_pkey, crypto::null_pkey},
m_subaddress_lookahead_major(SUBADDRESS_LOOKAHEAD_MAJOR),
m_subaddress_lookahead_minor(SUBADDRESS_LOOKAHEAD_MINOR),
m_light_wallet(false),
@@ -907,12 +911,15 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_light_wallet_connected(false),
m_light_wallet_balance(0),
m_light_wallet_unlocked_balance(0),
+ m_original_keys_available(false),
+ m_message_store(),
m_key_device_type(hw::device::device_type::SOFTWARE),
m_ring_history_saved(false),
m_ringdb(),
m_last_block_reward(0),
m_encrypt_keys_after_refresh(boost::none),
m_unattended(unattended),
+ m_devices_registered(false),
m_device_last_key_image_sync(0)
{
}
@@ -956,6 +963,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
command_line::add_arg(desc_params, opts.stagenet);
command_line::add_arg(desc_params, opts.shared_ringdb_dir);
command_line::add_arg(desc_params, opts.kdf_rounds);
+ mms::message_store::init_options(desc_params);
command_line::add_arg(desc_params, opts.hw_device);
command_line::add_arg(desc_params, opts.hw_device_derivation_path);
command_line::add_arg(desc_params, opts.tx_notify);
@@ -1441,8 +1449,9 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has
}
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data)
+void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
+ PERF_TIMER(process_new_transaction);
// In this function, tx (probably) only contains the base information
// (that is, the prunable stuff may or may not be included)
if (!miner_tx && !pool)
@@ -1679,6 +1688,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
if (!m_multisig && !m_watch_only)
m_key_images[td.m_key_image] = m_transfers.size()-1;
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
+ if (output_tracker_cache)
+ (*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = m_transfers.size() - 1;
if (m_multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@@ -1744,6 +1755,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_mask = rct::identity();
td.m_rct = false;
}
+ if (output_tracker_cache)
+ (*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = kit->second;
if (m_multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@@ -1775,11 +1788,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
if(in.type() != typeid(cryptonote::txin_to_key))
continue;
- auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
+ const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(in);
+ auto it = m_key_images.find(in_to_key.k_image);
if(it != m_key_images.end())
{
transfer_details& td = m_transfers[it->second];
- uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
+ uint64_t amount = in_to_key.amount;
if (amount > 0)
{
if(amount != td.amount())
@@ -1810,6 +1824,34 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
}
}
+
+ if (!pool && m_track_uses)
+ {
+ PERF_TIMER(track_uses);
+ const uint64_t amount = in_to_key.amount;
+ std::vector<uint64_t> offsets = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets);
+ if (output_tracker_cache)
+ {
+ for (uint64_t offset: offsets)
+ {
+ const std::map<std::pair<uint64_t, uint64_t>, size_t>::const_iterator i = output_tracker_cache->find(std::make_pair(amount, offset));
+ if (i != output_tracker_cache->end())
+ {
+ size_t idx = i->second;
+ THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Output tracker cache index out of range");
+ m_transfers[idx].m_uses.push_back(std::make_pair(height, txid));
+ }
+ }
+ }
+ else for (transfer_details &td: m_transfers)
+ {
+ if (amount != in_to_key.amount)
+ continue;
+ for (uint64_t offset: offsets)
+ if (offset == td.m_global_output_index)
+ td.m_uses.push_back(std::make_pair(height, txid));
+ }
+ }
}
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
@@ -1992,7 +2034,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
add_rings(tx);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset)
+void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
"block transactions=" + std::to_string(bche.txs.size()) +
@@ -2005,7 +2047,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
{
TIME_MEASURE_START(miner_tx_handle_time);
if (m_refresh_type != RefreshNoCoinbase)
- process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset]);
+ process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache);
++tx_cache_data_offset;
TIME_MEASURE_FINISH(miner_tx_handle_time);
@@ -2014,7 +2056,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx)
{
- process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++]);
+ process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache);
}
TIME_MEASURE_FINISH(txs_handle_time);
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
@@ -2112,7 +2154,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
hashes = std::move(res.m_block_ids);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added)
+void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
size_t current_index = start_height;
blocks_added = 0;
@@ -2151,7 +2193,6 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
const cryptonote::account_keys &keys = m_account.get_keys();
auto gender = [&](wallet2::is_out_data &iod) {
- boost::unique_lock<hw::device> hwdev_lock(hwdev);
if (!hwdev.generate_key_derivation(iod.pkey, keys.m_view_secret_key, iod.derivation))
{
MWARNING("Failed to generate key derivation from tx pubkey, skipping");
@@ -2160,12 +2201,16 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
}
};
- for (auto &slot: tx_cache_data)
+ for (size_t i = 0; i < tx_cache_data.size(); ++i)
{
- for (auto &iod: slot.primary)
- tpool.submit(&waiter, [&gender, &iod]() { gender(iod); }, true);
- for (auto &iod: slot.additional)
- tpool.submit(&waiter, [&gender, &iod]() { gender(iod); }, true);
+ tpool.submit(&waiter, [&hwdev, &gender, &tx_cache_data, i]() {
+ auto &slot = tx_cache_data[i];
+ boost::unique_lock<hw::device> hwdev_lock(hwdev);
+ for (auto &iod: slot.primary)
+ gender(iod);
+ for (auto &iod: slot.additional)
+ gender(iod);
+ }, true);
}
waiter.wait(&tpool);
@@ -2219,7 +2264,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
if(current_index >= m_blockchain.size())
{
- process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
+ process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
++blocks_added;
}
else if(bl_id != m_blockchain[current_index])
@@ -2231,7 +2276,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
string_tools::pod_to_hex(m_blockchain[current_index]));
detach_blockchain(current_index);
- process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
+ process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
}
else
{
@@ -2265,11 +2310,10 @@ void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks
THROW_WALLET_EXCEPTION_IF(prev_blocks.size() != prev_parsed_blocks.size(), error::wallet_internal_error, "size mismatch");
// prepend the last 3 blocks, should be enough to guard against a block or two's reorg
- std::vector<parsed_block>::const_reverse_iterator i = prev_parsed_blocks.rbegin();
- for (size_t n = 0; n < std::min((size_t)3, prev_parsed_blocks.size()); ++n)
+ auto s = std::next(prev_parsed_blocks.rbegin(), std::min((size_t)3, prev_parsed_blocks.size())).base();
+ for (; s != prev_parsed_blocks.end(); ++s)
{
- short_chain_history.push_front(i->hash);
- ++i;
+ short_chain_history.push_front(s->hash);
}
// pull the new blocks
@@ -2664,6 +2708,17 @@ bool wallet2::delete_address_book_row(std::size_t row_id) {
}
//----------------------------------------------------------------------------------------------------
+std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create_output_tracker_cache() const
+{
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> cache{new std::map<std::pair<uint64_t, uint64_t>, size_t>()};
+ for (size_t i = 0; i < m_transfers.size(); ++i)
+ {
+ const transfer_details &td = m_transfers[i];
+ (*cache)[std::make_pair(td.is_rct() ? 0 : td.amount(), td.m_global_output_index)] = i;
+ }
+ return cache;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
{
if(m_light_wallet) {
@@ -2710,6 +2765,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
std::vector<cryptonote::block_complete_entry> blocks;
std::vector<parsed_block> parsed_blocks;
bool refreshed = false;
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> output_tracker_cache;
// pull the first set of blocks
get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
@@ -2744,13 +2800,16 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
bool first = true;
while(m_run.load(std::memory_order_relaxed))
{
+ uint64_t next_blocks_start_height;
+ std::vector<cryptonote::block_complete_entry> next_blocks;
+ std::vector<parsed_block> next_parsed_blocks;
+ bool error;
try
{
// pull the next set of blocks while we're processing the current one
- uint64_t next_blocks_start_height;
- std::vector<cryptonote::block_complete_entry> next_blocks;
- std::vector<parsed_block> next_parsed_blocks;
- bool error = false;
+ error = false;
+ next_blocks.clear();
+ next_parsed_blocks.clear();
added_blocks = 0;
if (!first && blocks.empty())
{
@@ -2763,7 +2822,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
{
try
{
- process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks);
+ process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks, output_tracker_cache.get());
}
catch (const tools::error::out_of_hashchain_bounds_error&)
{
@@ -2788,6 +2847,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
start_height = stop_height;
throw std::runtime_error(""); // loop again
}
+ catch (const std::exception &e)
+ {
+ MERROR("Error parsing blocks: " << e.what());
+ error = true;
+ }
blocks_fetched += added_blocks;
}
waiter.wait(&tpool);
@@ -2806,6 +2870,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
throw std::runtime_error("proxy exception in refresh thread");
}
+ // if we've got at least 10 blocks to refresh, assume we're starting
+ // a long refresh, and setup a tracking output cache if we need to
+ if (m_track_uses && !output_tracker_cache && next_blocks.size() >= 10)
+ output_tracker_cache = create_output_tracker_cache();
+
// switch to the new blocks from the daemon
blocks_start_height = next_blocks_start_height;
blocks = std::move(next_blocks);
@@ -3178,12 +3247,18 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_ignore_fractional_outputs ? 1 : 0);
json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator());
+ value2.SetInt(m_track_uses ? 1 : 0);
+ json.AddMember("track_uses", value2, json.GetAllocator());
+
value2.SetUint(m_subaddress_lookahead_major);
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
value2.SetUint(m_subaddress_lookahead_minor);
json.AddMember("subaddress_lookahead_minor", value2, json.GetAllocator());
+ value2.SetInt(m_original_keys_available ? 1 : 0);
+ json.AddMember("original_keys_available", value2, json.GetAllocator());
+
value2.SetUint(1);
json.AddMember("encrypted_secret_keys", value2, json.GetAllocator());
@@ -3193,6 +3268,18 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value.SetString(m_device_derivation_path.c_str(), m_device_derivation_path.size());
json.AddMember("device_derivation_path", value, json.GetAllocator());
+ std::string original_address;
+ std::string original_view_secret_key;
+ if (m_original_keys_available)
+ {
+ original_address = get_account_address_as_str(m_nettype, false, m_original_address);
+ value.SetString(original_address.c_str(), original_address.length());
+ json.AddMember("original_address", value, json.GetAllocator());
+ original_view_secret_key = epee::string_tools::pod_to_hex(m_original_view_secret_key);
+ value.SetString(original_view_secret_key.c_str(), original_view_secret_key.length());
+ json.AddMember("original_view_secret_key", value, json.GetAllocator());
+ }
+
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -3309,8 +3396,10 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_key_reuse_mitigation2 = true;
m_segregation_height = 0;
m_ignore_fractional_outputs = true;
+ m_track_uses = false;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
+ m_original_keys_available = false;
m_device_name = "";
m_device_derivation_path = "";
m_key_device_type = hw::device::device_type::SOFTWARE;
@@ -3460,6 +3549,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregation_height = field_segregation_height;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true);
m_ignore_fractional_outputs = field_ignore_fractional_outputs;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false);
+ m_track_uses = field_track_uses;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
@@ -3483,6 +3574,35 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, device_derivation_path, std::string, String, false, std::string());
m_device_derivation_path = field_device_derivation_path;
+
+ if (json.HasMember("original_keys_available"))
+ {
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, original_keys_available, int, Int, false, false);
+ m_original_keys_available = field_original_keys_available;
+ if (m_original_keys_available)
+ {
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, original_address, std::string, String, true, std::string());
+ address_parse_info info;
+ bool ok = get_account_address_from_str(info, m_nettype, field_original_address);
+ if (!ok)
+ {
+ LOG_ERROR("Failed to parse original_address from JSON");
+ return false;
+ }
+ m_original_address = info.address;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, original_view_secret_key, std::string, String, true, std::string());
+ ok = epee::string_tools::hex_to_pod(field_original_view_secret_key, m_original_view_secret_key);
+ if (!ok)
+ {
+ LOG_ERROR("Failed to parse original_view_secret_key from JSON");
+ return false;
+ }
+ }
+ }
+ else
+ {
+ m_original_keys_available = false;
+ }
}
else
{
@@ -3809,6 +3929,10 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_key_device_type = hw::device::device_type::SOFTWARE;
setup_keys(password);
+ // Not possible to restore a multisig wallet that is able to activate the MMS
+ // (because the original keys are not (yet) part of the restore info)
+ m_original_keys_available = false;
+
create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
setup_new_blockchain();
@@ -3846,6 +3970,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
+ m_original_keys_available = false;
m_key_device_type = hw::device::device_type::SOFTWARE;
setup_keys(password);
@@ -3934,6 +4059,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
+ m_original_keys_available = false;
m_key_device_type = hw::device::device_type::SOFTWARE;
setup_keys(password);
@@ -3974,6 +4100,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
+ m_original_keys_available = false;
m_key_device_type = hw::device::device_type::SOFTWARE;
setup_keys(password);
@@ -4015,6 +4142,7 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
+ m_original_keys_available = false;
setup_keys(password);
m_device_name = device_name;
@@ -4127,6 +4255,15 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
m_multisig_derivations = derivations;
}
}
+
+ if (!m_original_keys_available)
+ {
+ // Save the original i.e. non-multisig keys so the MMS can continue to use them to encrypt and decrypt messages
+ // (making a wallet multisig overwrites those keys, see account_base::make_multisig)
+ m_original_address = m_account.get_keys().m_account_address;
+ m_original_view_secret_key = m_account.get_keys().m_view_secret_key;
+ m_original_keys_available = true;
+ }
clear();
MINFO("Creating view key...");
@@ -4560,8 +4697,8 @@ void wallet2::write_watch_only_wallet(const std::string& wallet_name, const epee
//----------------------------------------------------------------------------------------------------
void wallet2::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exists)
{
- std::string keys_file, wallet_file;
- do_prepare_file_names(file_path, keys_file, wallet_file);
+ std::string keys_file, wallet_file, mms_file;
+ do_prepare_file_names(file_path, keys_file, wallet_file, mms_file);
boost::system::error_code ignore;
keys_file_exists = boost::filesystem::exists(keys_file, ignore);
@@ -4615,7 +4752,7 @@ bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash&
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_file_names(const std::string& file_path)
{
- do_prepare_file_names(file_path, m_keys_file, m_wallet_file);
+ do_prepare_file_names(file_path, m_keys_file, m_wallet_file, m_mms_file);
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -4808,6 +4945,8 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
{
MERROR("Failed to save rings, will try again next time");
}
+
+ m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file);
}
//----------------------------------------------------------------------------------------------------
void wallet2::trim_hashchain()
@@ -4913,6 +5052,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
const std::string old_file = m_wallet_file;
const std::string old_keys_file = m_keys_file;
const std::string old_address_file = m_wallet_file + ".address.txt";
+ const std::string old_mms_file = m_mms_file;
// save keys to the new file
// if we here, main wallet file is saved and we only need to save keys and address files
@@ -4942,6 +5082,14 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
if (!r) {
LOG_ERROR("error removing file: " << old_address_file);
}
+ // remove old message store file
+ if (boost::filesystem::exists(old_mms_file))
+ {
+ r = boost::filesystem::remove(old_mms_file);
+ if (!r) {
+ LOG_ERROR("error removing file: " << old_mms_file);
+ }
+ }
} else {
// save to new file
#ifdef WIN32
@@ -4967,6 +5115,14 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
std::error_code e = tools::replace_file(new_file, m_wallet_file);
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
}
+
+ if (m_message_store.get_active())
+ {
+ // While the "m_message_store" object of course always exist, a file for the message
+ // store should only exist if the MMS is really active
+ m_message_store.write_to_file(get_multisig_wallet_state(), m_mms_file);
+ }
+
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::balance(uint32_t index_major) const
@@ -5181,6 +5337,10 @@ void wallet2::rescan_blockchain(bool hard, bool refresh)
m_transfers.clear();
m_key_images.clear();
m_pub_keys.clear();
+ m_unconfirmed_txs.clear();
+ m_payments.clear();
+ m_confirmed_txs.clear();
+ m_unconfirmed_payments.clear();
m_scanned_pool_txs[0].clear();
m_scanned_pool_txs[1].clear();
@@ -12027,6 +12187,29 @@ void wallet2::generate_genesis(cryptonote::block& b) const {
cryptonote::generate_genesis_block(b, get_config(m_nettype).GENESIS_TX, get_config(m_nettype).GENESIS_NONCE);
}
//----------------------------------------------------------------------------------------------------
+mms::multisig_wallet_state wallet2::get_multisig_wallet_state() const
+{
+ mms::multisig_wallet_state state;
+ state.nettype = m_nettype;
+ state.multisig = multisig(&state.multisig_is_ready);
+ state.has_multisig_partial_key_images = has_multisig_partial_key_images();
+ state.multisig_rounds_passed = m_multisig_rounds_passed;
+ state.num_transfer_details = m_transfers.size();
+ if (state.multisig)
+ {
+ THROW_WALLET_EXCEPTION_IF(!m_original_keys_available, error::wallet_internal_error, "MMS use not possible because own original Monero address not available");
+ state.address = m_original_address;
+ state.view_secret_key = m_original_view_secret_key;
+ }
+ else
+ {
+ state.address = m_account.get_keys().m_account_address;
+ state.view_secret_key = m_account.get_keys().m_view_secret_key;
+ }
+ state.mms_file=m_mms_file;
+ return state;
+}
+//----------------------------------------------------------------------------------------------------
wallet_device_callback * wallet2::get_device_callback()
{
if (!m_device_callback){