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.cpp96
1 files changed, 66 insertions, 30 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 490c05ad3..3af449455 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -141,13 +141,15 @@ struct options {
const command_line::arg_descriptor<bool> testnet = {"testnet", tools::wallet2::tr("For testnet. Daemon must also be launched with --testnet flag"), false};
const command_line::arg_descriptor<bool> stagenet = {"stagenet", tools::wallet2::tr("For stagenet. Daemon must also be launched with --stagenet flag"), false};
const command_line::arg_descriptor<bool> restricted = {"restricted-rpc", tools::wallet2::tr("Restricts to view-only commands"), false};
- const command_line::arg_descriptor<std::string, false, true> shared_ringdb_dir = {
+ const command_line::arg_descriptor<std::string, false, true, 2> shared_ringdb_dir = {
"shared-ringdb-dir", tools::wallet2::tr("Set shared ring database path"),
get_default_ringdb_path(),
- testnet,
- [](bool testnet, bool defaulted, std::string val)->std::string {
- if (testnet)
+ {{ &testnet, &stagenet }},
+ [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string {
+ if (testnet_stagenet[0])
return (boost::filesystem::path(val) / "testnet").string();
+ else if (testnet_stagenet[1])
+ return (boost::filesystem::path(val) / "stagenet").string();
return val;
}
};
@@ -2421,7 +2423,7 @@ void wallet2::detach_blockchain(uint64_t height)
// size 1 2 3 4 5 6 7 8 9
// block 0 1 2 3 4 5 6 7 8
// C
- THROW_WALLET_EXCEPTION_IF(height <= m_checkpoints.get_max_height() && m_blockchain.size() > m_checkpoints.get_max_height(),
+ THROW_WALLET_EXCEPTION_IF(height < m_blockchain.offset() && m_blockchain.size() > m_blockchain.offset(),
error::wallet_internal_error, "Daemon claims reorg below last checkpoint");
size_t transfers_detached = 0;
@@ -2628,6 +2630,12 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetUint(m_segregation_height);
json.AddMember("segregation_height", 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());
+
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -2702,6 +2710,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregate_pre_fork_outputs = true;
m_key_reuse_mitigation2 = true;
m_segregation_height = 0;
+ m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
+ m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_key_on_device = false;
}
else if(json.IsObject())
@@ -2826,6 +2836,10 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_key_reuse_mitigation2 = field_key_reuse_mitigation2;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, segregation_height, int, Uint, false, 0);
m_segregation_height = field_segregation_height;
+ 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);
+ m_subaddress_lookahead_minor = field_subaddress_lookahead_minor;
}
else
{
@@ -2871,6 +2885,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password) const
* \param keys_file_name Keys file to verify password for
* \param password Password to verify
* \param no_spend_key If set = only verify view keys, otherwise also spend keys
+ * \param hwdev The hardware device to use
* \return true if password is correct
*
* for verification only
@@ -2921,9 +2936,10 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
/*!
* \brief Generates a wallet or restores one.
- * \param wallet_ Name of wallet file
- * \param password Password of wallet file
- * \param multisig_data The multisig restore info and keys
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param multisig_data The multisig restore info and keys
+ * \param create_address_file Whether to create an address file
*/
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const std::string& multisig_data, bool create_address_file)
@@ -3016,12 +3032,13 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
/*!
* \brief Generates a wallet or restores one.
- * \param wallet_ Name of wallet file
- * \param password Password of wallet file
- * \param recovery_param If it is a restore, the recovery key
- * \param recover Whether it is a restore
- * \param two_random Whether it is a non-deterministic wallet
- * \return The secret key of the generated wallet
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param recovery_param If it is a restore, the recovery key
+ * \param recover Whether it is a restore
+ * \param two_random Whether it is a non-deterministic wallet
+ * \param create_address_file Whether to create an address file
+ * \return The secret key of the generated wallet
*/
crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const crypto::secret_key& recovery_param, bool recover, bool two_random, bool create_address_file)
@@ -3117,9 +3134,11 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
/*!
* \brief Creates a watch only wallet from a public address and a view secret key.
-* \param wallet_ Name of wallet file
-* \param password Password of wallet file
-* \param viewkey view secret key
+* \param wallet_ Name of wallet file
+* \param password Password of wallet file
+* \param account_public_address The account's public address
+* \param viewkey view secret key
+* \param create_address_file Whether to create an address file
*/
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const cryptonote::account_public_address &account_public_address,
@@ -3166,10 +3185,12 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
/*!
* \brief Creates a wallet from a public address and a spend/view secret key pair.
-* \param wallet_ Name of wallet file
-* \param password Password of wallet file
-* \param spendkey spend secret key
-* \param viewkey view secret key
+* \param wallet_ Name of wallet file
+* \param password Password of wallet file
+* \param account_public_address The account's public address
+* \param spendkey spend secret key
+* \param viewkey view secret key
+* \param create_address_file Whether to create an address file
*/
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const cryptonote::account_public_address &account_public_address,
@@ -3616,8 +3637,9 @@ void wallet2::rewrite(const std::string& wallet_name, const epee::wipeable_strin
}
/*!
* \brief Writes to a file named based on the normal wallet (doesn't generate key, assumes it's already there)
- * \param wallet_name Base name of wallet file
- * \param password Password for wallet file
+ * \param wallet_name Base name of wallet file
+ * \param password Password for wallet file
+ * \param new_keys_filename [OUT] Name of new keys file
*/
void wallet2::write_watch_only_wallet(const std::string& wallet_name, const epee::wipeable_string& password, std::string &new_keys_filename)
{
@@ -3863,6 +3885,11 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
void wallet2::trim_hashchain()
{
uint64_t height = m_checkpoints.get_max_height();
+
+ for (const transfer_details &td: m_transfers)
+ if (td.m_block_height < height)
+ height = td.m_block_height;
+
if (!m_blockchain.empty() && m_blockchain.size() == m_blockchain.offset())
{
MINFO("Fixing empty hashchain");
@@ -4996,7 +5023,7 @@ bool wallet2::save_multisig_tx(const multisig_tx_set &txs, const std::string &fi
return epee::file_io_utils::save_string_to_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
-std::string wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector)
+wallet2::multisig_tx_set wallet2::make_multisig_tx_set(const std::vector<pending_tx>& ptx_vector) const
{
multisig_tx_set txs;
txs.m_ptx = ptx_vector;
@@ -5008,8 +5035,12 @@ std::string wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector)
}
txs.m_signers.insert(get_multisig_signer_public_key());
+ return txs;
+}
- return save_multisig_tx(txs);
+std::string wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector)
+{
+ return save_multisig_tx(make_multisig_tx_set(ptx_vector));
}
//----------------------------------------------------------------------------------------------------
bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename)
@@ -5138,7 +5169,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
rct::multisig_out msout = ptx.multisig_sigs.front().msout;
auto sources = sd.sources;
const bool bulletproof = sd.use_rct && (ptx.tx.rct_signatures.type == rct::RCTTypeFullBulletproof || ptx.tx.rct_signatures.type == rct::RCTTypeSimpleBulletproof);
- bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, bulletproof, &msout);
+ bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, bulletproof, &msout, false);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
THROW_WALLET_EXCEPTION_IF(get_transaction_prefix_hash (tx) != get_transaction_prefix_hash(ptx.tx),
@@ -5893,9 +5924,10 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
auto end = std::unique(req_t.amounts.begin(), req_t.amounts.end());
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.cumulative = true;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout * 1000);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_distribution");
@@ -5912,6 +5944,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{
THROW_WALLET_EXCEPTION_IF(d.start_height > segregation_fork_height, error::get_output_distribution, "Distribution start_height too high");
THROW_WALLET_EXCEPTION_IF(segregation_fork_height - d.start_height >= d.distribution.size(), error::get_output_distribution, "Distribution size too small");
+ THROW_WALLET_EXCEPTION_IF(segregation_fork_height - RECENT_OUTPUT_BLOCKS - d.start_height >= d.distribution.size(), error::get_output_distribution, "Distribution size too small");
THROW_WALLET_EXCEPTION_IF(segregation_fork_height <= RECENT_OUTPUT_BLOCKS, error::wallet_internal_error, "Fork height too low");
THROW_WALLET_EXCEPTION_IF(segregation_fork_height - RECENT_OUTPUT_BLOCKS < d.start_height, error::get_output_distribution, "Bad start height");
uint64_t till_fork = d.distribution[segregation_fork_height - d.start_height];
@@ -6651,7 +6684,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
LOG_PRINT_L2("Creating supplementary multisig transaction");
cryptonote::transaction ms_tx;
auto sources_copy_copy = sources_copy;
- bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources_copy_copy, splitted_dsts, change_dts.addr, extra, ms_tx, unlock_time,tx_key, additional_tx_keys, true, bulletproof, &msout);
+ bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources_copy_copy, splitted_dsts, change_dts.addr, extra, ms_tx, unlock_time,tx_key, additional_tx_keys, true, bulletproof, &msout, false);
LOG_PRINT_L2("constructed tx, r="<<r);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype);
THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
@@ -8123,6 +8156,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
req_t.min_count = count;
req_t.max_count = 0;
req_t.unlocked = unlocked;
+ req_t.recent_cutoff = 0;
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_outputs_from_histogram");
@@ -8159,6 +8193,8 @@ uint64_t wallet2::get_num_rct_outputs()
req_t.amounts.push_back(0);
req_t.min_count = 0;
req_t.max_count = 0;
+ req_t.unlocked = true;
+ req_t.recent_cutoff = 0;
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_num_rct_outputs");
@@ -8179,14 +8215,14 @@ const wallet2::transfer_details &wallet2::get_transfer_details(size_t idx) const
std::vector<size_t> wallet2::select_available_unmixable_outputs(bool trusted_daemon)
{
// request all outputs with less than 3 instances
- const size_t min_mixin = use_fork_rules(6, 10) ? 4 : 2; // v6 increases min mixin from 2 to 4
+ const size_t min_mixin = use_fork_rules(7, 10) ? 6 : use_fork_rules(6, 10) ? 4 : 2; // v6 increases min mixin from 2 to 4, v7 to 6
return select_available_outputs_from_histogram(min_mixin + 1, false, true, false, trusted_daemon);
}
//----------------------------------------------------------------------------------------------------
std::vector<size_t> wallet2::select_available_mixable_outputs(bool trusted_daemon)
{
// request all outputs with at least 3 instances, so we can use mixin 2 with
- const size_t min_mixin = use_fork_rules(6, 10) ? 4 : 2; // v6 increases min mixin from 2 to 4
+ const size_t min_mixin = use_fork_rules(7, 10) ? 6 : use_fork_rules(6, 10) ? 4 : 2; // v6 increases min mixin from 2 to 4, v7 to 6
return select_available_outputs_from_histogram(min_mixin + 1, true, true, true, trusted_daemon);
}
//----------------------------------------------------------------------------------------------------