diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2012-05-14 23:44:52 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2012-05-24 20:26:19 +0200 |
commit | 1025440184ef100a22d07c7bb543ee45cf169d64 (patch) | |
tree | cd85ae7d981820189e506167e518adaf820aa638 /src | |
parent | fd61d6f5068cf92d34569862b4225f177049a4f0 (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')
-rw-r--r-- | src/base58.h | 101 | ||||
-rw-r--r-- | src/bitcoinrpc.cpp | 199 | ||||
-rw-r--r-- | src/init.cpp | 2 | ||||
-rw-r--r-- | src/key.h | 25 | ||||
-rw-r--r-- | src/keystore.cpp | 16 | ||||
-rw-r--r-- | src/keystore.h | 39 | ||||
-rw-r--r-- | src/qt/addresstablemodel.cpp | 22 | ||||
-rw-r--r-- | src/qt/messagepage.cpp | 10 | ||||
-rw-r--r-- | src/qt/transactiondesc.cpp | 24 | ||||
-rw-r--r-- | src/qt/transactionrecord.cpp | 13 | ||||
-rw-r--r-- | src/qt/verifymessagedialog.cpp | 3 | ||||
-rw-r--r-- | src/qt/walletmodel.cpp | 14 | ||||
-rw-r--r-- | src/rpcdump.cpp | 9 | ||||
-rw-r--r-- | src/script.cpp | 117 | ||||
-rw-r--r-- | src/script.h | 38 | ||||
-rw-r--r-- | src/test/DoS_tests.cpp | 10 | ||||
-rw-r--r-- | src/test/base58_tests.cpp | 4 | ||||
-rw-r--r-- | src/test/key_tests.cpp | 27 | ||||
-rw-r--r-- | src/test/multisig_tests.cpp | 34 | ||||
-rw-r--r-- | src/test/script_P2SH_tests.cpp | 26 | ||||
-rw-r--r-- | src/test/sigopcount_tests.cpp | 4 | ||||
-rw-r--r-- | src/test/transaction_tests.cpp | 4 | ||||
-rw-r--r-- | src/wallet.cpp | 56 | ||||
-rw-r--r-- | src/wallet.h | 16 | ||||
-rw-r--r-- | src/walletdb.cpp | 2 | ||||
-rw-r--r-- | src/walletdb.h | 1 |
26 files changed, 477 insertions, 339 deletions
diff --git a/src/base58.h b/src/base58.h index 26d8c5f9ed..b492cd683c 100644 --- a/src/base58.h +++ b/src/base58.h @@ -19,6 +19,7 @@ #include <vector> #include "bignum.h" #include "key.h" +#include "script.h" static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -258,6 +259,18 @@ public: * Script-hash-addresses have version 5 (or 196 testnet). * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. */ +class CBitcoinAddress; +class CBitcoinAddressVisitor : public boost::static_visitor<bool> +{ +private: + CBitcoinAddress *addr; +public: + CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { } + bool operator()(const CKeyID &id) const; + bool operator()(const CScriptID &id) const; + bool operator()(const CNoDestination &no) const; +}; + class CBitcoinAddress : public CBase58Data { public: @@ -269,21 +282,19 @@ public: SCRIPT_ADDRESS_TEST = 196, }; - bool SetHash160(const uint160& hash160) - { - SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &hash160, 20); + bool Set(const CKeyID &id) { + SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &id, 20); return true; } - void SetPubKey(const CPubKey& vchPubKey) - { - SetHash160(vchPubKey.GetID()); + bool Set(const CScriptID &id) { + SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &id, 20); + return true; } - bool SetScriptHash160(const uint160& hash160) + bool Set(const CTxDestination &dest) { - SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &hash160, 20); - return true; + return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); } bool IsValid() const @@ -315,27 +326,14 @@ public: } return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize; } - bool IsScript() const - { - if (!IsValid()) - return false; - if (fTestNet) - return nVersion == SCRIPT_ADDRESS_TEST; - return nVersion == SCRIPT_ADDRESS; - } CBitcoinAddress() { } - CBitcoinAddress(uint160 hash160In) - { - SetHash160(hash160In); - } - - CBitcoinAddress(const CPubKey& vchPubKey) + CBitcoinAddress(const CTxDestination &dest) { - SetPubKey(vchPubKey); + Set(dest); } CBitcoinAddress(const std::string& strAddress) @@ -348,15 +346,58 @@ public: SetString(pszAddress); } - uint160 GetHash160() const - { - assert(vchData.size() == 20); - uint160 hash160; - memcpy(&hash160, &vchData[0], 20); - return hash160; + CTxDestination Get() const { + if (!IsValid()) + return CNoDestination(); + switch (nVersion) { + case PUBKEY_ADDRESS: + case PUBKEY_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + return CKeyID(id); + } + case SCRIPT_ADDRESS: + case SCRIPT_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + return CScriptID(id); + } + } + return CNoDestination(); + } + + bool GetKeyID(CKeyID &keyID) const { + if (!IsValid()) + return false; + switch (nVersion) { + case PUBKEY_ADDRESS: + case PUBKEY_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + keyID = CKeyID(id); + return true; + } + default: return false; + } + } + + bool IsScript() const { + if (!IsValid()) + return false; + switch (nVersion) { + case SCRIPT_ADDRESS: + case SCRIPT_ADDRESS_TEST: { + return true; + } + default: return false; + } } }; +bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); } +bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); } +bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; } + /** A base58-encoded secret key */ class CBitcoinSecret : public CBase58Data { 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; } diff --git a/src/init.cpp b/src/init.cpp index 8295534e62..2a87311056 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -608,7 +608,7 @@ bool AppInit2() if (!pwalletMain->GetKeyFromPool(newDefaultKey, false)) strErrors << _("Cannot initialize keypool") << "\n"; pwalletMain->SetDefaultKey(newDefaultKey); - if (!pwalletMain->SetAddressBookName(CBitcoinAddress(pwalletMain->vchDefaultKey), "")) + if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) strErrors << _("Cannot write default address") << "\n"; } @@ -44,6 +44,23 @@ public: explicit key_error(const std::string& str) : std::runtime_error(str) {} }; +/** A reference to a CKey: the Hash160 of its serialized public key */ +class CKeyID : public uint160 +{ +public: + CKeyID() : uint160(0) { } + CKeyID(const uint160 &in) : uint160(in) { } +}; + +/** A reference to a CScript: the Hash160 of its serialization (see script.h) */ +class CScriptID : public uint160 +{ +public: + CScriptID() : uint160(0) { } + CScriptID(const uint160 &in) : uint160(in) { } +}; + +/** An encapsulated public key. */ class CPubKey { private: std::vector<unsigned char> vchPubKey; @@ -60,8 +77,8 @@ public: READWRITE(vchPubKey); ) - uint160 GetID() const { - return Hash160(vchPubKey); + CKeyID GetID() const { + return CKeyID(Hash160(vchPubKey)); } uint256 GetHash() const { @@ -72,6 +89,10 @@ public: return vchPubKey.size() == 33 || vchPubKey.size() == 65; } + bool IsCompressed() const { + return vchPubKey.size() == 33; + } + std::vector<unsigned char> Raw() const { return vchPubKey; } diff --git a/src/keystore.cpp b/src/keystore.cpp index 12ed3027ca..e0cf805a19 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -6,7 +6,7 @@ #include "keystore.h" #include "script.h" -bool CKeyStore::GetPubKey(const CBitcoinAddress &address, CPubKey &vchPubKeyOut) const +bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const { CKey key; if (!GetKey(address, key)) @@ -21,7 +21,7 @@ bool CBasicKeyStore::AddKey(const CKey& key) CSecret secret = key.GetSecret(fCompressed); { LOCK(cs_KeyStore); - mapKeys[CBitcoinAddress(key.GetPubKey())] = make_pair(secret, fCompressed); + mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed); } return true; } @@ -30,12 +30,12 @@ bool CBasicKeyStore::AddCScript(const CScript& redeemScript) { { LOCK(cs_KeyStore); - mapScripts[Hash160(redeemScript)] = redeemScript; + mapScripts[redeemScript.GetID()] = redeemScript; } return true; } -bool CBasicKeyStore::HaveCScript(const uint160& hash) const +bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const { bool result; { @@ -46,7 +46,7 @@ bool CBasicKeyStore::HaveCScript(const uint160& hash) const } -bool CBasicKeyStore::GetCScript(const uint160 &hash, CScript& redeemScriptOut) const +bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const { { LOCK(cs_KeyStore); @@ -147,12 +147,12 @@ bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector< if (!SetCrypted()) return false; - mapCryptedKeys[CBitcoinAddress(vchPubKey)] = make_pair(vchPubKey, vchCryptedSecret); + mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); } return true; } -bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const +bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const { { LOCK(cs_KeyStore); @@ -177,7 +177,7 @@ bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const return false; } -bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, CPubKey& vchPubKeyOut) const +bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const { { LOCK(cs_KeyStore); diff --git a/src/keystore.h b/src/keystore.h index cd72606d44..ab369bbf47 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -7,7 +7,6 @@ #include "crypter.h" #include "sync.h" -#include "base58.h" #include <boost/signals2/signal.hpp> class CScript; @@ -25,17 +24,17 @@ public: virtual bool AddKey(const CKey& key) =0; // Check whether a key corresponding to a given address is present in the store. - virtual bool HaveKey(const CBitcoinAddress &address) const =0; - virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0; - virtual void GetKeys(std::set<CBitcoinAddress> &setAddress) const =0; - virtual bool GetPubKey(const CBitcoinAddress &address, CPubKey& vchPubKeyOut) const; + virtual bool HaveKey(const CKeyID &address) const =0; + virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0; + virtual void GetKeys(std::set<CKeyID> &setAddress) const =0; + virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013 virtual bool AddCScript(const CScript& redeemScript) =0; - virtual bool HaveCScript(const uint160 &hash) const =0; - virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const =0; + virtual bool HaveCScript(const CScriptID &hash) const =0; + virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0; - virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret, bool &fCompressed) const + virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const { CKey key; if (!GetKey(address, key)) @@ -45,8 +44,8 @@ public: } }; -typedef std::map<CBitcoinAddress, std::pair<CSecret, bool> > KeyMap; -typedef std::map<uint160, CScript > ScriptMap; +typedef std::map<CKeyID, std::pair<CSecret, bool> > KeyMap; +typedef std::map<CScriptID, CScript > ScriptMap; /** Basic key store, that keeps keys in an address->secret map */ class CBasicKeyStore : public CKeyStore @@ -57,7 +56,7 @@ protected: public: bool AddKey(const CKey& key); - bool HaveKey(const CBitcoinAddress &address) const + bool HaveKey(const CKeyID &address) const { bool result; { @@ -66,7 +65,7 @@ public: } return result; } - void GetKeys(std::set<CBitcoinAddress> &setAddress) const + void GetKeys(std::set<CKeyID> &setAddress) const { setAddress.clear(); { @@ -79,7 +78,7 @@ public: } } } - bool GetKey(const CBitcoinAddress &address, CKey &keyOut) const + bool GetKey(const CKeyID &address, CKey &keyOut) const { { LOCK(cs_KeyStore); @@ -94,11 +93,11 @@ public: return false; } virtual bool AddCScript(const CScript& redeemScript); - virtual bool HaveCScript(const uint160 &hash) const; - virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const; + virtual bool HaveCScript(const CScriptID &hash) const; + virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const; }; -typedef std::map<CBitcoinAddress, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap; +typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap; /** Keystore which keeps the private keys encrypted. * It derives from the basic key store, which is used if no encryption is active. @@ -148,7 +147,7 @@ public: virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool AddKey(const CKey& key); - bool HaveKey(const CBitcoinAddress &address) const + bool HaveKey(const CKeyID &address) const { { LOCK(cs_KeyStore); @@ -158,9 +157,9 @@ public: } return false; } - bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const; - bool GetPubKey(const CBitcoinAddress &address, CPubKey& vchPubKeyOut) const; - void GetKeys(std::set<CBitcoinAddress> &setAddress) const + bool GetKey(const CKeyID &address, CKey& keyOut) const; + bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; + void GetKeys(std::set<CKeyID> &setAddress) const { if (!IsCrypted()) { diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 11dfc3e03d..e65d3915ec 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -3,6 +3,7 @@ #include "walletmodel.h" #include "wallet.h" +#include "base58.h" #include <QFont> #include <QColor> @@ -58,11 +59,11 @@ public: cachedAddressTable.clear(); { LOCK(wallet->cs_wallet); - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, std::string)& item, wallet->mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(CTxDestination, std::string)& item, wallet->mapAddressBook) { const CBitcoinAddress& address = item.first; const std::string& strName = item.second; - bool fMine = wallet->HaveKey(address); + bool fMine = IsMine(*wallet, address.Get()); cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending, QString::fromStdString(strName), QString::fromStdString(address.ToString()))); @@ -220,7 +221,8 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu switch(index.column()) { case Label: - wallet->SetAddressBookName(rec->address.toStdString(), value.toString().toStdString()); + wallet->SetAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get(), value.toString().toStdString()); + rec->label = value.toString(); break; case Address: // Refuse to set invalid address, set error status and return false @@ -235,9 +237,9 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu { LOCK(wallet->cs_wallet); // Remove old entry - wallet->DelAddressBookName(rec->address.toStdString()); + wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get()); // Add new entry with new address - wallet->SetAddressBookName(value.toString().toStdString(), rec->label.toStdString()); + wallet->SetAddressBookName(CBitcoinAddress(value.toString().toStdString()).Get(), rec->label.toStdString()); } } break; @@ -314,7 +316,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con // Check for duplicate addresses { LOCK(wallet->cs_wallet); - if(wallet->mapAddressBook.count(strAddress)) + if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get())) { editStatus = DUPLICATE_ADDRESS; return QString(); @@ -337,7 +339,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con editStatus = KEY_GENERATION_FAILURE; return QString(); } - strAddress = CBitcoinAddress(newKey).ToString(); + strAddress = CBitcoinAddress(newKey.GetID()).ToString(); } else { @@ -346,7 +348,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con // Add entry { LOCK(wallet->cs_wallet); - wallet->SetAddressBookName(strAddress, strLabel); + wallet->SetAddressBookName(CBitcoinAddress(strAddress).Get(), strLabel); } return QString::fromStdString(strAddress); } @@ -363,7 +365,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex & paren } { LOCK(wallet->cs_wallet); - wallet->DelAddressBookName(rec->address.toStdString()); + wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get()); } return true; } @@ -375,7 +377,7 @@ QString AddressTableModel::labelForAddress(const QString &address) const { LOCK(wallet->cs_wallet); CBitcoinAddress address_parsed(address.toStdString()); - std::map<CBitcoinAddress, std::string>::iterator mi = wallet->mapAddressBook.find(address_parsed); + std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get()); if (mi != wallet->mapAddressBook.end()) { return QString::fromStdString(mi->second); diff --git a/src/qt/messagepage.cpp b/src/qt/messagepage.cpp index 1f895e28ff..ab3ea5a0c5 100644 --- a/src/qt/messagepage.cpp +++ b/src/qt/messagepage.cpp @@ -10,6 +10,7 @@ #include "main.h" #include "wallet.h" #include "init.h" +#include "base58.h" #include "messagepage.h" #include "ui_messagepage.h" @@ -83,6 +84,13 @@ void MessagePage::on_signMessage_clicked() QMessageBox::Abort, QMessageBox::Abort); return; } + CKeyID keyID; + if (!addr.GetKeyID(keyID)) + { + QMessageBox::critical(this, tr("Error signing"), tr("%1 does not refer to a key.").arg(address), + QMessageBox::Abort, QMessageBox::Abort); + return; + } WalletModel::UnlockContext ctx(model->requestUnlock()); if(!ctx.isValid()) @@ -92,7 +100,7 @@ void MessagePage::on_signMessage_clicked() } CKey key; - if (!pwalletMain->GetKey(addr, key)) + if (!pwalletMain->GetKey(keyID, key)) { QMessageBox::critical(this, tr("Error signing"), tr("Private key for %1 is not available.").arg(address), QMessageBox::Abort, QMessageBox::Abort); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 286cddf2a9..10bcef0d90 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -7,6 +7,7 @@ #include "wallet.h" #include "db.h" #include "ui_interface.h" +#include "base58.h" #include <QString> @@ -85,14 +86,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { if (wallet->IsMine(txout)) { - CBitcoinAddress address; - if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address)) + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { if (wallet->mapAddressBook.count(address)) { strHTML += tr("<b>From:</b> ") + tr("unknown") + "<br>"; strHTML += tr("<b>To:</b> "); - strHTML += GUIUtil::HtmlEscape(address.ToString()); + strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); if (!wallet->mapAddressBook[address].empty()) strHTML += tr(" (yours, label: ") + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")"; else @@ -115,8 +116,9 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) // Online transaction strAddress = wtx.mapValue["to"]; strHTML += tr("<b>To:</b> "); - if (wallet->mapAddressBook.count(strAddress) && !wallet->mapAddressBook[strAddress].empty()) - strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[strAddress]) + " "; + CTxDestination dest = CBitcoinAddress(strAddress).Get(); + if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty()) + strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " "; strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>"; } @@ -170,13 +172,13 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) if (wtx.mapValue["to"].empty()) { // Offline transaction - CBitcoinAddress address; - if (ExtractAddress(txout.scriptPubKey, address)) + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address)) { strHTML += tr("<b>To:</b> "); if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " "; - strHTML += GUIUtil::HtmlEscape(address.ToString()); + strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); strHTML += "<br>"; } } @@ -260,12 +262,12 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { strHTML += "<li>"; const CTxOut &vout = prev.vout[prevout.n]; - CBitcoinAddress address; - if (ExtractAddress(vout.scriptPubKey, address)) + CTxDestination address; + if (ExtractDestination(vout.scriptPubKey, address)) { if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " "; - strHTML += QString::fromStdString(address.ToString()); + strHTML += QString::fromStdString(CBitcoinAddress(address).ToString()); } strHTML = strHTML + " Amount=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,vout.nValue); strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? "true" : "false") + "</li>"; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 017244ffd0..160973638d 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -1,6 +1,7 @@ #include "transactionrecord.h" #include "wallet.h" +#include "base58.h" /* Return positive answer if transaction should be shown in list. */ @@ -50,7 +51,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); - CBitcoinAddress address; + CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (wtx.IsCoinBase()) @@ -58,11 +59,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * // Generated sub.type = TransactionRecord::Generated; } - else if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address)) + else if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; - sub.address = address.ToString(); + sub.address = CBitcoinAddress(address).ToString(); } else { @@ -113,12 +114,12 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * continue; } - CBitcoinAddress address; - if (ExtractAddress(txout.scriptPubKey, address)) + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address)) { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; - sub.address = address.ToString(); + sub.address = CBitcoinAddress(address).ToString(); } else { diff --git a/src/qt/verifymessagedialog.cpp b/src/qt/verifymessagedialog.cpp index 0bac24820c..d71568d2e9 100644 --- a/src/qt/verifymessagedialog.cpp +++ b/src/qt/verifymessagedialog.cpp @@ -14,6 +14,7 @@ #include "walletmodel.h" #include "addresstablemodel.h" #include "guiutil.h" +#include "base58.h" VerifyMessageDialog::VerifyMessageDialog(AddressTableModel *addressModel, QWidget *parent) : QDialog(parent), @@ -62,7 +63,7 @@ bool VerifyMessageDialog::checkAddress() return false; } - CBitcoinAddress address(key.GetPubKey()); + CBitcoinAddress address(key.GetPubKey().GetID()); QString qStringAddress = QString::fromStdString(address.ToString()); ui->lnAddress->setText(qStringAddress); ui->copyToClipboard->setEnabled(true); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index b89c3dba33..033df98082 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -7,6 +7,7 @@ #include "ui_interface.h" #include "wallet.h" #include "walletdb.h" // for BackupWallet +#include "base58.h" #include <QSet> @@ -137,7 +138,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie foreach(const SendCoinsRecipient &rcp, recipients) { CScript scriptPubKey; - scriptPubKey.SetBitcoinAddress(rcp.address.toStdString()); + scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); } @@ -169,16 +170,17 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie foreach(const SendCoinsRecipient &rcp, recipients) { std::string strAddress = rcp.address.toStdString(); + CTxDestination dest = CBitcoinAddress(strAddress).Get(); std::string strLabel = rcp.label.toStdString(); { LOCK(wallet->cs_wallet); - std::map<CBitcoinAddress, std::string>::iterator mi = wallet->mapAddressBook.find(strAddress); + std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(dest); // Check if we have a new address or an updated label if (mi == wallet->mapAddressBook.end() || mi->second != strLabel) { - wallet->SetAddressBookName(strAddress, strLabel); + wallet->SetAddressBookName(dest, strLabel); } } } @@ -268,11 +270,11 @@ static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStor QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection); } -static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const std::string &address, const std::string &label, bool isMine, ChangeType status) +static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status) { - OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", address.c_str(), label.c_str(), isMine, status); + OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, status); QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(address)), + Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())), Q_ARG(QString, QString::fromStdString(label)), Q_ARG(bool, isMine), Q_ARG(int, status)); diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 4c74e7f30f..30e504a095 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -5,6 +5,7 @@ #include "init.h" // for pwalletMain #include "bitcoinrpc.h" #include "ui_interface.h" +#include "base58.h" #include <boost/lexical_cast.hpp> @@ -51,8 +52,7 @@ Value importprivkey(const Array& params, bool fHelp) bool fCompressed; CSecret secret = vchSecret.GetSecret(fCompressed); key.SetSecret(secret, fCompressed); - CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey()); - + CKeyID vchAddress = key.GetPubKey().GetID(); { LOCK2(cs_main, pwalletMain->cs_wallet); @@ -80,9 +80,12 @@ Value dumpprivkey(const Array& params, bool fHelp) CBitcoinAddress address; if (!address.SetString(strAddress)) throw JSONRPCError(-5, "Invalid Bitcoin address"); + CKeyID keyID; + if (!address.GetKeyID(keyID)) + throw JSONRPCError(-3, "Address does not refer to a key"); CSecret vchSecret; bool fCompressed; - if (!pwalletMain->GetSecret(address, vchSecret, fCompressed)) + if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed)) throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known"); return CBitcoinSecret(vchSecret, fCompressed).ToString(); } diff --git a/src/script.cpp b/src/script.cpp index 20013af1b6..2e1e1ad7de 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1312,7 +1312,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi } -bool Sign1(const CBitcoinAddress& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) +bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) { CKey key; if (!keystore.GetKey(address, key)) @@ -1334,9 +1334,8 @@ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint2 for (vector<valtype>::const_iterator it = multisigdata.begin()+1; it != multisigdata.begin()+multisigdata.size()-1; it++) { const valtype& pubkey = *it; - CBitcoinAddress address; - address.SetPubKey(pubkey); - if (Sign1(address, keystore, hash, nHashType, scriptSigRet)) + CKeyID keyID = CPubKey(pubkey).GetID(); + if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) { ++nSigned; if (nSigned == nRequired) break; @@ -1360,22 +1359,22 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; - CBitcoinAddress address; + CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: return false; case TX_PUBKEY: - address.SetPubKey(vSolutions[0]); - return Sign1(address, keystore, hash, nHashType, scriptSigRet); + keyID = CPubKey(vSolutions[0]).GetID(); + return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); case TX_PUBKEYHASH: - address.SetHash160(uint160(vSolutions[0])); - if (!Sign1(address, keystore, hash, nHashType, scriptSigRet)) + keyID = CKeyID(uint160(vSolutions[0])); + if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) return false; else { CPubKey vch; - keystore.GetPubKey(address, vch); + keystore.GetPubKey(keyID, vch); scriptSigRet << vch; } return true; @@ -1436,14 +1435,30 @@ unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore) unsigned int nResult = 0; BOOST_FOREACH(const valtype& pubkey, pubkeys) { - CBitcoinAddress address; - address.SetPubKey(pubkey); - if (keystore.HaveKey(address)) + CKeyID keyID = CPubKey(pubkey).GetID(); + if (keystore.HaveKey(keyID)) ++nResult; } return nResult; } + +class CKeyStoreIsMineVisitor : public boost::static_visitor<bool> +{ +private: + const CKeyStore *keystore; +public: + CKeyStoreIsMineVisitor(const CKeyStore *keystoreIn) : keystore(keystoreIn) { } + bool operator()(const CNoDestination &dest) const { return false; } + bool operator()(const CKeyID &keyID) const { return keystore->HaveKey(keyID); } + bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); } +}; + +bool IsMine(const CKeyStore &keystore, const CTxDestination &dest) +{ + return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest); +} + bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { vector<valtype> vSolutions; @@ -1451,21 +1466,21 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) if (!Solver(scriptPubKey, whichType, vSolutions)) return false; - CBitcoinAddress address; + CKeyID keyID; switch (whichType) { case TX_NONSTANDARD: return false; case TX_PUBKEY: - address.SetPubKey(vSolutions[0]); - return keystore.HaveKey(address); + keyID = CPubKey(vSolutions[0]).GetID(); + return keystore.HaveKey(keyID); case TX_PUBKEYHASH: - address.SetHash160(uint160(vSolutions[0])); - return keystore.HaveKey(address); + keyID = CKeyID(uint160(vSolutions[0])); + return keystore.HaveKey(keyID); case TX_SCRIPTHASH: { CScript subscript; - if (!keystore.GetCScript(uint160(vSolutions[0]), subscript)) + if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript)) return false; return IsMine(keystore, subscript); } @@ -1483,7 +1498,7 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) return false; } -bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet) +bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { vector<valtype> vSolutions; txnouttype whichType; @@ -1492,24 +1507,24 @@ bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet) if (whichType == TX_PUBKEY) { - addressRet.SetPubKey(vSolutions[0]); + addressRet = CPubKey(vSolutions[0]).GetID(); return true; } else if (whichType == TX_PUBKEYHASH) { - addressRet.SetHash160(uint160(vSolutions[0])); + addressRet = CKeyID(uint160(vSolutions[0])); return true; } else if (whichType == TX_SCRIPTHASH) { - addressRet.SetScriptHash160(uint160(vSolutions[0])); + addressRet = CScriptID(uint160(vSolutions[0])); return true; } // Multisig txns have more than one address... return false; } -bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, vector<CBitcoinAddress>& addressRet, int& nRequiredRet) +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet) { addressRet.clear(); typeRet = TX_NONSTANDARD; @@ -1522,21 +1537,16 @@ bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, vector<C nRequiredRet = vSolutions.front()[0]; for (unsigned int i = 1; i < vSolutions.size()-1; i++) { - CBitcoinAddress address; - address.SetPubKey(vSolutions[i]); + CTxDestination address = CPubKey(vSolutions[i]).GetID(); addressRet.push_back(address); } } else { nRequiredRet = 1; - CBitcoinAddress address; - if (typeRet == TX_PUBKEYHASH) - address.SetHash160(uint160(vSolutions.front())); - else if (typeRet == TX_SCRIPTHASH) - address.SetScriptHash160(uint160(vSolutions.front())); - else if (typeRet == TX_PUBKEY) - address.SetPubKey(vSolutions.front()); + CTxDestination address; + if (!ExtractDestination(scriptPubKey, address)) + return false; addressRet.push_back(address); } @@ -1694,13 +1704,34 @@ bool CScript::IsPayToScriptHash() const this->at(22) == OP_EQUAL); } -void CScript::SetBitcoinAddress(const CBitcoinAddress& address) +class CScriptVisitor : public boost::static_visitor<bool> { - this->clear(); - if (address.IsScript()) - *this << OP_HASH160 << address.GetHash160() << OP_EQUAL; - else - *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_CHECKSIG; +private: + CScript *script; +public: + CScriptVisitor(CScript *scriptin) { script = scriptin; } + + bool operator()(const CNoDestination &dest) const { + script->clear(); + return false; + } + + bool operator()(const CKeyID &keyID) const { + script->clear(); + *script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG; + return true; + } + + bool operator()(const CScriptID &scriptID) const { + script->clear(); + *script << OP_HASH160 << scriptID << OP_EQUAL; + return true; + } +}; + +void CScript::SetDestination(const CTxDestination& dest) +{ + boost::apply_visitor(CScriptVisitor(this), dest); } void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys) @@ -1712,11 +1743,3 @@ void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys) *this << key.GetPubKey(); *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; } - -void CScript::SetPayToScriptHash(const CScript& subscript) -{ - assert(!subscript.empty()); - uint160 subscriptHash = Hash160(subscript); - this->clear(); - *this << OP_HASH160 << subscriptHash << OP_EQUAL; -} diff --git a/src/script.h b/src/script.h index 163ce057d6..d490cd1824 100644 --- a/src/script.h +++ b/src/script.h @@ -5,15 +5,16 @@ #ifndef H_BITCOIN_SCRIPT #define H_BITCOIN_SCRIPT -#include "base58.h" - #include <string> #include <vector> #include <boost/foreach.hpp> +#include <boost/variant.hpp> + +#include "keystore.h" +#include "bignum.h" class CTransaction; -class CKeyStore; /** Signature hash types/flags */ enum @@ -35,6 +36,20 @@ enum txnouttype TX_MULTISIG, }; +class CNoDestination { +public: + friend bool operator==(const CNoDestination &a, const CNoDestination &b) { return true; } + friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } +}; + +/** A txout script template with a specific destination. It is either: + * * CNoDestination: no destination set + * * CKeyID: TX_PUBKEYHASH destination + * * CScriptID: TX_SCRIPTHASH destination + * A CTxDestination is the internal data type encoded in a CBitcoinAddress + */ +typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination; + const char* GetTxnOutputType(txnouttype t); /** Script opcodes */ @@ -521,13 +536,8 @@ public: } - void SetBitcoinAddress(const CBitcoinAddress& address); - void SetBitcoinAddress(const std::vector<unsigned char>& vchPubKey) - { - SetBitcoinAddress(CBitcoinAddress(vchPubKey)); - } + void SetDestination(const CTxDestination& address); void SetMultisig(int nRequired, const std::vector<CKey>& keys); - void SetPayToScriptHash(const CScript& subscript); void PrintHex() const @@ -562,6 +572,11 @@ public: { printf("%s\n", ToString().c_str()); } + + CScriptID GetID() const + { + return CScriptID(Hash160(*this)); + } }; @@ -573,8 +588,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions); bool IsStandard(const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); -bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet); -bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CBitcoinAddress>& addressRet, int& nRequiredRet); +bool IsMine(const CKeyStore& keystore, const CTxDestination &dest); +bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType); diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 3a9b2a902c..4a185b3cc5 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -161,7 +161,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey()); + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); CDataStream ds(SER_DISK, CLIENT_VERSION); ds << tx; @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vin[0].prevout.hash = txPrev.GetHash(); tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey()); + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); SignSignature(keystore, txPrev, tx, 0); CDataStream ds(SER_DISK, CLIENT_VERSION); @@ -195,7 +195,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) CTransaction tx; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey()); + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); tx.vin.resize(500); for (unsigned int j = 0; j < tx.vin.size(); j++) { @@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey()); + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); CDataStream ds(SER_DISK, CLIENT_VERSION); ds << tx; @@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) CTransaction tx; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey()); + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); tx.vin.resize(NPREV); for (unsigned int j = 0; j < tx.vin.size(); j++) { diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index de4096cd39..3f265f1fe3 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -1,8 +1,6 @@ #include <boost/test/unit_test.hpp> -#include "main.h" -#include "wallet.h" -#include "util.h" +#include "base58.h" BOOST_AUTO_TEST_SUITE(base58_tests) diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index a6dab623b0..0a6df88fef 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -10,11 +10,18 @@ using namespace std; -static const string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"); -static const string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"); -static const string strSecret1C("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"); -static const string strSecret2C("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"); -static const string strAddress1("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"); +static const string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"); +static const string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"); +static const string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"); +static const string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"); +static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"); +static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"); +static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"); +static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"); + + +static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"); + #ifdef KEY_TESTS_DUMPINFO void dumpKeyInfo(uint256 privkey) @@ -53,7 +60,7 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK( bsecret2.SetString (strSecret2)); BOOST_CHECK( bsecret1C.SetString(strSecret1C)); BOOST_CHECK( bsecret2C.SetString(strSecret2C)); - BOOST_CHECK(!baddress1.SetString(strAddress1)); + BOOST_CHECK(!baddress1.SetString(strAddressBad)); bool fCompressed; CSecret secret1 = bsecret1.GetSecret (fCompressed); @@ -74,10 +81,10 @@ BOOST_AUTO_TEST_CASE(key_test1) key1C.SetSecret(secret1, true); key2C.SetSecret(secret2, true); - BOOST_CHECK(CBitcoinAddress(key1.GetPubKey ()).ToString() == "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"); - BOOST_CHECK(CBitcoinAddress(key2.GetPubKey ()).ToString() == "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"); - BOOST_CHECK(CBitcoinAddress(key1C.GetPubKey()).ToString() == "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"); - BOOST_CHECK(CBitcoinAddress(key2C.GetPubKey()).ToString() == "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"); + BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID())); + BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID())); + BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID())); + BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID())); for (int n=0; n<16; n++) { diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index aa0050ca02..9cb0efecfd 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -175,12 +175,12 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) // CBasicKeyStore keystore, emptykeystore, partialkeystore; CKey key[3]; - CBitcoinAddress keyaddr[3]; + CTxDestination keyaddr[3]; for (int i = 0; i < 3; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); - keyaddr[i].SetPubKey(key[i].GetPubKey()); + keyaddr[i] = key[i].GetPubKey().GetID(); } partialkeystore.AddKey(key[0]); @@ -191,8 +191,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) s << key[0].GetPubKey() << OP_CHECKSIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 1); - CBitcoinAddress addr; - BOOST_CHECK(ExtractAddress(s, addr)); + CTxDestination addr; + BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); @@ -201,11 +201,11 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) vector<valtype> solutions; txnouttype whichType; CScript s; - s << OP_DUP << OP_HASH160 << Hash160(key[0].GetPubKey().Raw()) << OP_EQUALVERIFY << OP_CHECKSIG; + s << OP_DUP << OP_HASH160 << key[0].GetPubKey().GetID() << OP_EQUALVERIFY << OP_CHECKSIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 1); - CBitcoinAddress addr; - BOOST_CHECK(ExtractAddress(s, addr)); + CTxDestination addr; + BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); @@ -214,11 +214,11 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) vector<valtype> solutions; txnouttype whichType; CScript s; - s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey().Raw() << OP_2 << OP_CHECKMULTISIG; + s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK_EQUAL(solutions.size(), 4); - CBitcoinAddress addr; - BOOST_CHECK(!ExtractAddress(s, addr)); + CTxDestination addr; + BOOST_CHECK(!ExtractDestination(s, addr)); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); @@ -227,12 +227,12 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) vector<valtype> solutions; txnouttype whichType; CScript s; - s << OP_1 << key[0].GetPubKey().Raw() << key[1].GetPubKey().Raw() << OP_2 << OP_CHECKMULTISIG; + s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK_EQUAL(solutions.size(), 4); - vector<CBitcoinAddress> addrs; + vector<CTxDestination> addrs; int nRequired; - BOOST_CHECK(ExtractAddresses(s, whichType, addrs, nRequired)); + BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); BOOST_CHECK(addrs[0] == keyaddr[0]); BOOST_CHECK(addrs[1] == keyaddr[1]); BOOST_CHECK(nRequired = 1); @@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) vector<valtype> solutions; txnouttype whichType; CScript s; - s << OP_2 << key[0].GetPubKey().Raw() << key[1].GetPubKey().Raw() << key[2].GetPubKey().Raw() << OP_3 << OP_CHECKMULTISIG; + s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 5); } @@ -262,13 +262,13 @@ BOOST_AUTO_TEST_CASE(multisig_Sign) } CScript a_and_b; - a_and_b << OP_2 << key[0].GetPubKey().Raw() << key[1].GetPubKey().Raw() << OP_2 << OP_CHECKMULTISIG; + a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; CScript a_or_b; - a_or_b << OP_1 << key[0].GetPubKey().Raw() << key[1].GetPubKey().Raw() << OP_2 << OP_CHECKMULTISIG; + a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; CScript escrow; - escrow << OP_2 << key[0].GetPubKey().Raw() << key[1].GetPubKey().Raw() << key[2].GetPubKey().Raw() << OP_3 << OP_CHECKMULTISIG; + escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; CTransaction txFrom; // Funding transaction txFrom.vout.resize(3); diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index aa72c00092..f7bf5dfbf1 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -65,14 +65,14 @@ BOOST_AUTO_TEST_CASE(sign) // different keys, straight/P2SH, pubkey/pubkeyhash CScript standardScripts[4]; standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG; - standardScripts[1].SetBitcoinAddress(key[1].GetPubKey()); + standardScripts[1].SetDestination(key[1].GetPubKey().GetID()); standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG; - standardScripts[3].SetBitcoinAddress(key[2].GetPubKey()); + standardScripts[3].SetDestination(key[2].GetPubKey().GetID()); CScript evalScripts[4]; for (int i = 0; i < 4; i++) { keystore.AddCScript(standardScripts[i]); - evalScripts[i].SetPayToScriptHash(standardScripts[i]); + evalScripts[i].SetDestination(standardScripts[i].GetID()); } CTransaction txFrom; // Funding transaction: @@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(norecurse) invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE; CScript p2sh; - p2sh.SetPayToScriptHash(invalidAsScript); + p2sh.SetDestination(invalidAsScript.GetID()); CScript scriptSig; scriptSig << Serialize(invalidAsScript); @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(norecurse) // Try to recurse, and verification should succeed because // the inner HASH160 <> EQUAL should only check the hash: CScript p2sh2; - p2sh2.SetPayToScriptHash(p2sh); + p2sh2.SetDestination(p2sh.GetID()); CScript scriptSig2; scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); @@ -154,7 +154,7 @@ BOOST_AUTO_TEST_CASE(set) } CScript inner[4]; - inner[0].SetBitcoinAddress(key[0].GetPubKey()); + inner[0].SetDestination(key[0].GetPubKey().GetID()); inner[1].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+2)); inner[2].SetMultisig(1, std::vector<CKey>(keys.begin(), keys.begin()+2)); inner[3].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+3)); @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(set) CScript outer[4]; for (int i = 0; i < 4; i++) { - outer[i].SetPayToScriptHash(inner[i]); + outer[i].SetDestination(inner[i].GetID()); keystore.AddCScript(inner[i]); } @@ -232,7 +232,7 @@ BOOST_AUTO_TEST_CASE(switchover) scriptSig << Serialize(notValid); CScript fund; - fund.SetPayToScriptHash(notValid); + fund.SetDestination(notValid.GetID()); // Validation should succeed under old rules (hash is correct): @@ -258,9 +258,9 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txFrom.vout.resize(6); // First three are standard: - CScript pay1; pay1.SetBitcoinAddress(key[0].GetPubKey()); + CScript pay1; pay1.SetDestination(key[0].GetPubKey().GetID()); keystore.AddCScript(pay1); - CScript payScriptHash1; payScriptHash1.SetPayToScriptHash(pay1); + CScript payScriptHash1; payScriptHash1.SetDestination(pay1.GetID()); CScript pay1of3; pay1of3.SetMultisig(1, keys); txFrom.vout[0].scriptPubKey = payScriptHash1; @@ -278,13 +278,13 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) for (int i = 0; i < 11; i++) oneOfEleven << key[0].GetPubKey(); oneOfEleven << OP_11 << OP_CHECKMULTISIG; - txFrom.vout[5].scriptPubKey.SetPayToScriptHash(oneOfEleven); + txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID()); mapInputs[txFrom.GetHash()] = make_pair(CTxIndex(), txFrom); CTransaction txTo; txTo.vout.resize(1); - txTo.vout[0].scriptPubKey.SetBitcoinAddress(key[1].GetPubKey()); + txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); txTo.vin.resize(3); txTo.vin[0].prevout.n = 0; @@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) CTransaction txToNonStd; txToNonStd.vout.resize(1); - txToNonStd.vout[0].scriptPubKey.SetBitcoinAddress(key[1].GetPubKey()); + txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); txToNonStd.vin.resize(2); txToNonStd.vin[0].prevout.n = 4; txToNonStd.vin[0].prevout.hash = txFrom.GetHash(); diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index d301313a9d..59673f9b3d 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21); CScript p2sh; - p2sh.SetPayToScriptHash(s1); + p2sh.SetDestination(s1.GetID()); CScript scriptSig; scriptSig << OP_0 << Serialize(s1); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3); @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3); BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20); - p2sh.SetPayToScriptHash(s2); + p2sh.SetDestination(s2.GetID()); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0); CScript scriptSig2; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index b680ede9a5..be0d976d51 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -52,9 +52,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout[0].nValue = 21*CENT; - dummyTransactions[1].vout[0].scriptPubKey.SetBitcoinAddress(key[2].GetPubKey()); + dummyTransactions[1].vout[0].scriptPubKey.SetDestination(key[2].GetPubKey().GetID()); dummyTransactions[1].vout[1].nValue = 22*CENT; - dummyTransactions[1].vout[1].scriptPubKey.SetBitcoinAddress(key[3].GetPubKey()); + dummyTransactions[1].vout[1].scriptPubKey.SetDestination(key[3].GetPubKey().GetID()); inputsRet[dummyTransactions[1].GetHash()] = make_pair(CTxIndex(), dummyTransactions[1]); return dummyTransactions; diff --git a/src/wallet.cpp b/src/wallet.cpp index 2f8d7c05ab..3c4aeb4eaf 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -7,6 +7,7 @@ #include "walletdb.h" #include "crypter.h" #include "ui_interface.h" +#include "base58.h" using namespace std; @@ -361,7 +362,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) #ifndef QT_GUI // If default receiving address gets used, replace it with a new one CScript scriptDefaultKey; - scriptDefaultKey.SetBitcoinAddress(vchDefaultKey); + scriptDefaultKey.SetDestination(vchDefaultKey.GetID()); BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (txout.scriptPubKey == scriptDefaultKey) @@ -370,7 +371,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) if (GetKeyFromPool(newDefaultKey, false)) { SetDefaultKey(newDefaultKey); - SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""); + SetAddressBookName(vchDefaultKey.GetID(), ""); } } } @@ -455,7 +456,7 @@ int64 CWallet::GetDebit(const CTxIn &txin) const bool CWallet::IsChange(const CTxOut& txout) const { - CBitcoinAddress address; + CTxDestination address; // TODO: fix handling of 'change' outputs. The assumption is that any // payment to a TX_PUBKEYHASH that is mine but isn't in the address book @@ -464,7 +465,7 @@ bool CWallet::IsChange(const CTxOut& txout) const // a better way of identifying which outputs are 'the send' and which are // 'the change' will need to be implemented (maybe extend CWalletTx to remember // which output, if any, was change). - if (ExtractAddress(txout.scriptPubKey, address) && HaveKey(address)) + if (ExtractDestination(txout.scriptPubKey, address) && ::IsMine(*this, address)) { LOCK(cs_wallet); if (!mapAddressBook.count(address)) @@ -517,8 +518,8 @@ int CWalletTx::GetRequestCount() const return nRequests; } -void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CBitcoinAddress, int64> >& listReceived, - list<pair<CBitcoinAddress, int64> >& listSent, int64& nFee, string& strSentAccount) const +void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CTxDestination, int64> >& listReceived, + list<pair<CTxDestination, int64> >& listSent, int64& nFee, string& strSentAccount) const { nGeneratedImmature = nGeneratedMature = nFee = 0; listReceived.clear(); @@ -545,13 +546,12 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l // Sent/received. BOOST_FOREACH(const CTxOut& txout, vout) { - CBitcoinAddress address; + CTxDestination address; vector<unsigned char> vchPubKey; - if (!ExtractAddress(txout.scriptPubKey, address)) + if (!ExtractDestination(txout.scriptPubKey, address)) { printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString().c_str()); - address = " unknown "; } // Don't report 'change' txouts @@ -575,25 +575,25 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i 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; GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); if (strAccount == "") nGenerated = allGeneratedMature; if (strAccount == strSentAccount) { - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& s, listSent) + BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& s, listSent) nSent += s.second; nFee = allFee; } { LOCK(pwallet->cs_wallet); - BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived) + BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived) { if (pwallet->mapAddressBook.count(r.first)) { - map<CBitcoinAddress, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first); + map<CTxDestination, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first); if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount) nReceived += r.second; } @@ -1102,7 +1102,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW // TODO: pass in scriptChange instead of reservekey so // change transaction isn't always pay-to-bitcoin-address CScript scriptChange; - scriptChange.SetBitcoinAddress(vchPubKey); + scriptChange.SetDestination(vchPubKey.GetID()); // Insert change txn at random position: vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()); @@ -1240,7 +1240,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, -string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee) +string CWallet::SendMoneyToDestination(const CTxDestination& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee) { // Check amount if (nValue <= 0) @@ -1250,7 +1250,7 @@ string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 // Parse Bitcoin address CScript scriptPubKey; - scriptPubKey.SetBitcoinAddress(address); + scriptPubKey.SetDestination(address); return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee); } @@ -1285,23 +1285,23 @@ int CWallet::LoadWallet(bool& fFirstRunRet) } -bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName) +bool CWallet::SetAddressBookName(const CTxDestination& address, const string& strName) { - std::map<CBitcoinAddress, std::string>::iterator mi = mapAddressBook.find(address); + std::map<CTxDestination, std::string>::iterator mi = mapAddressBook.find(address); mapAddressBook[address] = strName; - NotifyAddressBookChanged(this, address.ToString(), strName, HaveKey(address), (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); + NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address), (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); if (!fFileBacked) return false; - return CWalletDB(strWalletFile).WriteName(address.ToString(), strName); + return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName); } -bool CWallet::DelAddressBookName(const CBitcoinAddress& address) +bool CWallet::DelAddressBookName(const CTxDestination& address) { mapAddressBook.erase(address); - NotifyAddressBookChanged(this, address.ToString(), "", HaveKey(address), CT_DELETED); + NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), CT_DELETED); if (!fFileBacked) return false; - return CWalletDB(strWalletFile).EraseName(address.ToString()); + return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); } @@ -1537,7 +1537,7 @@ void CReserveKey::ReturnKey() vchPubKey = CPubKey(); } -void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress) +void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) { setAddress.clear(); @@ -1549,11 +1549,11 @@ void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress) CKeyPool keypool; if (!walletdb.ReadPool(id, keypool)) throw runtime_error("GetAllReserveKeyHashes() : read failed"); - CBitcoinAddress address(keypool.vchPubKey); assert(keypool.vchPubKey.IsValid()); - if (!HaveKey(address)) + CKeyID keyID = keypool.vchPubKey.GetID(); + if (!HaveKey(keyID)) throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool"); - setAddress.insert(address); + setAddress.insert(keyID); } } diff --git a/src/wallet.h b/src/wallet.h index 6c99b3c4b8..618a00623a 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -105,7 +105,7 @@ public: std::map<uint256, CWalletTx> mapWallet; std::map<uint256, int> mapRequestCount; - std::map<CBitcoinAddress, std::string> mapAddressBook; + std::map<CTxDestination, std::string> mapAddressBook; CPubKey vchDefaultKey; @@ -148,7 +148,7 @@ public: bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); - std::string SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); + std::string SendMoneyToDestination(const CTxDestination &address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); bool NewKeyPool(); bool TopUpKeyPool(); @@ -158,7 +158,7 @@ public: void ReturnKey(int64 nIndex); bool GetKeyFromPool(CPubKey &key, bool fAllowReuse=true); int64 GetOldestKeyPoolTime(); - void GetAllReserveAddresses(std::set<CBitcoinAddress>& setAddress); + void GetAllReserveKeys(std::set<CKeyID>& setAddress); bool IsMine(const CTxIn& txin) const; int64 GetDebit(const CTxIn& txin) const; @@ -227,9 +227,9 @@ public: int LoadWallet(bool& fFirstRunRet); - bool SetAddressBookName(const CBitcoinAddress& address, const std::string& strName); + bool SetAddressBookName(const CTxDestination& address, const std::string& strName); - bool DelAddressBookName(const CBitcoinAddress& address); + bool DelAddressBookName(const CTxDestination& address); void UpdatedTransaction(const uint256 &hashTx); @@ -266,7 +266,7 @@ public: /** Address book entry changed. * @note called with lock cs_wallet held. */ - boost::signals2::signal<void (CWallet *wallet, const std::string &address, const std::string &label, bool isMine, ChangeType status)> NotifyAddressBookChanged; + boost::signals2::signal<void (CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status)> NotifyAddressBookChanged; /** Wallet transaction added, removed or updated. * @note called with lock cs_wallet held. @@ -532,8 +532,8 @@ public: return nChangeCached; } - void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list<std::pair<CBitcoinAddress, int64> >& listReceived, - std::list<std::pair<CBitcoinAddress, int64> >& listSent, int64& nFee, std::string& strSentAccount) const; + void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list<std::pair<CTxDestination, int64> >& listReceived, + std::list<std::pair<CTxDestination, int64> >& listSent, int64& nFee, std::string& strSentAccount) const; void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived, int64& nSent, int64& nFee) const; diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 34e0b80512..2c4d4c0ef0 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -151,7 +151,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) { string strAddress; ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[strAddress]; + ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()]; } else if (strType == "tx") { diff --git a/src/walletdb.h b/src/walletdb.h index de2b7f3aae..39182279d5 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -6,6 +6,7 @@ #define BITCOIN_WALLETDB_H #include "db.h" +#include "base58.h" class CKeyPool; class CAccount; |