Merge pull request #4746

f3019efe wallet-rpc: add on_restore_deterministic RPC call. (Hasan Pekdemir)
This commit is contained in:
Riccardo Spagni 2018-11-14 21:31:08 +02:00
commit dd42b642ee
No known key found for this signature in database
GPG Key ID: 55432DF31CCD4FCD
3 changed files with 233 additions and 0 deletions

View File

@ -3091,6 +3091,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) 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); if (!m_wallet) return not_open(er);

View File

@ -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("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("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("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("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("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) 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_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_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_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_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_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); 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);

View File

@ -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 COMMAND_RPC_IS_MULTISIG
{ {
struct request struct request