diff options
author | luigi1111 <luigi1111w@gmail.com> | 2024-05-20 22:35:57 -0500 |
---|---|---|
committer | luigi1111 <luigi1111w@gmail.com> | 2024-05-20 22:35:57 -0500 |
commit | 3a47cdad13fd8486b7d5559ec004ff49b3b3aa6d (patch) | |
tree | 36f61d20bad25b72e830274547509bbbbd5b625a | |
parent | Merge pull request #9243 (diff) | |
parent | replace 'multisig()' with 'get_multisig_status()' using multisig_account_stat... (diff) | |
download | monero-3a47cdad13fd8486b7d5559ec004ff49b3b3aa6d.tar.xz |
Merge pull request #7852
8d94d08 replace 'multisig()' with 'get_multisig_status()' using multisig_account_status and including '.kex_is_done' member (koe)
-rw-r--r-- | src/gen_multisig/gen_multisig.cpp | 7 | ||||
-rw-r--r-- | src/multisig/multisig_account.h | 13 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 137 | ||||
-rw-r--r-- | src/wallet/api/wallet.cpp | 29 | ||||
-rw-r--r-- | src/wallet/api/wallet2_api.h | 3 | ||||
-rw-r--r-- | src/wallet/message_store.h | 7 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 52 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 3 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 73 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_commands_defs.h | 2 | ||||
-rw-r--r-- | tests/unit_tests/multisig.cpp | 25 |
11 files changed, 197 insertions, 154 deletions
diff --git a/src/gen_multisig/gen_multisig.cpp b/src/gen_multisig/gen_multisig.cpp index 48cf818ef..fd82c66af 100644 --- a/src/gen_multisig/gen_multisig.cpp +++ b/src/gen_multisig/gen_multisig.cpp @@ -121,16 +121,15 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const std::str } // exchange keys until the wallets are done - bool ready{false}; - wallets[0]->multisig(&ready); - while (!ready) + multisig::multisig_account_status ms_status{wallets[0]->get_multisig_status()}; + while (!ms_status.is_ready) { for (size_t n = 0; n < total; ++n) { kex_msgs_intermediate[n] = wallets[n]->exchange_multisig_keys(pwd_container->password(), kex_msgs_intermediate); } - wallets[0]->multisig(&ready); + ms_status = wallets[0]->get_multisig_status(); } std::string address = wallets[0]->get_account().get_public_address_str(wallets[0]->nettype()); diff --git a/src/multisig/multisig_account.h b/src/multisig/multisig_account.h index 0d832f243..2ea8d0133 100644 --- a/src/multisig/multisig_account.h +++ b/src/multisig/multisig_account.h @@ -40,6 +40,19 @@ namespace multisig { + struct multisig_account_status + { + // is the multisig account active/initialized? + bool multisig_is_active{false}; + // has the multisig account completed the main key exchange rounds? + bool kex_is_done{false}; + // is the multisig account ready to use? + bool is_ready{false}; + // multisig is: M-of-N + std::uint32_t threshold{0}; // M + std::uint32_t total{0}; // N + }; + /** * multisig account: * diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 5a9d790cb..34681cddf 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -819,7 +819,6 @@ bool simple_wallet::print_seed(bool encrypted) { bool success = false; epee::wipeable_string seed; - bool ready, multisig; if (m_wallet->key_on_device()) { @@ -832,10 +831,10 @@ bool simple_wallet::print_seed(bool encrypted) return true; } - multisig = m_wallet->multisig(&ready); - if (multisig) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (ms_status.multisig_is_active) { - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("wallet is multisig but not yet finalized"); return true; @@ -844,7 +843,7 @@ bool simple_wallet::print_seed(bool encrypted) SCOPED_WALLET_UNLOCK(); - if (!multisig && !m_wallet->is_deterministic()) + if (!ms_status.multisig_is_active && !m_wallet->is_deterministic()) { fail_msg_writer() << tr("wallet is non-deterministic and has no seed"); return true; @@ -859,7 +858,7 @@ bool simple_wallet::print_seed(bool encrypted) seed_pass = pwd_container->password(); } - if (multisig) + if (ms_status.multisig_is_active) success = m_wallet->get_multisig_seed(seed, seed_pass); else if (m_wallet->is_deterministic()) success = m_wallet->get_seed(seed, seed_pass); @@ -898,7 +897,7 @@ bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = s fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("wallet is multisig and has no seed"); return true; @@ -1044,7 +1043,7 @@ bool simple_wallet::prepare_multisig_main(const std::vector<std::string> &args, fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("This wallet is already multisig"); return false; @@ -1091,7 +1090,7 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("This wallet is already multisig"); return false; @@ -1136,9 +1135,7 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo auto local_args = args; local_args.erase(local_args.begin()); std::string multisig_extra_info = m_wallet->make_multisig(orig_pwd_container->password(), local_args, threshold); - bool ready; - m_wallet->multisig(&ready); - if (!ready) + if (!m_wallet->get_multisig_status().is_ready) { success_msg_writer() << tr("Another step is needed"); success_msg_writer() << multisig_extra_info; @@ -1156,13 +1153,13 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo return false; } - uint32_t total; - if (!m_wallet->multisig(NULL, &threshold, &total)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("Error creating multisig: new wallet is not multisig"); return false; } - success_msg_writer() << std::to_string(threshold) << "/" << total << tr(" multisig address: ") + success_msg_writer() << std::to_string(ms_status.threshold) << "/" << ms_status.total << tr(" multisig address: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); return true; @@ -1188,18 +1185,18 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> & const bool force_update_use_with_caution, const bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (!m_wallet->multisig(&ready)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This wallet is not multisig"); return false; } - if (ready) + if (ms_status.is_ready) { fail_msg_writer() << tr("This wallet is already finalized"); return false; @@ -1215,9 +1212,7 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> & try { std::string multisig_extra_info = m_wallet->exchange_multisig_keys(orig_pwd_container->password(), args, force_update_use_with_caution); - bool ready; - m_wallet->multisig(&ready); - if (!ready) + if (!m_wallet->get_multisig_status().is_ready) { message_writer() << tr("Another step is needed"); message_writer() << multisig_extra_info; @@ -1228,9 +1223,8 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> & } return true; } else { - uint32_t threshold, total; - m_wallet->multisig(NULL, &threshold, &total); - success_msg_writer() << tr("Multisig wallet has been successfully created. Current wallet type: ") << threshold << "/" << total; + const multisig::multisig_account_status ms_status_new{m_wallet->get_multisig_status()}; + success_msg_writer() << tr("Multisig wallet has been successfully created. Current wallet type: ") << ms_status_new.threshold << "/" << ms_status_new.total; success_msg_writer() << tr("Multisig address: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } } @@ -1253,18 +1247,18 @@ bool simple_wallet::export_multisig(const std::vector<std::string> &args) bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (!m_wallet->multisig(&ready)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This wallet is not multisig"); return false; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return false; @@ -1320,24 +1314,24 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args) bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; - uint32_t threshold, total; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (!m_wallet->multisig(&ready, &threshold, &total)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This wallet is not multisig"); return false; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return false; } - if (args.size() < threshold - 1) + if (args.size() + 1 < ms_status.threshold) { PRINT_USAGE(USAGE_IMPORT_MULTISIG_INFO); return false; @@ -1417,18 +1411,19 @@ bool simple_wallet::sign_multisig(const std::vector<std::string> &args) bool simple_wallet::sign_multisig_main(const std::vector<std::string> &args, bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()};\ + if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if(!m_wallet->multisig(&ready)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This is not a multisig wallet"); return false; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return false; @@ -1502,9 +1497,7 @@ bool simple_wallet::sign_multisig_main(const std::vector<std::string> &args, boo if (txids.empty()) { - uint32_t threshold; - m_wallet->multisig(NULL, &threshold); - uint32_t signers_needed = threshold - signers - 1; + uint32_t signers_needed = ms_status.threshold - signers - 1; success_msg_writer(true) << tr("Transaction successfully signed to file ") << filename << ", " << signers_needed << " more signer(s) needed"; return true; @@ -1534,19 +1527,19 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args) bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; - uint32_t threshold; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (!m_wallet->multisig(&ready, &threshold)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This is not a multisig wallet"); return false; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return false; @@ -1584,10 +1577,10 @@ bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, b return false; } } - if (txs.m_signers.size() < threshold) + if (txs.m_signers.size() < ms_status.threshold) { fail_msg_writer() << (boost::format(tr("Multisig transaction signed by only %u signers, needs %u more signatures")) - % txs.m_signers.size() % (threshold - txs.m_signers.size())).str(); + % txs.m_signers.size() % (ms_status.threshold - txs.m_signers.size())).str(); return false; } @@ -1616,19 +1609,19 @@ bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, b bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args) { CHECK_MULTISIG_ENABLED(); - bool ready; - uint32_t threshold; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if (!m_wallet->multisig(&ready, &threshold)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This is not a multisig wallet"); return true; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return true; @@ -1654,10 +1647,10 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args) fail_msg_writer() << tr("Failed to load multisig transaction from file"); return true; } - if (txs.m_signers.size() < threshold) + if (txs.m_signers.size() < ms_status.threshold) { fail_msg_writer() << (boost::format(tr("Multisig transaction signed by only %u signers, needs %u more signatures")) - % txs.m_signers.size() % (threshold - txs.m_signers.size())).str(); + % txs.m_signers.size() % (ms_status.threshold - txs.m_signers.size())).str(); return true; } @@ -3870,7 +3863,7 @@ void simple_wallet::print_seed(const epee::wipeable_string &seed) { success_msg_writer(true) << "\n" << boost::format(tr("NOTE: the following %s can be used to recover access to your wallet. " "Write them down and store them somewhere safe and secure. Please do not store them in " - "your email or on file storage services outside of your immediate control.\n")) % (m_wallet->multisig() ? tr("string") : tr("25 words")); + "your email or on file storage services outside of your immediate control.\n")) % (m_wallet->get_multisig_status().multisig_is_active ? tr("string") : tr("25 words")); // don't log int space_index = 0; size_t len = seed.size(); @@ -4922,14 +4915,14 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr const epee::wipeable_string &msig_keys = m_wallet->decrypt<epee::wipeable_string>(std::string(multisig_keys.data(), multisig_keys.size()), key, true); m_wallet->generate(m_wallet_file, std::move(rc.second).password(), msig_keys, create_address_file); } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total) || !ready) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active || !ms_status.is_ready) { fail_msg_writer() << tr("failed to generate new mutlisig wallet"); return {}; } - message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total + message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % ms_status.threshold % ms_status.total << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } catch (const std::exception& e) @@ -4973,12 +4966,11 @@ boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::p m_wallet->callback(this); m_wallet->load(m_wallet_file, password); std::string prefix; - bool ready; - uint32_t threshold, total; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; if (m_wallet->watch_only()) prefix = tr("Opened watch-only wallet"); - 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 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 prefix = tr("Opened wallet"); message_writer(console_color_white, true) << @@ -5096,7 +5088,7 @@ bool simple_wallet::save(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("wallet is multisig and cannot save a watch-only version"); return true; @@ -6676,7 +6668,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri } // actually commit the transactions - if (m_wallet->multisig() && called_by_mms) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (ms_status.multisig_is_active && called_by_mms) { std::string ciphertext = m_wallet->save_multisig_tx(ptx_vector); if (!ciphertext.empty()) @@ -6685,7 +6678,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to MMS"); } } - else if (m_wallet->multisig()) + else if (ms_status.multisig_is_active) { bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); if (!r) @@ -6839,7 +6832,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_) } // actually commit the transactions - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); @@ -7144,7 +7137,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co } // actually commit the transactions - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); @@ -7379,7 +7372,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_) } // actually commit the transactions - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); @@ -7727,7 +7720,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_) fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if(m_wallet->multisig()) + if(m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("This is a multisig wallet, it can only sign with sign_multisig"); return true; @@ -8260,7 +8253,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args) return true; } - if (m_wallet->watch_only() || m_wallet->multisig()) + if (m_wallet->watch_only() || m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("The reserve proof can be generated only by a full wallet"); return true; @@ -9748,8 +9741,8 @@ bool simple_wallet::status(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::wallet_info(const std::vector<std::string> &args) { - bool ready; - uint32_t threshold, total; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + std::string description = m_wallet->get_description(); if (description.empty()) { @@ -9761,8 +9754,8 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args) std::string type; if (m_wallet->watch_only()) type = tr("Watch only"); - else if (m_wallet->multisig(&ready, &threshold, &total)) - type = (boost::format(tr("%u/%u multisig%s")) % threshold % total % (ready ? "" : " (not yet finalized)")).str(); + 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 type = tr("Normal"); message_writer() << tr("Type: ") << type; @@ -9789,7 +9782,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args) fail_msg_writer() << tr("wallet is watch-only and cannot sign"); return true; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("This wallet is multisig and cannot sign"); return true; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 7f4dbbc79..572079182 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -38,6 +38,7 @@ #include "subaddress_account.h" #include "common_defines.h" #include "common/util.h" +#include "multisig/multisig_account.h" #include "mnemonics/electrum-words.h" #include "mnemonics/english.h" @@ -87,12 +88,13 @@ namespace { throw runtime_error("Wallet is not initialized yet"); } - bool ready; - if (!wallet->multisig(&ready)) { + const multisig::multisig_account_status ms_status{wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { throw runtime_error("Wallet is not multisig"); } - if (!ready) { + if (!ms_status.is_ready) { throw runtime_error("Multisig wallet is not finalized yet"); } } @@ -105,12 +107,13 @@ namespace { throw runtime_error("Wallet is not initialized yet"); } - bool ready; - if (!wallet->multisig(&ready)) { + const multisig::multisig_account_status ms_status{wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { throw runtime_error("Wallet is not multisig"); } - if (ready) { + if (ms_status.is_ready) { throw runtime_error("Multisig wallet is already finalized"); } } @@ -1297,7 +1300,13 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex MultisigState WalletImpl::multisig() const { MultisigState state; - state.isMultisig = m_wallet->multisig(&state.isReady, &state.threshold, &state.total); + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + state.isMultisig = ms_status.multisig_is_active; + state.kexIsDone = ms_status.kex_is_done; + state.isReady = ms_status.is_ready; + state.threshold = ms_status.threshold; + state.total = ms_status.total; return state; } @@ -1318,7 +1327,7 @@ string WalletImpl::makeMultisig(const vector<string>& info, const uint32_t thres try { clearStatus(); - if (m_wallet->multisig()) { + if (m_wallet->get_multisig_status().multisig_is_active) { throw runtime_error("Wallet is already multisig"); } @@ -2053,8 +2062,8 @@ std::string WalletImpl::signMultisigParticipant(const std::string &message) cons { clearStatus(); - bool ready = false; - if (!m_wallet->multisig(&ready) || !ready) { + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (!ms_status.multisig_is_active || !ms_status.is_ready) { m_status = Status_Error; m_errorString = tr("The wallet must be in multisig ready state"); return {}; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index df86da847..53210832b 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -322,9 +322,10 @@ struct SubaddressAccount }; struct MultisigState { - MultisigState() : isMultisig(false), isReady(false), threshold(0), total(0) {} + MultisigState() : isMultisig(false), kexIsDone(false), isReady(false), threshold(0), total(0) {} bool isMultisig; + bool kexIsDone; bool isReady; uint32_t threshold; uint32_t total; diff --git a/src/wallet/message_store.h b/src/wallet/message_store.h index 202d77be6..c0afa2afa 100644 --- a/src/wallet/message_store.h +++ b/src/wallet/message_store.h @@ -245,18 +245,23 @@ namespace mms crypto::secret_key view_secret_key; bool multisig; bool multisig_is_ready; + bool multisig_kex_is_done; bool has_multisig_partial_key_images; uint32_t multisig_rounds_passed; size_t num_transfer_details; std::string mms_file; BEGIN_SERIALIZE_OBJECT() - VERSION_FIELD(0) + VERSION_FIELD(1) FIELD(address) VARINT_FIELD(nettype) FIELD(view_secret_key) FIELD(multisig) FIELD(multisig_is_ready) + if (version > 0) + FIELD(multisig_kex_is_done) + else + multisig_kex_is_done = multisig_is_ready; FIELD(has_multisig_partial_key_images) VARINT_FIELD(multisig_rounds_passed) VARINT_FIELD(num_transfer_details) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a9ad67f04..867e8201f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1438,14 +1438,14 @@ bool wallet2::get_seed(epee::wipeable_string& electrum_words, const epee::wipeab //---------------------------------------------------------------------------------------------------- bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeable_string &passphrase) const { - bool ready; - uint32_t threshold, total; - if (!multisig(&ready, &threshold, &total)) + const multisig::multisig_account_status ms_status{get_multisig_status()}; + + if (!ms_status.multisig_is_active) { std::cout << "This is not a multisig wallet" << std::endl; return false; } - if (!ready) + if (!ms_status.is_ready) { std::cout << "This multisig wallet is not yet finalized" << std::endl; return false; @@ -1459,8 +1459,8 @@ bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeabl THROW_WALLET_EXCEPTION_IF(num_expected_ms_keys != keys.m_multisig_keys.size(), error::wallet_internal_error, "Unexpected number of private multisig keys") epee::wipeable_string data; - data.append((const char*)&threshold, sizeof(uint32_t)); - data.append((const char*)&total, sizeof(uint32_t)); + data.append((const char*)&ms_status.threshold, sizeof(uint32_t)); + data.append((const char*)&ms_status.total, sizeof(uint32_t)); skey = keys.m_spend_secret_key; data.append((const char*)&skey, sizeof(skey)); pkey = keys.m_account_address.m_spend_public_key; @@ -5617,8 +5617,8 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor const std::vector<std::string> &kex_messages, const bool force_update_use_with_caution /*= false*/) { - bool ready{false}; - CHECK_AND_ASSERT_THROW_MES(multisig(&ready), "The wallet is not multisig"); + const multisig::multisig_account_status ms_status{get_multisig_status()}; + CHECK_AND_ASSERT_THROW_MES(ms_status.multisig_is_active, "The wallet is not multisig"); // decrypt account keys epee::misc_utils::auto_scope_leave_caller keys_reencryptor; @@ -5745,20 +5745,30 @@ std::string wallet2::get_multisig_first_kex_msg() const return multisig_account.get_next_kex_round_msg(); } //---------------------------------------------------------------------------------------------------- -bool wallet2::multisig(bool *ready, uint32_t *threshold, uint32_t *total) const +multisig::multisig_account_status wallet2::get_multisig_status() const { - if (!m_multisig) - return false; - if (threshold) - *threshold = m_multisig_threshold; - if (total) - *total = m_multisig_signers.size(); - if (ready) + multisig::multisig_account_status ret; + + if (m_multisig) { - *ready = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity())) && + ret.multisig_is_active = true; + ret.threshold = m_multisig_threshold; + ret.total = m_multisig_signers.size(); + ret.kex_is_done = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity())) && + (m_multisig_rounds_passed >= multisig::multisig_kex_rounds_required(m_multisig_signers.size(), m_multisig_threshold)); + ret.is_ready = ret.kex_is_done && (m_multisig_rounds_passed == multisig::multisig_setup_rounds_required(m_multisig_signers.size(), m_multisig_threshold)); } - return true; + else + { + ret.multisig_is_active = false; + ret.threshold = 0; + ret.total = 0; + ret.kex_is_done = false; + ret.is_ready = false; + } + + return ret; } //---------------------------------------------------------------------------------------------------- bool wallet2::has_multisig_partial_key_images() const @@ -14302,9 +14312,13 @@ void wallet2::generate_genesis(cryptonote::block& b) const { //---------------------------------------------------------------------------------------------------- mms::multisig_wallet_state wallet2::get_multisig_wallet_state() const { + const multisig::multisig_account_status ms_status{get_multisig_status()}; + mms::multisig_wallet_state state; state.nettype = m_nettype; - state.multisig = multisig(&state.multisig_is_ready); + state.multisig = ms_status.multisig_is_active; + state.multisig_is_ready = ms_status.is_ready; + state.multisig_kex_is_done = ms_status.kex_is_done; state.has_multisig_partial_key_images = has_multisig_partial_key_images(); state.multisig_rounds_passed = m_multisig_rounds_passed; state.num_transfer_details = m_transfers.size(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 5f884e374..3d17bec57 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -57,6 +57,7 @@ #include "common/util.h" #include "crypto/chacha.h" #include "crypto/hash.h" +#include "multisig/multisig_account.h" #include "ringct/rctTypes.h" #include "ringct/rctOps.h" #include "checkpoints/checkpoints.h" @@ -1059,7 +1060,7 @@ private: cryptonote::network_type nettype() const { return m_nettype; } bool watch_only() const { return m_watch_only; } - bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const; + multisig::multisig_account_status get_multisig_status() const; bool has_multisig_partial_key_images() const; bool has_unknown_key_images() const; bool get_multisig_seed(epee::wipeable_string& seed, const epee::wipeable_string &passphrase = std::string()) const; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index d7aa80e0a..da02e1e83 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -65,7 +65,7 @@ using namespace epee; #define CHECK_MULTISIG_ENABLED() \ do \ { \ - if (m_wallet->multisig() && !m_wallet->is_multisig_enabled()) \ + if (m_wallet->get_multisig_status().multisig_is_active && !m_wallet->is_multisig_enabled()) \ { \ er.code = WALLET_RPC_ERROR_CODE_DISABLED; \ er.message = "This wallet is multisig, and multisig is disabled. Multisig is an experimental feature and may have bugs. Things that could go wrong include: funds sent to a multisig wallet can't be spent at all, can only be spent with the participation of a malicious group member, or can be stolen by a malicious group member. You can enable it by running this once in monero-wallet-cli: set enable-multisig-experimental 1"; \ @@ -459,7 +459,7 @@ namespace tools { res.balance = req.all_accounts ? m_wallet->balance_all(req.strict) : m_wallet->balance(req.account_index, req.strict); res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock, &res.time_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock, &res.time_to_unlock); - res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images(); + res.multisig_import_needed = m_wallet->get_multisig_status().multisig_is_active && m_wallet->has_multisig_partial_key_images(); std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account; std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>>> unlocked_balance_per_subaddress_per_account; if (req.all_accounts) @@ -1024,7 +1024,7 @@ namespace tools fill(spent_key_images, key_image_list); } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector)); if (multisig_txset.empty()) @@ -2066,10 +2066,11 @@ namespace tools if (req.key_type.compare("mnemonic") == 0) { epee::wipeable_string seed; - bool ready; - if (m_wallet->multisig(&ready)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (ms_status.multisig_is_active) { - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -3979,7 +3980,14 @@ 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, const connection_context *ctx) { if (!m_wallet) return not_open(er); - res.multisig = m_wallet->multisig(&res.ready, &res.threshold, &res.total); + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + res.multisig = ms_status.multisig_is_active; + res.kex_is_done = ms_status.kex_is_done; + res.ready = ms_status.is_ready; + res.threshold = ms_status.threshold; + res.total = ms_status.total; + return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -3992,7 +4000,7 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG; er.message = "This wallet is already multisig"; @@ -4021,7 +4029,7 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG; er.message = "This wallet is already multisig"; @@ -4059,14 +4067,15 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - if (!m_wallet->multisig(&ready)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -4100,15 +4109,15 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -4116,7 +4125,7 @@ namespace tools } CHECK_MULTISIG_ENABLED(); - if (req.info.size() < threshold - 1) + if (req.info.size() + 1 < ms_status.threshold) { er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; er.message = "Needs multisig export info from more participants"; @@ -4180,9 +4189,9 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) + multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; @@ -4190,7 +4199,7 @@ namespace tools } CHECK_MULTISIG_ENABLED(); - if (req.multisig_info.size() + 1 < total) + if (req.multisig_info.size() + 1 < ms_status.total) { er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; er.message = "Needs multisig info from more participants"; @@ -4200,8 +4209,8 @@ namespace tools try { res.multisig_info = m_wallet->exchange_multisig_keys(req.password, req.multisig_info, req.force_update_use_with_caution); - m_wallet->multisig(&ready); - if (ready) + ms_status = m_wallet->get_multisig_status(); + if (ms_status.is_ready) { res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } @@ -4224,15 +4233,15 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -4294,15 +4303,15 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -4327,7 +4336,7 @@ namespace tools return false; } - if (txs.m_signers.size() < threshold) + if (txs.m_signers.size() < ms_status.threshold) { er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; er.message = "Not enough signers signed this transaction."; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index f9f534097..2173f5b6e 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -2323,12 +2323,14 @@ namespace wallet_rpc struct response_t { bool multisig; + bool kex_is_done; bool ready; uint32_t threshold; uint32_t total; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(multisig) + KV_SERIALIZE(kex_is_done) KV_SERIALIZE(ready) KV_SERIALIZE(threshold) KV_SERIALIZE(total) diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp index a79b81e84..c044591c1 100644 --- a/tests/unit_tests/multisig.cpp +++ b/tests/unit_tests/multisig.cpp @@ -159,12 +159,12 @@ static void check_results(const std::vector<std::string> &intermediate_infos, for (size_t i = 0; i < wallets.size(); ++i) { EXPECT_TRUE(!intermediate_infos[i].empty()); - bool ready; - uint32_t threshold, total; - EXPECT_TRUE(wallets[i].multisig(&ready, &threshold, &total)); - EXPECT_TRUE(ready); - EXPECT_TRUE(threshold == M); - EXPECT_TRUE(total == wallets.size()); + const multisig::multisig_account_status ms_status{wallets[i].get_multisig_status()}; + EXPECT_TRUE(ms_status.multisig_is_active); + EXPECT_TRUE(ms_status.kex_is_done); + EXPECT_TRUE(ms_status.is_ready); + EXPECT_TRUE(ms_status.threshold == M); + EXPECT_TRUE(ms_status.total == wallets.size()); wallets[i].decrypt_keys(""); @@ -226,10 +226,8 @@ static void make_wallets(const unsigned int M, const unsigned int N, const bool } // wallets should not be multisig yet - for (const auto &wallet: wallets) - { - ASSERT_FALSE(wallet.multisig()); - } + for (const auto& wallet: wallets) + ASSERT_FALSE(wallet.get_multisig_status().multisig_is_active); // make wallets multisig, get second round kex messages (if appropriate) std::vector<std::string> intermediate_infos(wallets.size()); @@ -242,16 +240,15 @@ static void make_wallets(const unsigned int M, const unsigned int N, const bool ++rounds_complete; // perform kex rounds until kex is complete - bool ready; - wallets[0].multisig(&ready); - while (!ready) + multisig::multisig_account_status ms_status{wallets[0].get_multisig_status()}; + while (!ms_status.is_ready) { if (force_update) intermediate_infos = exchange_round_force_update(wallets, intermediate_infos, rounds_complete + 1); else intermediate_infos = exchange_round(wallets, intermediate_infos); - wallets[0].multisig(&ready); + ms_status = wallets[0].get_multisig_status(); ++rounds_complete; } |