changeset 2698:19e29b1fcdee draft

Merge pull request #1357 from sipa/keyid Refactor: split CKeyID/CScriptID/CTxDestination from CBitcoinAddress
author Pieter Wuille <pieter.wuille@gmail.com>
date Sat, 26 May 2012 10:17:27 -0700
parents 6fcf025a464b (current diff) 2c65e5d626eb (diff)
children 95190fd43cc0
files src/init.cpp
diffstat 28 files changed, 582 insertions(+), 403 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
  * 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 @@
         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 std::vector<unsigned char>& vchPubKey)
-    {
-        SetHash160(Hash160(vchPubKey));
+    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 @@
         }
         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)
+    CBitcoinAddress(const CTxDestination &dest)
     {
-        SetHash160(hash160In);
-    }
-
-    CBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
-    {
-        SetPubKey(vchPubKey);
+        Set(dest);
     }
 
     CBitcoinAddress(const std::string& strAddress)
@@ -348,15 +346,58 @@
         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
 {
--- 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 @@
         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 @@
     }
 
     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 @@
 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 @@
     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));
 }
 
@@ -590,14 +591,14 @@
         pwalletMain->TopUpKeyPool();
 
     // Generate a new key that is added to wallet
-    std::vector<unsigned char> newKey;
+    CPubKey newKey;
     if (!pwalletMain->GetKeyFromPool(newKey, false))
         throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
-    CBitcoinAddress address(newKey);
-
-    pwalletMain->SetAddressBookName(address, strAccount);
-
-    return address.ToString();
+    CKeyID keyID = newKey.GetID();
+
+    pwalletMain->SetAddressBookName(keyID, strAccount);
+
+    return CBitcoinAddress(keyID).ToString();
 }
 
 
@@ -611,12 +612,12 @@
     bool bKeyUsed = false;
 
     // Check if the current key has been used
-    if (!account.vchPubKey.empty())
+    if (account.vchPubKey.IsValid())
     {
         CScript scriptPubKey;
-        scriptPubKey.SetBitcoinAddress(account.vchPubKey);
+        scriptPubKey.SetDestination(account.vchPubKey.GetID());
         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
-             it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
+             it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
              ++it)
         {
             const CWalletTx& wtx = (*it).second;
@@ -627,16 +628,16 @@
     }
 
     // Generate a new key
-    if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
+    if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
     {
         if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
             throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
 
-        pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
+        pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount);
         walletdb.WriteAccount(strAccount, account);
     }
 
-    return CBitcoinAddress(account.vchPubKey);
+    return CBitcoinAddress(account.vchPubKey.GetID());
 }
 
 Value getaccountaddress(const Array& params, bool fHelp)
@@ -675,14 +676,14 @@
         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 @@
         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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 }
 
 
-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 @@
 
     // 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 @@
 
         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 @@
             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 @@
         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 @@
         setAddress.insert(address);
 
         CScript scriptPubKey;
-        scriptPubKey.SetBitcoinAddress(address);
+        scriptPubKey.SetDestination(address.Get());
         int64 nAmount = AmountFromValue(s.value_); 
         totalAmount += nAmount;
 
@@ -1200,22 +1208,23 @@
         CBitcoinAddress address(ks);
         if (address.IsValid())
         {
-            if (address.IsScript())
+            CKeyID keyID;
+            if (!address.GetKeyID(keyID))
                 throw runtime_error(
-                    strprintf("%s is a pay-to-script address",ks.c_str()));
-            std::vector<unsigned char> vchPubKey;
-            if (!pwalletMain->GetPubKey(address, vchPubKey))
+                    strprintf("%s does not refer to a key",ks.c_str()));
+            CPubKey vchPubKey;
+            if (!pwalletMain->GetPubKey(keyID, vchPubKey))
                 throw runtime_error(
                     strprintf("no full public key for address %s",ks.c_str()));
-            if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
+            if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
                 throw runtime_error(" Invalid public key: "+ks);
         }
 
         // Case 2: hex public key
         else if (IsHex(ks))
         {
-            vector<unsigned char> vchPubKey = ParseHex(ks);
-            if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
+            CPubKey vchPubKey(ParseHex(ks));
+            if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
                 throw runtime_error(" Invalid public key: "+ks);
         }
         else
@@ -1227,16 +1236,11 @@
     // 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 @@
 
         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 @@
 {
     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 @@
     // 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 @@
     // 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 @@
             {
                 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 @@
         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 @@
         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 @@
     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 @@
     ret.push_back(Pair("isvalid", isValid));
     if (isValid)
     {
-        // Call Hash160ToAddress() so we always return current ADDRESSVERSION
-        // version of the address:
+        CTxDestination dest = address.Get();
         string currentAddress = address.ToString();
         ret.push_back(Pair("address", currentAddress));
-        if (pwalletMain->HaveKey(address))
-        {
-            ret.push_back(Pair("ismine", true));
-            std::vector<unsigned char> vchPubKey;
-            pwalletMain->GetPubKey(address, vchPubKey);
-            ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
-            CKey key;
-            key.SetPubKey(vchPubKey);
-            ret.push_back(Pair("iscompressed", key.IsCompressed()));
+        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 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));
-        }
-        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;
 }
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -605,11 +605,11 @@
         // Create new keyUser and set as default key
         RandAddSeedPerfmon();
 
-        std::vector<unsigned char> newDefaultKey;
+        CPubKey newDefaultKey;
         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";
     }
 
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -239,18 +239,18 @@
     return vchPrivKey;
 }
 
-bool CKey::SetPubKey(const std::vector<unsigned char>& vchPubKey)
+bool CKey::SetPubKey(const CPubKey& vchPubKey)
 {
-    const unsigned char* pbegin = &vchPubKey[0];
-    if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
+    const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
+    if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
         return false;
     fSet = true;
-    if (vchPubKey.size() == 33)
+    if (vchPubKey.vchPubKey.size() == 33)
         SetCompressedPubKey();
     return true;
 }
 
-std::vector<unsigned char> CKey::GetPubKey() const
+CPubKey CKey::GetPubKey() const
 {
     int nSize = i2o_ECPublicKey(pkey, NULL);
     if (!nSize)
@@ -259,7 +259,7 @@
     unsigned char* pbegin = &vchPubKey[0];
     if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
         throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
-    return vchPubKey;
+    return CPubKey(vchPubKey);
 }
 
 bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
--- a/src/key.h
+++ b/src/key.h
@@ -9,7 +9,9 @@
 #include <vector>
 
 #include "allocators.h"
+#include "serialize.h"
 #include "uint256.h"
+#include "util.h"
 
 #include <openssl/ec.h> // for EC_KEY definition
 
@@ -42,6 +44,60 @@
     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;
+    friend class CKey;
+
+public:
+    CPubKey() { }
+    CPubKey(const std::vector<unsigned char> &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { }
+    friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; }
+    friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; }
+    friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; }
+
+    IMPLEMENT_SERIALIZE(
+        READWRITE(vchPubKey);
+    )
+
+    CKeyID GetID() const {
+        return CKeyID(Hash160(vchPubKey));
+    }
+
+    uint256 GetHash() const {
+        return Hash(vchPubKey.begin(), vchPubKey.end());
+    }
+
+    bool IsValid() const {
+        return vchPubKey.size() == 33 || vchPubKey.size() == 65;
+    }
+
+    bool IsCompressed() const {
+        return vchPubKey.size() == 33;
+    }
+
+    std::vector<unsigned char> Raw() const {
+        return vchPubKey;
+    }
+};
+
 
 // secure_allocator is defined in serialize.h
 // CPrivKey is a serialized private key, with all parameters included (279 bytes)
@@ -78,8 +134,8 @@
     bool SetSecret(const CSecret& vchSecret, bool fCompressed = false);
     CSecret GetSecret(bool &fCompressed) const;
     CPrivKey GetPrivKey() const;
-    bool SetPubKey(const std::vector<unsigned char>& vchPubKey);
-    std::vector<unsigned char> GetPubKey() const;
+    bool SetPubKey(const CPubKey& vchPubKey);
+    CPubKey GetPubKey() const;
 
     bool Sign(uint256 hash, std::vector<unsigned char>& vchSig);
 
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -6,7 +6,7 @@
 #include "keystore.h"
 #include "script.h"
 
-bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const
+bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
 {
     CKey key;
     if (!GetKey(address, key))
@@ -21,7 +21,7 @@
     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 @@
 {
     {
         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::GetCScript(const uint160 &hash, CScript& redeemScriptOut) const
+bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
 {
     {
         LOCK(cs_KeyStore);
@@ -97,10 +97,10 @@
         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
         for (; mi != mapCryptedKeys.end(); ++mi)
         {
-            const std::vector<unsigned char> &vchPubKey = (*mi).second.first;
+            const CPubKey &vchPubKey = (*mi).second.first;
             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
             CSecret vchSecret;
-            if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
+            if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
                 return false;
             if (vchSecret.size() != 32)
                 return false;
@@ -128,9 +128,9 @@
             return false;
 
         std::vector<unsigned char> vchCryptedSecret;
-        std::vector<unsigned char> vchPubKey = key.GetPubKey();
+        CPubKey vchPubKey = key.GetPubKey();
         bool fCompressed;
-        if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
+        if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
             return false;
 
         if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
@@ -140,19 +140,19 @@
 }
 
 
-bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
+bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
 {
     {
         LOCK(cs_KeyStore);
         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);
@@ -162,10 +162,10 @@
         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
         if (mi != mapCryptedKeys.end())
         {
-            const std::vector<unsigned char> &vchPubKey = (*mi).second.first;
+            const CPubKey &vchPubKey = (*mi).second.first;
             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
             CSecret vchSecret;
-            if (!DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
+            if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
                 return false;
             if (vchSecret.size() != 32)
                 return false;
@@ -177,7 +177,7 @@
     return false;
 }
 
-bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const
+bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
 {
     {
         LOCK(cs_KeyStore);
@@ -207,10 +207,10 @@
             CKey key;
             if (!key.SetSecret(mKey.second.first, mKey.second.second))
                 return false;
-            const std::vector<unsigned char> vchPubKey = key.GetPubKey();
+            const CPubKey vchPubKey = key.GetPubKey();
             std::vector<unsigned char> vchCryptedSecret;
             bool fCompressed;
-            if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
+            if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
                 return false;
             if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
                 return false;
--- 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 @@
     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, std::vector<unsigned char>& 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 @@
     }
 };
 
-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 @@
 
 public:
     bool AddKey(const CKey& key);
-    bool HaveKey(const CBitcoinAddress &address) const
+    bool HaveKey(const CKeyID &address) const
     {
         bool result;
         {
@@ -66,7 +65,7 @@
         }
         return result;
     }
-    void GetKeys(std::set<CBitcoinAddress> &setAddress) const
+    void GetKeys(std::set<CKeyID> &setAddress) const
     {
         setAddress.clear();
         {
@@ -79,7 +78,7 @@
             }
         }
     }
-    bool GetKey(const CBitcoinAddress &address, CKey &keyOut) const
+    bool GetKey(const CKeyID &address, CKey &keyOut) const
     {
         {
             LOCK(cs_KeyStore);
@@ -94,11 +93,11 @@
         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<std::vector<unsigned char>, 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.
@@ -146,9 +145,9 @@
 
     bool Lock();
 
-    virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
+    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 @@
         }
         return false;
     }
-    bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const;
-    bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& 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())
         {
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2304,7 +2304,7 @@
 
 bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
 {
-    static map<CService, vector<unsigned char> > mapReuseKey;
+    static map<CService, CPubKey> mapReuseKey;
     RandAddSeedPerfmon();
     if (fDebug)
         printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
--- 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 @@
         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 @@
         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 @@
                 {
                     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 @@
         // 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();
@@ -331,13 +333,13 @@
             editStatus = WALLET_UNLOCK_FAILURE;
             return QString();
         }
-        std::vector<unsigned char> newKey;
+        CPubKey newKey;
         if(!wallet->GetKeyFromPool(newKey, true))
         {
             editStatus = KEY_GENERATION_FAILURE;
             return QString();
         }
-        strAddress = CBitcoinAddress(newKey).ToString();
+        strAddress = CBitcoinAddress(newKey.GetID()).ToString();
     }
     else
     {
@@ -346,7 +348,7 @@
     // Add entry
     {
         LOCK(wallet->cs_wallet);
-        wallet->SetAddressBookName(strAddress, strLabel);
+        wallet->SetAddressBookName(CBitcoinAddress(strAddress).Get(), strLabel);
     }
     return QString::fromStdString(strAddress);
 }
@@ -363,7 +365,7 @@
     }
     {
         LOCK(wallet->cs_wallet);
-        wallet->DelAddressBookName(rec->address.toStdString());
+        wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get());
     }
     return true;
 }
@@ -375,7 +377,7 @@
     {
         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);
--- 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 @@
                               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 @@
     }
 
     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);
--- 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 @@
                 {
                     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 @@
             // 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 @@
                     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 @@
                         {
                             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>";
--- 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 @@
             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 @@
                     // 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 @@
                     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
                 {
--- 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 @@
         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);
--- 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 @@
         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 @@
     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 @@
     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));
--- 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 @@
     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 @@
     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();
 }
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -1312,7 +1312,7 @@
 }
 
 
-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 @@
     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 @@
     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
         {
-            valtype vch;
-            keystore.GetPubKey(address, vch);
+            CPubKey vch;
+            keystore.GetPubKey(keyID, vch);
             scriptSigRet << vch;
         }
         return true;
@@ -1436,14 +1435,30 @@
     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 @@
     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 @@
     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 @@
 
     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 @@
         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 @@
             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 @@
         *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;
-}
--- 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 @@
     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 */
@@ -320,6 +335,12 @@
         return *this;
     }
 
+    CScript& operator<<(const CPubKey& key)
+    {
+        std::vector<unsigned char> vchKey = key.Raw();
+        return (*this) << vchKey;
+    }
+
     CScript& operator<<(const CBigNum& b)
     {
         *this << b.getvch();
@@ -515,13 +536,8 @@
     }
 
 
-    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
@@ -556,6 +572,11 @@
     {
         printf("%s\n", ToString().c_str());
     }
+
+    CScriptID GetID() const
+    {
+        return CScriptID(Hash160(*this));
+    }
 };
 
 
@@ -567,8 +588,9 @@
 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);
 
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -161,7 +161,7 @@
         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 @@
         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 @@
         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 @@
         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 @@
     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++)
     {
--- 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)
 
--- 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_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 @@
     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++)
     {
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -175,12 +175,12 @@
     //
     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 @@
         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 @@
         vector<valtype> solutions;
         txnouttype whichType;
         CScript s;
-        s << OP_DUP << OP_HASH160 << Hash160(key[0].GetPubKey()) << 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));
@@ -217,8 +217,8 @@
         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));
@@ -230,9 +230,9 @@
         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);
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -65,14 +65,14 @@
     // 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 @@
     invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE;
 
     CScript p2sh;
-    p2sh.SetPayToScriptHash(invalidAsScript);
+    p2sh.SetDestination(invalidAsScript.GetID());
 
     CScript scriptSig;
     scriptSig << Serialize(invalidAsScript);
@@ -133,7 +133,7 @@
     // 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 @@
     }
 
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 
     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();
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -32,7 +32,7 @@
     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_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;
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -52,9 +52,9 @@
 
     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;
--- 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;
 
@@ -16,7 +17,7 @@
 // mapWallet
 //
 
-std::vector<unsigned char> CWallet::GenerateNewKey()
+CPubKey CWallet::GenerateNewKey()
 {
     bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
 
@@ -44,7 +45,7 @@
     return true;
 }
 
-bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
+bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
 {
     if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
         return false;
@@ -361,16 +362,16 @@
 #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)
             {
-                std::vector<unsigned char> newDefaultKey;
+                CPubKey newDefaultKey;
                 if (GetKeyFromPool(newDefaultKey, false))
                 {
                     SetDefaultKey(newDefaultKey);
-                    SetAddressBookName(CBitcoinAddress(vchDefaultKey), "");
+                    SetAddressBookName(vchDefaultKey.GetID(), "");
                 }
             }
         }
@@ -455,7 +456,7 @@
 
 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 @@
     // 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 @@
     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 @@
     // 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 @@
     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;
             }
@@ -1095,14 +1095,14 @@
                     //  post-backup change.
 
                     // Reserve a new key pair from key pool
-                    vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
+                    CPubKey vchPubKey = reservekey.GetReservedKey();
                     // assert(mapKeys.count(vchPubKey));
 
                     // Fill a vout to ourself
                     // 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::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 @@
 
     // Parse Bitcoin address
     CScript scriptPubKey;
-    scriptPubKey.SetBitcoinAddress(address);
+    scriptPubKey.SetDestination(address);
 
     return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
 }
@@ -1278,30 +1278,30 @@
 
     if (nLoadWalletRet != DB_LOAD_OK)
         return nLoadWalletRet;
-    fFirstRunRet = vchDefaultKey.empty();
+    fFirstRunRet = !vchDefaultKey.IsValid();
 
     CreateThread(ThreadFlushWalletDB, &strWalletFile);
     return DB_LOAD_OK;
 }
 
 
-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());
 }
 
 
@@ -1332,7 +1332,7 @@
     return false;
 }
 
-bool CWallet::SetDefaultKey(const std::vector<unsigned char> &vchPubKey)
+bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
 {
     if (fFileBacked)
     {
@@ -1408,7 +1408,7 @@
 void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
 {
     nIndex = -1;
-    keypool.vchPubKey.clear();
+    keypool.vchPubKey = CPubKey();
     {
         LOCK(cs_wallet);
 
@@ -1425,9 +1425,9 @@
         setKeyPool.erase(setKeyPool.begin());
         if (!walletdb.ReadPool(nIndex, keypool))
             throw runtime_error("ReserveKeyFromKeyPool() : read failed");
-        if (!HaveKey(Hash160(keypool.vchPubKey)))
+        if (!HaveKey(keypool.vchPubKey.GetID()))
             throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
-        assert(!keypool.vchPubKey.empty());
+        assert(keypool.vchPubKey.IsValid());
         printf("keypool reserve %"PRI64d"\n", nIndex);
     }
 }
@@ -1468,7 +1468,7 @@
     printf("keypool return %"PRI64d"\n", nIndex);
 }
 
-bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse)
+bool CWallet::GetKeyFromPool(CPubKey& result, bool fAllowReuse)
 {
     int64 nIndex = 0;
     CKeyPool keypool;
@@ -1477,7 +1477,7 @@
         ReserveKeyFromKeyPool(nIndex, keypool);
         if (nIndex == -1)
         {
-            if (fAllowReuse && !vchDefaultKey.empty())
+            if (fAllowReuse && vchDefaultKey.IsValid())
             {
                 result = vchDefaultKey;
                 return true;
@@ -1503,7 +1503,7 @@
     return keypool.nTime;
 }
 
-vector<unsigned char> CReserveKey::GetReservedKey()
+CPubKey CReserveKey::GetReservedKey()
 {
     if (nIndex == -1)
     {
@@ -1517,7 +1517,7 @@
             vchPubKey = pwallet->vchDefaultKey;
         }
     }
-    assert(!vchPubKey.empty());
+    assert(vchPubKey.IsValid());
     return vchPubKey;
 }
 
@@ -1526,7 +1526,7 @@
     if (nIndex != -1)
         pwallet->KeepKey(nIndex);
     nIndex = -1;
-    vchPubKey.clear();
+    vchPubKey = CPubKey();
 }
 
 void CReserveKey::ReturnKey()
@@ -1534,10 +1534,10 @@
     if (nIndex != -1)
         pwallet->ReturnKey(nIndex);
     nIndex = -1;
-    vchPubKey.clear();
+    vchPubKey = CPubKey();
 }
 
-void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress)
+void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress)
 {
     setAddress.clear();
 
@@ -1549,11 +1549,11 @@
         CKeyPool keypool;
         if (!walletdb.ReadPool(id, keypool))
             throw runtime_error("GetAllReserveKeyHashes() : read failed");
-        CBitcoinAddress address(keypool.vchPubKey);
-        assert(!keypool.vchPubKey.empty());
-        if (!HaveKey(address))
+        assert(keypool.vchPubKey.IsValid());
+        CKeyID keyID = keypool.vchPubKey.GetID();
+        if (!HaveKey(keyID))
             throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool");
-        setAddress.insert(address);
+        setAddress.insert(keyID);
     }
 }
 
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -32,14 +32,14 @@
 {
 public:
     int64 nTime;
-    std::vector<unsigned char> vchPubKey;
+    CPubKey vchPubKey;
 
     CKeyPool()
     {
         nTime = GetTime();
     }
 
-    CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
+    CKeyPool(const CPubKey& vchPubKeyIn)
     {
         nTime = GetTime();
         vchPubKey = vchPubKeyIn;
@@ -105,16 +105,16 @@
     std::map<uint256, CWalletTx> mapWallet;
     std::map<uint256, int> mapRequestCount;
 
-    std::map<CBitcoinAddress, std::string> mapAddressBook;
+    std::map<CTxDestination, std::string> mapAddressBook;
 
-    std::vector<unsigned char> vchDefaultKey;
+    CPubKey vchDefaultKey;
 
     // check whether we are allowed to upgrade (or already support) to the named feature
     bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; }
 
     // keystore implementation
     // Generate a new key
-    std::vector<unsigned char> GenerateNewKey();
+    CPubKey GenerateNewKey();
     // Adds a key to the store, and saves it to disk.
     bool AddKey(const CKey& key);
     // Adds a key to the store, without saving it to disk (used by LoadWallet)
@@ -123,9 +123,9 @@
     bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
 
     // Adds an encrypted key to the store, and saves it to disk.
-    bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
+    bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
     // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
-    bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
+    bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
     bool AddCScript(const CScript& redeemScript);
     bool LoadCScript(const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(redeemScript); }
 
@@ -148,7 +148,7 @@
     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();
@@ -156,9 +156,9 @@
     void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
     void KeepKey(int64 nIndex);
     void ReturnKey(int64 nIndex);
-    bool GetKeyFromPool(std::vector<unsigned char> &key, bool fAllowReuse=true);
+    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 @@
 
     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);
 
@@ -252,7 +252,7 @@
 
     bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
 
-    bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);
+    bool SetDefaultKey(const CPubKey &vchPubKey);
 
     // signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
     bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false);
@@ -266,7 +266,7 @@
     /** 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.
@@ -280,7 +280,7 @@
 protected:
     CWallet* pwallet;
     int64 nIndex;
-    std::vector<unsigned char> vchPubKey;
+    CPubKey vchPubKey;
 public:
     CReserveKey(CWallet* pwalletIn)
     {
@@ -295,7 +295,7 @@
     }
 
     void ReturnKey();
-    std::vector<unsigned char> GetReservedKey();
+    CPubKey GetReservedKey();
     void KeepKey();
 };
 
@@ -532,8 +532,8 @@
         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;
@@ -640,7 +640,7 @@
 class CAccount
 {
 public:
-    std::vector<unsigned char> vchPubKey;
+    CPubKey vchPubKey;
 
     CAccount()
     {
@@ -649,7 +649,7 @@
 
     void SetNull()
     {
-        vchPubKey.clear();
+        vchPubKey = CPubKey();
     }
 
     IMPLEMENT_SERIALIZE
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -104,7 +104,7 @@
 
 int CWalletDB::LoadWallet(CWallet* pwallet)
 {
-    pwallet->vchDefaultKey.clear();
+    pwallet->vchDefaultKey = CPubKey();
     int nFileVersion = 0;
     vector<uint256> vWalletUpgrade;
     bool fIsEncrypted = false;
@@ -151,7 +151,7 @@
             {
                 string strAddress;
                 ssKey >> strAddress;
-                ssValue >> pwallet->mapAddressBook[strAddress];
+                ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()];
             }
             else if (strType == "tx")
             {
--- 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;
@@ -59,27 +60,27 @@
         return Erase(std::make_pair(std::string("tx"), hash));
     }
 
-    bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
+    bool ReadKey(const CPubKey& vchPubKey, CPrivKey& vchPrivKey)
     {
         vchPrivKey.clear();
-        return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey);
+        return Read(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey);
     }
 
-    bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
+    bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey)
     {
         nWalletDBUpdated++;
-        return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
+        return Write(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey, false);
     }
 
-    bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
+    bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
     {
         nWalletDBUpdated++;
-        if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
+        if (!Write(std::make_pair(std::string("ckey"), vchPubKey.Raw()), vchCryptedSecret, false))
             return false;
         if (fEraseUnencryptedKey)
         {
-            Erase(std::make_pair(std::string("key"), vchPubKey));
-            Erase(std::make_pair(std::string("wkey"), vchPubKey));
+            Erase(std::make_pair(std::string("key"), vchPubKey.Raw()));
+            Erase(std::make_pair(std::string("wkey"), vchPubKey.Raw()));
         }
         return true;
     }
@@ -120,10 +121,10 @@
         return Read(std::string("defaultkey"), vchPubKey);
     }
 
-    bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
+    bool WriteDefaultKey(const CPubKey& vchPubKey)
     {
         nWalletDBUpdated++;
-        return Write(std::string("defaultkey"), vchPubKey);
+        return Write(std::string("defaultkey"), vchPubKey.Raw());
     }
 
     bool ReadPool(int64 nPool, CKeyPool& keypool)