aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/wallet.cpp6
-rw-r--r--src/wallet/wallet2.cpp60
-rw-r--r--src/wallet/wallet2.h2
-rw-r--r--src/wallet/wallet_args.cpp8
-rw-r--r--src/wallet/wallet_rpc_server.cpp231
-rw-r--r--src/wallet/wallet_rpc_server.h2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h37
7 files changed, 315 insertions, 31 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index ddf2d74ff..7cd3b65bb 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -507,7 +507,7 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas
auto key_images = m_wallet->export_key_images();
uint64_t spent = 0;
uint64_t unspent = 0;
- view_wallet->import_key_images(key_images,spent,unspent,false);
+ view_wallet->import_key_images(key_images.second, key_images.first, spent, unspent, false);
clearStatus();
} catch (const std::exception &e) {
LOG_ERROR("Error creating view only wallet: " << e.what());
@@ -1051,8 +1051,8 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file
// Check tx data and construct confirmation message
std::string extra_message;
- if (!transaction->m_unsigned_tx_set.transfers.empty())
- extra_message = (boost::format("%u outputs to import. ") % (unsigned)transaction->m_unsigned_tx_set.transfers.size()).str();
+ if (!transaction->m_unsigned_tx_set.transfers.second.empty())
+ extra_message = (boost::format("%u outputs to import. ") % (unsigned)transaction->m_unsigned_tx_set.transfers.second.size()).str();
transaction->checkLoadedTx([&transaction](){return transaction->m_unsigned_tx_set.txes.size();}, [&transaction](size_t n)->const tools::wallet2::tx_construction_data&{return transaction->m_unsigned_tx_set.txes[n];}, extra_message);
setStatus(transaction->status(), transaction->errorString());
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 58ed5dcad..de1fb6f99 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1929,6 +1929,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
entry.first->second.m_subaddr_indices = subaddr_indices;
}
+ entry.first->second.m_rings.clear();
for (const auto &in: tx.vin)
{
if (in.type() != typeid(cryptonote::txin_to_key))
@@ -2300,7 +2301,7 @@ void wallet2::remove_obsolete_pool_txs(const std::vector<crypto::hash> &tx_hashe
//----------------------------------------------------------------------------------------------------
void wallet2::update_pool_state(bool refreshed)
{
- MDEBUG("update_pool_state start");
+ MTRACE("update_pool_state start");
auto keys_reencryptor = epee::misc_utils::create_scope_leave_handler([&, this]() {
if (m_encrypt_keys_after_refresh)
@@ -2319,7 +2320,7 @@ void wallet2::update_pool_state(bool refreshed)
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_transaction_pool_hashes.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_transaction_pool_hashes.bin");
THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
- MDEBUG("update_pool_state got pool");
+ MTRACE("update_pool_state got pool");
// remove any pending tx that's not in the pool
std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin();
@@ -2376,7 +2377,7 @@ void wallet2::update_pool_state(bool refreshed)
}
}
}
- MDEBUG("update_pool_state done first loop");
+ MTRACE("update_pool_state done first loop");
// remove pool txes to us that aren't in the pool anymore
// but only if we just refreshed, so that the tx can go in
@@ -2385,7 +2386,7 @@ void wallet2::update_pool_state(bool refreshed)
if (refreshed)
remove_obsolete_pool_txs(res.tx_hashes);
- MDEBUG("update_pool_state done second loop");
+ MTRACE("update_pool_state done second loop");
// gather txids of new pool txes to us
std::vector<std::pair<crypto::hash, bool>> txids;
@@ -2522,7 +2523,7 @@ void wallet2::update_pool_state(bool refreshed)
LOG_PRINT_L0("Error calling gettransactions daemon RPC: r " << r << ", status " << res.status);
}
}
- MDEBUG("update_pool_state end");
+ MTRACE("update_pool_state end");
}
//----------------------------------------------------------------------------------------------------
void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force)
@@ -2730,7 +2731,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
short_chain_history.clear();
get_short_chain_history(short_chain_history);
fast_refresh(stop_height, blocks_start_height, short_chain_history, true);
- THROW_WALLET_EXCEPTION_IF(m_blockchain.size() != stop_height, error::wallet_internal_error, "Unexpected hashchain size");
+ THROW_WALLET_EXCEPTION_IF((m_blockchain.size() == stop_height || (m_blockchain.size() == 1 && stop_height == 0) ? false : true), error::wallet_internal_error, "Unexpected hashchain size");
THROW_WALLET_EXCEPTION_IF(m_blockchain.offset() != 0, error::wallet_internal_error, "Unexpected hashchain offset");
for (const auto &h: tip)
m_blockchain.push_back(h);
@@ -2851,10 +2852,11 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response res = AUTO_VAL_INIT(res);
req.amounts.push_back(0);
req.from_height = 0;
- req.cumulative = true;
+ req.cumulative = false;
req.binary = true;
+ req.compress = true;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req, res, m_http_client, rpc_timeout);
+ bool r = net_utils::invoke_http_bin("/get_output_distribution.bin", req, res, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
if (!r)
{
@@ -2881,6 +2883,8 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
MWARNING("Failed to request output distribution: results are not for amount 0");
return false;
}
+ for (size_t i = 1; i < res.distributions[0].data.distribution.size(); ++i)
+ res.distributions[0].data.distribution[i] += res.distributions[0].data.distribution[i-1];
start_height = res.distributions[0].data.start_height;
distribution = std::move(res.distributions[0].data.distribution);
return true;
@@ -3144,7 +3148,6 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
account_data = buffer.GetString();
// Encrypt the entire JSON object.
- crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
std::string cipher;
cipher.resize(account_data.size());
keys_file_data.iv = crypto::rand<crypto::chacha_iv>();
@@ -6027,10 +6030,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
rct::RangeProofType range_proof_type = rct::RangeProofBorromean;
if (sd.use_bulletproofs)
{
- range_proof_type = rct::RangeProofBulletproof;
- for (const rct::Bulletproof &proof: ptx.tx.rct_signatures.p.bulletproofs)
- if (proof.V.size() > 1)
- range_proof_type = rct::RangeProofPaddedBulletproof;
+ range_proof_type = rct::RangeProofPaddedBulletproof;
}
bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, range_proof_type, &msout, false);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
@@ -6841,21 +6841,23 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
//static const double shape = m_testnet ? 17.02 : 17.28;
static const double scale = 1/1.61;
std::gamma_distribution<double> gamma(shape, scale);
+ THROW_WALLET_EXCEPTION_IF(rct_offsets.size() <= CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, error::wallet_internal_error, "Bad offset calculation");
+ uint64_t last_usable_block = rct_offsets.size() - 1;
auto pick_gamma = [&]()
{
double x = gamma(engine);
x = exp(x);
uint64_t block_offset = x / DIFFICULTY_TARGET_V2; // this assumes constant target over the whole rct range
- if (block_offset >= rct_offsets.size() - 1)
+ if (block_offset > last_usable_block - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE)
return std::numeric_limits<uint64_t>::max(); // bad pick
- block_offset = rct_offsets.size() - 2 - block_offset;
- THROW_WALLET_EXCEPTION_IF(block_offset >= rct_offsets.size() - 1, error::wallet_internal_error, "Bad offset calculation");
- THROW_WALLET_EXCEPTION_IF(rct_offsets[block_offset + 1] < rct_offsets[block_offset],
+ block_offset = last_usable_block - block_offset;
+ THROW_WALLET_EXCEPTION_IF(block_offset > last_usable_block, error::wallet_internal_error, "Bad offset calculation");
+ THROW_WALLET_EXCEPTION_IF(block_offset > 0 && rct_offsets[block_offset] < rct_offsets[block_offset - 1],
error::get_output_distribution, "Decreasing offsets in rct distribution: " +
- std::to_string(block_offset) + ": " + std::to_string(rct_offsets[block_offset]) + ", " +
- std::to_string(block_offset + 1) + ": " + std::to_string(rct_offsets[block_offset + 1]));
+ std::to_string(block_offset - 1) + ": " + std::to_string(rct_offsets[block_offset - 1]) + ", " +
+ std::to_string(block_offset) + ": " + std::to_string(rct_offsets[block_offset]));
uint64_t first_block_offset = block_offset, last_block_offset = block_offset;
- for (size_t half_window = 0; half_window < GAMMA_PICK_HALF_WINDOW; ++half_window)
+ for (size_t half_window = 0; half_window <= GAMMA_PICK_HALF_WINDOW; ++half_window)
{
// end when we have a non empty block
uint64_t cum0 = first_block_offset > 0 ? rct_offsets[first_block_offset] - rct_offsets[first_block_offset - 1] : rct_offsets[0];
@@ -6864,19 +6866,24 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
uint64_t cum1 = last_block_offset > 0 ? rct_offsets[last_block_offset] - rct_offsets[last_block_offset - 1] : rct_offsets[0];
if (cum1 > 1)
break;
- if (first_block_offset == 0 && last_block_offset >= rct_offsets.size() - 2)
+ if (first_block_offset == 0 && last_block_offset >= last_usable_block)
break;
// expand up to bounds
if (first_block_offset > 0)
--first_block_offset;
- if (last_block_offset < rct_offsets.size() - 1)
+ else
+ return std::numeric_limits<uint64_t>::max(); // bad pick
+ if (last_block_offset < last_usable_block - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE)
++last_block_offset;
+ else
+ return std::numeric_limits<uint64_t>::max(); // bad pick
}
- const uint64_t n_rct = rct_offsets[last_block_offset] - (first_block_offset == 0 ? 0 : rct_offsets[first_block_offset - 1]);
+ const uint64_t first_rct = first_block_offset == 0 ? 0 : rct_offsets[first_block_offset - 1];
+ const uint64_t n_rct = rct_offsets[last_block_offset] - first_rct;
if (n_rct == 0)
return rct_offsets[block_offset] ? rct_offsets[block_offset] - 1 : 0;
- MDEBUG("Picking 1/" << n_rct << " in " << (last_block_offset - first_block_offset + 1) << " blocks centered around " << block_offset);
- return rct_offsets[first_block_offset] + crypto::rand<uint64_t>() % n_rct;
+ MDEBUG("Picking 1/" << n_rct << " in " << (last_block_offset - first_block_offset + 1) << " blocks centered around " << block_offset + rct_start_height);
+ return first_rct + crypto::rand<uint64_t>() % n_rct;
};
size_t num_selected_transfers = 0;
@@ -11069,7 +11076,8 @@ std::string wallet2::export_outputs_to_str() const
std::stringstream oss;
boost::archive::portable_binary_oarchive ar(oss);
- ar << export_outputs();
+ const auto& outputs = export_outputs();
+ ar << outputs;
std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC));
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index dbfd45c53..eb0763131 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -230,7 +230,7 @@ namespace tools
bool error;
boost::optional<cryptonote::subaddress_receive_info> received;
- tx_scan_info_t(): money_transfered(0), error(true) {}
+ tx_scan_info_t(): amount(0), money_transfered(0), error(true) {}
};
struct transfer_details
diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp
index 95a4e0ad6..b9d0a6a75 100644
--- a/src/wallet/wallet_args.cpp
+++ b/src/wallet/wallet_args.cpp
@@ -211,6 +211,14 @@ namespace wallet_args
Print(print) << boost::format(wallet_args::tr("Logging to %s")) % log_path;
+ const ssize_t lockable_memory = tools::get_lockable_memory();
+ if (lockable_memory >= 0 && lockable_memory < 256 * 4096) // 256 pages -> at least 256 secret keys and other such small/medium objects
+ Print(print) << tr("WARNING: You may not have a high enough lockable memory limit")
+#ifdef ELPP_OS_UNIX
+ << ", " << tr("see ulimit -l")
+#endif
+ ;
+
return {std::move(vm), should_terminate};
}
}
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index d91a69ed1..0eb09b9f1 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -982,7 +982,11 @@ namespace tools
{
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
if (req.get_tx_keys)
+ {
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
+ for (const crypto::secret_key& additional_tx_key : ptx.additional_tx_keys)
+ res.tx_key_list.back() += epee::string_tools::pod_to_hex(additional_tx_key);
+ }
}
if (req.export_raw)
@@ -1742,11 +1746,42 @@ namespace tools
if (req.key_type.compare("mnemonic") == 0)
{
epee::wipeable_string seed;
- if (!m_wallet->get_seed(seed))
+ bool ready;
+ if (m_wallet->multisig(&ready))
+ {
+ if (!ready)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG;
+ er.message = "This wallet is multisig, but not yet finalized";
+ return false;
+ }
+ if (!m_wallet->get_multisig_seed(seed))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to get multisig seed.";
+ return false;
+ }
+ }
+ else
{
+ if (m_wallet->watch_only())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY;
+ er.message = "The wallet is watch-only. Cannot display seed.";
+ return false;
+ }
+ if (!m_wallet->is_deterministic())
+ {
er.code = WALLET_RPC_ERROR_CODE_NON_DETERMINISTIC;
er.message = "The wallet is non-deterministic. Cannot display seed.";
return false;
+ }
+ if (!m_wallet->get_seed(seed))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to get seed.";
+ return false;
+ }
}
res.key = std::string(seed.data(), seed.size()); // send to the network, then wipe RAM :D
}
@@ -3091,6 +3126,200 @@ namespace tools
}
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_restore_deterministic_wallet(const wallet_rpc::COMMAND_RPC_RESTORE_DETERMINISTIC_WALLET::request &req, wallet_rpc::COMMAND_RPC_RESTORE_DETERMINISTIC_WALLET::response &res, epee::json_rpc::error &er)
+ {
+ if (m_wallet_dir.empty())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NO_WALLET_DIR;
+ er.message = "No wallet dir configured";
+ return false;
+ }
+
+ // early check for mandatory fields
+ if (req.filename.empty())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "field 'filename' is mandatory. Please provide a filename to save the restored wallet to.";
+ return false;
+ }
+ if (req.seed.empty())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "field 'seed' is mandatory. Please provide a seed you want to restore from.";
+ return false;
+ }
+
+ namespace po = boost::program_options;
+ po::variables_map vm2;
+ const char *ptr = strchr(req.filename.c_str(), '/');
+ #ifdef _WIN32
+ if (!ptr)
+ ptr = strchr(req.filename.c_str(), '\\');
+ if (!ptr)
+ ptr = strchr(req.filename.c_str(), ':');
+ #endif
+ if (ptr)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Invalid filename";
+ return false;
+ }
+ std::string wallet_file = m_wallet_dir + "/" + req.filename;
+ // check if wallet file already exists
+ if (!wallet_file.empty())
+ {
+ try
+ {
+ boost::system::error_code ignored_ec;
+ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(wallet_file, ignored_ec), error::file_exists, wallet_file);
+ }
+ catch (const std::exception &e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Wallet already exists.";
+ return false;
+ }
+ }
+ crypto::secret_key recovery_key;
+ std::string old_language;
+
+ // check the given seed
+ {
+ if (!crypto::ElectrumWords::words_to_bytes(req.seed, recovery_key, old_language))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Electrum-style word list failed verification";
+ return false;
+ }
+ }
+
+ // process seed_offset if given
+ {
+ if (!req.seed_offset.empty())
+ {
+ recovery_key = cryptonote::decrypt_key(recovery_key, req.seed_offset);
+ }
+ }
+ {
+ po::options_description desc("dummy");
+ const command_line::arg_descriptor<std::string, true> arg_password = {"password", "password"};
+ const char *argv[4];
+ int argc = 3;
+ argv[0] = "wallet-rpc";
+ argv[1] = "--password";
+ argv[2] = req.password.c_str();
+ argv[3] = NULL;
+ vm2 = *m_vm;
+ command_line::add_arg(desc, arg_password);
+ po::store(po::parse_command_line(argc, argv, desc), vm2);
+ }
+
+ auto rc = tools::wallet2::make_new(vm2, true, nullptr);
+ std::unique_ptr<wallet2> wal;
+ wal = std::move(rc.first);
+ if (!wal)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to create wallet";
+ return false;
+ }
+
+ epee::wipeable_string password = rc.second.password();
+
+ bool was_deprecated_wallet = ((old_language == crypto::ElectrumWords::old_language_name) ||
+ crypto::ElectrumWords::get_is_old_style_seed(req.seed));
+
+ std::string mnemonic_language = old_language;
+ if (was_deprecated_wallet)
+ {
+ // The user had used an older version of the wallet with old style mnemonics.
+ res.was_deprecated = true;
+ }
+
+ if (old_language == crypto::ElectrumWords::old_language_name)
+ {
+ if (req.language.empty())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Wallet was using the old seed language. You need to specify a new seed language.";
+ return false;
+ }
+ std::vector<std::string> language_list;
+ std::vector<std::string> language_list_en;
+ crypto::ElectrumWords::get_language_list(language_list);
+ crypto::ElectrumWords::get_language_list(language_list_en, true);
+ if (std::find(language_list.begin(), language_list.end(), req.language) == language_list.end() &&
+ std::find(language_list_en.begin(), language_list_en.end(), req.language) == language_list_en.end())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Wallet was using the old seed language, and the specified new seed language is invalid.";
+ return false;
+ }
+ mnemonic_language = req.language;
+ }
+
+ wal->set_seed_language(mnemonic_language);
+
+ crypto::secret_key recovery_val;
+ try
+ {
+ recovery_val = wal->generate(wallet_file, std::move(rc.second).password(), recovery_key, true, false, false);
+ MINFO("Wallet has been restored.\n");
+ }
+ catch (const std::exception &e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+
+ // // Convert the secret key back to seed
+ epee::wipeable_string electrum_words;
+ if (!crypto::ElectrumWords::bytes_to_words(recovery_val, electrum_words, mnemonic_language))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to encode seed";
+ return false;
+ }
+ res.seed = electrum_words.data();
+
+ if (!wal)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to generate wallet";
+ return false;
+ }
+
+ // set blockheight if given
+ try
+ {
+ wal->set_refresh_from_block_height(req.restore_height);
+ wal->rewrite(wallet_file, password);
+ }
+ catch (const std::exception &e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+
+ if (m_wallet)
+ {
+ try
+ {
+ m_wallet->store();
+ }
+ catch (const std::exception &e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+ delete m_wallet;
+ }
+ m_wallet = wal.release();
+ res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
+ res.info = "Wallet has been restored successfully.";
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_is_multisig(const wallet_rpc::COMMAND_RPC_IS_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IS_MULTISIG::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 887723ed5..abbbe82c5 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -137,6 +137,7 @@ namespace tools
MAP_JON_RPC_WE("open_wallet", on_open_wallet, wallet_rpc::COMMAND_RPC_OPEN_WALLET)
MAP_JON_RPC_WE("close_wallet", on_close_wallet, wallet_rpc::COMMAND_RPC_CLOSE_WALLET)
MAP_JON_RPC_WE("change_wallet_password", on_change_wallet_password, wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD)
+ MAP_JON_RPC_WE("restore_deterministic_wallet", on_restore_deterministic_wallet, wallet_rpc::COMMAND_RPC_RESTORE_DETERMINISTIC_WALLET)
MAP_JON_RPC_WE("is_multisig", on_is_multisig, wallet_rpc::COMMAND_RPC_IS_MULTISIG)
MAP_JON_RPC_WE("prepare_multisig", on_prepare_multisig, wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG)
MAP_JON_RPC_WE("make_multisig", on_make_multisig, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG)
@@ -216,6 +217,7 @@ namespace tools
bool on_open_wallet(const wallet_rpc::COMMAND_RPC_OPEN_WALLET::request& req, wallet_rpc::COMMAND_RPC_OPEN_WALLET::response& res, epee::json_rpc::error& er);
bool on_close_wallet(const wallet_rpc::COMMAND_RPC_CLOSE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CLOSE_WALLET::response& res, epee::json_rpc::error& er);
bool on_change_wallet_password(const wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD::request& req, wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD::response& res, epee::json_rpc::error& er);
+ bool on_restore_deterministic_wallet(const wallet_rpc::COMMAND_RPC_RESTORE_DETERMINISTIC_WALLET::request& req, wallet_rpc::COMMAND_RPC_RESTORE_DETERMINISTIC_WALLET::response& res, epee::json_rpc::error& er);
bool on_is_multisig(const wallet_rpc::COMMAND_RPC_IS_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IS_MULTISIG::response& res, epee::json_rpc::error& er);
bool on_prepare_multisig(const wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::response& res, epee::json_rpc::error& er);
bool on_make_multisig(const wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::response& res, epee::json_rpc::error& er);
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 20cd65e8e..afb8c6e91 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -1931,6 +1931,43 @@ namespace wallet_rpc
};
};
+ struct COMMAND_RPC_RESTORE_DETERMINISTIC_WALLET
+ {
+ struct request
+ {
+ uint64_t restore_height;
+ std::string filename;
+ std::string seed;
+ std::string seed_offset;
+ std::string password;
+ std::string language;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_OPT(restore_height, (uint64_t)0)
+ KV_SERIALIZE(filename)
+ KV_SERIALIZE(seed)
+ KV_SERIALIZE(seed_offset)
+ KV_SERIALIZE(password)
+ KV_SERIALIZE(language)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string address;
+ std::string seed;
+ std::string info;
+ bool was_deprecated;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(address)
+ KV_SERIALIZE(seed)
+ KV_SERIALIZE(info)
+ KV_SERIALIZE(was_deprecated)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
struct COMMAND_RPC_IS_MULTISIG
{
struct request