mirror of
https://github.com/monero-project/monero.git
synced 2024-12-04 23:51:08 +02:00
Merge pull request #8619
e71c8bf
wallet: background sync with just the view key (j-berman)
This commit is contained in:
commit
d7eece3cae
@ -152,6 +152,17 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
m_keys.m_multisig_keys.clear();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::set_spend_key(const crypto::secret_key& spend_secret_key)
|
||||
{
|
||||
// make sure derived spend public key matches saved public spend key
|
||||
crypto::public_key spend_public_key;
|
||||
crypto::secret_key_to_public_key(spend_secret_key, spend_public_key);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_keys.m_account_address.m_spend_public_key == spend_public_key,
|
||||
"Unexpected derived public spend key");
|
||||
|
||||
m_keys.m_spend_secret_key = spend_secret_key;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
|
||||
{
|
||||
crypto::secret_key first = generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, recovery_key, recover);
|
||||
|
@ -95,6 +95,7 @@ namespace cryptonote
|
||||
bool store(const std::string& file_path);
|
||||
|
||||
void forget_spend_key();
|
||||
void set_spend_key(const crypto::secret_key& spend_secret_key);
|
||||
const std::vector<crypto::secret_key> &get_multisig_keys() const { return m_keys.m_multisig_keys; }
|
||||
|
||||
void encrypt_keys(const crypto::chacha_key &key) { m_keys.encrypt(key); }
|
||||
|
@ -241,6 +241,8 @@ namespace config
|
||||
const unsigned char HASH_KEY_ENCRYPTED_PAYMENT_ID = 0x8d;
|
||||
const unsigned char HASH_KEY_WALLET = 0x8c;
|
||||
const unsigned char HASH_KEY_WALLET_CACHE = 0x8d;
|
||||
const unsigned char HASH_KEY_BACKGROUND_CACHE = 0x8e;
|
||||
const unsigned char HASH_KEY_BACKGROUND_KEYS_FILE = 0x8f;
|
||||
const unsigned char HASH_KEY_RPC_PAYMENT_NONCE = 0x58;
|
||||
const unsigned char HASH_KEY_MEMORY = 'k';
|
||||
const unsigned char HASH_KEY_MULTISIG[] = {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
@ -148,6 +148,17 @@ typedef cryptonote::simple_wallet sw;
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CHECK_IF_BACKGROUND_SYNCING(msg) \
|
||||
do \
|
||||
{ \
|
||||
if (m_wallet->is_background_wallet() || m_wallet->is_background_syncing()) \
|
||||
{ \
|
||||
std::string type = m_wallet->is_background_wallet() ? "background wallet" : "background syncing wallet"; \
|
||||
fail_msg_writer() << boost::format(tr("%s %s")) % type % msg; \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static std::string get_human_readable_timespan(std::chrono::seconds seconds);
|
||||
static std::string get_human_readable_timespan(uint64_t seconds);
|
||||
|
||||
@ -314,7 +325,7 @@ namespace
|
||||
auto pwd_container = tools::password_container::prompt(verify, prompt);
|
||||
if (!pwd_container)
|
||||
{
|
||||
tools::fail_msg_writer() << sw::tr("failed to read wallet password");
|
||||
tools::fail_msg_writer() << sw::tr("failed to read password");
|
||||
}
|
||||
return pwd_container;
|
||||
}
|
||||
@ -324,6 +335,11 @@ namespace
|
||||
return password_prompter(verify ? sw::tr("Enter a new password for the wallet") : sw::tr("Wallet password"), verify);
|
||||
}
|
||||
|
||||
boost::optional<tools::password_container> background_sync_cache_password_prompter(bool verify)
|
||||
{
|
||||
return password_prompter(verify ? sw::tr("Enter a custom password for the background sync cache") : sw::tr("Background sync cache password"), verify);
|
||||
}
|
||||
|
||||
inline std::string interpret_rpc_response(bool ok, const std::string& status)
|
||||
{
|
||||
std::string err;
|
||||
@ -441,6 +457,41 @@ namespace
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
const struct
|
||||
{
|
||||
const char *name;
|
||||
tools::wallet2::BackgroundSyncType background_sync_type;
|
||||
} background_sync_type_names[] =
|
||||
{
|
||||
{ "off", tools::wallet2::BackgroundSyncOff },
|
||||
{ "reuse-wallet-password", tools::wallet2::BackgroundSyncReusePassword },
|
||||
{ "custom-background-password", tools::wallet2::BackgroundSyncCustomPassword },
|
||||
};
|
||||
|
||||
bool parse_background_sync_type(const std::string &s, tools::wallet2::BackgroundSyncType &background_sync_type)
|
||||
{
|
||||
for (size_t n = 0; n < sizeof(background_sync_type_names) / sizeof(background_sync_type_names[0]); ++n)
|
||||
{
|
||||
if (s == background_sync_type_names[n].name)
|
||||
{
|
||||
background_sync_type = background_sync_type_names[n].background_sync_type;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
fail_msg_writer() << cryptonote::simple_wallet::tr("failed to parse background sync type");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string get_background_sync_type_name(tools::wallet2::BackgroundSyncType type)
|
||||
{
|
||||
for (size_t n = 0; n < sizeof(background_sync_type_names) / sizeof(background_sync_type_names[0]); ++n)
|
||||
{
|
||||
if (type == background_sync_type_names[n].background_sync_type)
|
||||
return background_sync_type_names[n].name;
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
std::string get_version_string(uint32_t version)
|
||||
{
|
||||
return boost::lexical_cast<std::string>(version >> 16) + "." + boost::lexical_cast<std::string>(version & 0xffff);
|
||||
@ -793,6 +844,7 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
|
||||
fail_msg_writer() << tr("wallet is watch-only and has no spend key");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("has no spend key");
|
||||
// don't log
|
||||
PAUSE_READLINE();
|
||||
if (m_wallet->key_on_device()) {
|
||||
@ -823,6 +875,7 @@ bool simple_wallet::print_seed(bool encrypted)
|
||||
fail_msg_writer() << tr("wallet is watch-only and has no seed");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("has no seed");
|
||||
|
||||
const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()};
|
||||
if (ms_status.multisig_is_active)
|
||||
@ -900,6 +953,7 @@ bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = s
|
||||
fail_msg_writer() << tr("wallet is watch-only and has no seed");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("has no seed");
|
||||
|
||||
epee::wipeable_string password;
|
||||
{
|
||||
@ -1046,6 +1100,7 @@ bool simple_wallet::prepare_multisig_main(const std::vector<std::string> &args,
|
||||
fail_msg_writer() << tr("wallet is watch-only and cannot be made multisig");
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot be made multisig");
|
||||
|
||||
if(m_wallet->get_num_transfer_details())
|
||||
{
|
||||
@ -2105,6 +2160,7 @@ bool simple_wallet::save_known_rings(const std::vector<std::string> &args)
|
||||
|
||||
bool simple_wallet::freeze_thaw(const std::vector<std::string> &args, bool freeze)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot freeze/thaw");
|
||||
if (args.empty())
|
||||
{
|
||||
fail_msg_writer() << boost::format(tr("usage: %s <key_image>|<pubkey>")) % (freeze ? "freeze" : "thaw");
|
||||
@ -2144,6 +2200,7 @@ bool simple_wallet::thaw(const std::vector<std::string> &args)
|
||||
|
||||
bool simple_wallet::frozen(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot see frozen key images");
|
||||
if (args.empty())
|
||||
{
|
||||
size_t ntd = m_wallet->get_num_transfer_details();
|
||||
@ -2794,6 +2851,57 @@ bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool simple_wallet::setup_background_sync(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
if (m_wallet->get_multisig_status().multisig_is_active)
|
||||
{
|
||||
fail_msg_writer() << tr("background sync not implemented for multisig wallet");
|
||||
return true;
|
||||
}
|
||||
if (m_wallet->watch_only())
|
||||
{
|
||||
fail_msg_writer() << tr("background sync not implemented for watch only wallet");
|
||||
return true;
|
||||
}
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
|
||||
tools::wallet2::BackgroundSyncType background_sync_type;
|
||||
if (!parse_background_sync_type(args[1], background_sync_type))
|
||||
{
|
||||
fail_msg_writer() << tr("invalid option");
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto pwd_container = get_and_verify_password();
|
||||
if (!pwd_container)
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
boost::optional<epee::wipeable_string> background_cache_password = boost::none;
|
||||
if (background_sync_type == tools::wallet2::BackgroundSyncCustomPassword)
|
||||
{
|
||||
const auto background_pwd_container = background_sync_cache_password_prompter(true);
|
||||
if (!background_pwd_container)
|
||||
return true;
|
||||
background_cache_password = background_pwd_container->password();
|
||||
}
|
||||
|
||||
LOCK_IDLE_SCOPE();
|
||||
m_wallet->setup_background_sync(background_sync_type, pwd_container->password(), background_cache_password);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
fail_msg_writer() << tr("Error setting background sync type: ") << e.what();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool simple_wallet::set_show_wallet_name_when_locked(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
const auto pwd_container = get_and_verify_password();
|
||||
@ -3026,6 +3134,7 @@ bool simple_wallet::apropos(const std::vector<std::string> &args)
|
||||
|
||||
bool simple_wallet::scan_tx(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot scan tx");
|
||||
if (args.empty())
|
||||
{
|
||||
PRINT_USAGE(USAGE_SCAN_TX);
|
||||
@ -3243,6 +3352,8 @@ simple_wallet::simple_wallet()
|
||||
" Ignore outputs of amount below this threshold when spending.\n "
|
||||
"track-uses <1|0>\n "
|
||||
" Whether to keep track of owned outputs uses.\n "
|
||||
"background-sync <off|reuse-wallet-password|custom-background-password>\n "
|
||||
" Set this to enable scanning in the background with just the view key while the wallet is locked.\n "
|
||||
"setup-background-mining <1|0>\n "
|
||||
" Whether to enable background mining. Set this to support the network and to get a chance to receive new monero.\n "
|
||||
"device-name <device_name[:device_spec]>\n "
|
||||
@ -3645,6 +3756,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||
success_msg_writer() << "ignore-outputs-above = " << cryptonote::print_money(m_wallet->ignore_outputs_above());
|
||||
success_msg_writer() << "ignore-outputs-below = " << cryptonote::print_money(m_wallet->ignore_outputs_below());
|
||||
success_msg_writer() << "track-uses = " << m_wallet->track_uses();
|
||||
success_msg_writer() << "background-sync = " << get_background_sync_type_name(m_wallet->background_sync_type());
|
||||
success_msg_writer() << "setup-background-mining = " << setup_background_mining_string;
|
||||
success_msg_writer() << "device-name = " << m_wallet->device_name();
|
||||
success_msg_writer() << "export-format = " << (m_wallet->export_format() == tools::wallet2::ExportFormat::Ascii ? "ascii" : "binary");
|
||||
@ -3660,6 +3772,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot change wallet settings");
|
||||
|
||||
#define CHECK_SIMPLE_VARIABLE(name, f, help) do \
|
||||
if (args[0] == name) { \
|
||||
@ -3713,6 +3826,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||
CHECK_SIMPLE_VARIABLE("ignore-outputs-above", set_ignore_outputs_above, tr("amount"));
|
||||
CHECK_SIMPLE_VARIABLE("ignore-outputs-below", set_ignore_outputs_below, tr("amount"));
|
||||
CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
|
||||
CHECK_SIMPLE_VARIABLE("background-sync", setup_background_sync, tr("off (default); reuse-wallet-password (reuse the wallet password to encrypt the background cache); custom-background-password (use a custom background password to encrypt the background cache)"));
|
||||
CHECK_SIMPLE_VARIABLE("show-wallet-name-when-locked", set_show_wallet_name_when_locked, tr("1 or 0"));
|
||||
CHECK_SIMPLE_VARIABLE("inactivity-lock-timeout", set_inactivity_lock_timeout, tr("unsigned integer (seconds, 0 to disable)"));
|
||||
CHECK_SIMPLE_VARIABLE("setup-background-mining", set_setup_background_mining, tr("1/yes or 0/no"));
|
||||
@ -4653,7 +4767,10 @@ std::string simple_wallet::get_mnemonic_language()
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
boost::optional<tools::password_container> simple_wallet::get_and_verify_password() const
|
||||
{
|
||||
auto pwd_container = default_password_prompter(m_wallet_file.empty());
|
||||
const bool verify = m_wallet_file.empty();
|
||||
auto pwd_container = (m_wallet->is_background_wallet() && m_wallet->background_sync_type() == tools::wallet2::BackgroundSyncCustomPassword)
|
||||
? background_sync_cache_password_prompter(verify)
|
||||
: default_password_prompter(verify);
|
||||
if (!pwd_container)
|
||||
return boost::none;
|
||||
|
||||
@ -4956,6 +5073,8 @@ boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::p
|
||||
prefix = tr("Opened watch-only wallet");
|
||||
else if (ms_status.multisig_is_active)
|
||||
prefix = (boost::format(tr("Opened %u/%u multisig wallet%s")) % ms_status.threshold % ms_status.total % (ms_status.is_ready ? "" : " (not yet finalized)")).str();
|
||||
else if (m_wallet->is_background_wallet())
|
||||
prefix = tr("Opened background wallet");
|
||||
else
|
||||
prefix = tr("Opened wallet");
|
||||
message_writer(console_color_white, true) <<
|
||||
@ -5163,6 +5282,10 @@ void simple_wallet::stop_background_mining()
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void simple_wallet::check_background_mining(const epee::wipeable_string &password)
|
||||
{
|
||||
// Background mining can be toggled from the main wallet
|
||||
if (m_wallet->is_background_wallet() || m_wallet->is_background_syncing())
|
||||
return;
|
||||
|
||||
tools::wallet2::BackgroundMiningSetupType setup = m_wallet->setup_background_mining();
|
||||
if (setup == tools::wallet2::BackgroundMiningNo)
|
||||
{
|
||||
@ -5978,6 +6101,7 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot rescan spent");
|
||||
if (!m_wallet->is_trusted_daemon())
|
||||
{
|
||||
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
||||
@ -6233,10 +6357,27 @@ void simple_wallet::check_for_inactivity_lock(bool user)
|
||||
" || ||" << std::endl <<
|
||||
"" << std::endl;
|
||||
}
|
||||
|
||||
bool started_background_sync = false;
|
||||
if (!m_wallet->is_background_wallet() &&
|
||||
m_wallet->background_sync_type() != tools::wallet2::BackgroundSyncOff)
|
||||
{
|
||||
LOCK_IDLE_SCOPE();
|
||||
m_wallet->start_background_sync();
|
||||
started_background_sync = true;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
const char *inactivity_msg = user ? "" : tr("Locked due to inactivity.");
|
||||
tools::msg_writer() << inactivity_msg << (inactivity_msg[0] ? " " : "") << tr("The wallet password is required to unlock the console.");
|
||||
tools::msg_writer() << inactivity_msg << (inactivity_msg[0] ? " " : "") << (
|
||||
(m_wallet->is_background_wallet() && m_wallet->background_sync_type() == tools::wallet2::BackgroundSyncCustomPassword)
|
||||
? tr("The background password is required to unlock the console.")
|
||||
: tr("The wallet password is required to unlock the console.")
|
||||
);
|
||||
|
||||
if (m_wallet->is_background_syncing())
|
||||
tools::msg_writer() << tr("\nSyncing in the background while locked...") << std::endl;
|
||||
|
||||
const bool show_wallet_name = m_wallet->show_wallet_name_when_locked();
|
||||
if (show_wallet_name)
|
||||
@ -6249,8 +6390,16 @@ void simple_wallet::check_for_inactivity_lock(bool user)
|
||||
}
|
||||
try
|
||||
{
|
||||
if (get_and_verify_password())
|
||||
const auto pwd_container = get_and_verify_password();
|
||||
if (pwd_container)
|
||||
{
|
||||
if (started_background_sync)
|
||||
{
|
||||
LOCK_IDLE_SCOPE();
|
||||
m_wallet->stop_background_sync(pwd_container->password());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (...) { /* do nothing, just let the loop loop */ }
|
||||
}
|
||||
@ -6277,6 +6426,7 @@ bool simple_wallet::on_command(bool (simple_wallet::*cmd)(const std::vector<std:
|
||||
bool simple_wallet::transfer_main(const std::vector<std::string> &args_, bool called_by_mms)
|
||||
{
|
||||
// "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot transfer");
|
||||
if (!try_connect_to_daemon())
|
||||
return false;
|
||||
|
||||
@ -6690,6 +6840,7 @@ bool simple_wallet::transfer_main(const std::vector<std::string> &args_, bool ca
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot transfer");
|
||||
if (args_.size() < 1)
|
||||
{
|
||||
PRINT_USAGE(USAGE_TRANSFER);
|
||||
@ -6702,6 +6853,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
||||
|
||||
bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
if (!try_connect_to_daemon())
|
||||
return true;
|
||||
|
||||
@ -6809,6 +6961,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_main(uint32_t account, uint64_t below, const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
auto print_usage = [this, account, below]()
|
||||
{
|
||||
if (below)
|
||||
@ -7090,6 +7243,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, const std::vect
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
if (!try_connect_to_daemon())
|
||||
return true;
|
||||
|
||||
@ -7328,12 +7482,14 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
sweep_main(m_current_subaddress_account, 0, args_);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_account(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
auto local_args = args_;
|
||||
if (local_args.empty())
|
||||
{
|
||||
@ -7354,6 +7510,7 @@ bool simple_wallet::sweep_account(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
uint64_t below = 0;
|
||||
if (args_.size() < 1)
|
||||
{
|
||||
@ -7372,6 +7529,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::donate(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot donate");
|
||||
std::vector<std::string> local_args = args_;
|
||||
if(local_args.empty() || local_args.size() > 5)
|
||||
{
|
||||
@ -7433,6 +7591,7 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot load tx");
|
||||
// gather info to ask the user
|
||||
uint64_t amount = 0, amount_to_dests = 0, change = 0;
|
||||
size_t min_ring_size = ~0;
|
||||
@ -7613,6 +7772,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
|
||||
fail_msg_writer() << tr("This is a watch only wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sign transfer");
|
||||
|
||||
bool export_raw = false;
|
||||
std::string unsigned_filename = "unsigned_monero_tx";
|
||||
@ -7720,6 +7880,8 @@ std::string get_tx_key_stream(crypto::secret_key tx_key, std::vector<crypto::sec
|
||||
|
||||
bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get tx key");
|
||||
|
||||
std::vector<std::string> local_args = args_;
|
||||
|
||||
if (m_wallet->key_on_device() && m_wallet->get_account().get_device().get_type() != hw::device::TREZOR)
|
||||
@ -7760,6 +7922,8 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::set_tx_key(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot set tx key");
|
||||
|
||||
std::vector<std::string> local_args = args_;
|
||||
|
||||
if(local_args.size() != 2 && local_args.size() != 3) {
|
||||
@ -7836,6 +8000,8 @@ bool simple_wallet::set_tx_key(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get tx proof");
|
||||
|
||||
if (args.size() != 2 && args.size() != 3)
|
||||
{
|
||||
PRINT_USAGE(USAGE_GET_TX_PROOF);
|
||||
@ -8042,6 +8208,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get spend proof");
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
@ -8126,6 +8293,7 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get reserve proof");
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
@ -8812,6 +8980,8 @@ bool simple_wallet::unspent_outputs(const std::vector<std::string> &args_)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot rescan");
|
||||
|
||||
uint64_t start_height = 0;
|
||||
ResetType reset_type = ResetSoft;
|
||||
|
||||
@ -9036,6 +9206,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
if (command == "new")
|
||||
{
|
||||
// create a new account and switch to it
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot create new account");
|
||||
std::string label = boost::join(local_args, " ");
|
||||
if (label.empty())
|
||||
label = tr("(Untitled account)");
|
||||
@ -9066,6 +9237,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
else if (command == "label" && local_args.size() >= 1)
|
||||
{
|
||||
// set label of the specified account
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify account");
|
||||
uint32_t index_major;
|
||||
if (!epee::string_tools::get_xtype_from_string(index_major, local_args[0]))
|
||||
{
|
||||
@ -9087,6 +9259,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
}
|
||||
else if (command == "tag" && local_args.size() >= 2)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify account");
|
||||
const std::string tag = local_args[0];
|
||||
std::set<uint32_t> account_indices;
|
||||
for (size_t i = 1; i < local_args.size(); ++i)
|
||||
@ -9111,6 +9284,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
}
|
||||
else if (command == "untag" && local_args.size() >= 1)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify account");
|
||||
std::set<uint32_t> account_indices;
|
||||
for (size_t i = 0; i < local_args.size(); ++i)
|
||||
{
|
||||
@ -9134,6 +9308,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
|
||||
}
|
||||
else if (command == "tag_description" && local_args.size() >= 1)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify account");
|
||||
const std::string tag = local_args[0];
|
||||
std::string description;
|
||||
if (local_args.size() > 1)
|
||||
@ -9251,6 +9426,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
}
|
||||
else if (local_args[0] == "new")
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot add address");
|
||||
local_args.erase(local_args.begin());
|
||||
std::string label;
|
||||
if (local_args.size() > 0)
|
||||
@ -9263,6 +9439,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
}
|
||||
else if (local_args[0] == "mnew")
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot add addresses");
|
||||
local_args.erase(local_args.begin());
|
||||
if (local_args.size() != 1)
|
||||
{
|
||||
@ -9288,6 +9465,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
}
|
||||
else if (local_args[0] == "one-off")
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot add address");
|
||||
local_args.erase(local_args.begin());
|
||||
std::string label;
|
||||
if (local_args.size() != 2)
|
||||
@ -9306,6 +9484,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
}
|
||||
else if (local_args.size() >= 2 && local_args[0] == "label")
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot modify address");
|
||||
if (!epee::string_tools::get_xtype_from_string(index, local_args[1]))
|
||||
{
|
||||
fail_msg_writer() << tr("failed to parse index: ") << local_args[1];
|
||||
@ -9452,6 +9631,8 @@ bool simple_wallet::print_integrated_address(const std::vector<std::string> &arg
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get address book");
|
||||
|
||||
if (args.size() == 0)
|
||||
{
|
||||
}
|
||||
@ -9512,6 +9693,8 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::set_tx_note(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot set tx note");
|
||||
|
||||
if (args.size() == 0)
|
||||
{
|
||||
PRINT_USAGE(USAGE_SET_TX_NOTE);
|
||||
@ -9540,6 +9723,8 @@ bool simple_wallet::set_tx_note(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_tx_note(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get tx note");
|
||||
|
||||
if (args.size() != 1)
|
||||
{
|
||||
PRINT_USAGE(USAGE_GET_TX_NOTE);
|
||||
@ -9565,6 +9750,8 @@ bool simple_wallet::get_tx_note(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::set_description(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot set description");
|
||||
|
||||
// 0 arguments allowed, for setting the description to empty string
|
||||
|
||||
std::string description = "";
|
||||
@ -9581,6 +9768,8 @@ bool simple_wallet::set_description(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_description(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot get description");
|
||||
|
||||
if (args.size() != 0)
|
||||
{
|
||||
PRINT_USAGE(USAGE_GET_DESCRIPTION);
|
||||
@ -9639,6 +9828,8 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args)
|
||||
type = tr("Watch only");
|
||||
else if (ms_status.multisig_is_active)
|
||||
type = (boost::format(tr("%u/%u multisig%s")) % ms_status.threshold % ms_status.total % (ms_status.is_ready ? "" : " (not yet finalized)")).str();
|
||||
else if (m_wallet->is_background_wallet())
|
||||
type = tr("Background wallet");
|
||||
else
|
||||
type = tr("Normal");
|
||||
message_writer() << tr("Type: ") << type;
|
||||
@ -9650,6 +9841,7 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args)
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sign(const std::vector<std::string> &args)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sign");
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
@ -9757,6 +9949,7 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args_)
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot export key images");
|
||||
auto args = args_;
|
||||
|
||||
if (m_wallet->watch_only())
|
||||
@ -9810,6 +10003,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot import key images");
|
||||
if (!m_wallet->is_trusted_daemon())
|
||||
{
|
||||
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
||||
@ -9918,6 +10112,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args_)
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot export outputs");
|
||||
auto args = args_;
|
||||
|
||||
bool all = false;
|
||||
@ -9967,6 +10162,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
|
||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||
return true;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot import outputs");
|
||||
if (args.size() != 1)
|
||||
{
|
||||
PRINT_USAGE(USAGE_IMPORT_OUTPUTS);
|
||||
|
@ -147,6 +147,7 @@ namespace cryptonote
|
||||
bool set_ignore_outputs_above(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_ignore_outputs_below(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool setup_background_sync(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_show_wallet_name_when_locked(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_inactivity_lock_timeout(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_setup_background_mining(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
|
@ -58,6 +58,40 @@ using namespace cryptonote;
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "WalletAPI"
|
||||
|
||||
#define LOCK_REFRESH() \
|
||||
bool refresh_enabled = m_refreshEnabled; \
|
||||
m_refreshEnabled = false; \
|
||||
m_wallet->stop(); \
|
||||
m_refreshCV.notify_one(); \
|
||||
boost::mutex::scoped_lock lock(m_refreshMutex); \
|
||||
boost::mutex::scoped_lock lock2(m_refreshMutex2); \
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ \
|
||||
/* m_refreshMutex's still locked here */ \
|
||||
if (refresh_enabled) \
|
||||
startRefresh(); \
|
||||
})
|
||||
|
||||
#define PRE_VALIDATE_BACKGROUND_SYNC() \
|
||||
do \
|
||||
{ \
|
||||
clearStatus(); \
|
||||
if (m_wallet->key_on_device()) \
|
||||
{ \
|
||||
setStatusError(tr("HW wallet cannot use background sync")); \
|
||||
return false; \
|
||||
} \
|
||||
if (m_wallet->watch_only()) \
|
||||
{ \
|
||||
setStatusError(tr("View only wallet cannot use background sync")); \
|
||||
return false; \
|
||||
} \
|
||||
if (m_wallet->get_multisig_status().multisig_is_active) \
|
||||
{ \
|
||||
setStatusError(tr("Multisig wallet cannot use background sync")); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
namespace Monero {
|
||||
|
||||
namespace {
|
||||
@ -766,6 +800,8 @@ bool WalletImpl::close(bool store)
|
||||
|
||||
std::string WalletImpl::seed(const std::string& seed_offset) const
|
||||
{
|
||||
if (checkBackgroundSync("cannot get seed"))
|
||||
return std::string();
|
||||
epee::wipeable_string seed;
|
||||
if (m_wallet)
|
||||
m_wallet->get_seed(seed, seed_offset);
|
||||
@ -779,6 +815,8 @@ std::string WalletImpl::getSeedLanguage() const
|
||||
|
||||
void WalletImpl::setSeedLanguage(const std::string &arg)
|
||||
{
|
||||
if (checkBackgroundSync("cannot set seed language"))
|
||||
return;
|
||||
m_wallet->set_seed_language(arg);
|
||||
}
|
||||
|
||||
@ -802,6 +840,8 @@ void WalletImpl::statusWithErrorString(int& status, std::string& errorString) co
|
||||
|
||||
bool WalletImpl::setPassword(const std::string &password)
|
||||
{
|
||||
if (checkBackgroundSync("cannot change password"))
|
||||
return false;
|
||||
clearStatus();
|
||||
try {
|
||||
m_wallet->change_password(m_wallet->get_wallet_file(), m_password, password);
|
||||
@ -931,6 +971,8 @@ bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transact
|
||||
|
||||
void WalletImpl::setRefreshFromBlockHeight(uint64_t refresh_from_block_height)
|
||||
{
|
||||
if (checkBackgroundSync("cannot change refresh height"))
|
||||
return;
|
||||
m_wallet->set_refresh_from_block_height(refresh_from_block_height);
|
||||
}
|
||||
|
||||
@ -1039,6 +1081,8 @@ void WalletImpl::refreshAsync()
|
||||
|
||||
bool WalletImpl::rescanBlockchain()
|
||||
{
|
||||
if (checkBackgroundSync("cannot rescan blockchain"))
|
||||
return false;
|
||||
clearStatus();
|
||||
m_refreshShouldRescan = true;
|
||||
doRefresh();
|
||||
@ -1047,6 +1091,8 @@ bool WalletImpl::rescanBlockchain()
|
||||
|
||||
void WalletImpl::rescanBlockchainAsync()
|
||||
{
|
||||
if (checkBackgroundSync("cannot rescan blockchain"))
|
||||
return;
|
||||
m_refreshShouldRescan = true;
|
||||
refreshAsync();
|
||||
}
|
||||
@ -1070,7 +1116,7 @@ int WalletImpl::autoRefreshInterval() const
|
||||
UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_filename) {
|
||||
clearStatus();
|
||||
UnsignedTransactionImpl * transaction = new UnsignedTransactionImpl(*this);
|
||||
if (!m_wallet->load_unsigned_tx(unsigned_filename, transaction->m_unsigned_tx_set)){
|
||||
if (checkBackgroundSync("cannot load tx") || !m_wallet->load_unsigned_tx(unsigned_filename, transaction->m_unsigned_tx_set)){
|
||||
setStatusError(tr("Failed to load unsigned transactions"));
|
||||
transaction->m_status = UnsignedTransaction::Status::Status_Error;
|
||||
transaction->m_errorString = errorString();
|
||||
@ -1090,6 +1136,8 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file
|
||||
|
||||
bool WalletImpl::submitTransaction(const string &fileName) {
|
||||
clearStatus();
|
||||
if (checkBackgroundSync("cannot submit tx"))
|
||||
return false;
|
||||
std::unique_ptr<PendingTransactionImpl> transaction(new PendingTransactionImpl(*this));
|
||||
|
||||
bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx);
|
||||
@ -1113,6 +1161,8 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all)
|
||||
setStatusError(tr("Wallet is view only"));
|
||||
return false;
|
||||
}
|
||||
if (checkBackgroundSync("cannot export key images"))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
@ -1133,6 +1183,8 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all)
|
||||
|
||||
bool WalletImpl::importKeyImages(const string &filename)
|
||||
{
|
||||
if (checkBackgroundSync("cannot import key images"))
|
||||
return false;
|
||||
if (!trustedDaemon()) {
|
||||
setStatusError(tr("Key images can only be imported with a trusted daemon"));
|
||||
return false;
|
||||
@ -1156,6 +1208,8 @@ bool WalletImpl::importKeyImages(const string &filename)
|
||||
|
||||
bool WalletImpl::exportOutputs(const string &filename, bool all)
|
||||
{
|
||||
if (checkBackgroundSync("cannot export outputs"))
|
||||
return false;
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
setStatusError(string(tr("Not supported on HW wallets.")) + filename);
|
||||
@ -1186,6 +1240,8 @@ bool WalletImpl::exportOutputs(const string &filename, bool all)
|
||||
|
||||
bool WalletImpl::importOutputs(const string &filename)
|
||||
{
|
||||
if (checkBackgroundSync("cannot import outputs"))
|
||||
return false;
|
||||
if (m_wallet->key_on_device())
|
||||
{
|
||||
setStatusError(string(tr("Not supported on HW wallets.")) + filename);
|
||||
@ -1218,6 +1274,8 @@ bool WalletImpl::importOutputs(const string &filename)
|
||||
|
||||
bool WalletImpl::scanTransactions(const std::vector<std::string> &txids)
|
||||
{
|
||||
if (checkBackgroundSync("cannot scan transactions"))
|
||||
return false;
|
||||
if (txids.empty())
|
||||
{
|
||||
setStatusError(string(tr("Failed to scan transactions: no transaction ids provided.")));
|
||||
@ -1256,8 +1314,86 @@ bool WalletImpl::scanTransactions(const std::vector<std::string> &txids)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WalletImpl::setupBackgroundSync(const Wallet::BackgroundSyncType background_sync_type, const std::string &wallet_password, const optional<std::string> &background_cache_password)
|
||||
{
|
||||
try
|
||||
{
|
||||
PRE_VALIDATE_BACKGROUND_SYNC();
|
||||
|
||||
tools::wallet2::BackgroundSyncType bgs_type;
|
||||
switch (background_sync_type)
|
||||
{
|
||||
case Wallet::BackgroundSync_Off: bgs_type = tools::wallet2::BackgroundSyncOff; break;
|
||||
case Wallet::BackgroundSync_ReusePassword: bgs_type = tools::wallet2::BackgroundSyncReusePassword; break;
|
||||
case Wallet::BackgroundSync_CustomPassword: bgs_type = tools::wallet2::BackgroundSyncCustomPassword; break;
|
||||
default: setStatusError(tr("Unknown background sync type")); return false;
|
||||
}
|
||||
|
||||
boost::optional<epee::wipeable_string> bgc_password = background_cache_password
|
||||
? boost::optional<epee::wipeable_string>(*background_cache_password)
|
||||
: boost::none;
|
||||
|
||||
LOCK_REFRESH();
|
||||
m_wallet->setup_background_sync(bgs_type, wallet_password, bgc_password);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
LOG_ERROR("Failed to setup background sync: " << e.what());
|
||||
setStatusError(string(tr("Failed to setup background sync: ")) + e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Wallet::BackgroundSyncType WalletImpl::getBackgroundSyncType() const
|
||||
{
|
||||
switch (m_wallet->background_sync_type())
|
||||
{
|
||||
case tools::wallet2::BackgroundSyncOff: return Wallet::BackgroundSync_Off;
|
||||
case tools::wallet2::BackgroundSyncReusePassword: return Wallet::BackgroundSync_ReusePassword;
|
||||
case tools::wallet2::BackgroundSyncCustomPassword: return Wallet::BackgroundSync_CustomPassword;
|
||||
default: setStatusError(tr("Unknown background sync type")); return Wallet::BackgroundSync_Off;
|
||||
}
|
||||
}
|
||||
|
||||
bool WalletImpl::startBackgroundSync()
|
||||
{
|
||||
try
|
||||
{
|
||||
PRE_VALIDATE_BACKGROUND_SYNC();
|
||||
LOCK_REFRESH();
|
||||
m_wallet->start_background_sync();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
LOG_ERROR("Failed to start background sync: " << e.what());
|
||||
setStatusError(string(tr("Failed to start background sync: ")) + e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WalletImpl::stopBackgroundSync(const std::string &wallet_password)
|
||||
{
|
||||
try
|
||||
{
|
||||
PRE_VALIDATE_BACKGROUND_SYNC();
|
||||
LOCK_REFRESH();
|
||||
m_wallet->stop_background_sync(epee::wipeable_string(wallet_password));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
LOG_ERROR("Failed to stop background sync: " << e.what());
|
||||
setStatusError(string(tr("Failed to stop background sync: ")) + e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WalletImpl::addSubaddressAccount(const std::string& label)
|
||||
{
|
||||
if (checkBackgroundSync("cannot add account"))
|
||||
return;
|
||||
m_wallet->add_subaddress_account(label);
|
||||
}
|
||||
size_t WalletImpl::numSubaddressAccounts() const
|
||||
@ -1270,10 +1406,14 @@ size_t WalletImpl::numSubaddresses(uint32_t accountIndex) const
|
||||
}
|
||||
void WalletImpl::addSubaddress(uint32_t accountIndex, const std::string& label)
|
||||
{
|
||||
if (checkBackgroundSync("cannot add subbaddress"))
|
||||
return;
|
||||
m_wallet->add_subaddress(accountIndex, label);
|
||||
}
|
||||
std::string WalletImpl::getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const
|
||||
{
|
||||
if (checkBackgroundSync("cannot get subbaddress label"))
|
||||
return "";
|
||||
try
|
||||
{
|
||||
return m_wallet->get_subaddress_label({accountIndex, addressIndex});
|
||||
@ -1287,6 +1427,8 @@ std::string WalletImpl::getSubaddressLabel(uint32_t accountIndex, uint32_t addre
|
||||
}
|
||||
void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label)
|
||||
{
|
||||
if (checkBackgroundSync("cannot set subbaddress label"))
|
||||
return;
|
||||
try
|
||||
{
|
||||
return m_wallet->set_subaddress_label({accountIndex, addressIndex}, label);
|
||||
@ -1300,6 +1442,9 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex
|
||||
|
||||
MultisigState WalletImpl::multisig() const {
|
||||
MultisigState state;
|
||||
if (checkBackgroundSync("cannot use multisig"))
|
||||
return state;
|
||||
|
||||
const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()};
|
||||
|
||||
state.isMultisig = ms_status.multisig_is_active;
|
||||
@ -1312,6 +1457,8 @@ MultisigState WalletImpl::multisig() const {
|
||||
}
|
||||
|
||||
string WalletImpl::getMultisigInfo() const {
|
||||
if (checkBackgroundSync("cannot use multisig"))
|
||||
return string();
|
||||
try {
|
||||
clearStatus();
|
||||
return m_wallet->get_multisig_first_kex_msg();
|
||||
@ -1324,6 +1471,8 @@ string WalletImpl::getMultisigInfo() const {
|
||||
}
|
||||
|
||||
string WalletImpl::makeMultisig(const vector<string>& info, const uint32_t threshold) {
|
||||
if (checkBackgroundSync("cannot make multisig"))
|
||||
return string();
|
||||
try {
|
||||
clearStatus();
|
||||
|
||||
@ -1479,6 +1628,9 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
|
||||
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
|
||||
|
||||
do {
|
||||
if (checkBackgroundSync("cannot create transactions"))
|
||||
break;
|
||||
|
||||
std::vector<uint8_t> extra;
|
||||
std::string extra_nonce;
|
||||
vector<cryptonote::tx_destination_entry> dsts;
|
||||
@ -1645,6 +1797,9 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
|
||||
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
|
||||
|
||||
do {
|
||||
if (checkBackgroundSync("cannot sweep"))
|
||||
break;
|
||||
|
||||
try {
|
||||
transaction->m_pending_tx = m_wallet->create_unmixable_sweep_transactions();
|
||||
pendingTxPostProcess(transaction);
|
||||
@ -1778,11 +1933,15 @@ uint32_t WalletImpl::defaultMixin() const
|
||||
|
||||
void WalletImpl::setDefaultMixin(uint32_t arg)
|
||||
{
|
||||
if (checkBackgroundSync("cannot set default mixin"))
|
||||
return;
|
||||
m_wallet->default_mixin(arg);
|
||||
}
|
||||
|
||||
bool WalletImpl::setCacheAttribute(const std::string &key, const std::string &val)
|
||||
{
|
||||
if (checkBackgroundSync("cannot set cache attribute"))
|
||||
return false;
|
||||
m_wallet->set_attribute(key, val);
|
||||
return true;
|
||||
}
|
||||
@ -1796,6 +1955,8 @@ std::string WalletImpl::getCacheAttribute(const std::string &key) const
|
||||
|
||||
bool WalletImpl::setUserNote(const std::string &txid, const std::string ¬e)
|
||||
{
|
||||
if (checkBackgroundSync("cannot set user note"))
|
||||
return false;
|
||||
cryptonote::blobdata txid_data;
|
||||
if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash))
|
||||
return false;
|
||||
@ -1807,6 +1968,8 @@ bool WalletImpl::setUserNote(const std::string &txid, const std::string ¬e)
|
||||
|
||||
std::string WalletImpl::getUserNote(const std::string &txid) const
|
||||
{
|
||||
if (checkBackgroundSync("cannot get user note"))
|
||||
return "";
|
||||
cryptonote::blobdata txid_data;
|
||||
if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash))
|
||||
return "";
|
||||
@ -1817,6 +1980,9 @@ std::string WalletImpl::getUserNote(const std::string &txid) const
|
||||
|
||||
std::string WalletImpl::getTxKey(const std::string &txid_str) const
|
||||
{
|
||||
if (checkBackgroundSync("cannot get tx key"))
|
||||
return "";
|
||||
|
||||
crypto::hash txid;
|
||||
if(!epee::string_tools::hex_to_pod(txid_str, txid))
|
||||
{
|
||||
@ -1901,6 +2067,9 @@ bool WalletImpl::checkTxKey(const std::string &txid_str, std::string tx_key_str,
|
||||
|
||||
std::string WalletImpl::getTxProof(const std::string &txid_str, const std::string &address_str, const std::string &message) const
|
||||
{
|
||||
if (checkBackgroundSync("cannot get tx proof"))
|
||||
return "";
|
||||
|
||||
crypto::hash txid;
|
||||
if (!epee::string_tools::hex_to_pod(txid_str, txid))
|
||||
{
|
||||
@ -1957,6 +2126,9 @@ bool WalletImpl::checkTxProof(const std::string &txid_str, const std::string &ad
|
||||
}
|
||||
|
||||
std::string WalletImpl::getSpendProof(const std::string &txid_str, const std::string &message) const {
|
||||
if (checkBackgroundSync("cannot get spend proof"))
|
||||
return "";
|
||||
|
||||
crypto::hash txid;
|
||||
if(!epee::string_tools::hex_to_pod(txid_str, txid))
|
||||
{
|
||||
@ -1999,6 +2171,9 @@ bool WalletImpl::checkSpendProof(const std::string &txid_str, const std::string
|
||||
}
|
||||
|
||||
std::string WalletImpl::getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const {
|
||||
if (checkBackgroundSync("cannot get reserve proof"))
|
||||
return "";
|
||||
|
||||
try
|
||||
{
|
||||
clearStatus();
|
||||
@ -2045,6 +2220,9 @@ bool WalletImpl::checkReserveProof(const std::string &address, const std::string
|
||||
|
||||
std::string WalletImpl::signMessage(const std::string &message, const std::string &address)
|
||||
{
|
||||
if (checkBackgroundSync("cannot sign message"))
|
||||
return "";
|
||||
|
||||
if (address.empty()) {
|
||||
return m_wallet->sign(message, tools::wallet2::sign_with_spend_key);
|
||||
}
|
||||
@ -2171,6 +2349,16 @@ bool WalletImpl::isDeterministic() const
|
||||
return m_wallet->is_deterministic();
|
||||
}
|
||||
|
||||
bool WalletImpl::isBackgroundSyncing() const
|
||||
{
|
||||
return m_wallet->is_background_syncing();
|
||||
}
|
||||
|
||||
bool WalletImpl::isBackgroundWallet() const
|
||||
{
|
||||
return m_wallet->is_background_wallet();
|
||||
}
|
||||
|
||||
void WalletImpl::clearStatus() const
|
||||
{
|
||||
boost::lock_guard<boost::mutex> l(m_statusMutex);
|
||||
@ -2239,9 +2427,7 @@ void WalletImpl::doRefresh()
|
||||
if(rescan)
|
||||
m_wallet->rescan_blockchain(false);
|
||||
m_wallet->refresh(trustedDaemon());
|
||||
if (!m_synchronized) {
|
||||
m_synchronized = true;
|
||||
}
|
||||
m_synchronized = m_wallet->is_synced();
|
||||
// assuming if we have empty history, it wasn't initialized yet
|
||||
// for further history changes client need to update history in
|
||||
// "on_money_received" and "on_money_sent" callbacks
|
||||
@ -2344,6 +2530,24 @@ bool WalletImpl::doInit(const string &daemon_address, const std::string &proxy_a
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WalletImpl::checkBackgroundSync(const std::string &message) const
|
||||
{
|
||||
clearStatus();
|
||||
if (m_wallet->is_background_wallet())
|
||||
{
|
||||
LOG_ERROR("Background wallets " + message);
|
||||
setStatusError(tr("Background wallets ") + message);
|
||||
return true;
|
||||
}
|
||||
if (m_wallet->is_background_syncing())
|
||||
{
|
||||
LOG_ERROR(message + " while background syncing");
|
||||
setStatusError(message + tr(" while background syncing. Stop background syncing first."));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error)
|
||||
{
|
||||
return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
|
||||
@ -2362,6 +2566,8 @@ std::string WalletImpl::getDefaultDataDir() const
|
||||
bool WalletImpl::rescanSpent()
|
||||
{
|
||||
clearStatus();
|
||||
if (checkBackgroundSync("cannot rescan spent"))
|
||||
return false;
|
||||
if (!trustedDaemon()) {
|
||||
setStatusError(tr("Rescan spent can only be used with a trusted daemon"));
|
||||
return false;
|
||||
|
@ -173,6 +173,13 @@ public:
|
||||
bool importOutputs(const std::string &filename) override;
|
||||
bool scanTransactions(const std::vector<std::string> &txids) override;
|
||||
|
||||
bool setupBackgroundSync(const BackgroundSyncType background_sync_type, const std::string &wallet_password, const optional<std::string> &background_cache_password = optional<std::string>()) override;
|
||||
BackgroundSyncType getBackgroundSyncType() const override;
|
||||
bool startBackgroundSync() override;
|
||||
bool stopBackgroundSync(const std::string &wallet_password) override;
|
||||
bool isBackgroundSyncing() const override;
|
||||
bool isBackgroundWallet() const override;
|
||||
|
||||
virtual void disposeTransaction(PendingTransaction * t) override;
|
||||
virtual uint64_t estimateTransactionFee(const std::vector<std::pair<std::string, uint64_t>> &destinations,
|
||||
PendingTransaction::Priority priority) const override;
|
||||
@ -239,6 +246,7 @@ private:
|
||||
bool isNewWallet() const;
|
||||
void pendingTxPostProcess(PendingTransactionImpl * pending);
|
||||
bool doInit(const std::string &daemon_address, const std::string &proxy_address, uint64_t upper_transaction_size_limit = 0, bool ssl = false);
|
||||
bool checkBackgroundSync(const std::string &message) const;
|
||||
|
||||
private:
|
||||
friend class PendingTransactionImpl;
|
||||
@ -254,6 +262,10 @@ private:
|
||||
mutable boost::mutex m_statusMutex;
|
||||
mutable int m_status;
|
||||
mutable std::string m_errorString;
|
||||
// TODO: harden password handling in the wallet API, see relevant discussion
|
||||
// https://github.com/monero-project/monero-gui/issues/1537
|
||||
// https://github.com/feather-wallet/feather/issues/72#issuecomment-1405602142
|
||||
// https://github.com/monero-project/monero/pull/8619#issuecomment-1632951461
|
||||
std::string m_password;
|
||||
std::unique_ptr<TransactionHistoryImpl> m_history;
|
||||
std::unique_ptr<Wallet2CallbackImpl> m_wallet2Callback;
|
||||
|
@ -446,6 +446,12 @@ struct Wallet
|
||||
ConnectionStatus_WrongVersion
|
||||
};
|
||||
|
||||
enum BackgroundSyncType {
|
||||
BackgroundSync_Off = 0,
|
||||
BackgroundSync_ReusePassword = 1,
|
||||
BackgroundSync_CustomPassword = 2
|
||||
};
|
||||
|
||||
virtual ~Wallet() = 0;
|
||||
virtual std::string seed(const std::string& seed_offset = "") const = 0;
|
||||
virtual std::string getSeedLanguage() const = 0;
|
||||
@ -946,6 +952,42 @@ struct Wallet
|
||||
*/
|
||||
virtual bool scanTransactions(const std::vector<std::string> &txids) = 0;
|
||||
|
||||
/*!
|
||||
* \brief setupBackgroundSync - setup background sync mode with just a view key
|
||||
* \param background_sync_type - the mode the wallet background syncs in
|
||||
* \param wallet_password
|
||||
* \param background_cache_password - custom password to encrypt background cache, only needed for custom password background sync type
|
||||
* \return - true on success
|
||||
*/
|
||||
virtual bool setupBackgroundSync(const BackgroundSyncType background_sync_type, const std::string &wallet_password, const optional<std::string> &background_cache_password) = 0;
|
||||
|
||||
/*!
|
||||
* \brief getBackgroundSyncType - get mode the wallet background syncs in
|
||||
* \return - the type, or off if type is unknown
|
||||
*/
|
||||
virtual BackgroundSyncType getBackgroundSyncType() const = 0;
|
||||
|
||||
/**
|
||||
* @brief startBackgroundSync - sync the chain in the background with just view key
|
||||
*/
|
||||
virtual bool startBackgroundSync() = 0;
|
||||
|
||||
/**
|
||||
* @brief stopBackgroundSync - bring back spend key and process background synced txs
|
||||
* \param wallet_password
|
||||
*/
|
||||
virtual bool stopBackgroundSync(const std::string &wallet_password) = 0;
|
||||
|
||||
/**
|
||||
* @brief isBackgroundSyncing - returns true if the wallet is background syncing
|
||||
*/
|
||||
virtual bool isBackgroundSyncing() const = 0;
|
||||
|
||||
/**
|
||||
* @brief isBackgroundWallet - returns true if the wallet is a background wallet
|
||||
*/
|
||||
virtual bool isBackgroundWallet() const = 0;
|
||||
|
||||
virtual TransactionHistory * history() = 0;
|
||||
virtual AddressBook * addressBook() = 0;
|
||||
virtual Subaddress * subaddress() = 0;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -250,6 +250,20 @@ private:
|
||||
BackgroundMiningNo = 2,
|
||||
};
|
||||
|
||||
enum BackgroundSyncType {
|
||||
BackgroundSyncOff = 0,
|
||||
BackgroundSyncReusePassword = 1,
|
||||
BackgroundSyncCustomPassword = 2,
|
||||
};
|
||||
|
||||
static BackgroundSyncType background_sync_type_from_str(const std::string &background_sync_type_str)
|
||||
{
|
||||
if (background_sync_type_str == "off") return BackgroundSyncOff;
|
||||
if (background_sync_type_str == "reuse-wallet-password") return BackgroundSyncReusePassword;
|
||||
if (background_sync_type_str == "custom-background-password") return BackgroundSyncCustomPassword;
|
||||
throw std::logic_error("Unknown background sync type");
|
||||
};
|
||||
|
||||
enum ExportFormat {
|
||||
Binary = 0,
|
||||
Ascii,
|
||||
@ -276,7 +290,12 @@ private:
|
||||
//! Just parses variables.
|
||||
static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm, bool unattended, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter);
|
||||
|
||||
static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds);
|
||||
static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds)
|
||||
{
|
||||
crypto::secret_key spend_key = crypto::null_skey;
|
||||
return verify_password(keys_file_name, password, no_spend_key, hwdev, kdf_rounds, spend_key);
|
||||
};
|
||||
static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds, crypto::secret_key &spend_key_out);
|
||||
static bool query_device(hw::device::device_type& device_type, const std::string& keys_file_name, const epee::wipeable_string& password, uint64_t kdf_rounds = 1);
|
||||
|
||||
wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, uint64_t kdf_rounds = 1, bool unattended = false, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory = std::unique_ptr<epee::net_utils::http::http_client_factory>(new net::http::client_factory()));
|
||||
@ -786,6 +805,54 @@ private:
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct background_synced_tx_t
|
||||
{
|
||||
uint64_t index_in_background_sync_data;
|
||||
cryptonote::transaction tx;
|
||||
std::vector<uint64_t> output_indices;
|
||||
uint64_t height;
|
||||
uint64_t block_timestamp;
|
||||
bool double_spend_seen;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VERSION_FIELD(0)
|
||||
VARINT_FIELD(index_in_background_sync_data)
|
||||
|
||||
// prune tx; don't need to keep signature data
|
||||
if (!tx.serialize_base(ar))
|
||||
return false;
|
||||
|
||||
FIELD(output_indices)
|
||||
VARINT_FIELD(height)
|
||||
VARINT_FIELD(block_timestamp)
|
||||
FIELD(double_spend_seen)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct background_sync_data_t
|
||||
{
|
||||
bool first_refresh_done = false;
|
||||
uint64_t start_height = 0;
|
||||
std::unordered_map<crypto::hash, background_synced_tx_t> txs;
|
||||
|
||||
// Relevant wallet settings
|
||||
uint64_t wallet_refresh_from_block_height;
|
||||
size_t subaddress_lookahead_major;
|
||||
size_t subaddress_lookahead_minor;
|
||||
RefreshType wallet_refresh_type;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VERSION_FIELD(0)
|
||||
FIELD(first_refresh_done)
|
||||
FIELD(start_height)
|
||||
FIELD(txs)
|
||||
FIELD(wallet_refresh_from_block_height)
|
||||
VARINT_FIELD(subaddress_lookahead_major)
|
||||
VARINT_FIELD(subaddress_lookahead_minor)
|
||||
VARINT_FIELD(wallet_refresh_type)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
typedef std::tuple<uint64_t, crypto::public_key, rct::key> get_outs_entry;
|
||||
|
||||
struct parsed_block
|
||||
@ -998,7 +1065,8 @@ private:
|
||||
/*!
|
||||
* \brief verifies given password is correct for default wallet keys file
|
||||
*/
|
||||
bool verify_password(const epee::wipeable_string& password);
|
||||
bool verify_password(const epee::wipeable_string& password) {crypto::secret_key key = crypto::null_skey; return verify_password(password, key);};
|
||||
bool verify_password(const epee::wipeable_string& password, crypto::secret_key &spend_key_out);
|
||||
cryptonote::account_base& get_account(){return m_account;}
|
||||
const cryptonote::account_base& get_account()const{return m_account;}
|
||||
|
||||
@ -1085,6 +1153,7 @@ private:
|
||||
|
||||
cryptonote::network_type nettype() const { return m_nettype; }
|
||||
bool watch_only() const { return m_watch_only; }
|
||||
bool is_background_wallet() const { return m_is_background_wallet; }
|
||||
multisig::multisig_account_status get_multisig_status() const;
|
||||
bool has_multisig_partial_key_images() const;
|
||||
bool has_unknown_key_images() const;
|
||||
@ -1294,11 +1363,17 @@ private:
|
||||
return;
|
||||
}
|
||||
a & m_has_ever_refreshed_from_node;
|
||||
if(ver < 31)
|
||||
{
|
||||
m_background_sync_data = background_sync_data_t{};
|
||||
return;
|
||||
}
|
||||
a & m_background_sync_data;
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
MAGIC_FIELD("monero wallet cache")
|
||||
VERSION_FIELD(1)
|
||||
VERSION_FIELD(2)
|
||||
FIELD(m_blockchain)
|
||||
FIELD(m_transfers)
|
||||
FIELD(m_account_public_address)
|
||||
@ -1331,6 +1406,12 @@ private:
|
||||
return true;
|
||||
}
|
||||
FIELD(m_has_ever_refreshed_from_node)
|
||||
if (version < 2)
|
||||
{
|
||||
m_background_sync_data = background_sync_data_t{};
|
||||
return true;
|
||||
}
|
||||
FIELD(m_background_sync_data)
|
||||
END_SERIALIZE()
|
||||
|
||||
/*!
|
||||
@ -1346,6 +1427,8 @@ private:
|
||||
* \return Whether path is valid format
|
||||
*/
|
||||
static bool wallet_valid_path_format(const std::string& file_path);
|
||||
static std::string make_background_wallet_file_name(const std::string &wallet_file);
|
||||
static std::string make_background_keys_file_name(const std::string &wallet_file);
|
||||
static bool parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id);
|
||||
static bool parse_short_payment_id(const std::string& payment_id_str, crypto::hash8& payment_id);
|
||||
static bool parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id);
|
||||
@ -1392,6 +1475,9 @@ private:
|
||||
void ignore_outputs_below(uint64_t value) { m_ignore_outputs_below = value; }
|
||||
bool track_uses() const { return m_track_uses; }
|
||||
void track_uses(bool value) { m_track_uses = value; }
|
||||
BackgroundSyncType background_sync_type() const { return m_background_sync_type; }
|
||||
void setup_background_sync(BackgroundSyncType background_sync_type, const epee::wipeable_string &wallet_password, const boost::optional<epee::wipeable_string> &background_cache_password);
|
||||
bool is_background_syncing() const { return m_background_syncing; }
|
||||
bool show_wallet_name_when_locked() const { return m_show_wallet_name_when_locked; }
|
||||
void show_wallet_name_when_locked(bool value) { m_show_wallet_name_when_locked = value; }
|
||||
BackgroundMiningSetupType setup_background_mining() const { return m_setup_background_mining; }
|
||||
@ -1666,6 +1752,9 @@ private:
|
||||
uint64_t get_bytes_sent() const;
|
||||
uint64_t get_bytes_received() const;
|
||||
|
||||
void start_background_sync();
|
||||
void stop_background_sync(const epee::wipeable_string &wallet_password, const crypto::secret_key &spend_secret_key = crypto::null_skey);
|
||||
|
||||
// MMS -------------------------------------------------------------------------------------------------
|
||||
mms::message_store& get_message_store() { return m_message_store; };
|
||||
const mms::message_store& get_message_store() const { return m_message_store; };
|
||||
@ -1698,6 +1787,9 @@ private:
|
||||
* \return Whether it was successful.
|
||||
*/
|
||||
bool store_keys(const std::string& keys_file_name, const epee::wipeable_string& password, bool watch_only = false);
|
||||
bool store_keys(const std::string& keys_file_name, const crypto::chacha_key& key, bool watch_only = false, bool background_keys_file = false);
|
||||
boost::optional<wallet2::keys_file_data> get_keys_file_data(const crypto::chacha_key& key, bool watch_only = false, bool background_keys_file = false);
|
||||
bool store_keys_file_data(const std::string& keys_file_name, wallet2::keys_file_data &keys_file_data, bool background_keys_file = false);
|
||||
/*!
|
||||
* \brief Load wallet keys information from wallet file.
|
||||
* \param keys_file_name Name of wallet file
|
||||
@ -1711,6 +1803,7 @@ private:
|
||||
*/
|
||||
bool load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password);
|
||||
bool load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password, boost::optional<crypto::chacha_key>& keys_to_encrypt);
|
||||
void load_wallet_cache(const bool use_fs, const std::string& cache_buf = "");
|
||||
void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, 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 = NULL, bool ignore_callbacks = false);
|
||||
bool should_skip_block(const cryptonote::block &b, uint64_t height) const;
|
||||
void 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 = NULL);
|
||||
@ -1719,6 +1812,15 @@ private:
|
||||
void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const;
|
||||
bool clear();
|
||||
void clear_soft(bool keep_key_images=false);
|
||||
/*
|
||||
* clear_user_data clears data created by the user, which is mostly data
|
||||
* that a view key cannot identify on chain. This function was initially
|
||||
* added to ensure that a "background" wallet (a wallet that syncs with just
|
||||
* a view key hot in memory) does not have any sensitive data loaded that it
|
||||
* does not need in order to sync. Future devs should take care to ensure
|
||||
* that this function deletes data that is not useful for background syncing
|
||||
*/
|
||||
void clear_user_data();
|
||||
void pull_blocks(bool first, bool try_incremental, uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> &o_indices, uint64_t ¤t_height, std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>>& process_pool_txs);
|
||||
void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes);
|
||||
void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false);
|
||||
@ -1770,10 +1872,23 @@ private:
|
||||
bool get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
|
||||
crypto::chacha_key get_ringdb_key();
|
||||
void setup_keys(const epee::wipeable_string &password);
|
||||
const crypto::chacha_key get_cache_key();
|
||||
void verify_password_with_cached_key(const epee::wipeable_string &password);
|
||||
void verify_password_with_cached_key(const crypto::chacha_key &key);
|
||||
size_t get_transfer_details(const crypto::key_image &ki) const;
|
||||
tx_entry_data get_tx_entries(const std::unordered_set<crypto::hash> &txids);
|
||||
void sort_scan_tx_entries(std::vector<process_tx_entry_t> &unsorted_tx_entries);
|
||||
void process_scan_txs(const tx_entry_data &txs_to_scan, const tx_entry_data &txs_to_reprocess, const std::unordered_set<crypto::hash> &tx_hashes_to_reprocess, detached_blockchain_data &dbd);
|
||||
void write_background_sync_wallet(const epee::wipeable_string &wallet_password, const epee::wipeable_string &background_cache_password);
|
||||
void process_background_cache_on_open();
|
||||
void process_background_cache(const background_sync_data_t &background_sync_data, const hashchain &background_chain, uint64_t last_block_reward);
|
||||
void reset_background_sync_data(background_sync_data_t &background_sync_data);
|
||||
void store_background_cache(const crypto::chacha_key &custom_background_key, const bool do_reset_background_sync_data = true);
|
||||
void store_background_keys(const crypto::chacha_key &custom_background_key);
|
||||
|
||||
bool lock_background_keys_file(const std::string &background_keys_file);
|
||||
bool unlock_background_keys_file();
|
||||
bool is_background_keys_file_locked() const;
|
||||
|
||||
void register_devices();
|
||||
hw::device& lookup_device(const std::string & device_descriptor);
|
||||
@ -1885,6 +2000,8 @@ private:
|
||||
uint64_t m_ignore_outputs_above;
|
||||
uint64_t m_ignore_outputs_below;
|
||||
bool m_track_uses;
|
||||
bool m_is_background_wallet;
|
||||
BackgroundSyncType m_background_sync_type;
|
||||
bool m_show_wallet_name_when_locked;
|
||||
uint32_t m_inactivity_lock_timeout;
|
||||
BackgroundMiningSetupType m_setup_background_mining;
|
||||
@ -1912,6 +2029,7 @@ private:
|
||||
|
||||
uint64_t m_last_block_reward;
|
||||
std::unique_ptr<tools::file_locker> m_keys_file_locker;
|
||||
std::unique_ptr<tools::file_locker> m_background_keys_file_locker;
|
||||
|
||||
mms::message_store m_message_store;
|
||||
bool m_original_keys_available;
|
||||
@ -1919,6 +2037,7 @@ private:
|
||||
crypto::secret_key m_original_view_secret_key;
|
||||
|
||||
crypto::chacha_key m_cache_key;
|
||||
boost::optional<crypto::chacha_key> m_custom_background_key = boost::none;
|
||||
std::shared_ptr<wallet_keys_unlocker> m_encrypt_keys_after_refresh;
|
||||
|
||||
bool m_unattended;
|
||||
@ -1934,9 +2053,13 @@ private:
|
||||
|
||||
static boost::mutex default_daemon_address_lock;
|
||||
static std::string default_daemon_address;
|
||||
|
||||
bool m_background_syncing;
|
||||
bool m_processing_background_cache;
|
||||
background_sync_data_t m_background_sync_data;
|
||||
};
|
||||
}
|
||||
BOOST_CLASS_VERSION(tools::wallet2, 30)
|
||||
BOOST_CLASS_VERSION(tools::wallet2, 31)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 12)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
|
||||
@ -1952,6 +2075,8 @@ BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 1)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 4)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 3)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 1)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::background_synced_tx_t, 0)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::background_sync_data_t, 0)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@ -2450,6 +2575,29 @@ namespace boost
|
||||
return;
|
||||
a & x.multisig_sigs;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive& a, tools::wallet2::background_synced_tx_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.index_in_background_sync_data;
|
||||
a & x.tx;
|
||||
a & x.output_indices;
|
||||
a & x.height;
|
||||
a & x.block_timestamp;
|
||||
a & x.double_spend_seen;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive& a, tools::wallet2::background_sync_data_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.first_refresh_done;
|
||||
a & x.start_height;
|
||||
a & x.txs;
|
||||
a & x.wallet_refresh_from_block_height;
|
||||
a & x.subaddress_lookahead_major;
|
||||
a & x.subaddress_lookahead_minor;
|
||||
a & x.wallet_refresh_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,7 @@ namespace tools
|
||||
// invalid_password
|
||||
// invalid_priority
|
||||
// invalid_multisig_seed
|
||||
// invalid_spend_key
|
||||
// refresh_error *
|
||||
// acc_outs_lookup_error
|
||||
// block_parse_error
|
||||
@ -97,6 +98,9 @@ namespace tools
|
||||
// wallet_files_doesnt_correspond
|
||||
// scan_tx_error *
|
||||
// wont_reprocess_recent_txs_via_untrusted_daemon
|
||||
// background_sync_error *
|
||||
// background_wallet_already_open
|
||||
// background_custom_password_same_as_wallet_password
|
||||
//
|
||||
// * - class with protected ctor
|
||||
|
||||
@ -304,6 +308,16 @@ namespace tools
|
||||
std::string to_string() const { return wallet_logic_error::to_string(); }
|
||||
};
|
||||
|
||||
struct invalid_spend_key : public wallet_logic_error
|
||||
{
|
||||
explicit invalid_spend_key(std::string&& loc)
|
||||
: wallet_logic_error(std::move(loc), "invalid spend key")
|
||||
{
|
||||
}
|
||||
|
||||
std::string to_string() const { return wallet_logic_error::to_string(); }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
struct invalid_pregenerated_random : public wallet_logic_error
|
||||
{
|
||||
@ -948,6 +962,31 @@ namespace tools
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
struct background_sync_error : public wallet_logic_error
|
||||
{
|
||||
protected:
|
||||
explicit background_sync_error(std::string&& loc, const std::string& message)
|
||||
: wallet_logic_error(std::move(loc), message)
|
||||
{
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
struct background_wallet_already_open : public background_sync_error
|
||||
{
|
||||
explicit background_wallet_already_open(std::string&& loc, const std::string& background_wallet_file)
|
||||
: background_sync_error(std::move(loc), "background wallet " + background_wallet_file + " is already opened by another wallet program")
|
||||
{
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
struct background_custom_password_same_as_wallet_password : public background_sync_error
|
||||
{
|
||||
explicit background_custom_password_same_as_wallet_password(std::string&& loc)
|
||||
: background_sync_error(std::move(loc), "custom background password must be different than wallet password")
|
||||
{
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
|
||||
|
@ -73,6 +73,54 @@ using namespace epee;
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CHECK_IF_BACKGROUND_SYNCING() \
|
||||
do \
|
||||
{ \
|
||||
if (!m_wallet) { return not_open(er); } \
|
||||
if (m_wallet->is_background_wallet()) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_IS_BACKGROUND_WALLET; \
|
||||
er.message = "This command is disabled for background wallets."; \
|
||||
return false; \
|
||||
} \
|
||||
if (m_wallet->is_background_syncing()) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_IS_BACKGROUND_SYNCING; \
|
||||
er.message = "This command is disabled while background syncing. Stop background syncing to use this command."; \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define PRE_VALIDATE_BACKGROUND_SYNC() \
|
||||
do \
|
||||
{ \
|
||||
if (!m_wallet) { return not_open(er); } \
|
||||
if (m_restricted) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_DENIED; \
|
||||
er.message = "Command unavailable in restricted mode."; \
|
||||
return false; \
|
||||
} \
|
||||
if (m_wallet->key_on_device()) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; \
|
||||
er.message = "Command not supported by HW wallet"; \
|
||||
return false; \
|
||||
} \
|
||||
if (m_wallet->get_multisig_status().multisig_is_active) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; \
|
||||
er.message = "Multisig wallet cannot enable background sync"; \
|
||||
return false; \
|
||||
} \
|
||||
if (m_wallet->watch_only()) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY; \
|
||||
er.message = "Watch-only wallet cannot enable background sync"; \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
namespace
|
||||
{
|
||||
const command_line::arg_descriptor<std::string, true> arg_rpc_bind_port = {"rpc-bind-port", "Sets bind port for server"};
|
||||
@ -291,6 +339,9 @@ namespace tools
|
||||
{
|
||||
if (!m_wallet)
|
||||
return;
|
||||
// Background mining can be toggled from the main wallet
|
||||
if (m_wallet->is_background_wallet() || m_wallet->is_background_syncing())
|
||||
return;
|
||||
|
||||
tools::wallet2::BackgroundMiningSetupType setup = m_wallet->setup_background_mining();
|
||||
if (setup == tools::wallet2::BackgroundMiningNo)
|
||||
@ -581,6 +632,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_create_address(const wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
if (req.count < 1 || req.count > 65536) {
|
||||
@ -618,6 +670,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_label_address(const wallet_rpc::COMMAND_RPC_LABEL_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_LABEL_ADDRESS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
m_wallet->set_subaddress_label(req.index, req.label);
|
||||
@ -680,6 +733,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_create_account(const wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
m_wallet->add_subaddress_account(req.label);
|
||||
@ -697,6 +751,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_label_account(const wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
m_wallet->set_subaddress_label({req.account_index, 0}, req.label);
|
||||
@ -712,6 +767,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_get_account_tags(const wallet_rpc::COMMAND_RPC_GET_ACCOUNT_TAGS::request& req, wallet_rpc::COMMAND_RPC_GET_ACCOUNT_TAGS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
const std::pair<std::map<std::string, std::string>, std::vector<std::string>> account_tags = m_wallet->get_account_tags();
|
||||
for (const std::pair<const std::string, std::string>& p : account_tags.first)
|
||||
{
|
||||
@ -731,6 +787,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_tag_accounts(const wallet_rpc::COMMAND_RPC_TAG_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_TAG_ACCOUNTS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
m_wallet->set_account_tag(req.accounts, req.tag);
|
||||
@ -746,6 +803,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_untag_accounts(const wallet_rpc::COMMAND_RPC_UNTAG_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_UNTAG_ACCOUNTS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
m_wallet->set_account_tag(req.accounts, "");
|
||||
@ -761,6 +819,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_set_account_tag_description(const wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::request& req, wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
m_wallet->set_account_tag_description(req.tag, req.description);
|
||||
@ -791,6 +850,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_freeze(const wallet_rpc::COMMAND_RPC_FREEZE::request& req, wallet_rpc::COMMAND_RPC_FREEZE::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
if (req.key_image.empty())
|
||||
@ -819,6 +879,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_thaw(const wallet_rpc::COMMAND_RPC_THAW::request& req, wallet_rpc::COMMAND_RPC_THAW::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
if (req.key_image.empty())
|
||||
@ -847,6 +908,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_frozen(const wallet_rpc::COMMAND_RPC_FROZEN::request& req, wallet_rpc::COMMAND_RPC_FROZEN::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
if (req.key_image.empty())
|
||||
@ -874,6 +936,8 @@ namespace tools
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
crypto::hash8 integrated_payment_id = crypto::null_hash8;
|
||||
std::string extra_nonce;
|
||||
for (auto it = destinations.begin(); it != destinations.end(); it++)
|
||||
@ -1203,6 +1267,7 @@ namespace tools
|
||||
}
|
||||
|
||||
CHECK_MULTISIG_ENABLED();
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
cryptonote::blobdata blob;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob))
|
||||
@ -1284,6 +1349,7 @@ namespace tools
|
||||
er.message = "command not supported by watch-only wallet";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
if(req.unsigned_txset.empty() && req.multisig_txset.empty())
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
@ -1553,6 +1619,7 @@ namespace tools
|
||||
}
|
||||
|
||||
CHECK_MULTISIG_ENABLED();
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
try
|
||||
{
|
||||
@ -2115,6 +2182,7 @@ namespace tools
|
||||
er.message = "The wallet is watch-only. Cannot retrieve seed.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
if (!m_wallet->is_deterministic())
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_NON_DETERMINISTIC;
|
||||
@ -2143,6 +2211,7 @@ namespace tools
|
||||
er.message = "The wallet is watch-only. Cannot retrieve spend key.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
epee::wipeable_string key = epee::to_hex::wipeable_string(m_wallet->get_account().get_keys().m_spend_secret_key);
|
||||
res.key = std::string(key.data(), key.size());
|
||||
}
|
||||
@ -2164,6 +2233,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
try
|
||||
{
|
||||
@ -2177,6 +2247,79 @@ namespace tools
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_setup_background_sync(const wallet_rpc::COMMAND_RPC_SETUP_BACKGROUND_SYNC::request& req, wallet_rpc::COMMAND_RPC_SETUP_BACKGROUND_SYNC::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
PRE_VALIDATE_BACKGROUND_SYNC();
|
||||
const tools::wallet2::BackgroundSyncType background_sync_type = tools::wallet2::background_sync_type_from_str(req.background_sync_type);
|
||||
boost::optional<epee::wipeable_string> background_cache_password = boost::none;
|
||||
if (background_sync_type == tools::wallet2::BackgroundSyncCustomPassword)
|
||||
background_cache_password = boost::optional<epee::wipeable_string>(req.background_cache_password);
|
||||
m_wallet->setup_background_sync(background_sync_type, req.wallet_password, background_cache_password);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_start_background_sync(const wallet_rpc::COMMAND_RPC_START_BACKGROUND_SYNC::request& req, wallet_rpc::COMMAND_RPC_START_BACKGROUND_SYNC::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
PRE_VALIDATE_BACKGROUND_SYNC();
|
||||
m_wallet->start_background_sync();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_stop_background_sync(const wallet_rpc::COMMAND_RPC_STOP_BACKGROUND_SYNC::request& req, wallet_rpc::COMMAND_RPC_STOP_BACKGROUND_SYNC::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
PRE_VALIDATE_BACKGROUND_SYNC();
|
||||
crypto::secret_key spend_secret_key = crypto::null_skey;
|
||||
|
||||
// Load the spend key from seed if seed is provided
|
||||
if (!req.seed.empty())
|
||||
{
|
||||
crypto::secret_key recovery_key;
|
||||
std::string language;
|
||||
|
||||
if (!crypto::ElectrumWords::words_to_bytes(req.seed, recovery_key, language))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = "Electrum-style word list failed verification";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!req.seed_offset.empty())
|
||||
recovery_key = cryptonote::decrypt_key(recovery_key, req.seed_offset);
|
||||
|
||||
// generate spend key
|
||||
cryptonote::account_base account;
|
||||
account.generate(recovery_key, true, false);
|
||||
spend_secret_key = account.get_keys().m_spend_secret_key;
|
||||
}
|
||||
|
||||
m_wallet->stop_background_sync(req.wallet_password, spend_secret_key);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
@ -2186,6 +2329,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
tools::wallet2::message_signature_type_t signature_type = tools::wallet2::sign_with_spend_key;
|
||||
if (req.signature_type == "spend" || req.signature_type == "")
|
||||
@ -2278,6 +2422,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
if (req.txids.size() != req.notes.size())
|
||||
{
|
||||
@ -2350,6 +2495,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
m_wallet->set_attribute(req.key, req.value);
|
||||
|
||||
@ -2377,6 +2523,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_get_tx_key(const wallet_rpc::COMMAND_RPC_GET_TX_KEY::request& req, wallet_rpc::COMMAND_RPC_GET_TX_KEY::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
crypto::hash txid;
|
||||
if (!epee::string_tools::hex_to_pod(req.txid, txid))
|
||||
@ -2468,6 +2615,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_get_tx_proof(const wallet_rpc::COMMAND_RPC_GET_TX_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_TX_PROOF::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
crypto::hash txid;
|
||||
if (!epee::string_tools::hex_to_pod(req.txid, txid))
|
||||
@ -2584,6 +2732,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_get_reserve_proof(const wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
boost::optional<std::pair<uint32_t, uint64_t>> account_minreserve;
|
||||
if (!req.all)
|
||||
@ -2826,6 +2975,7 @@ namespace tools
|
||||
er.message = "command not supported by HW wallet";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
try
|
||||
{
|
||||
@ -2855,6 +3005,7 @@ namespace tools
|
||||
er.message = "command not supported by HW wallet";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
cryptonote::blobdata blob;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(req.outputs_data_hex, blob))
|
||||
@ -2880,6 +3031,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all);
|
||||
@ -2916,6 +3068,7 @@ namespace tools
|
||||
er.message = "This command requires a trusted daemon.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
|
||||
@ -2984,6 +3137,7 @@ namespace tools
|
||||
bool wallet_rpc_server::on_get_address_book(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
const auto ab = m_wallet->get_address_book();
|
||||
if (req.entries.empty())
|
||||
{
|
||||
@ -3029,6 +3183,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
cryptonote::address_parse_info info;
|
||||
er.message = "";
|
||||
@ -3071,6 +3226,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
const auto ab = m_wallet->get_address_book();
|
||||
if (req.index >= ab.size())
|
||||
@ -3133,6 +3289,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
const auto ab = m_wallet->get_address_book();
|
||||
if (req.index >= ab.size())
|
||||
@ -3203,6 +3360,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
std::unordered_set<crypto::hash> txids;
|
||||
std::list<std::string>::const_iterator i = req.txids.begin();
|
||||
@ -3242,6 +3400,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
try
|
||||
{
|
||||
m_wallet->rescan_spent();
|
||||
@ -3506,6 +3665,7 @@ namespace tools
|
||||
er.message = "Command unavailable in restricted mode.";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
if (m_wallet->verify_password(req.old_password))
|
||||
{
|
||||
try
|
||||
@ -4039,6 +4199,7 @@ namespace tools
|
||||
er.message = "wallet is watch-only and cannot be made multisig";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
res.multisig_info = m_wallet->get_multisig_first_kex_msg();
|
||||
return true;
|
||||
@ -4066,6 +4227,7 @@ namespace tools
|
||||
er.message = "wallet is watch-only and cannot be made multisig";
|
||||
return false;
|
||||
}
|
||||
CHECK_IF_BACKGROUND_SYNCING();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -160,6 +160,9 @@ namespace tools
|
||||
MAP_JON_RPC_WE("set_log_categories", on_set_log_categories, wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES)
|
||||
MAP_JON_RPC_WE("estimate_tx_size_and_weight", on_estimate_tx_size_and_weight, wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT)
|
||||
MAP_JON_RPC_WE("get_version", on_get_version, wallet_rpc::COMMAND_RPC_GET_VERSION)
|
||||
MAP_JON_RPC_WE("setup_background_sync", on_setup_background_sync, wallet_rpc::COMMAND_RPC_SETUP_BACKGROUND_SYNC)
|
||||
MAP_JON_RPC_WE("start_background_sync", on_start_background_sync, wallet_rpc::COMMAND_RPC_START_BACKGROUND_SYNC)
|
||||
MAP_JON_RPC_WE("stop_background_sync", on_stop_background_sync, wallet_rpc::COMMAND_RPC_STOP_BACKGROUND_SYNC)
|
||||
END_JSON_RPC_MAP()
|
||||
END_URI_MAP2()
|
||||
|
||||
@ -252,6 +255,9 @@ namespace tools
|
||||
bool on_set_log_categories(const wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES::request& req, wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||
bool on_estimate_tx_size_and_weight(const wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::request& req, wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||
bool on_get_version(const wallet_rpc::COMMAND_RPC_GET_VERSION::request& req, wallet_rpc::COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||
bool on_setup_background_sync(const wallet_rpc::COMMAND_RPC_SETUP_BACKGROUND_SYNC::request& req, wallet_rpc::COMMAND_RPC_SETUP_BACKGROUND_SYNC::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||
bool on_start_background_sync(const wallet_rpc::COMMAND_RPC_START_BACKGROUND_SYNC::request& req, wallet_rpc::COMMAND_RPC_START_BACKGROUND_SYNC::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||
bool on_stop_background_sync(const wallet_rpc::COMMAND_RPC_STOP_BACKGROUND_SYNC::request& req, wallet_rpc::COMMAND_RPC_STOP_BACKGROUND_SYNC::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||
|
||||
//json rpc v2
|
||||
bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||
|
@ -2729,5 +2729,69 @@ namespace wallet_rpc
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_SETUP_BACKGROUND_SYNC
|
||||
{
|
||||
struct request_t
|
||||
{
|
||||
std::string background_sync_type;
|
||||
std::string wallet_password;
|
||||
std::string background_cache_password;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(background_sync_type)
|
||||
KV_SERIALIZE(wallet_password)
|
||||
KV_SERIALIZE_OPT(background_cache_password, (std::string)"")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
struct response_t
|
||||
{
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_START_BACKGROUND_SYNC
|
||||
{
|
||||
struct request_t
|
||||
{
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
struct response_t
|
||||
{
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_STOP_BACKGROUND_SYNC
|
||||
{
|
||||
struct request_t
|
||||
{
|
||||
std::string wallet_password;
|
||||
std::string seed;
|
||||
std::string seed_offset;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(wallet_password)
|
||||
KV_SERIALIZE_OPT(seed, (std::string)"")
|
||||
KV_SERIALIZE_OPT(seed_offset, (std::string)"")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
struct response_t
|
||||
{
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -81,3 +81,5 @@
|
||||
#define WALLET_RPC_ERROR_CODE_DISABLED -48
|
||||
#define WALLET_RPC_ERROR_CODE_PROXY_ALREADY_DEFINED -49
|
||||
#define WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME -50
|
||||
#define WALLET_RPC_ERROR_CODE_IS_BACKGROUND_WALLET -51
|
||||
#define WALLET_RPC_ERROR_CODE_IS_BACKGROUND_SYNCING -52
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
from __future__ import print_function
|
||||
import json
|
||||
import util_resources
|
||||
import pprint
|
||||
from deepdiff import DeepDiff
|
||||
pp = pprint.PrettyPrinter(indent=2)
|
||||
@ -46,6 +47,17 @@ seeds = [
|
||||
'dilute gutter certain antics pamphlet macro enjoy left slid guarded bogeys upload nineteen bomb jubilee enhanced irritate turnip eggs swung jukebox loudly reduce sedan slid',
|
||||
]
|
||||
|
||||
def diff_transfers(actual_transfers, expected_transfers, ignore_order = True):
|
||||
# The payments containers aren't ordered; re-scanning can lead to diff orders
|
||||
diff = DeepDiff(actual_transfers, expected_transfers, ignore_order = ignore_order)
|
||||
if diff != {}:
|
||||
pp.pprint(diff)
|
||||
assert diff == {}
|
||||
|
||||
def diff_incoming_transfers(actual_transfers, expected_transfers):
|
||||
# wallet2 m_transfers container is ordered and order should be the same across rescans
|
||||
diff_transfers(actual_transfers, expected_transfers, ignore_order = False)
|
||||
|
||||
class TransferTest():
|
||||
def run_test(self):
|
||||
self.reset()
|
||||
@ -64,6 +76,8 @@ class TransferTest():
|
||||
self.check_multiple_submissions()
|
||||
self.check_scan_tx()
|
||||
self.check_subtract_fee_from_outputs()
|
||||
self.check_background_sync()
|
||||
self.check_background_sync_reorg_recovery()
|
||||
|
||||
def reset(self):
|
||||
print('Resetting blockchain')
|
||||
@ -875,12 +889,6 @@ class TransferTest():
|
||||
|
||||
print('Testing scan_tx')
|
||||
|
||||
def diff_transfers(actual_transfers, expected_transfers):
|
||||
diff = DeepDiff(actual_transfers, expected_transfers)
|
||||
if diff != {}:
|
||||
pp.pprint(diff)
|
||||
assert diff == {}
|
||||
|
||||
# set up sender_wallet
|
||||
sender_wallet = self.wallet[0]
|
||||
try: sender_wallet.close_wallet()
|
||||
@ -1162,5 +1170,385 @@ class TransferTest():
|
||||
except AssertionError:
|
||||
pass
|
||||
|
||||
def check_background_sync(self):
|
||||
daemon = Daemon()
|
||||
|
||||
print('Testing background sync')
|
||||
|
||||
# Some helper functions
|
||||
def stop_with_wrong_inputs(wallet, wallet_password, seed = ''):
|
||||
invalid = False
|
||||
try: wallet.stop_background_sync(wallet_password = wallet_password, seed = seed)
|
||||
except: invalid = True
|
||||
assert invalid
|
||||
|
||||
def open_with_wrong_password(wallet, filename, password):
|
||||
invalid_password = False
|
||||
try: wallet.open_wallet(filename, password = password)
|
||||
except: invalid_password = True
|
||||
assert invalid_password
|
||||
|
||||
def restore_wallet(wallet, seed, filename = '', password = ''):
|
||||
wallet.close_wallet()
|
||||
if filename != '':
|
||||
util_resources.remove_wallet_files(filename)
|
||||
wallet.restore_deterministic_wallet(seed = seed, filename = filename, password = password)
|
||||
wallet.auto_refresh(enable = False)
|
||||
assert wallet.get_transfers() == {}
|
||||
|
||||
def assert_correct_transfers(wallet, expected_transfers, expected_inc_transfers, expected_balance):
|
||||
diff_transfers(wallet.get_transfers(), expected_transfers)
|
||||
diff_incoming_transfers(wallet.incoming_transfers(transfer_type = 'all'), expected_inc_transfers)
|
||||
assert wallet.get_balance().balance == expected_balance
|
||||
|
||||
# Set up sender_wallet. Prepare to sweep single output to receiver.
|
||||
# We're testing a sweep because it makes sure background sync can
|
||||
# properly pick up txs which do not have a change output back to sender.
|
||||
sender_wallet = self.wallet[0]
|
||||
try: sender_wallet.close_wallet()
|
||||
except: pass
|
||||
sender_wallet.restore_deterministic_wallet(seed = seeds[0])
|
||||
sender_wallet.auto_refresh(enable = False)
|
||||
sender_wallet.refresh()
|
||||
res = sender_wallet.incoming_transfers(transfer_type = 'available')
|
||||
unlocked = [x for x in res.transfers if x.unlocked and x.amount > 0]
|
||||
assert len(unlocked) > 0
|
||||
ki = unlocked[0].key_image
|
||||
amount = unlocked[0].amount
|
||||
spent_txid = unlocked[0].tx_hash
|
||||
sender_wallet.refresh()
|
||||
res = sender_wallet.get_transfers()
|
||||
out_len = 0 if 'out' not in res else len(res.out)
|
||||
sender_starting_balance = sender_wallet.get_balance().balance
|
||||
|
||||
# Background sync type options
|
||||
reuse_password = sender_wallet.background_sync_options.reuse_password
|
||||
custom_password = sender_wallet.background_sync_options.custom_password
|
||||
|
||||
# set up receiver_wallet
|
||||
receiver_wallet = self.wallet[1]
|
||||
try: receiver_wallet.close_wallet()
|
||||
except: pass
|
||||
receiver_wallet.restore_deterministic_wallet(seed = seeds[1])
|
||||
receiver_wallet.auto_refresh(enable = False)
|
||||
receiver_wallet.refresh()
|
||||
res = receiver_wallet.get_transfers()
|
||||
in_len = 0 if 'in' not in res else len(res['in'])
|
||||
receiver_starting_balance = receiver_wallet.get_balance().balance
|
||||
|
||||
# transfer from sender_wallet to receiver_wallet
|
||||
dst = '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW'
|
||||
res = sender_wallet.sweep_single(dst, key_image = ki)
|
||||
assert len(res.tx_hash) == 32*2
|
||||
txid = res.tx_hash
|
||||
assert res.fee > 0
|
||||
fee = res.fee
|
||||
assert res.amount == amount - fee
|
||||
|
||||
expected_sender_balance = sender_starting_balance - amount
|
||||
expected_receiver_balance = receiver_starting_balance + (amount - fee)
|
||||
|
||||
print('Checking background sync on outgoing wallet')
|
||||
sender_wallet.setup_background_sync(background_sync_type = reuse_password)
|
||||
sender_wallet.start_background_sync()
|
||||
# Mine block to an uninvolved wallet
|
||||
daemon.generateblocks('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 1)
|
||||
# sender should still be able to scan the transfer normally because we
|
||||
# spent an output that had a known key image
|
||||
sender_wallet.refresh()
|
||||
transfers = sender_wallet.get_transfers()
|
||||
assert 'pending' not in transfers or len(transfers.pending) == 0
|
||||
assert 'pool' not in transfers or len (transfers.pool) == 0
|
||||
assert len(transfers.out) == out_len + 1
|
||||
tx = [x for x in transfers.out if x.txid == txid]
|
||||
assert len(tx) == 1
|
||||
tx = tx[0]
|
||||
assert tx.amount == amount - fee
|
||||
assert tx.fee == fee
|
||||
assert len(tx.destinations) == 1
|
||||
assert tx.destinations[0].amount == amount - fee
|
||||
assert tx.destinations[0].address == dst
|
||||
incoming_transfers = sender_wallet.incoming_transfers(transfer_type = 'all')
|
||||
assert len([x for x in incoming_transfers.transfers if x.tx_hash == spent_txid and x.key_image == ki and x.spent]) == 1
|
||||
assert sender_wallet.get_balance().balance == expected_sender_balance
|
||||
|
||||
# Restore and check background syncing outgoing wallet
|
||||
restore_wallet(sender_wallet, seeds[0])
|
||||
sender_wallet.setup_background_sync(background_sync_type = reuse_password)
|
||||
sender_wallet.start_background_sync()
|
||||
sender_wallet.refresh()
|
||||
for i, out_tx in enumerate(transfers.out):
|
||||
if 'destinations' in out_tx:
|
||||
del transfers.out[i]['destinations'] # destinations are not expected after wallet restore
|
||||
# sender's balance should be higher because can't detect spends while
|
||||
# background sync enabled, only receives
|
||||
background_bal = sender_wallet.get_balance().balance
|
||||
assert background_bal > expected_sender_balance
|
||||
background_transfers = sender_wallet.get_transfers()
|
||||
assert 'out' not in background_transfers or len(background_transfers.out) == 0
|
||||
assert 'in' in background_transfers and len(background_transfers['in']) > 0
|
||||
background_incoming_transfers = sender_wallet.incoming_transfers(transfer_type = 'all')
|
||||
assert len(background_incoming_transfers) == len(incoming_transfers)
|
||||
assert len([x for x in background_incoming_transfers.transfers if x.spent or x.key_image != '']) == 0
|
||||
assert len([x for x in background_incoming_transfers.transfers if x.tx_hash == spent_txid]) == 1
|
||||
|
||||
# Try to stop background sync with the wrong seed
|
||||
stop_with_wrong_inputs(sender_wallet, wallet_password = '', seed = seeds[1])
|
||||
|
||||
# Stop background sync and check transfers update correctly
|
||||
sender_wallet.stop_background_sync(wallet_password = '', seed = seeds[0])
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
# Check stopping a wallet with wallet files saved to disk
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
sender_wallet.start_background_sync()
|
||||
sender_wallet.refresh()
|
||||
assert_correct_transfers(sender_wallet, background_transfers, background_incoming_transfers, background_bal)
|
||||
stop_with_wrong_inputs(sender_wallet, 'wrong_password')
|
||||
sender_wallet.stop_background_sync(wallet_password = 'test_password')
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
# Close wallet while background syncing, then reopen
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
sender_wallet.start_background_sync()
|
||||
sender_wallet.refresh()
|
||||
assert_correct_transfers(sender_wallet, background_transfers, background_incoming_transfers, background_bal)
|
||||
sender_wallet.close_wallet()
|
||||
open_with_wrong_password(sender_wallet, 'test1', 'wrong_password')
|
||||
sender_wallet.open_wallet('test1', password = 'test_password')
|
||||
# It should reopen with spend key loaded and correctly scan all transfers
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
# Close wallet while syncing normally, then reopen
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
sender_wallet.refresh()
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
sender_wallet.close_wallet()
|
||||
open_with_wrong_password(sender_wallet, 'test1', 'wrong_password')
|
||||
sender_wallet.open_wallet('test1', password = 'test_password')
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
# Create background cache using custom password, then use it to sync, then reopen main wallet
|
||||
for background_cache_password in ['background_password', '']:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
sender_wallet.setup_background_sync(background_sync_type = custom_password, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
assert util_resources.file_exists('test1.background')
|
||||
assert util_resources.file_exists('test1.background.keys')
|
||||
sender_wallet.close_wallet()
|
||||
open_with_wrong_password(sender_wallet, 'test1.background', 'test_password')
|
||||
sender_wallet.open_wallet('test1.background', password = background_cache_password)
|
||||
sender_wallet.refresh()
|
||||
assert_correct_transfers(sender_wallet, background_transfers, background_incoming_transfers, background_bal)
|
||||
sender_wallet.close_wallet()
|
||||
sender_wallet.open_wallet('test1', password = 'test_password')
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
# Check that main wallet keeps background cache encrypted with custom password in sync
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = 'background_password')
|
||||
sender_wallet.refresh()
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
sender_wallet.close_wallet()
|
||||
sender_wallet.open_wallet('test1.background', password = 'background_password')
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
# Try using wallet password as custom background password
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
same_password = False
|
||||
try: sender_wallet.setup_background_sync(background_sync_type = custom_password, wallet_password = 'test_password', background_cache_password = 'test_password')
|
||||
except: same_password = True
|
||||
assert same_password
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
|
||||
# Turn off background sync
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
|
||||
if background_sync_type == custom_password:
|
||||
assert util_resources.file_exists('test1.background')
|
||||
assert util_resources.file_exists('test1.background.keys')
|
||||
sender_wallet.close_wallet()
|
||||
assert util_resources.file_exists('test1.background')
|
||||
assert util_resources.file_exists('test1.background.keys')
|
||||
else:
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
sender_wallet.close_wallet()
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
sender_wallet.open_wallet('test1', password = 'test_password')
|
||||
sender_wallet.setup_background_sync(background_sync_type = sender_wallet.background_sync_options.off, wallet_password = 'test_password')
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
sender_wallet.close_wallet()
|
||||
assert not util_resources.file_exists('test1.background')
|
||||
assert not util_resources.file_exists('test1.background.keys')
|
||||
sender_wallet.open_wallet('test1', password = 'test_password')
|
||||
|
||||
# Sanity check against outgoing wallet restored at height 0
|
||||
sender_wallet.close_wallet()
|
||||
sender_wallet.restore_deterministic_wallet(seed = seeds[0], restore_height = 0)
|
||||
sender_wallet.refresh()
|
||||
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
|
||||
|
||||
print('Checking background sync on incoming wallet')
|
||||
receiver_wallet.setup_background_sync(background_sync_type = reuse_password)
|
||||
receiver_wallet.start_background_sync()
|
||||
receiver_wallet.refresh()
|
||||
transfers = receiver_wallet.get_transfers()
|
||||
assert 'pending' not in transfers or len(transfers.pending) == 0
|
||||
assert 'pool' not in transfers or len (transfers.pool) == 0
|
||||
assert len(transfers['in']) == in_len + 1
|
||||
tx = [x for x in transfers['in'] if x.txid == txid]
|
||||
assert len(tx) == 1
|
||||
tx = tx[0]
|
||||
assert tx.amount == amount - fee
|
||||
assert tx.fee == fee
|
||||
incoming_transfers = receiver_wallet.incoming_transfers(transfer_type = 'all')
|
||||
assert len([x for x in incoming_transfers.transfers if x.tx_hash == txid and x.key_image == '' and not x.spent]) == 1
|
||||
assert receiver_wallet.get_balance().balance == expected_receiver_balance
|
||||
|
||||
# Restore and check background syncing incoming wallet
|
||||
restore_wallet(receiver_wallet, seeds[1])
|
||||
receiver_wallet.setup_background_sync(background_sync_type = reuse_password)
|
||||
receiver_wallet.start_background_sync()
|
||||
receiver_wallet.refresh()
|
||||
if 'out' in transfers:
|
||||
for i, out_tx in enumerate(transfers.out):
|
||||
if 'destinations' in out_tx:
|
||||
del transfers.out[i]['destinations'] # destinations are not expected after wallet restore
|
||||
background_bal = receiver_wallet.get_balance().balance
|
||||
assert background_bal >= expected_receiver_balance
|
||||
background_transfers = receiver_wallet.get_transfers()
|
||||
assert 'out' not in background_transfers or len(background_transfers.out) == 0
|
||||
assert 'in' in background_transfers and len(background_transfers['in']) > 0
|
||||
background_incoming_transfers = receiver_wallet.incoming_transfers(transfer_type = 'all')
|
||||
assert len(background_incoming_transfers) == len(incoming_transfers)
|
||||
assert len([x for x in background_incoming_transfers.transfers if x.spent or x.key_image != '']) == 0
|
||||
assert len([x for x in background_incoming_transfers.transfers if x.tx_hash == txid]) == 1
|
||||
|
||||
# Stop background sync and check transfers update correctly
|
||||
receiver_wallet.stop_background_sync(wallet_password = '', seed = seeds[1])
|
||||
diff_transfers(receiver_wallet.get_transfers(), transfers)
|
||||
incoming_transfers = receiver_wallet.incoming_transfers(transfer_type = 'all')
|
||||
assert len(background_incoming_transfers) == len(incoming_transfers)
|
||||
assert len([x for x in incoming_transfers.transfers if x.tx_hash == txid and x.key_image != '' and not x.spent]) == 1
|
||||
assert receiver_wallet.get_balance().balance == expected_receiver_balance
|
||||
|
||||
# Check a fresh incoming wallet with wallet files saved to disk and encrypted with password
|
||||
restore_wallet(receiver_wallet, seeds[1], 'test2', 'test_password')
|
||||
receiver_wallet.setup_background_sync(background_sync_type = reuse_password, wallet_password = 'test_password')
|
||||
receiver_wallet.start_background_sync()
|
||||
receiver_wallet.refresh()
|
||||
assert_correct_transfers(receiver_wallet, background_transfers, background_incoming_transfers, background_bal)
|
||||
stop_with_wrong_inputs(receiver_wallet, 'wrong_password')
|
||||
receiver_wallet.stop_background_sync(wallet_password = 'test_password')
|
||||
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
|
||||
|
||||
# Close receiver's wallet while background sync is enabled then reopen
|
||||
restore_wallet(receiver_wallet, seeds[1], 'test2', 'test_password')
|
||||
receiver_wallet.setup_background_sync(background_sync_type = reuse_password, wallet_password = 'test_password')
|
||||
receiver_wallet.start_background_sync()
|
||||
receiver_wallet.refresh()
|
||||
diff_transfers(receiver_wallet.get_transfers(), background_transfers)
|
||||
diff_incoming_transfers(receiver_wallet.incoming_transfers(transfer_type = 'all'), background_incoming_transfers)
|
||||
assert receiver_wallet.get_balance().balance == background_bal
|
||||
receiver_wallet.close_wallet()
|
||||
receiver_wallet.open_wallet('test2', password = 'test_password')
|
||||
# It should reopen with spend key loaded and correctly scan all transfers
|
||||
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
|
||||
|
||||
# Sanity check against incoming wallet restored at height 0
|
||||
receiver_wallet.close_wallet()
|
||||
receiver_wallet.restore_deterministic_wallet(seed = seeds[1], restore_height = 0)
|
||||
receiver_wallet.refresh()
|
||||
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
|
||||
|
||||
# Clean up
|
||||
util_resources.remove_wallet_files('test1')
|
||||
util_resources.remove_wallet_files('test2')
|
||||
for i in range(2):
|
||||
self.wallet[i].close_wallet()
|
||||
self.wallet[i].restore_deterministic_wallet(seed = seeds[i])
|
||||
|
||||
def check_background_sync_reorg_recovery(self):
|
||||
daemon = Daemon()
|
||||
|
||||
print('Testing background sync reorg recovery')
|
||||
|
||||
# Disconnect daemon from peers
|
||||
daemon.out_peers(0)
|
||||
|
||||
# Background sync type options
|
||||
sender_wallet = self.wallet[0]
|
||||
reuse_password = sender_wallet.background_sync_options.reuse_password
|
||||
custom_password = sender_wallet.background_sync_options.custom_password
|
||||
|
||||
for background_sync_type in [reuse_password, custom_password]:
|
||||
# Set up wallet saved to disk
|
||||
sender_wallet.close_wallet()
|
||||
util_resources.remove_wallet_files('test1')
|
||||
sender_wallet.restore_deterministic_wallet(seed = seeds[0], filename = 'test1', password = '')
|
||||
sender_wallet.auto_refresh(enable = False)
|
||||
sender_wallet.refresh()
|
||||
sender_starting_balance = sender_wallet.get_balance().balance
|
||||
|
||||
# Send tx and mine a block
|
||||
amount = 1000000000000
|
||||
assert sender_starting_balance > amount
|
||||
dst = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': amount}
|
||||
res = sender_wallet.transfer([dst])
|
||||
assert len(res.tx_hash) == 32*2
|
||||
txid = res.tx_hash
|
||||
|
||||
daemon.generateblocks('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 1)
|
||||
|
||||
# Make sure the wallet can see the tx
|
||||
sender_wallet.refresh()
|
||||
transfers = sender_wallet.get_transfers()
|
||||
assert 'pool' not in transfers or len (transfers.pool) == 0
|
||||
tx = [x for x in transfers.out if x.txid == txid]
|
||||
assert len(tx) == 1
|
||||
tx = tx[0]
|
||||
assert sender_wallet.get_balance().balance < (sender_starting_balance - amount)
|
||||
|
||||
# Pop the block while background syncing
|
||||
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
|
||||
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = '', background_cache_password = background_cache_password)
|
||||
sender_wallet.start_background_sync()
|
||||
daemon.pop_blocks(1)
|
||||
daemon.flush_txpool()
|
||||
|
||||
daemon.generateblocks('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 1)
|
||||
|
||||
# Make sure the wallet can no longer see the tx
|
||||
sender_wallet.refresh()
|
||||
sender_wallet.stop_background_sync(wallet_password = '', seed = seeds[0])
|
||||
transfers = sender_wallet.get_transfers()
|
||||
no_tx = [x for x in transfers.out if x.txid == txid]
|
||||
assert len(no_tx) == 0
|
||||
assert sender_wallet.get_balance().balance == sender_starting_balance
|
||||
|
||||
# Clean up
|
||||
daemon.out_peers(12)
|
||||
util_resources.remove_wallet_files('test1')
|
||||
self.wallet[0].close_wallet()
|
||||
self.wallet[0].restore_deterministic_wallet(seed = seeds[0])
|
||||
|
||||
if __name__ == '__main__':
|
||||
TransferTest().run_test()
|
||||
|
@ -37,6 +37,8 @@
|
||||
from __future__ import print_function
|
||||
import subprocess
|
||||
import psutil
|
||||
import os
|
||||
import errno
|
||||
|
||||
def available_ram_gb():
|
||||
ram_bytes = psutil.virtual_memory().available
|
||||
@ -51,3 +53,26 @@ def get_time_pi_seconds(cores, app_dir='.'):
|
||||
miliseconds = int(decoded)
|
||||
|
||||
return miliseconds / 1000.0
|
||||
|
||||
def remove_file(name):
|
||||
WALLET_DIRECTORY = os.environ['WALLET_DIRECTORY']
|
||||
assert WALLET_DIRECTORY != ''
|
||||
try:
|
||||
os.unlink(WALLET_DIRECTORY + '/' + name)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
def get_file_path(name):
|
||||
WALLET_DIRECTORY = os.environ['WALLET_DIRECTORY']
|
||||
assert WALLET_DIRECTORY != ''
|
||||
return WALLET_DIRECTORY + '/' + name
|
||||
|
||||
def remove_wallet_files(name):
|
||||
for suffix in ['', '.keys', '.background', '.background.keys', '.address.txt']:
|
||||
remove_file(name + suffix)
|
||||
|
||||
def file_exists(name):
|
||||
WALLET_DIRECTORY = os.environ['WALLET_DIRECTORY']
|
||||
assert WALLET_DIRECTORY != ''
|
||||
return os.path.isfile(WALLET_DIRECTORY + '/' + name)
|
||||
|
@ -34,8 +34,7 @@
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import os
|
||||
import errno
|
||||
import util_resources
|
||||
|
||||
from framework.wallet import Wallet
|
||||
from framework.daemon import Daemon
|
||||
@ -54,24 +53,6 @@ class WalletTest():
|
||||
self.change_password()
|
||||
self.store()
|
||||
|
||||
def remove_file(self, name):
|
||||
WALLET_DIRECTORY = os.environ['WALLET_DIRECTORY']
|
||||
assert WALLET_DIRECTORY != ''
|
||||
try:
|
||||
os.unlink(WALLET_DIRECTORY + '/' + name)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
def remove_wallet_files(self, name):
|
||||
for suffix in ['', '.keys']:
|
||||
self.remove_file(name + suffix)
|
||||
|
||||
def file_exists(self, name):
|
||||
WALLET_DIRECTORY = os.environ['WALLET_DIRECTORY']
|
||||
assert WALLET_DIRECTORY != ''
|
||||
return os.path.isfile(WALLET_DIRECTORY + '/' + name)
|
||||
|
||||
def reset(self):
|
||||
print('Resetting blockchain')
|
||||
daemon = Daemon()
|
||||
@ -333,7 +314,7 @@ class WalletTest():
|
||||
try: wallet.close_wallet()
|
||||
except: pass
|
||||
|
||||
self.remove_wallet_files('test1')
|
||||
util_resources.remove_wallet_files('test1')
|
||||
|
||||
seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted'
|
||||
res = wallet.restore_deterministic_wallet(seed = seed, filename = 'test1')
|
||||
@ -359,7 +340,7 @@ class WalletTest():
|
||||
|
||||
wallet.close_wallet()
|
||||
|
||||
self.remove_wallet_files('test1')
|
||||
util_resources.remove_wallet_files('test1')
|
||||
|
||||
def store(self):
|
||||
print('Testing store')
|
||||
@ -369,22 +350,26 @@ class WalletTest():
|
||||
try: wallet.close_wallet()
|
||||
except: pass
|
||||
|
||||
self.remove_wallet_files('test1')
|
||||
util_resources.remove_wallet_files('test1')
|
||||
|
||||
seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted'
|
||||
res = wallet.restore_deterministic_wallet(seed = seed, filename = 'test1')
|
||||
assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||
assert res.seed == seed
|
||||
|
||||
self.remove_file('test1')
|
||||
assert self.file_exists('test1.keys')
|
||||
assert not self.file_exists('test1')
|
||||
util_resources.remove_file('test1')
|
||||
assert util_resources.file_exists('test1.keys')
|
||||
assert not util_resources.file_exists('test1')
|
||||
wallet.store()
|
||||
assert self.file_exists('test1.keys')
|
||||
assert self.file_exists('test1')
|
||||
assert util_resources.file_exists('test1.keys')
|
||||
assert util_resources.file_exists('test1')
|
||||
|
||||
wallet.close_wallet()
|
||||
self.remove_wallet_files('test1')
|
||||
|
||||
wallet.open_wallet(filename = 'test1', password = '')
|
||||
wallet.close_wallet()
|
||||
|
||||
util_resources.remove_wallet_files('test1')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -211,3 +211,15 @@ TEST(wipeable_string, to_hex)
|
||||
ASSERT_TRUE(epee::to_hex::wipeable_string(epee::span<const uint8_t>((const uint8_t*)"", 0)) == epee::wipeable_string(""));
|
||||
ASSERT_TRUE(epee::to_hex::wipeable_string(epee::span<const uint8_t>((const uint8_t*)"abc", 3)) == epee::wipeable_string("616263"));
|
||||
}
|
||||
|
||||
TEST(wipeable_string, to_string)
|
||||
{
|
||||
// Converting a wipeable_string to a string defeats the purpose of wipeable_string,
|
||||
// but nice to know this works
|
||||
std::string str;
|
||||
{
|
||||
epee::wipeable_string wipeable_str("foo");
|
||||
str = std::string(wipeable_str.data(), wipeable_str.size());
|
||||
}
|
||||
ASSERT_TRUE(str == std::string("foo"));
|
||||
}
|
||||
|
@ -1153,3 +1153,45 @@ class Wallet(object):
|
||||
'id': '0'
|
||||
}
|
||||
return self.rpc.send_json_rpc_request(frozen)
|
||||
|
||||
class BackgroundSyncOptions(object):
|
||||
def __init__(self):
|
||||
self.off = 'off'
|
||||
self.reuse_password = 'reuse-wallet-password'
|
||||
self.custom_password = 'custom-background-password'
|
||||
background_sync_options = BackgroundSyncOptions()
|
||||
|
||||
def setup_background_sync(self, background_sync_type = background_sync_options.off, wallet_password = '', background_cache_password = ''):
|
||||
setup_background_sync = {
|
||||
'method': 'setup_background_sync',
|
||||
'jsonrpc': '2.0',
|
||||
'params' : {
|
||||
'background_sync_type': background_sync_type,
|
||||
'wallet_password': wallet_password,
|
||||
'background_cache_password': background_cache_password,
|
||||
},
|
||||
'id': '0'
|
||||
}
|
||||
return self.rpc.send_json_rpc_request(setup_background_sync)
|
||||
|
||||
def start_background_sync(self):
|
||||
start_background_sync = {
|
||||
'method': 'start_background_sync',
|
||||
'jsonrpc': '2.0',
|
||||
'params' : {},
|
||||
'id': '0'
|
||||
}
|
||||
return self.rpc.send_json_rpc_request(start_background_sync)
|
||||
|
||||
def stop_background_sync(self, wallet_password = '', seed = '', seed_offset = ''):
|
||||
stop_background_sync = {
|
||||
'method': 'stop_background_sync',
|
||||
'jsonrpc': '2.0',
|
||||
'params' : {
|
||||
'wallet_password': wallet_password,
|
||||
'seed': seed,
|
||||
'seed_offset': seed_offset,
|
||||
},
|
||||
'id': '0'
|
||||
}
|
||||
return self.rpc.send_json_rpc_request(stop_background_sync)
|
||||
|
Loading…
Reference in New Issue
Block a user