aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet/simplewallet.cpp
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2018-01-02 00:29:35 +0200
committerRiccardo Spagni <ric@spagni.net>2018-01-02 00:29:36 +0200
commiteb617be8f4d3aabcc36ab561887aa9313773a05d (patch)
tree66ea57cda256cafe9b96f0629380e29538eca24e /src/simplewallet/simplewallet.cpp
parentMerge pull request #2956 (diff)
parentwallet: support for multisig seeds (diff)
downloadmonero-eb617be8f4d3aabcc36ab561887aa9313773a05d.tar.xz
Merge pull request #2960
5cbcf0aa wallet: support for multisig seeds (moneromooo-monero)
Diffstat (limited to 'src/simplewallet/simplewallet.cpp')
-rw-r--r--src/simplewallet/simplewallet.cpp192
1 files changed, 147 insertions, 45 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index bc3b3e926..f4f24ed77 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -121,6 +121,7 @@ namespace
const command_line::arg_descriptor<std::string> arg_mnemonic_language = {"mnemonic-language", sw::tr("Language for mnemonic"), ""};
const command_line::arg_descriptor<std::string> arg_electrum_seed = {"electrum-seed", sw::tr("Specify Electrum seed for wallet recovery/creation"), ""};
const command_line::arg_descriptor<bool> arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false};
+ const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Create non-deterministic view and spend keys"), false};
const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
@@ -516,48 +517,55 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
bool simple_wallet::print_seed(bool encrypted)
{
bool success = false;
- std::string electrum_words;
+ std::string seed;
+ bool ready, multisig;
- if (m_wallet->multisig())
- {
- fail_msg_writer() << tr("wallet is multisig and has no seed");
- return true;
- }
if (m_wallet->watch_only())
{
fail_msg_writer() << tr("wallet is watch-only and has no seed");
return true;
}
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
- if (m_wallet->is_deterministic())
- {
- if (m_wallet->get_seed_language().empty())
- {
- std::string mnemonic_language = get_mnemonic_language();
- if (mnemonic_language.empty())
- return true;
- m_wallet->set_seed_language(mnemonic_language);
- }
- epee::wipeable_string seed_pass;
- if (encrypted)
+ multisig = m_wallet->multisig(&ready);
+ if (multisig)
+ {
+ if (!ready)
{
- auto pwd_container = tools::password_container::prompt(true, tr("Enter optional seed encryption passphrase, empty to see raw seed"));
- if (std::cin.eof() || !pwd_container)
- return true;
- seed_pass = pwd_container->password();
+ fail_msg_writer() << tr("wallet is multisig but not yet finalized");
+ return true;
}
+ }
+ else if (!m_wallet->is_deterministic())
+ {
+ fail_msg_writer() << tr("wallet is non-deterministic and has no seed");
+ return true;
+ }
- success = m_wallet->get_seed(electrum_words, seed_pass);
+ epee::wipeable_string seed_pass;
+ if (encrypted)
+ {
+#ifdef HAVE_READLINE
+ rdln::suspend_readline pause_readline;
+#endif
+ auto pwd_container = tools::password_container::prompt(true, tr("Enter optional seed encryption passphrase, empty to see raw seed"));
+ if (std::cin.eof() || !pwd_container)
+ return true;
+ seed_pass = pwd_container->password();
}
+ if (multisig)
+ success = m_wallet->get_multisig_seed(seed, seed_pass);
+ else if (m_wallet->is_deterministic())
+ success = m_wallet->get_seed(seed, seed_pass);
+
if (success)
{
- print_seed(electrum_words);
+ print_seed(seed);
}
else
{
- fail_msg_writer() << tr("wallet is non-deterministic and has no seed");
+ fail_msg_writer() << tr("Failed to retrieve seed");
}
return true;
}
@@ -1984,6 +1992,8 @@ static bool might_be_partial_seed(std::string words)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
+ std::string multisig_keys;
+
if (!handle_command_line(vm))
return false;
@@ -2001,49 +2011,91 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
std::string old_language;
// check for recover flag. if present, require electrum word list (only recovery option for now).
- if (m_restore_deterministic_wallet)
+ if (m_restore_deterministic_wallet || m_restore_multisig_wallet)
{
if (m_non_deterministic)
{
- fail_msg_writer() << tr("can't specify both --restore-deterministic-wallet and --non-deterministic");
+ fail_msg_writer() << tr("can't specify both --restore-deterministic-wallet or --restore-multisig-wallet and --non-deterministic");
return false;
}
if (!m_wallet_file.empty())
{
- fail_msg_writer() << tr("--restore-deterministic-wallet uses --generate-new-wallet, not --wallet-file");
+ if (m_restore_multisig_wallet)
+ fail_msg_writer() << tr("--restore-multisig-wallet uses --generate-new-wallet, not --wallet-file");
+ else
+ fail_msg_writer() << tr("--restore-deterministic-wallet uses --generate-new-wallet, not --wallet-file");
return false;
}
if (m_electrum_seed.empty())
{
- m_electrum_seed = "";
- do
+ if (m_restore_multisig_wallet)
{
- const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed: " : "Electrum seed continued: ";
- std::string electrum_seed = input_line(prompt);
- if (std::cin.eof())
- return false;
- if (electrum_seed.empty())
+ const char *prompt = "Specify multisig seed: ";
+ m_electrum_seed = input_line(prompt);
+ if (std::cin.eof())
+ return false;
+ if (m_electrum_seed.empty())
+ {
+ fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"multisig seed here\"");
+ return false;
+ }
+ }
+ else
+ {
+ m_electrum_seed = "";
+ do
{
- fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"words list here\"");
- return false;
- }
- m_electrum_seed += electrum_seed + " ";
- } while (might_be_partial_seed(m_electrum_seed));
+ const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed: " : "Electrum seed continued: ";
+ std::string electrum_seed = input_line(prompt);
+ if (std::cin.eof())
+ return false;
+ if (electrum_seed.empty())
+ {
+ fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"words list here\"");
+ return false;
+ }
+ m_electrum_seed += electrum_seed + " ";
+ } while (might_be_partial_seed(m_electrum_seed));
+ }
}
- if (!crypto::ElectrumWords::words_to_bytes(m_electrum_seed, m_recovery_key, old_language))
+ if (m_restore_multisig_wallet)
{
- fail_msg_writer() << tr("Electrum-style word list failed verification");
- return false;
+ if (!epee::string_tools::parse_hexstr_to_binbuff(m_electrum_seed, multisig_keys))
+ {
+ fail_msg_writer() << tr("Multisig seed failed verification");
+ return false;
+ }
+ }
+ else
+ {
+ if (!crypto::ElectrumWords::words_to_bytes(m_electrum_seed, m_recovery_key, old_language))
+ {
+ fail_msg_writer() << tr("Electrum-style word list failed verification");
+ return false;
+ }
}
+#ifdef HAVE_READLINE
+ rdln::suspend_readline pause_readline;
+#endif
auto pwd_container = tools::password_container::prompt(false, tr("Enter seed encryption passphrase, empty if none"));
if (std::cin.eof() || !pwd_container)
return false;
epee::wipeable_string seed_pass = pwd_container->password();
if (!seed_pass.empty())
- m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
+ {
+ if (m_restore_multisig_wallet)
+ {
+ crypto::secret_key key;
+ crypto::cn_slow_hash(seed_pass.data(), seed_pass.size(), (crypto::hash&)key);
+ sc_reduce32((unsigned char*)key.data);
+ multisig_keys = m_wallet->decrypt(multisig_keys, key, true);
+ }
+ else
+ m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
+ }
}
if (!m_generate_from_view_key.empty())
{
@@ -2354,7 +2406,11 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
m_wallet_file = m_generate_new;
- bool r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
+ bool r;
+ if (m_restore_multisig_wallet)
+ r = new_wallet(vm, multisig_keys, old_language);
+ else
+ r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
}
if (!m_restore_height && m_restoring)
@@ -2485,6 +2541,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_mnemonic_language = command_line::get_arg(vm, arg_mnemonic_language);
m_electrum_seed = command_line::get_arg(vm, arg_electrum_seed);
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
+ m_restore_multisig_wallet = command_line::get_arg(vm, arg_restore_multisig_wallet);
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon);
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
@@ -2495,7 +2552,8 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
!m_generate_from_keys.empty() ||
!m_generate_from_multisig_keys.empty() ||
!m_generate_from_json.empty() ||
- m_restore_deterministic_wallet;
+ m_restore_deterministic_wallet ||
+ m_restore_multisig_wallet;
return true;
}
@@ -2695,6 +2753,49 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+ const std::string &multisig_keys, const std::string &old_language)
+{
+ auto rc = tools::wallet2::make_new(vm, password_prompter);
+ m_wallet = std::move(rc.first);
+ if (!m_wallet)
+ {
+ return false;
+ }
+
+ std::string mnemonic_language = old_language;
+
+ std::vector<std::string> language_list;
+ crypto::ElectrumWords::get_language_list(language_list);
+ if (mnemonic_language.empty() && std::find(language_list.begin(), language_list.end(), m_mnemonic_language) != language_list.end())
+ {
+ mnemonic_language = m_mnemonic_language;
+ }
+
+ m_wallet->set_seed_language(mnemonic_language);
+
+ try
+ {
+ m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys);
+ bool ready;
+ uint32_t threshold, total;
+ if (!m_wallet->multisig(&ready, &threshold, &total) || !ready)
+ {
+ fail_msg_writer() << tr("failed to generate new mutlisig wallet");
+ return false;
+ }
+ message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total
+ << m_wallet->get_account().get_public_address_str(m_wallet->testnet());
+ }
+ catch (const std::exception& e)
+ {
+ fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
+ return false;
+ }
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
{
if (!tools::wallet2::wallet_valid_path_format(m_wallet_file))
@@ -6473,6 +6574,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_command);
command_line::add_arg(desc_params, arg_restore_deterministic_wallet );
+ command_line::add_arg(desc_params, arg_restore_multisig_wallet );
command_line::add_arg(desc_params, arg_non_deterministic );
command_line::add_arg(desc_params, arg_electrum_seed );
command_line::add_arg(desc_params, arg_trusted_daemon);