From 98db7ee467fb4f73ce5e748d4891326b84a4c93a Mon Sep 17 00:00:00 2001
From: moneromooo-monero <moneromooo-monero@users.noreply.github.com>
Date: Sat, 18 Nov 2017 11:24:38 +0000
Subject: [PATCH] wallet: factor multisig info parsing

---
 src/simplewallet/simplewallet.cpp | 57 +++----------------------------
 src/wallet/wallet2.cpp            | 54 +++++++++++++++++++++++++++++
 src/wallet/wallet2.h              |  8 +++++
 src/wallet/wallet_rpc_server.cpp  | 51 +--------------------------
 4 files changed, 68 insertions(+), 102 deletions(-)

diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 5c94f1704..64e665fb3 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -771,61 +771,13 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args)
     return true;
   }
 
-  // parse all multisig info
-  std::vector<crypto::secret_key> secret_keys(args.size() - 1);
-  std::vector<crypto::public_key> public_keys(args.size() - 1);
-  for (size_t i = 1; i < args.size(); ++i)
-  {
-    if (!tools::wallet2::verify_multisig_info(args[i], secret_keys[i - 1], public_keys[i - 1]))
-    {
-      fail_msg_writer() << tr("Bad multisig info: ") << args[i];
-      return true;
-    }
-  }
-
-  // remove duplicates
-  for (size_t i = 0; i < secret_keys.size(); ++i)
-  {
-    for (size_t j = i + 1; j < secret_keys.size(); ++j)
-    {
-      if (rct::sk2rct(secret_keys[i]) == rct::sk2rct(secret_keys[j]))
-      {
-        message_writer() << tr("Duplicate key found, ignoring");
-        secret_keys[j] = secret_keys.back();
-        public_keys[j] = public_keys.back();
-        secret_keys.pop_back();
-        public_keys.pop_back();
-        --j;
-      }
-    }
-  }
-
-  // people may include their own, weed it out
-  const crypto::secret_key local_skey = cryptonote::get_multisig_blinded_secret_key(m_wallet->get_account().get_keys().m_view_secret_key);
-  const crypto::public_key local_pkey = m_wallet->get_multisig_signer_public_key(m_wallet->get_account().get_keys().m_spend_secret_key);
-  for (size_t i = 0; i < secret_keys.size(); ++i)
-  {
-    if (secret_keys[i] == local_skey)
-    {
-      message_writer() << tr("Local key is present, ignoring");
-      secret_keys[i] = secret_keys.back();
-      public_keys[i] = public_keys.back();
-      secret_keys.pop_back();
-      public_keys.pop_back();
-      --i;
-    }
-    else if (public_keys[i] == local_pkey)
-    {
-      fail_msg_writer() << tr("Found local spend public key, but not local view secret key - something very weird");
-      return true;
-    }
-  }
-
   LOCK_IDLE_SCOPE();
 
   try
   {
-    std::string multisig_extra_info = m_wallet->make_multisig(orig_pwd_container->password(), secret_keys, public_keys, threshold);
+    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);
     if (!multisig_extra_info.empty())
     {
       success_msg_writer() << tr("Another step is needed");
@@ -840,7 +792,8 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args)
     return true;
   }
 
-  uint32_t total = secret_keys.size() + 1;
+  uint32_t total;
+  m_wallet->multisig(NULL, &threshold, &total);
   success_msg_writer() << std::to_string(threshold) << "/" << total << tr(" multisig address: ")
       << m_wallet->get_account().get_public_address_str(m_wallet->testnet());
 
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 635264d70..70180e080 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -2895,6 +2895,60 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
   return extra_multisig_info;
 }
 
+std::string wallet2::make_multisig(const epee::wipeable_string &password,
+  const std::vector<std::string> &info,
+  uint32_t threshold)
+{
+  // parse all multisig info
+  std::vector<crypto::secret_key> secret_keys(info.size());
+  std::vector<crypto::public_key> public_keys(info.size());
+  for (size_t i = 0; i < info.size(); ++i)
+  {
+    THROW_WALLET_EXCEPTION_IF(!verify_multisig_info(info[i], secret_keys[i], public_keys[i]),
+        error::wallet_internal_error, "Bad multisig info: " + info[i]);
+  }
+
+  // remove duplicates
+  for (size_t i = 0; i < secret_keys.size(); ++i)
+  {
+    for (size_t j = i + 1; j < secret_keys.size(); ++j)
+    {
+      if (rct::sk2rct(secret_keys[i]) == rct::sk2rct(secret_keys[j]))
+      {
+        MDEBUG("Duplicate key found, ignoring");
+        secret_keys[j] = secret_keys.back();
+        public_keys[j] = public_keys.back();
+        secret_keys.pop_back();
+        public_keys.pop_back();
+        --j;
+      }
+    }
+  }
+
+  // people may include their own, weed it out
+  const crypto::secret_key local_skey = cryptonote::get_multisig_blinded_secret_key(get_account().get_keys().m_view_secret_key);
+  const crypto::public_key local_pkey = get_multisig_signer_public_key(get_account().get_keys().m_spend_secret_key);
+  for (size_t i = 0; i < secret_keys.size(); ++i)
+  {
+    if (secret_keys[i] == local_skey)
+    {
+      MDEBUG("Local key is present, ignoring");
+      secret_keys[i] = secret_keys.back();
+      public_keys[i] = public_keys.back();
+      secret_keys.pop_back();
+      public_keys.pop_back();
+      --i;
+    }
+    else
+    {
+      THROW_WALLET_EXCEPTION_IF(public_keys[i] == local_pkey, error::wallet_internal_error,
+          "Found local spend public key, but not local view secret key - something very weird");
+    }
+  }
+
+  return make_multisig(password, secret_keys, public_keys, threshold);
+}
+
 bool wallet2::finalize_multisig(const epee::wipeable_string &password, std::unordered_set<crypto::public_key> pkeys, std::vector<crypto::public_key> signers)
 {
   CHECK_AND_ASSERT_THROW_MES(!pkeys.empty(), "empty pkeys");
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index cb9d7e980..399287c3e 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -471,6 +471,14 @@ namespace tools
      * \return empty if done, non empty if we need to send another string
      * to other participants
      */
+    std::string make_multisig(const epee::wipeable_string &password,
+      const std::vector<std::string> &info,
+      uint32_t threshold);
+    /*!
+     * \brief Creates a multisig wallet
+     * \return empty if done, non empty if we need to send another string
+     * to other participants
+     */
     std::string make_multisig(const epee::wipeable_string &password,
       const std::vector<crypto::secret_key> &view_keys,
       const std::vector<crypto::public_key> &spend_keys,
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 4c14433f4..0482b9dd6 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -2539,58 +2539,9 @@ namespace tools
       return false;
     }
 
-    // parse all multisig info
-    std::vector<crypto::secret_key> secret_keys(req.multisig_info.size());
-    std::vector<crypto::public_key> public_keys(req.multisig_info.size());
-    for (size_t i = 0; i < req.multisig_info.size(); ++i)
-    {
-      if (!m_wallet->verify_multisig_info(req.multisig_info[i], secret_keys[i], public_keys[i]))
-      {
-        er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_INFO;
-        er.message = "Bad multisig info: " + req.multisig_info[i];
-        return false;
-      }
-    }
-
-    // remove duplicates
-    for (size_t i = 1; i < secret_keys.size(); ++i)
-    {
-      for (size_t j = i + 1; j < secret_keys.size(); ++j)
-      {
-        if (rct::sk2rct(secret_keys[i]) == rct::sk2rct(secret_keys[j]))
-        {
-          secret_keys[j] = secret_keys.back();
-          public_keys[j] = public_keys.back();
-          secret_keys.pop_back();
-          public_keys.pop_back();
-          --j;
-        }
-      }
-    }
-
-    // people may include their own, weed it out
-    crypto::secret_key local_skey = cryptonote::get_multisig_blinded_secret_key(m_wallet->get_account().get_keys().m_view_secret_key);
-    for (size_t i = 0; i < secret_keys.size(); ++i)
-    {
-      if (rct::sk2rct(secret_keys[i]) == rct::sk2rct(local_skey))
-      {
-        secret_keys[i] = secret_keys.back();
-        public_keys[i] = public_keys.back();
-        secret_keys.pop_back();
-        public_keys.pop_back();
-        --i;
-      }
-      else if (public_keys[i] == m_wallet->get_account().get_keys().m_account_address.m_spend_public_key)
-      {
-        er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_INFO;
-        er.message = "Found local spend public key, but not local view secret key - something very weird";
-        return false;
-      }
-    }
-
     try
     {
-      res.multisig_info = m_wallet->make_multisig(req.password, secret_keys, public_keys, req.threshold);
+      res.multisig_info = m_wallet->make_multisig(req.password, req.multisig_info, req.threshold);
       res.address = m_wallet->get_account().get_public_address_str(m_wallet->testnet());
     }
     catch (const std::exception &e)