]> Git Repo - VerusCoin.git/commitdiff
Merge branch 'master' into async-ipv6-rpc
authorGiel van Schijndel <[email protected]>
Sun, 17 Jun 2012 12:30:37 +0000 (14:30 +0200)
committerGiel van Schijndel <[email protected]>
Sun, 17 Jun 2012 12:30:37 +0000 (14:30 +0200)
Conflicts:
src/bitcoinrpc.cpp

Signed-off-by: Giel van Schijndel <[email protected]>
1  2 
src/bitcoinrpc.cpp

diff --combined src/bitcoinrpc.cpp
index 9e785a3e376574177b8eb28ddc55889cee00637e,8c3a615fd11f8534ed52dba61747a53415a42e59..01142ab7cdbdb4f267e6e40acb5668e12e7c73d7
  #include "net.h"
  #include "init.h"
  #include "ui_interface.h"
+ #include "base58.h"
  #include "bitcoinrpc.h"
  
  #undef printf
  #include <boost/asio.hpp>
 +#include <boost/asio/ip/v6_only.hpp>
 +#include <boost/bind.hpp>
  #include <boost/filesystem.hpp>
 +#include <boost/foreach.hpp>
  #include <boost/iostreams/concepts.hpp>
  #include <boost/iostreams/stream.hpp>
  #include <boost/algorithm/string.hpp>
  #include <boost/lexical_cast.hpp>
- #include <boost/asio/ssl.hpp> 
+ #include <boost/asio/ssl.hpp>
  #include <boost/filesystem/fstream.hpp>
 -typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
 +#include <boost/shared_ptr.hpp>
 +#include <list>
  
  #define printf OutputDebugStringF
  // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
@@@ -188,10 -185,10 +189,10 @@@ ScriptSigToJSON(const CTxIn& txin, Obje
          return;
  
      txnouttype type;
-     vector<CBitcoinAddress> addresses;
+     vector<CTxDestination> addresses;
      int nRequired;
  
-     if (!ExtractAddresses(txprev.vout[txin.prevout.n].scriptPubKey, type,
+     if (!ExtractDestinations(txprev.vout[txin.prevout.n].scriptPubKey, type,
                            addresses, nRequired))
      {
          out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
      }
  
      Array a;
-     BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
-         a.push_back(addr.ToString());
+     BOOST_FOREACH(const CTxDestination& addr, addresses)
+         a.push_back(CBitcoinAddress(addr).ToString());
      out.push_back(Pair("addresses", a));
  }
  
@@@ -215,13 -212,13 +216,13 @@@ voi
  ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
  {
      txnouttype type;
-     vector<CBitcoinAddress> addresses;
+     vector<CTxDestination> addresses;
      int nRequired;
  
      out.push_back(Pair("asm", scriptPubKey.ToString()));
      out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
  
-     if (!ExtractAddresses(scriptPubKey, type, addresses, nRequired))
+     if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
      {
          out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
          return;
      out.push_back(Pair("type", GetTxnOutputType(type)));
  
      Array a;
-     BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
-         a.push_back(addr.ToString());
+     BOOST_FOREACH(const CTxDestination& addr, addresses)
+         a.push_back(CBitcoinAddress(addr).ToString());
      out.push_back(Pair("addresses", a));
  }
  
@@@ -439,7 -436,7 +440,7 @@@ Value stop(const Array& params, bool fH
              "stop\n"
              "Stop Bitcoin server.");
      // Shutdown will take long enough that the response should get back
-     uiInterface.QueueShutdown();
+     StartShutdown();
      return "Bitcoin server stopping";
  }
  
@@@ -534,6 -531,9 +535,9 @@@ Value getinfo(const Array& params, boo
              "getinfo\n"
              "Returns an object containing various state info.");
  
+     CService addrProxy;
+     GetProxy(NET_IPV4, addrProxy);
      Object obj;
      obj.push_back(Pair("version",       (int)CLIENT_VERSION));
      obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
      obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
      obj.push_back(Pair("blocks",        (int)nBestHeight));
      obj.push_back(Pair("connections",   (int)vNodes.size()));
-     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
+     obj.push_back(Pair("proxy",         (addrProxy.IsValid() ? addrProxy.ToStringIPPort() : string())));
      obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
      obj.push_back(Pair("testnet",       fTestNet));
      obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
@@@ -594,14 -594,14 +598,14 @@@ Value getnewaddress(const Array& params
          pwalletMain->TopUpKeyPool();
  
      // Generate a new key that is added to wallet
-     std::vector<unsigned char> newKey;
+     CPubKey newKey;
      if (!pwalletMain->GetKeyFromPool(newKey, false))
          throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
-     CBitcoinAddress address(newKey);
+     CKeyID keyID = newKey.GetID();
  
-     pwalletMain->SetAddressBookName(address, strAccount);
+     pwalletMain->SetAddressBookName(keyID, strAccount);
  
-     return address.ToString();
+     return CBitcoinAddress(keyID).ToString();
  }
  
  
@@@ -615,12 -615,12 +619,12 @@@ CBitcoinAddress GetAccountAddress(strin
      bool bKeyUsed = false;
  
      // Check if the current key has been used
-     if (!account.vchPubKey.empty())
+     if (account.vchPubKey.IsValid())
      {
          CScript scriptPubKey;
-         scriptPubKey.SetBitcoinAddress(account.vchPubKey);
+         scriptPubKey.SetDestination(account.vchPubKey.GetID());
          for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
-              it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
+              it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
               ++it)
          {
              const CWalletTx& wtx = (*it).second;
      }
  
      // Generate a new key
-     if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
+     if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
      {
          if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
              throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
  
-         pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
+         pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
          walletdb.WriteAccount(strAccount, account);
      }
  
-     return CBitcoinAddress(account.vchPubKey);
+     return CBitcoinAddress(account.vchPubKey.GetID());
  }
  
  Value getaccountaddress(const Array& params, bool fHelp)
@@@ -679,14 -679,14 +683,14 @@@ Value setaccount(const Array& params, b
          strAccount = AccountFromValue(params[1]);
  
      // Detect when changing the account of an address that is the 'unused current key' of another account:
-     if (pwalletMain->mapAddressBook.count(address))
+     if (pwalletMain->mapAddressBook.count(address.Get()))
      {
-         string strOldAccount = pwalletMain->mapAddressBook[address];
+         string strOldAccount = pwalletMain->mapAddressBook[address.Get()];
          if (address == GetAccountAddress(strOldAccount))
              GetAccountAddress(strOldAccount, true);
      }
  
-     pwalletMain->SetAddressBookName(address, strAccount);
+     pwalletMain->SetAddressBookName(address.Get(), strAccount);
  
      return Value::null;
  }
@@@ -704,7 -704,7 +708,7 @@@ Value getaccount(const Array& params, b
          throw JSONRPCError(-5, "Invalid Bitcoin address");
  
      string strAccount;
-     map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
+     map<CTxDestination, string>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
      if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
          strAccount = (*mi).second;
      return strAccount;
@@@ -773,7 -773,7 +777,7 @@@ Value sendtoaddress(const Array& params
      if (pwalletMain->IsLocked())
          throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
  
-     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
+     string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
      if (strError != "")
          throw JSONRPCError(-4, strError);
  
@@@ -796,8 -796,12 +800,12 @@@ Value signmessage(const Array& params, 
      if (!addr.IsValid())
          throw JSONRPCError(-3, "Invalid address");
  
+     CKeyID keyID;
+     if (!addr.GetKeyID(keyID))
+         throw JSONRPCError(-3, "Address does not refer to key");
      CKey key;
-     if (!pwalletMain->GetKey(addr, key))
+     if (!pwalletMain->GetKey(keyID, key))
          throw JSONRPCError(-4, "Private key not available");
  
      CDataStream ss(SER_GETHASH, 0);
@@@ -826,6 -830,10 +834,10 @@@ Value verifymessage(const Array& params
      if (!addr.IsValid())
          throw JSONRPCError(-3, "Invalid address");
  
+     CKeyID keyID;
+     if (!addr.GetKeyID(keyID))
+         throw JSONRPCError(-3, "Address does not refer to key");
      bool fInvalid = false;
      vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
  
      if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
          return false;
  
-     return (CBitcoinAddress(key.GetPubKey()) == addr);
+     return (key.GetPubKey().GetID() == keyID);
  }
  
  
@@@ -856,7 -864,7 +868,7 @@@ Value getreceivedbyaddress(const Array
      CScript scriptPubKey;
      if (!address.IsValid())
          throw JSONRPCError(-5, "Invalid Bitcoin address");
-     scriptPubKey.SetBitcoinAddress(address);
+     scriptPubKey.SetDestination(address.Get());
      if (!IsMine(*pwalletMain,scriptPubKey))
          return (double)0.0;
  
  }
  
  
- void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
+ void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
  {
-     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
+     BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
      {
-         const CBitcoinAddress& address = item.first;
+         const CTxDestination& address = item.first;
          const string& strName = item.second;
          if (strName == strAccount)
              setAddress.insert(address);
      }
  }
  
  Value getreceivedbyaccount(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() < 1 || params.size() > 2)
  
      // Get the set of pub keys assigned to account
      string strAccount = AccountFromValue(params[0]);
-     set<CBitcoinAddress> setAddress;
+     set<CTxDestination> setAddress;
      GetAccountAddresses(strAccount, setAddress);
  
      // Tally
  
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
-             CBitcoinAddress address;
-             if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
+             CTxDestination address;
+             if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
                  if (wtx.GetDepthInMainChain() >= nMinDepth)
                      nAmount += txout.nValue;
          }
@@@ -994,15 -1001,15 +1005,15 @@@ Value getbalance(const Array& params, b
              int64 allGeneratedImmature, allGeneratedMature, allFee;
              allGeneratedImmature = allGeneratedMature = allFee = 0;
              string strSentAccount;
-             list<pair<CBitcoinAddress, int64> > listReceived;
-             list<pair<CBitcoinAddress, int64> > listSent;
+             list<pair<CTxDestination, int64> > listReceived;
+             list<pair<CTxDestination, int64> > listSent;
              wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
              if (wtx.GetDepthInMainChain() >= nMinDepth)
              {
-                 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
+                 BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived)
                      nBalance += r.second;
              }
-             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
+             BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent)
                  nBalance -= r.second;
              nBalance -= allFee;
              nBalance += allGeneratedMature;
@@@ -1098,7 -1105,7 +1109,7 @@@ Value sendfrom(const Array& params, boo
          throw JSONRPCError(-6, "Account has insufficient funds");
  
      // Send
-     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
+     string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
      if (strError != "")
          throw JSONRPCError(-4, strError);
  
@@@ -1140,8 -1147,8 +1151,8 @@@ Value sendmany(const Array& params, boo
          setAddress.insert(address);
  
          CScript scriptPubKey;
-         scriptPubKey.SetBitcoinAddress(address);
-         int64 nAmount = AmountFromValue(s.value_); 
+         scriptPubKey.SetDestination(address.Get());
+         int64 nAmount = AmountFromValue(s.value_);
          totalAmount += nAmount;
  
          vecSend.push_back(make_pair(scriptPubKey, nAmount));
@@@ -1204,22 -1211,23 +1215,23 @@@ Value addmultisigaddress(const Array& p
          CBitcoinAddress address(ks);
          if (address.IsValid())
          {
-             if (address.IsScript())
+             CKeyID keyID;
+             if (!address.GetKeyID(keyID))
                  throw runtime_error(
-                     strprintf("%s is a pay-to-script address",ks.c_str()));
-             std::vector<unsigned char> vchPubKey;
-             if (!pwalletMain->GetPubKey(address, vchPubKey))
+                     strprintf("%s does not refer to a key",ks.c_str()));
+             CPubKey vchPubKey;
+             if (!pwalletMain->GetPubKey(keyID, vchPubKey))
                  throw runtime_error(
                      strprintf("no full public key for address %s",ks.c_str()));
-             if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
+             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
                  throw runtime_error(" Invalid public key: "+ks);
          }
  
          // Case 2: hex public key
          else if (IsHex(ks))
          {
-             vector<unsigned char> vchPubKey = ParseHex(ks);
-             if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
+             CPubKey vchPubKey(ParseHex(ks));
+             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
                  throw runtime_error(" Invalid public key: "+ks);
          }
          else
      // Construct using pay-to-script-hash:
      CScript inner;
      inner.SetMultisig(nRequired, pubkeys);
-     uint160 scriptHash = Hash160(inner);
-     CScript scriptPubKey;
-     scriptPubKey.SetPayToScriptHash(inner);
+     CScriptID innerID = inner.GetID();
      pwalletMain->AddCScript(inner);
-     CBitcoinAddress address;
-     address.SetScriptHash160(scriptHash);
  
-     pwalletMain->SetAddressBookName(address, strAccount);
-     return address.ToString();
+     pwalletMain->SetAddressBookName(innerID, strAccount);
+     return CBitcoinAddress(innerID).ToString();
  }
  
  
@@@ -1282,8 -1285,8 +1289,8 @@@ Value ListReceived(const Array& params
  
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
-             CBitcoinAddress address;
-             if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
+             CTxDestination address;
+             if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
                  continue;
  
              tallyitem& item = mapTally[address];
@@@ -1380,8 -1383,8 +1387,8 @@@ void ListTransactions(const CWalletTx& 
  {
      int64 nGeneratedImmature, nGeneratedMature, nFee;
      string strSentAccount;
-     list<pair<CBitcoinAddress, int64> > listReceived;
-     list<pair<CBitcoinAddress, int64> > listSent;
+     list<pair<CTxDestination, int64> > listReceived;
+     list<pair<CTxDestination, int64> > listSent;
  
      wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
  
      // Sent
      if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
      {
-         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
+         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
          {
              Object entry;
              entry.push_back(Pair("account", strSentAccount));
-             entry.push_back(Pair("address", s.first.ToString()));
+             entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString()));
              entry.push_back(Pair("category", "send"));
              entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
              entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
      // Received
      if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
      {
-         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
+         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
          {
              string account;
              if (pwalletMain->mapAddressBook.count(r.first))
              {
                  Object entry;
                  entry.push_back(Pair("account", account));
-                 entry.push_back(Pair("address", r.first.ToString()));
+                 entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString()));
                  entry.push_back(Pair("category", "receive"));
                  entry.push_back(Pair("amount", ValueFromAmount(r.second)));
                  if (fLong)
@@@ -1521,7 -1524,7 +1528,7 @@@ Value listtransactions(const Array& par
          if ((int)ret.size() >= (nCount+nFrom)) break;
      }
      // ret is newest to oldest
-     
      if (nFrom > (int)ret.size())
          nFrom = ret.size();
      if ((nFrom + nCount) > (int)ret.size())
@@@ -1551,8 -1554,8 +1558,8 @@@ Value listaccounts(const Array& params
          nMinDepth = params[0].get_int();
  
      map<string, int64> mapAccountBalances;
-     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
-         if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
+     BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
+         if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
              mapAccountBalances[entry.second] = 0;
      }
  
          const CWalletTx& wtx = (*it).second;
          int64 nGeneratedImmature, nGeneratedMature, nFee;
          string strSentAccount;
-         list<pair<CBitcoinAddress, int64> > listReceived;
-         list<pair<CBitcoinAddress, int64> > listSent;
+         list<pair<CTxDestination, int64> > listReceived;
+         list<pair<CTxDestination, int64> > listSent;
          wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
          mapAccountBalances[strSentAccount] -= nFee;
-         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
+         BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent)
              mapAccountBalances[strSentAccount] -= s.second;
          if (wtx.GetDepthInMainChain() >= nMinDepth)
          {
              mapAccountBalances[""] += nGeneratedMature;
-             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
+             BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived)
                  if (pwalletMain->mapAddressBook.count(r.first))
                      mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
                  else
@@@ -1932,10 -1935,44 +1939,44 @@@ Value encryptwallet(const Array& params
      // BDB seems to have a bad habit of writing old data into
      // slack space in .dat files; that is bad if the old data is
      // unencrypted private keys.  So:
-     uiInterface.QueueShutdown();
+     StartShutdown();
      return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet";
  }
  
+ class DescribeAddressVisitor : public boost::static_visitor<Object>
+ {
+ public:
+     Object operator()(const CNoDestination &dest) const { return Object(); }
+     Object operator()(const CKeyID &keyID) const {
+         Object obj;
+         CPubKey vchPubKey;
+         pwalletMain->GetPubKey(keyID, vchPubKey);
+         obj.push_back(Pair("isscript", false));
+         obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
+         obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
+         return obj;
+     }
+     Object operator()(const CScriptID &scriptID) const {
+         Object obj;
+         obj.push_back(Pair("isscript", true));
+         CScript subscript;
+         pwalletMain->GetCScript(scriptID, subscript);
+         std::vector<CTxDestination> addresses;
+         txnouttype whichType;
+         int nRequired;
+         ExtractDestinations(subscript, whichType, addresses, nRequired);
+         obj.push_back(Pair("script", GetTxnOutputType(whichType)));
+         Array a;
+         BOOST_FOREACH(const CTxDestination& addr, addresses)
+             a.push_back(CBitcoinAddress(addr).ToString());
+         obj.push_back(Pair("addresses", a));
+         if (whichType == TX_MULTISIG)
+             obj.push_back(Pair("sigsrequired", nRequired));
+         return obj;
+     }
+ };
  
  Value validateaddress(const Array& params, bool fHelp)
  {
      ret.push_back(Pair("isvalid", isValid));
      if (isValid)
      {
-         // Call Hash160ToAddress() so we always return current ADDRESSVERSION
-         // version of the address:
+         CTxDestination dest = address.Get();
          string currentAddress = address.ToString();
          ret.push_back(Pair("address", currentAddress));
-         if (pwalletMain->HaveKey(address))
-         {
-             ret.push_back(Pair("ismine", true));
-             std::vector<unsigned char> vchPubKey;
-             pwalletMain->GetPubKey(address, vchPubKey);
-             ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
-             CKey key;
-             key.SetPubKey(vchPubKey);
-             ret.push_back(Pair("iscompressed", key.IsCompressed()));
-         }
-         else if (pwalletMain->HaveCScript(address.GetHash160()))
-         {
-             ret.push_back(Pair("isscript", true));
-             CScript subscript;
-             pwalletMain->GetCScript(address.GetHash160(), subscript);
-             ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
-             std::vector<CBitcoinAddress> addresses;
-             txnouttype whichType;
-             int nRequired;
-             ExtractAddresses(subscript, whichType, addresses, nRequired);
-             ret.push_back(Pair("script", GetTxnOutputType(whichType)));
-             Array a;
-             BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
-                 a.push_back(addr.ToString());
-             ret.push_back(Pair("addresses", a));
-             if (whichType == TX_MULTISIG)
-                 ret.push_back(Pair("sigsrequired", nRequired));
+         bool fMine = IsMine(*pwalletMain, dest);
+         ret.push_back(Pair("ismine", fMine));
+         if (fMine) {
+             Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
+             ret.insert(ret.end(), detail.begin(), detail.end());
          }
-         else
-             ret.push_back(Pair("ismine", false));
-         if (pwalletMain->mapAddressBook.count(address))
-             ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
+         if (pwalletMain->mapAddressBook.count(dest))
+             ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest]));
      }
      return ret;
  }
@@@ -2252,7 -2264,7 +2268,7 @@@ Value sendrawtx(const Array& params, bo
      CInv inv(MSG_TX, tx.GetHash());
      RelayInventory(inv);
  
-     return true;
+     return tx.GetHash().GetHex();
  }
  
  
@@@ -2549,22 -2561,10 +2565,22 @@@ void ErrorReply(std::ostream& stream, c
      stream << HTTPReply(nStatus, strReply, false) << std::flush;
  }
  
 -bool ClientAllowed(const string& strAddress)
 +bool ClientAllowed(const boost::asio::ip::address& address)
  {
 -    if (strAddress == asio::ip::address_v4::loopback().to_string())
 +    // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
 +    if (address.is_v6()
 +     && (address.to_v6().is_v4_compatible()
 +      || address.to_v6().is_v4_mapped()))
 +        return ClientAllowed(address.to_v6().to_v4());
 +
 +    if (address == asio::ip::address_v4::loopback()
 +     || address == asio::ip::address_v6::loopback()
 +     || (address.is_v4()
 +         // Chech whether IPv4 addresses match 127.0.0.0/8 (loopback subnet)
 +      && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000))
          return true;
 +
 +    const string strAddress = address.to_string();
      const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
      BOOST_FOREACH(string strAllow, vAllow)
          if (WildcardMatch(strAddress, strAllow))
  //
  // IOStream device that speaks SSL but can also speak non-SSL
  //
 +template <typename Protocol>
  class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
  public:
 -    SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
 +    SSLIOStreamDevice(asio::ssl::stream<typename Protocol::socket> &streamIn, bool fUseSSLIn) : stream(streamIn)
      {
          fUseSSL = fUseSSLIn;
          fNeedHandshake = fUseSSLIn;
  private:
      bool fNeedHandshake;
      bool fUseSSL;
 -    SSLStream& stream;
 +    asio::ssl::stream<typename Protocol::socket>& stream;
  };
  
  class AcceptedConnection
  {
 -    public:
 -    SSLStream sslStream;
 -    SSLIOStreamDevice d;
 -    iostreams::stream<SSLIOStreamDevice> stream;
 +public:
 +    virtual ~AcceptedConnection() {}
 +
 +    virtual std::iostream& stream() = 0;
 +    virtual std::string peer_address_to_string() const = 0;
 +    virtual void close() = 0;
 +};
 +
 +template <typename Protocol>
 +class AcceptedConnectionImpl : public AcceptedConnection
 +{
 +public:
 +    AcceptedConnectionImpl(
 +            asio::io_service& io_service,
 +            ssl::context &context,
 +            bool fUseSSL) :
 +        sslStream(io_service, context),
 +        _d(sslStream, fUseSSL),
 +        _stream(_d)
 +    {
 +    }
  
 -    ip::tcp::endpoint peer;
 +    virtual std::iostream& stream()
 +    {
 +        return _stream;
 +    }
 +
 +    virtual std::string peer_address_to_string() const
 +    {
 +        return peer.address().to_string();
 +    }
  
 -    AcceptedConnection(asio::io_service &io_service, ssl::context &context,
 -     bool fUseSSL) : sslStream(io_service, context), d(sslStream, fUseSSL),
 -     stream(d) { ; }
 +    virtual void close()
 +    {
 +        _stream.close();
 +    }
 +
 +    typename Protocol::endpoint peer;
 +    asio::ssl::stream<typename Protocol::socket> sslStream;
 +
 +private:
 +    SSLIOStreamDevice<Protocol> _d;
 +    iostreams::stream< SSLIOStreamDevice<Protocol> > _stream;
  };
  
  void ThreadRPCServer(void* parg)
      printf("ThreadRPCServer exited\n");
  }
  
 +// Forward declaration required for RPCListen
 +template <typename Protocol, typename SocketAcceptorService>
 +static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
 +                             ssl::context& context,
 +                             bool fUseSSL,
 +                             AcceptedConnection* conn,
 +                             const boost::system::error_code& error);
 +
 +/**
 + * Sets up I/O resources to accept and handle a new connection.
 + */
 +template <typename Protocol, typename SocketAcceptorService>
 +static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
 +                   ssl::context& context,
 +                   const bool fUseSSL)
 +{
 +
 +    // Accept connection
 +    AcceptedConnectionImpl<Protocol>* conn = new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL);
 +
 +    acceptor->async_accept(
 +            conn->sslStream.lowest_layer(),
 +            conn->peer,
 +            boost::bind(&RPCAcceptHandler<Protocol, SocketAcceptorService>,
 +                acceptor,
 +                boost::ref(context),
 +                fUseSSL,
 +                conn,
 +                boost::asio::placeholders::error));
 +}
 +
 +/**
 + * Accept and handle incoming connection.
 + */
 +template <typename Protocol, typename SocketAcceptorService>
 +static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
 +                             ssl::context& context,
 +                             const bool fUseSSL,
 +                             AcceptedConnection* conn,
 +                             const boost::system::error_code& error)
 +{
 +    vnThreadsRunning[THREAD_RPCLISTENER]++;
 +
 +    // Immediately start accepting new connections
 +    RPCListen(acceptor, context, fUseSSL);
 +
 +    AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn);
 +
 +    // TODO: Actually handle errors
 +    if (error)
 +    {
 +        delete conn;
 +    }
 +
 +    // Restrict callers by IP.  It is important to
 +    // do this before starting client thread, to filter out
 +    // certain DoS and misbehaving clients.
 +    else if (tcp_conn
 +          && !ClientAllowed(tcp_conn->peer.address()))
 +    {
 +        // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
 +        if (!fUseSSL)
 +            conn->stream() << HTTPReply(403, "", false) << std::flush;
 +        delete conn;
 +    }
 +
 +    // start HTTP client thread
 +    else if (!CreateThread(ThreadRPCServer3, conn)) {
 +        printf("Failed to create RPC server client thread\n");
 +        delete conn;
 +    }
 +
 +    vnThreadsRunning[THREAD_RPCLISTENER]--;
 +}
 +
  void ThreadRPCServer2(void* parg)
  {
      printf("ThreadRPCServer started\n");
                  GetConfigFile().string().c_str(),
                  EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
              _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
-         uiInterface.QueueShutdown();
+         StartShutdown();
          return;
      }
  
 -    bool fUseSSL = GetBoolArg("-rpcssl");
 -    asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
 +    const bool fUseSSL = GetBoolArg("-rpcssl");
  
      asio::io_service io_service;
 -    ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
 -    ip::tcp::acceptor acceptor(io_service);
 -    try
 -    {
 -        acceptor.open(endpoint.protocol());
 -        acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
 -        acceptor.bind(endpoint);
 -        acceptor.listen(socket_base::max_connections);
 -    }
 -    catch(boost::system::system_error &e)
 -    {
 -        uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
 -                             _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
 -        StartShutdown();
 -        return;
 -    }
 +
 +    // Make sure that we'll get stopped when the application shuts down
 +    boost::signals2::scoped_connection rpc_listen_thread_stop(
 +            uiInterface.QueueShutdown.connect(boost::bind(
 +                &asio::io_service::stop, &io_service)));
  
      ssl::context context(io_service, ssl::context::sslv23);
      if (fUseSSL)
          SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
      }
  
 -    loop
 +    // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets
 +    const bool loopback = !mapArgs.count("-rpcallowip");
 +    asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any();
 +    ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
 +
 +    std::list< boost::shared_ptr<ip::tcp::acceptor> > acceptors;
 +    try
      {
 -        // Accept connection
 -        AcceptedConnection *conn =
 -                    new AcceptedConnection(io_service, context, fUseSSL);
 +        acceptors.push_back(boost::shared_ptr<ip::tcp::acceptor>(new ip::tcp::acceptor(io_service)));
 +        acceptors.back()->open(endpoint.protocol());
 +        acceptors.back()->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
  
 -        vnThreadsRunning[THREAD_RPCLISTENER]--;
 -        acceptor.accept(conn->sslStream.lowest_layer(), conn->peer);
 -        vnThreadsRunning[THREAD_RPCLISTENER]++;
 +        // Try making the socket dual IPv6/IPv4 (if listening on the "any" address)
 +        boost::system::error_code v6_only_error;
 +        acceptors.back()->set_option(boost::asio::ip::v6_only(loopback), v6_only_error);
  
 -        if (fShutdown)
 -        {
 -            delete conn;
 -            return;
 -        }
 +        acceptors.back()->bind(endpoint);
 +        acceptors.back()->listen(socket_base::max_connections);
  
 -        // Restrict callers by IP.  It is important to
 -        // do this before starting client thread, to filter out
 -        // certain DoS and misbehaving clients.
 -        if (!ClientAllowed(conn->peer.address().to_string()))
 +        RPCListen(acceptors.back(), context, fUseSSL);
 +
 +        // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately
 +        if (loopback || v6_only_error)
          {
 -            // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
 -            if (!fUseSSL)
 -                conn->stream << HTTPReply(403, "", false) << std::flush;
 -            delete conn;
 -        }
 +            bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any();
 +            endpoint.address(bindAddress);
  
 -        // start HTTP client thread
 -        else if (!CreateThread(ThreadRPCServer3, conn)) {
 -            printf("Failed to create RPC server client thread\n");
 -            delete conn;
 +            acceptors.push_back(boost::shared_ptr<ip::tcp::acceptor>(new ip::tcp::acceptor(io_service)));
 +            acceptors.back()->open(endpoint.protocol());
 +            acceptors.back()->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
 +            acceptors.back()->bind(endpoint);
 +            acceptors.back()->listen(socket_base::max_connections);
 +
 +            RPCListen(acceptors.back(), context, fUseSSL);
          }
      }
-         uiInterface.QueueShutdown();
 +    catch(boost::system::system_error &e)
 +    {
 +        uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
 +                             _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
-     io_service.run();
++        StartShutdown();
 +        return;
 +    }
 +
 +    vnThreadsRunning[THREAD_RPCLISTENER]--;
++    while (!fShutdown)
++        io_service.run_one();
 +    vnThreadsRunning[THREAD_RPCLISTENER]++;
 +
 +    // Terminate all outstanding accept-requests
 +    BOOST_FOREACH(boost::shared_ptr<ip::tcp::acceptor>& acceptor, acceptors)
 +    {
 +        acceptor->cancel();
 +        acceptor->close();
 +    }
 +    acceptors.clear();
  }
  
  void ThreadRPCServer3(void* parg)
      loop {
          if (fShutdown || !fRun)
          {
 -            conn->stream.close();
 +            conn->close();
              delete conn;
              --vnThreadsRunning[THREAD_RPCHANDLER];
              return;
          map<string, string> mapHeaders;
          string strRequest;
  
 -        ReadHTTP(conn->stream, mapHeaders, strRequest);
 +        ReadHTTP(conn->stream(), mapHeaders, strRequest);
  
          // Check authorization
          if (mapHeaders.count("authorization") == 0)
          {
 -            conn->stream << HTTPReply(401, "", false) << std::flush;
 +            conn->stream() << HTTPReply(401, "", false) << std::flush;
              break;
          }
          if (!HTTPAuthorized(mapHeaders))
          {
 -            printf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer.address().to_string().c_str());
 +            printf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string().c_str());
              /* Deter brute-forcing short passwords.
                 If this results in a DOS the user really
                 shouldn't have their RPC port exposed.*/
              if (mapArgs["-rpcpassword"].size() < 20)
                  Sleep(250);
  
 -            conn->stream << HTTPReply(401, "", false) << std::flush;
 +            conn->stream() << HTTPReply(401, "", false) << std::flush;
              break;
          }
          if (mapHeaders["connection"] == "close")
  
              // Send reply
              string strReply = JSONRPCReply(result, Value::null, id);
 -            conn->stream << HTTPReply(200, strReply, fRun) << std::flush;
 +            conn->stream() << HTTPReply(200, strReply, fRun) << std::flush;
          }
          catch (Object& objError)
          {
 -            ErrorReply(conn->stream, objError, id);
 +            ErrorReply(conn->stream(), objError, id);
              break;
          }
          catch (std::exception& e)
          {
 -            ErrorReply(conn->stream, JSONRPCError(-32700, e.what()), id);
 +            ErrorReply(conn->stream(), JSONRPCError(-32700, e.what()), id);
              break;
          }
      }
@@@ -3018,9 -2899,9 +3035,9 @@@ Object CallRPC(const string& strMethod
      asio::io_service io_service;
      ssl::context context(io_service, ssl::context::sslv23);
      context.set_options(ssl::context::no_sslv2);
 -    SSLStream sslStream(io_service, context);
 -    SSLIOStreamDevice d(sslStream, fUseSSL);
 -    iostreams::stream<SSLIOStreamDevice> stream(d);
 +    asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
 +    SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
 +    iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
      if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
          throw runtime_error("couldn't connect to server");
  
@@@ -3111,24 -2992,11 +3128,11 @@@ Array RPCConvertValues(const std::strin
      if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
      if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
      if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
-     if (strMethod == "sendmany"               && n > 1)
-     {
-         string s = params[1].get_str();
-         Value v;
-         if (!read_string(s, v) || v.type() != obj_type)
-             throw runtime_error("type mismatch");
-         params[1] = v.get_obj();
-     }
-     if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
-     if (strMethod == "addmultisigaddress"      && n > 0) ConvertTo<boost::int64_t>(params[0]);
-     if (strMethod == "addmultisigaddress"      && n > 1)
-     {
-         string s = params[1].get_str();
-         Value v;
-         if (!read_string(s, v) || v.type() != array_type)
-             throw runtime_error("type mismatch "+s);
-         params[1] = v.get_array();
-     }
+     if (strMethod == "sendmany"               && n > 1) ConvertTo<Object>(params[1]);
+     if (strMethod == "sendmany"               && n > 2) ConvertTo<boost::int64_t>(params[2]);
+     if (strMethod == "addmultisigaddress"     && n > 0) ConvertTo<boost::int64_t>(params[0]);
+     if (strMethod == "addmultisigaddress"     && n > 1) ConvertTo<Array>(params[1]);
      return params;
  }
  
This page took 0.069167 seconds and 4 git commands to generate.