From 265290388bd2134108d689818518f7d9c830292c Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 1 Oct 2017 14:06:54 +0100 Subject: [PATCH] wallet: guard against partly initialized multisig wallet --- src/simplewallet/simplewallet.cpp | 47 ++++++++++++++++---- src/wallet/wallet2.cpp | 4 +- src/wallet/wallet2.h | 2 +- src/wallet/wallet_rpc_server.cpp | 29 ++++++++++-- src/wallet/wallet_rpc_server_commands_defs.h | 2 + tests/unit_tests/multisig.cpp | 17 ++++--- 6 files changed, 82 insertions(+), 19 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index b0aec186c..40226ec34 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -849,11 +849,17 @@ bool simple_wallet::make_multisig(const std::vector &args) bool simple_wallet::finalize_multisig(const std::vector &args) { - if (!m_wallet->multisig()) + bool ready; + if (!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This wallet is not multisig"); return true; } + if (ready) + { + fail_msg_writer() << tr("This wallet is already finalized"); + return true; + } const auto orig_pwd_container = get_and_verify_password(); if(orig_pwd_container == boost::none) @@ -887,11 +893,17 @@ bool simple_wallet::finalize_multisig(const std::vector &args) bool simple_wallet::export_multisig(const std::vector &args) { - if (!m_wallet->multisig()) + bool ready; + if (!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This wallet is not multisig"); return true; } + if (!ready) + { + fail_msg_writer() << tr("This multisig wallet is not yet finalized"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: export_multisig_info "); @@ -937,12 +949,18 @@ bool simple_wallet::export_multisig(const std::vector &args) bool simple_wallet::import_multisig(const std::vector &args) { + bool ready; uint32_t threshold, total; - if (!m_wallet->multisig(&threshold, &total)) + if (!m_wallet->multisig(&ready, &threshold, &total)) { fail_msg_writer() << tr("This wallet is not multisig"); return true; } + if (!ready) + { + fail_msg_writer() << tr("This multisig wallet is not yet finalized"); + return true; + } if (args.size() < threshold - 1) { fail_msg_writer() << tr("usage: import_multisig_info [...] - one for each other participant"); @@ -1065,11 +1083,17 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::multisig_tx_set &txs) bool simple_wallet::sign_multisig(const std::vector &args) { - if(!m_wallet->multisig()) + bool ready; + if(!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This is not a multisig wallet"); return true; } + if (!ready) + { + fail_msg_writer() << tr("This multisig wallet is not yet finalized"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: sign_multisig "); @@ -1103,7 +1127,7 @@ bool simple_wallet::sign_multisig(const std::vector &args) if (txids.empty()) { uint32_t threshold; - m_wallet->multisig(&threshold); + m_wallet->multisig(NULL, &threshold); uint32_t signers_needed = threshold - signers - 1; success_msg_writer(true) << tr("Transaction successfully signed to file ") << filename << ", " << signers_needed << " more signer(s) needed"; @@ -1126,12 +1150,18 @@ bool simple_wallet::sign_multisig(const std::vector &args) bool simple_wallet::submit_multisig(const std::vector &args) { + bool ready; uint32_t threshold; - if (!m_wallet->multisig(&threshold)) + if (!m_wallet->multisig(&ready, &threshold)) { fail_msg_writer() << tr("This is not a multisig wallet"); return true; } + if (!ready) + { + fail_msg_writer() << tr("This multisig wallet is not yet finalized"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: submit_multisig "); @@ -2717,11 +2747,12 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm) } std::string prefix; + bool ready; uint32_t threshold, total; if (m_wallet->watch_only()) prefix = tr("Opened watch-only wallet"); - else if (m_wallet->multisig(&threshold, &total)) - prefix = (boost::format(tr("Opened %u/%u multisig wallet")) % threshold % total).str(); + else if (m_wallet->multisig(&ready, &threshold, &total)) + prefix = (boost::format(tr("Opened %u/%u multisig wallet%s")) % threshold % total % (ready ? "" : " (not yet finalized)")).str(); else prefix = tr("Opened wallet"); message_writer(console_color_white, true) << diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2bba6f9e1..9c2587f25 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3039,7 +3039,7 @@ bool wallet2::verify_extra_multisig_info(const std::string &data, std::unordered return true; } -bool wallet2::multisig(uint32_t *threshold, uint32_t *total) const +bool wallet2::multisig(bool *ready, uint32_t *threshold, uint32_t *total) const { if (!m_multisig) return false; @@ -3047,6 +3047,8 @@ bool wallet2::multisig(uint32_t *threshold, uint32_t *total) const *threshold = m_multisig_threshold; if (total) *total = m_multisig_signers.size(); + if (ready) + *ready = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity())); return true; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 8abc42ff3..79199a30c 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -598,7 +598,7 @@ namespace tools bool testnet() const { return m_testnet; } bool restricted() const { return m_restricted; } bool watch_only() const { return m_watch_only; } - bool multisig(uint32_t *threshold = NULL, uint32_t *total = NULL) const; + bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const; bool has_multisig_partial_key_images() const; // locked & unlocked balance of given or current subaddress account diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index ac991d861..043890fd1 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -2342,7 +2342,7 @@ namespace tools 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); - res.multisig = m_wallet->multisig(&res.threshold, &res.total); + res.multisig = m_wallet->multisig(&res.ready, &res.threshold, &res.total); return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -2468,12 +2468,19 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - if (!m_wallet->multisig()) + bool ready; + if (!m_wallet->multisig(&ready)) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } + if (!ready) + { + er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; + er.message = "This wallet is multisig, but not yet finalized"; + return false; + } std::vector info; try @@ -2514,13 +2521,20 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } + bool ready; uint32_t threshold, total; - if (!m_wallet->multisig(&threshold, &total)) + if (!m_wallet->multisig(&ready, &threshold, &total)) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } + if (!ready) + { + er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; + er.message = "This wallet is multisig, but not yet finalized"; + return false; + } if (req.info.size() < threshold - 1) { @@ -2607,13 +2621,20 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } + bool ready; uint32_t threshold, total; - if (!m_wallet->multisig(&threshold, &total)) + if (!m_wallet->multisig(&ready, &threshold, &total)) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } + if (ready) + { + er.code = WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG; + er.message = "This wallet is multisig, and already finalized"; + return false; + } if (req.multisig_info.size() < threshold - 1) { diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index d17af9980..bff4fdd7c 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -1499,11 +1499,13 @@ namespace wallet_rpc struct response { bool multisig; + bool ready; uint32_t threshold; uint32_t total; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(multisig) + KV_SERIALIZE(ready) KV_SERIALIZE(threshold) KV_SERIALIZE(total) END_KV_SERIALIZE_MAP() diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp index 0e8a6b168..aab1ce420 100644 --- a/tests/unit_tests/multisig.cpp +++ b/tests/unit_tests/multisig.cpp @@ -94,11 +94,14 @@ static void make_M_2_wallet(tools::wallet2 &wallet0, tools::wallet2 &wallet1, un ASSERT_TRUE(wallet0.get_account().get_public_address_str(true) == wallet1.get_account().get_public_address_str(true)); + bool ready; uint32_t threshold, total; - ASSERT_TRUE(wallet0.multisig(&threshold, &total)); + ASSERT_TRUE(wallet0.multisig(&ready, &threshold, &total)); + ASSERT_TRUE(ready); ASSERT_TRUE(threshold == M); ASSERT_TRUE(total == 2); - ASSERT_TRUE(wallet1.multisig(&threshold, &total)); + ASSERT_TRUE(wallet1.multisig(&ready, &threshold, &total)); + ASSERT_TRUE(ready); ASSERT_TRUE(threshold == M); ASSERT_TRUE(total == 2); } @@ -149,14 +152,18 @@ static void make_M_3_wallet(tools::wallet2 &wallet0, tools::wallet2 &wallet1, to ASSERT_TRUE(wallet0.get_account().get_public_address_str(true) == wallet1.get_account().get_public_address_str(true)); ASSERT_TRUE(wallet0.get_account().get_public_address_str(true) == wallet2.get_account().get_public_address_str(true)); + bool ready; uint32_t threshold, total; - ASSERT_TRUE(wallet0.multisig(&threshold, &total)); + ASSERT_TRUE(wallet0.multisig(&ready, &threshold, &total)); + ASSERT_TRUE(ready); ASSERT_TRUE(threshold == M); ASSERT_TRUE(total == 3); - ASSERT_TRUE(wallet1.multisig(&threshold, &total)); + ASSERT_TRUE(wallet1.multisig(&ready, &threshold, &total)); + ASSERT_TRUE(ready); ASSERT_TRUE(threshold == M); ASSERT_TRUE(total == 3); - ASSERT_TRUE(wallet2.multisig(&threshold, &total)); + ASSERT_TRUE(wallet2.multisig(&ready, &threshold, &total)); + ASSERT_TRUE(ready); ASSERT_TRUE(threshold == M); ASSERT_TRUE(total == 3); }