aboutsummaryrefslogtreecommitdiff
path: root/src/bitcoinrpc.cpp
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2012-05-14 23:44:52 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2012-05-24 20:26:19 +0200
commit1025440184ef100a22d07c7bb543ee45cf169d64 (patch)
treecd85ae7d981820189e506167e518adaf820aa638 /src/bitcoinrpc.cpp
parentfd61d6f5068cf92d34569862b4225f177049a4f0 (diff)
Refactor: split CKeyID/CScriptID/CTxDestination from CBitcoinAddress
This introduces internal types: * CKeyID: reference (hash160) of a key * CScriptID: reference (hash160) of a script * CTxDestination: a boost::variant of the former two CBitcoinAddress is retrofitted to be a Base58 encoding of a CTxDestination. This allows all internal code to only use the internal types, and only have RPC and GUI depend on the base58 code. Furthermore, the header dependencies are a lot saner now. base58.h is at the top (right below rpc and gui) instead of at the bottom. For the rest: wallet -> script -> keystore -> key. Only keystore still requires a forward declaration of CScript. Solving that would require splitting script into two layers.
Diffstat (limited to 'src/bitcoinrpc.cpp')
-rw-r--r--src/bitcoinrpc.cpp199
1 files changed, 106 insertions, 93 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index f227e363c3..75e3fd6e92 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -10,6 +10,7 @@
#include "net.h"
#include "init.h"
#include "ui_interface.h"
+#include "base58.h"
#include "bitcoinrpc.h"
#undef printf
@@ -184,10 +185,10 @@ ScriptSigToJSON(const CTxIn& txin, Object& out)
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)));
@@ -202,8 +203,8 @@ ScriptSigToJSON(const CTxIn& txin, Object& out)
}
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));
}
@@ -211,13 +212,13 @@ void
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;
@@ -227,8 +228,8 @@ ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
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));
}
@@ -593,11 +594,11 @@ Value getnewaddress(const Array& params, bool fHelp)
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();
}
@@ -614,7 +615,7 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
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.IsValid();
++it)
@@ -632,11 +633,11 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
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)
@@ -675,14 +676,14 @@ Value setaccount(const Array& params, bool fHelp)
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;
}
@@ -700,7 +701,7 @@ Value getaccount(const Array& params, bool fHelp)
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;
@@ -769,7 +770,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
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);
@@ -792,8 +793,12 @@ Value signmessage(const Array& params, bool fHelp)
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);
@@ -822,6 +827,10 @@ Value verifymessage(const Array& params, bool fHelp)
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);
@@ -836,7 +845,7 @@ Value verifymessage(const Array& params, bool fHelp)
if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
return false;
- return (CBitcoinAddress(key.GetPubKey()) == addr);
+ return (key.GetPubKey().GetID() == keyID);
}
@@ -852,7 +861,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
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;
@@ -879,18 +888,17 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
}
-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)
@@ -905,7 +913,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
// Get the set of pub keys assigned to account
string strAccount = AccountFromValue(params[0]);
- set<CBitcoinAddress> setAddress;
+ set<CTxDestination> setAddress;
GetAccountAddresses(strAccount, setAddress);
// Tally
@@ -918,8 +926,8 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
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;
}
@@ -990,15 +998,15 @@ Value getbalance(const Array& params, bool fHelp)
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;
@@ -1094,7 +1102,7 @@ Value sendfrom(const Array& params, bool fHelp)
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);
@@ -1136,7 +1144,7 @@ Value sendmany(const Array& params, bool fHelp)
setAddress.insert(address);
CScript scriptPubKey;
- scriptPubKey.SetBitcoinAddress(address);
+ scriptPubKey.SetDestination(address.Get());
int64 nAmount = AmountFromValue(s.value_);
totalAmount += nAmount;
@@ -1200,11 +1208,12 @@ Value addmultisigaddress(const Array& params, bool fHelp)
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()));
+ strprintf("%s does not refer to a key",ks.c_str()));
CPubKey vchPubKey;
- if (!pwalletMain->GetPubKey(address, vchPubKey))
+ if (!pwalletMain->GetPubKey(keyID, vchPubKey))
throw runtime_error(
strprintf("no full public key for address %s",ks.c_str()));
if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
@@ -1227,16 +1236,11 @@ Value addmultisigaddress(const Array& params, bool fHelp)
// 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();
}
@@ -1278,8 +1282,8 @@ Value ListReceived(const Array& params, bool fByAccounts)
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];
@@ -1376,8 +1380,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
{
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);
@@ -1406,11 +1410,11 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// 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)));
@@ -1423,7 +1427,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// 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))
@@ -1432,7 +1436,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
{
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)
@@ -1547,8 +1551,8 @@ Value listaccounts(const Array& params, bool fHelp)
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;
}
@@ -1557,16 +1561,16 @@ Value listaccounts(const Array& params, bool fHelp)
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,6 +1936,40 @@ Value encryptwallet(const Array& params, bool fHelp)
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)
{
@@ -1947,42 +1985,17 @@ 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));
- CPubKey vchPubKey;
- pwalletMain->GetPubKey(address, vchPubKey);
- ret.push_back(Pair("pubkey", HexStr(vchPubKey.Raw())));
- 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;
}