changeset 1613:8bf9748cc2e9 draft

Merge branch 'op_eval'
author Gavin Andresen <gavinandresen@gmail.com>
date Tue, 20 Dec 2011 14:43:31 -0500
parents dcc1587cadb0 (current diff) c211ddfb15f0 (diff)
children 3fd32de4e88f
files src/bitcoinrpc.cpp src/main.cpp src/main.h src/wallet.cpp
diffstat 27 files changed, 1625 insertions(+), 470 deletions(-) [+]
line wrap: on
line diff
--- a/src/base58.h
+++ b/src/base58.h
@@ -253,14 +253,26 @@
 };
 
 // base58-encoded bitcoin addresses
-// Addresses have version 0 or 111 (testnet)
+// Public-key-hash-addresses have version 0 (or 192 testnet)
 // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key
+// Script-hash-addresses (OP_EVAL) have version 5 (or 196 testnet)
+// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script
 class CBitcoinAddress : public CBase58Data
 {
 public:
-    void SetHash160(const uint160& hash160)
+    enum
     {
-        SetData(fTestNet ? 111 : 0, &hash160, 20);
+        PUBKEY_ADDRESS = 0,
+        SCRIPT_ADDRESS = 5,
+        PUBKEY_ADDRESS_TEST = 192,
+        PUBKEY_ADDRESS_TEST_LEGACY = 111,  // Deprecated: old testnet address
+        SCRIPT_ADDRESS_TEST = 196,
+    };
+
+    bool SetHash160(const uint160& hash160)
+    {
+        SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &hash160, 20);
+        return true;
     }
 
     void SetPubKey(const std::vector<unsigned char>& vchPubKey)
@@ -268,16 +280,34 @@
         SetHash160(Hash160(vchPubKey));
     }
 
+    bool SetScriptHash160(const uint160& hash160)
+    {
+        SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &hash160, 20);
+        return true;
+    }
+
     bool IsValid() const
     {
         int nExpectedSize = 20;
         bool fExpectTestNet = false;
         switch(nVersion)
         {
-            case 0:
+            case PUBKEY_ADDRESS:
+                nExpectedSize = 20; // Hash of public key
+                fExpectTestNet = false;
+                break;
+            case SCRIPT_ADDRESS:
+                nExpectedSize = 20; // OP_EVAL, hash of CScript
+                fExpectTestNet = false;
                 break;
 
-            case 111:
+            case PUBKEY_ADDRESS_TEST_LEGACY:
+            case PUBKEY_ADDRESS_TEST:
+                nExpectedSize = 20;
+                fExpectTestNet = true;
+                break;
+            case SCRIPT_ADDRESS_TEST:
+                nExpectedSize = 20;
                 fExpectTestNet = true;
                 break;
 
@@ -286,6 +316,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()
     {
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -673,7 +673,7 @@
     if (params.size() > 1)
         nMinDepth = params[1].get_int();
 
-    // Get the set of pub keys that have the label
+    // Get the set of pub keys assigned to account
     string strAccount = AccountFromValue(params[0]);
     set<CBitcoinAddress> setAddress;
     GetAccountAddresses(strAccount, setAddress);
@@ -942,6 +942,68 @@
     return wtx.GetHash().GetHex();
 }
 
+Value addmultisigaddress(const Array& params, bool fHelp)
+{
+    if (fHelp || params.size() < 2 || params.size() > 3)
+    {
+        string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
+            "Add a nrequired-to-sign multisignature address to the wallet\"\n"
+            "each key is a bitcoin address, hex or base58 public key\n"
+            "If [account] is specified, assign address to [account].";
+        throw runtime_error(msg);
+    }
+    if (!fTestNet)
+        throw runtime_error("addmultisigaddress available only when running -testnet\n");
+
+    int nRequired = params[0].get_int();
+    const Array& keys = params[1].get_array();
+    string strAccount;
+    if (params.size() > 2)
+        strAccount = AccountFromValue(params[2]);
+
+    // Gather public keys
+    if (keys.size() < nRequired)
+        throw runtime_error(
+            strprintf("addmultisigaddress: wrong number of keys (got %d, need at least %d)", keys.size(), nRequired));
+    std::vector<CKey> pubkeys;
+    pubkeys.resize(keys.size());
+    for (int i = 0; i < keys.size(); i++)
+    {
+        const std::string& ks = keys[i].get_str();
+        if (ks.size() == 130) // hex public key
+            pubkeys[i].SetPubKey(ParseHex(ks));
+        else if (ks.size() > 34) // base58-encoded
+        {
+            std::vector<unsigned char> vchPubKey;
+            if (DecodeBase58(ks, vchPubKey))
+                pubkeys[i].SetPubKey(vchPubKey);
+            else
+                throw runtime_error("Error base58 decoding key: "+ks);
+        }
+        else // bitcoin address for key in this wallet
+        {
+            CBitcoinAddress address(ks);
+            if (!pwalletMain->GetKey(address, pubkeys[i]))
+                throw runtime_error(
+                    strprintf("addmultisigaddress: unknown address: %s",ks.c_str()));
+        }
+    }
+
+    // Construct using OP_EVAL
+    CScript inner;
+    inner.SetMultisig(nRequired, pubkeys);
+
+    uint160 scriptHash = Hash160(inner);
+    CScript scriptPubKey;
+    scriptPubKey.SetEval(inner);
+    pwalletMain->AddCScript(scriptHash, inner);
+    CBitcoinAddress address;
+    address.SetScriptHash160(scriptHash);
+
+    pwalletMain->SetAddressBookName(address, strAccount);
+    return address.ToString();
+}
+
 
 struct tallyitem
 {
@@ -1602,7 +1664,35 @@
         // version of the address:
         string currentAddress = address.ToString();
         ret.push_back(Pair("address", currentAddress));
-        ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
+        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)));
+            std::string strPubKey(vchPubKey.begin(), vchPubKey.end());
+            ret.push_back(Pair("pubkey58", EncodeBase58(vchPubKey)));
+        }
+        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, pwalletMain, 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]));
     }
@@ -1847,6 +1937,7 @@
     make_pair("move",                   &movecmd),
     make_pair("sendfrom",               &sendfrom),
     make_pair("sendmany",               &sendmany),
+    make_pair("addmultisigaddress",     &addmultisigaddress),
     make_pair("gettransaction",         &gettransaction),
     make_pair("listtransactions",       &listtransactions),
     make_pair("signmessage",            &signmessage),
@@ -2490,6 +2581,15 @@
             params[1] = v.get_obj();
         }
         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
+        if (strMethod == "addmultisigaddress"      && n > 0) ConvertTo<boost::int64_t>(params[0]);
+        if (strMethod == "addmultisigaddress"      && n > 1)
+        {
+            string s = params[1].get_str();
+            Value v;
+            if (!read_string(s, v) || v.type() != array_type)
+                throw runtime_error("addmultisigaddress: type mismatch "+s);
+            params[1] = v.get_array();
+        }
 
         // Execute
         Object reply = CallRPC(strMethod, params);
--- a/src/crypter.h
+++ b/src/crypter.h
@@ -4,6 +4,7 @@
 #ifndef __CRYPTER_H__
 #define __CRYPTER_H__
 
+#include "util.h" /* for SecureString */
 #include "key.h"
 
 const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -934,6 +934,15 @@
                 if (nMinVersion > CLIENT_VERSION)
                     return DB_TOO_NEW;
             }
+            else if (strType == "cscript")
+            {
+                uint160 hash;
+                ssKey >> hash;
+                CScript script;
+                ssValue >> script;
+                if (!pwallet->LoadCScript(hash, script))
+                    return DB_CORRUPT;
+            }
         }
         pcursor->close();
     }
--- a/src/db.h
+++ b/src/db.h
@@ -13,17 +13,17 @@
 
 #include <db_cxx.h>
 
-class CTxIndex;
+class CAccount;
+class CAccountingEntry;
+class CAddress;
+class CBlockLocator;
 class CDiskBlockIndex;
 class CDiskTxPos;
+class CMasterKey;
 class COutPoint;
-class CAddress;
-class CWalletTx;
+class CTxIndex;
 class CWallet;
-class CAccount;
-class CAccountingEntry;
-class CBlockLocator;
-
+class CWalletTx;
 
 extern unsigned int nWalletDBUpdated;
 extern DbEnv dbenv;
@@ -420,6 +420,19 @@
         return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
     }
 
+    // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
+    bool ReadCScript(const uint160 &hash, CScript& redeemScript)
+    {
+        redeemScript.clear();
+        return Read(std::make_pair(std::string("cscript"), hash), redeemScript);
+    }
+
+    bool WriteCScript(const uint160& hash, const CScript& redeemScript)
+    {
+        nWalletDBUpdated++;
+        return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
+    }
+
     bool WriteBestBlock(const CBlockLocator& locator)
     {
         nWalletDBUpdated++;
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -4,8 +4,9 @@
 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
 
 #include "headers.h"
+#include "crypter.h"
 #include "db.h"
-#include "crypter.h"
+#include "script.h"
 
 std::vector<unsigned char> CKeyStore::GenerateNewKey()
 {
@@ -33,6 +34,36 @@
     return true;
 }
 
+bool CBasicKeyStore::AddCScript(const uint160 &hash, const CScript& redeemScript)
+{
+    CRITICAL_BLOCK(cs_KeyStore)
+        mapScripts[hash] = redeemScript;
+    return true;
+}
+
+bool CBasicKeyStore::HaveCScript(const uint160& hash) const
+{
+    bool result;
+    CRITICAL_BLOCK(cs_KeyStore)
+        result = (mapScripts.count(hash) > 0);
+    return result;
+}
+
+
+bool CBasicKeyStore::GetCScript(const uint160 &hash, CScript& redeemScriptOut) const
+{
+    CRITICAL_BLOCK(cs_KeyStore)
+    {
+        ScriptMap::const_iterator mi = mapScripts.find(hash);
+        if (mi != mapScripts.end())
+        {
+            redeemScriptOut = (*mi).second;
+            return true;
+        }
+    }
+    return false;
+}
+
 bool CCryptoKeyStore::SetCrypted()
 {
     CRITICAL_BLOCK(cs_KeyStore)
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -6,6 +6,7 @@
 #define BITCOIN_KEYSTORE_H
 
 #include "crypter.h"
+#include "script.h"
 
 // A virtual base class for key stores
 class CKeyStore
@@ -31,6 +32,11 @@
     virtual void GetKeys(std::set<CBitcoinAddress> &setAddress) const =0;
     virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
 
+    // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
+    virtual bool AddCScript(const uint160 &hash, const CScript& redeemScript) =0;
+    virtual bool HaveCScript(const uint160 &hash) const =0;
+    virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const =0;
+
     // Generate a new key, and add it to the store
     virtual std::vector<unsigned char> GenerateNewKey();
     virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const
@@ -44,12 +50,14 @@
 };
 
 typedef std::map<CBitcoinAddress, CSecret> KeyMap;
+typedef std::map<uint160, CScript > ScriptMap;
 
 // Basic key store, that keeps keys in an address->secret map
 class CBasicKeyStore : public CKeyStore
 {
 protected:
     KeyMap mapKeys;
+    ScriptMap mapScripts;
 
 public:
     bool AddKey(const CKey& key);
@@ -86,6 +94,9 @@
         }
         return false;
     }
+    virtual bool AddCScript(const uint160 &hash, const CScript& redeemScript);
+    virtual bool HaveCScript(const uint160 &hash) const;
+    virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const;
 };
 
 typedef std::map<CBitcoinAddress, std::pair<std::vector<unsigned char>, std::vector<unsigned char> > > CryptedKeyMap;
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -246,6 +246,67 @@
     return ReadFromDisk(txdb, prevout, txindex);
 }
 
+bool CTransaction::IsStandard() const
+{
+    BOOST_FOREACH(const CTxIn& txin, vin)
+    {
+        // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
+        // in an OP_EVAL, which is 3 ~80-byte signatures, 3
+        // ~65-byte public keys, plus a few script ops.
+        if (txin.scriptSig.size() > 500)
+            return error("nonstandard txin, size %d is too large\n", txin.scriptSig.size());
+        if (!txin.scriptSig.IsPushOnly())
+            return error("nonstandard txin (opcodes other than PUSH): %s", txin.scriptSig.ToString().c_str());
+    }
+    BOOST_FOREACH(const CTxOut& txout, vout)
+        if (!::IsStandard(txout.scriptPubKey))
+            return error("nonstandard txout: %s", txout.scriptPubKey.ToString().c_str());
+    return true;
+}
+
+//
+// Check transaction inputs, and make sure any
+// OP_EVAL transactions are evaluating IsStandard scripts
+//
+// Why bother? To avoid denial-of-service attacks; an attacker
+// can submit a standard DUP HASH... OP_EVAL transaction,
+// which will get accepted into blocks. The script being
+// EVAL'ed can be anything; an attacker could use a very
+// expensive-to-check-upon-redemption script like:
+//   DUP CHECKSIG DROP ... repeated 100 times... OP_1
+//
+bool CTransaction::AreInputsStandard(std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs) const
+{
+    if (fTestNet)
+        return true; // Allow non-standard on testnet
+
+    for (int i = 0; i < vin.size(); i++)
+    {
+        COutPoint prevout = vin[i].prevout;
+        assert(mapInputs.count(prevout.hash) > 0);
+        CTransaction& txPrev = mapInputs[prevout.hash].second;
+
+        vector<vector<unsigned char> > vSolutions;
+        txnouttype whichType;
+        // get the scriptPubKey corresponding to this input:
+        CScript& prevScript = txPrev.vout[prevout.n].scriptPubKey;
+        if (!Solver(prevScript, whichType, vSolutions))
+            return error("nonstandard txin (spending nonstandard txout %s)", prevScript.ToString().c_str());
+        if (whichType == TX_SCRIPTHASH)
+        {
+            vector<vector<unsigned char> > stack;
+            int nUnused;
+            if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0, true, nUnused))
+                return false;
+            CScript subscript(stack.back().begin(), stack.back().end());
+            if (!::IsStandard(subscript))
+                return error("nonstandard txin (nonstandard OP_EVAL subscript %s)", subscript.ToString().c_str());
+        }
+    }
+
+    return true;
+}
+
 
 
 int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
@@ -369,15 +430,6 @@
     if ((int64)nLockTime > std::numeric_limits<int>::max())
         return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
 
-    // Safety limits
-    unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
-    // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
-    // attacks disallow transactions with more than one SigOp per 34 bytes.
-    // 34 bytes because a TxOut is:
-    //   20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length
-    if (GetSigOpCount() > nSize / 34 || nSize < 100)
-        return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
-
     // Rather not work on nonstandard transactions (unless -testnet)
     if (!fTestNet && !IsStandard())
         return error("AcceptToMemoryPool() : nonstandard transaction type");
@@ -421,15 +473,34 @@
 
     if (fCheckInputs)
     {
-        // Check against previous transactions
+        map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
         map<uint256, CTxIndex> mapUnused;
+        if (!FetchInputs(txdb, mapUnused, false, false, mapInputs))
+        {
+            if (pfMissingInputs)
+                *pfMissingInputs = true;
+            return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
+        }
+
+        // Check for non-standard OP_EVALs in inputs
+        if (!AreInputsStandard(mapInputs))
+            return error("AcceptToMemoryPool() : nonstandard transaction input");
+
+        // Check against previous transactions
         int64 nFees = 0;
-        if (!ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false))
+        int nSigOps = 0;
+        if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false, nSigOps))
         {
             if (pfMissingInputs)
                 *pfMissingInputs = true;
             return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
         }
+        // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
+        // attacks disallow transactions with more than one SigOp per 65 bytes.
+        // 65 bytes because that is the minimum size of an ECDSA signature
+        unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
+        if (nSigOps > nSize / 65 || nSize < 100)
+            return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
 
         // Don't accept it if it can't get into a block
         if (nFees < GetMinFee(1000, true, true))
@@ -826,8 +897,61 @@
 }
 
 
-bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
-                                 CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee)
+bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool,
+                               bool fBlock, bool fMiner, map<uint256, pair<CTxIndex, CTransaction> >& inputsRet)
+{
+    if (IsCoinBase())
+        return true; // Coinbase transactions have no inputs to fetch.
+
+    for (int i = 0; i < vin.size(); i++)
+    {
+        COutPoint prevout = vin[i].prevout;
+        if (inputsRet.count(prevout.hash))
+            continue; // Got it already
+
+        // Read txindex
+        CTxIndex& txindex = inputsRet[prevout.hash].first;
+        bool fFound = true;
+        if ((fBlock || fMiner) && mapTestPool.count(prevout.hash))
+        {
+            // Get txindex from current proposed changes
+            txindex = mapTestPool.find(prevout.hash)->second;
+        }
+        else
+        {
+            // Read txindex from txdb
+            fFound = txdb.ReadTxIndex(prevout.hash, txindex);
+        }
+        if (!fFound && (fBlock || fMiner))
+            return fMiner ? false : error("FetchInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
+
+        // Read txPrev
+        CTransaction& txPrev = inputsRet[prevout.hash].second;
+        if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
+        {
+            // Get prev tx from single transactions in memory
+            CRITICAL_BLOCK(cs_mapTransactions)
+            {
+                if (!mapTransactions.count(prevout.hash))
+                    return error("FetchInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
+                txPrev = mapTransactions[prevout.hash];
+            }
+            if (!fFound)
+                txindex.vSpent.resize(txPrev.vout.size());
+        }
+        else
+        {
+            // Get prev tx from disk
+            if (!txPrev.ReadFromDisk(txindex.pos))
+                return error("FetchInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
+        }
+    }
+    return true;
+}
+
+bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inputs,
+                                 map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
+                                 CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64 nMinFee)
 {
     // Take over previous transactions' spent pointers
     // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
@@ -839,43 +963,9 @@
         for (int i = 0; i < vin.size(); i++)
         {
             COutPoint prevout = vin[i].prevout;
-
-            // Read txindex
-            CTxIndex txindex;
-            bool fFound = true;
-            if ((fBlock || fMiner) && mapTestPool.count(prevout.hash))
-            {
-                // Get txindex from current proposed changes
-                txindex = mapTestPool[prevout.hash];
-            }
-            else
-            {
-                // Read txindex from txdb
-                fFound = txdb.ReadTxIndex(prevout.hash, txindex);
-            }
-            if (!fFound && (fBlock || fMiner))
-                return fMiner ? false : error("ConnectInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
-
-            // Read txPrev
-            CTransaction txPrev;
-            if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
-            {
-                // Get prev tx from single transactions in memory
-                CRITICAL_BLOCK(cs_mapTransactions)
-                {
-                    if (!mapTransactions.count(prevout.hash))
-                        return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
-                    txPrev = mapTransactions[prevout.hash];
-                }
-                if (!fFound)
-                    txindex.vSpent.resize(txPrev.vout.size());
-            }
-            else
-            {
-                // Get prev tx from disk
-                if (!txPrev.ReadFromDisk(txindex.pos))
-                    return error("ConnectInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
-            }
+            assert(inputs.count(prevout.hash) > 0);
+            CTxIndex& txindex = inputs[prevout.hash].first;
+            CTransaction& txPrev = inputs[prevout.hash].second;
 
             if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
                 return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
@@ -890,9 +980,27 @@
             // (before the last blockchain checkpoint). This is safe because block merkle hashes are
             // still computed and checked, and any change will be caught at the next checkpoint.
             if (!(fBlock && IsInitialBlockDownload()))
+            {
+                bool fStrictOpEval = true;
+                // This code should be removed when OP_EVAL has
+                // a majority of hashing power on the network.
+                if (fBlock)
+                {
+                    // To avoid being on the short end of a block-chain split,
+                    // interpret OP_EVAL as a NO_OP until blocks with timestamps
+                    // after opevaltime:
+                    int64 nEvalSwitchTime = GetArg("opevaltime", 1328054400); // Feb 1, 2012
+                    fStrictOpEval = (pindexBlock->nTime >= nEvalSwitchTime);
+                }
+                // if !fBlock, then always be strict-- don't accept
+                // invalid-under-new-rules OP_EVAL transactions into
+                // our memory pool (don't relay them, don't include them
+                // in blocks we mine).
+
                 // Verify signature
-                if (!VerifySignature(txPrev, *this, i))
+                if (!VerifySignature(txPrev, *this, i, nSigOpsRet, fStrictOpEval))
                     return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
+            }
 
             // Check for conflicts (double-spend)
             // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
@@ -965,7 +1073,8 @@
                 return false;
 
             // Verify signature
-            if (!VerifySignature(txPrev, *this, i))
+            int nUnused = 0;
+            if (!VerifySignature(txPrev, *this, i, nUnused, false))
                 return error("ConnectInputs() : VerifySignature failed");
 
             ///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of
@@ -1023,14 +1132,21 @@
 
     map<uint256, CTxIndex> mapQueuedChanges;
     int64 nFees = 0;
+    int nSigOps = 0;
     BOOST_FOREACH(CTransaction& tx, vtx)
     {
         CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
         nTxPos += ::GetSerializeSize(tx, SER_DISK);
 
-        if (!tx.ConnectInputs(txdb, mapQueuedChanges, posThisTx, pindex, nFees, true, false))
+        map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
+        if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs))
+            return false;
+        if (!tx.ConnectInputs(mapInputs, mapQueuedChanges, posThisTx, pindex, nFees, true, false, nSigOps))
             return false;
+        if (nSigOps > MAX_BLOCK_SIGOPS)
+            return DoS(100, error("ConnectBlock() : too many sigops"));
     }
+
     // Write queued txindex changes
     for (map<uint256, CTxIndex>::iterator mi = mapQueuedChanges.begin(); mi != mapQueuedChanges.end(); ++mi)
     {
@@ -1291,8 +1407,21 @@
         if (!tx.CheckTransaction())
             return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
 
-    // Check that it's not full of nonstandard transactions
-    if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
+    // This code should be removed when a compatibility-breaking block chain split has passed.
+    // Compatibility check for old clients that counted sigops differently:
+    int nSigOps = 0;
+    BOOST_FOREACH(const CTransaction& tx, vtx)
+    {
+        BOOST_FOREACH(const CTxIn& txin, tx.vin)
+        {
+            nSigOps += txin.scriptSig.GetSigOpCount();
+        }
+        BOOST_FOREACH(const CTxOut& txout, tx.vout)
+        {
+            nSigOps += txout.scriptPubKey.GetSigOpCount();
+        }
+    }
+    if (nSigOps > MAX_BLOCK_SIGOPS)
         return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
 
     // Check merkleroot
@@ -2827,9 +2956,6 @@
             unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
             if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
                 continue;
-            int nTxSigOps = tx.GetSigOpCount();
-            if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
-                continue;
 
             // Transaction fee required depends on block size
             bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority));
@@ -2838,7 +2964,13 @@
             // Connecting shouldn't fail due to dependency on other memory pool transactions
             // because we're already processing them in order of dependency
             map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
-            if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee))
+            map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
+            if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs))
+                continue;
+            int nTxSigOps = 0;
+            if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nTxSigOps, nMinFee))
+                continue;
+            if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
                 continue;
             swap(mapTestPool, mapTestPoolTmp);
 
@@ -2887,6 +3019,13 @@
     }
     ++nExtraNonce;
     pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nTime << CBigNum(nExtraNonce);
+
+    // Put "OP_EVAL" in the coinbase so everybody can tell when
+    // a majority of miners support it
+    const char* pOpEvalName = GetOpName(OP_EVAL);
+    pblock->vtx[0].vin[0].scriptSig += CScript() << std::vector<unsigned char>(pOpEvalName, pOpEvalName+strlen(pOpEvalName));
+    assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
+
     pblock->hashMerkleRoot = pblock->BuildMerkleTree();
 }
 
--- a/src/main.h
+++ b/src/main.h
@@ -493,26 +493,8 @@
         return (vin.size() == 1 && vin[0].prevout.IsNull());
     }
 
-    int GetSigOpCount() const
-    {
-        int n = 0;
-        BOOST_FOREACH(const CTxIn& txin, vin)
-            n += txin.scriptSig.GetSigOpCount();
-        BOOST_FOREACH(const CTxOut& txout, vout)
-            n += txout.scriptPubKey.GetSigOpCount();
-        return n;
-    }
-
-    bool IsStandard() const
-    {
-        BOOST_FOREACH(const CTxIn& txin, vin)
-            if (!txin.scriptSig.IsPushOnly())
-                return error("nonstandard txin: %s", txin.scriptSig.ToString().c_str());
-        BOOST_FOREACH(const CTxOut& txout, vout)
-            if (!::IsStandard(txout.scriptPubKey))
-                return error("nonstandard txout: %s", txout.scriptPubKey.ToString().c_str());
-        return true;
-    }
+    bool IsStandard() const;
+    bool AreInputsStandard(std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs) const;
 
     int64 GetValueOut() const
     {
@@ -640,8 +622,13 @@
     bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
     bool ReadFromDisk(COutPoint prevout);
     bool DisconnectInputs(CTxDB& txdb);
-    bool ConnectInputs(CTxDB& txdb, std::map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
-                       CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
+
+    // Fetch from memory and/or disk. inputsRet keys are transaction hashes.
+    bool FetchInputs(CTxDB& txdb, const std::map<uint256, CTxIndex>& mapTestPool,
+                     bool fBlock, bool fMiner, std::map<uint256, std::pair<CTxIndex, CTransaction> >& inputsRet);
+    bool ConnectInputs(std::map<uint256, std::pair<CTxIndex, CTransaction> > inputs,
+                       std::map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
+                       CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64 nMinFee=0);
     bool ClientConnectInputs();
     bool CheckTransaction() const;
     bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
@@ -851,13 +838,6 @@
         return (int64)nTime;
     }
 
-    int GetSigOpCount() const
-    {
-        int n = 0;
-        BOOST_FOREACH(const CTransaction& tx, vtx)
-            n += tx.GetSigOpCount();
-        return n;
-    }
 
 
     uint256 BuildMerkleTree() const
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -10,6 +10,7 @@
 DEPSDIR=/opt/local
 
 INCLUDEPATHS= \
+ -I"$(CURDIR)" \
  -I"$(DEPSDIR)/include" \
  -I"$(DEPSDIR)/include/db48"
 
@@ -112,6 +113,8 @@
 bitcoind: $(OBJS:obj/%=obj/nogui/%)
 	$(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
 
+TESTOBJS := $(patsubst test/%.cpp,obj/test/%.o,$(wildcard test/*.cpp))
+
 obj/test/%.o: test/%.cpp
 	$(CXX) -c $(CFLAGS) -MMD -o $@ $<
 	@cp $(@:%.o=%.d) $(@:%.o=%.P); \
@@ -119,7 +122,7 @@
 	      -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
 	  rm -f $(@:%.o=%.d)
 
-test_bitcoin: obj/test/test_bitcoin.o $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%))
+test_bitcoin: $(TESTOBJS) $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%))
 	$(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) $(DEPSDIR)/lib/libboost_unit_test_framework-mt.a
 
 clean:
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -6,7 +6,7 @@
 
 DEFS=-DNOPCH
 
-DEFS += $(addprefix -I,$(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
+DEFS += $(addprefix -I,$(CURDIR) $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
 LIBS += $(addprefix -l,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
 
 LMODE = dynamic
@@ -141,6 +141,8 @@
 bitcoind: $(OBJS:obj/%=obj/nogui/%)
 	$(CXX) $(xCXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
 
+TESTOBJS := $(patsubst test/%.cpp,obj/test/%.o,$(wildcard test/*.cpp))
+
 obj/test/%.o: test/%.cpp
 	$(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
 	@cp $(@:%.o=%.d) $(@:%.o=%.P); \
@@ -148,7 +150,7 @@
 	      -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
 	  rm -f $(@:%.o=%.d)
 
-test_bitcoin: obj/test/test_bitcoin.o $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%))
+test_bitcoin: $(TESTOBJS) $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%))
 	$(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LDFLAGS) $(LIBS)
 
 clean:
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -70,20 +70,186 @@
 }
 
 
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType)
+const char* GetTxnOutputType(txnouttype t)
+{
+    switch (t)
+    {
+    case TX_NONSTANDARD: return "nonstandard";
+    case TX_PUBKEY: return "pubkey";
+    case TX_PUBKEYHASH: return "pubkeyhash";
+    case TX_SCRIPTHASH: return "scripthash";
+    case TX_MULTISIG: return "multisig";
+    }
+    return NULL;
+}
+
+
+const char* GetOpName(opcodetype opcode)
+{
+    switch (opcode)
+    {
+    // push value
+    case OP_0                      : return "0";
+    case OP_PUSHDATA1              : return "OP_PUSHDATA1";
+    case OP_PUSHDATA2              : return "OP_PUSHDATA2";
+    case OP_PUSHDATA4              : return "OP_PUSHDATA4";
+    case OP_1NEGATE                : return "-1";
+    case OP_RESERVED               : return "OP_RESERVED";
+    case OP_1                      : return "1";
+    case OP_2                      : return "2";
+    case OP_3                      : return "3";
+    case OP_4                      : return "4";
+    case OP_5                      : return "5";
+    case OP_6                      : return "6";
+    case OP_7                      : return "7";
+    case OP_8                      : return "8";
+    case OP_9                      : return "9";
+    case OP_10                     : return "10";
+    case OP_11                     : return "11";
+    case OP_12                     : return "12";
+    case OP_13                     : return "13";
+    case OP_14                     : return "14";
+    case OP_15                     : return "15";
+    case OP_16                     : return "16";
+
+    // control
+    case OP_NOP                    : return "OP_NOP";
+    case OP_VER                    : return "OP_VER";
+    case OP_IF                     : return "OP_IF";
+    case OP_NOTIF                  : return "OP_NOTIF";
+    case OP_VERIF                  : return "OP_VERIF";
+    case OP_VERNOTIF               : return "OP_VERNOTIF";
+    case OP_ELSE                   : return "OP_ELSE";
+    case OP_ENDIF                  : return "OP_ENDIF";
+    case OP_VERIFY                 : return "OP_VERIFY";
+    case OP_RETURN                 : return "OP_RETURN";
+
+    // stack ops
+    case OP_TOALTSTACK             : return "OP_TOALTSTACK";
+    case OP_FROMALTSTACK           : return "OP_FROMALTSTACK";
+    case OP_2DROP                  : return "OP_2DROP";
+    case OP_2DUP                   : return "OP_2DUP";
+    case OP_3DUP                   : return "OP_3DUP";
+    case OP_2OVER                  : return "OP_2OVER";
+    case OP_2ROT                   : return "OP_2ROT";
+    case OP_2SWAP                  : return "OP_2SWAP";
+    case OP_IFDUP                  : return "OP_IFDUP";
+    case OP_DEPTH                  : return "OP_DEPTH";
+    case OP_DROP                   : return "OP_DROP";
+    case OP_DUP                    : return "OP_DUP";
+    case OP_NIP                    : return "OP_NIP";
+    case OP_OVER                   : return "OP_OVER";
+    case OP_PICK                   : return "OP_PICK";
+    case OP_ROLL                   : return "OP_ROLL";
+    case OP_ROT                    : return "OP_ROT";
+    case OP_SWAP                   : return "OP_SWAP";
+    case OP_TUCK                   : return "OP_TUCK";
+
+    // splice ops
+    case OP_CAT                    : return "OP_CAT";
+    case OP_SUBSTR                 : return "OP_SUBSTR";
+    case OP_LEFT                   : return "OP_LEFT";
+    case OP_RIGHT                  : return "OP_RIGHT";
+    case OP_SIZE                   : return "OP_SIZE";
+
+    // bit logic
+    case OP_INVERT                 : return "OP_INVERT";
+    case OP_AND                    : return "OP_AND";
+    case OP_OR                     : return "OP_OR";
+    case OP_XOR                    : return "OP_XOR";
+    case OP_EQUAL                  : return "OP_EQUAL";
+    case OP_EQUALVERIFY            : return "OP_EQUALVERIFY";
+    case OP_RESERVED1              : return "OP_RESERVED1";
+    case OP_RESERVED2              : return "OP_RESERVED2";
+
+    // numeric
+    case OP_1ADD                   : return "OP_1ADD";
+    case OP_1SUB                   : return "OP_1SUB";
+    case OP_2MUL                   : return "OP_2MUL";
+    case OP_2DIV                   : return "OP_2DIV";
+    case OP_NEGATE                 : return "OP_NEGATE";
+    case OP_ABS                    : return "OP_ABS";
+    case OP_NOT                    : return "OP_NOT";
+    case OP_0NOTEQUAL              : return "OP_0NOTEQUAL";
+    case OP_ADD                    : return "OP_ADD";
+    case OP_SUB                    : return "OP_SUB";
+    case OP_MUL                    : return "OP_MUL";
+    case OP_DIV                    : return "OP_DIV";
+    case OP_MOD                    : return "OP_MOD";
+    case OP_LSHIFT                 : return "OP_LSHIFT";
+    case OP_RSHIFT                 : return "OP_RSHIFT";
+    case OP_BOOLAND                : return "OP_BOOLAND";
+    case OP_BOOLOR                 : return "OP_BOOLOR";
+    case OP_NUMEQUAL               : return "OP_NUMEQUAL";
+    case OP_NUMEQUALVERIFY         : return "OP_NUMEQUALVERIFY";
+    case OP_NUMNOTEQUAL            : return "OP_NUMNOTEQUAL";
+    case OP_LESSTHAN               : return "OP_LESSTHAN";
+    case OP_GREATERTHAN            : return "OP_GREATERTHAN";
+    case OP_LESSTHANOREQUAL        : return "OP_LESSTHANOREQUAL";
+    case OP_GREATERTHANOREQUAL     : return "OP_GREATERTHANOREQUAL";
+    case OP_MIN                    : return "OP_MIN";
+    case OP_MAX                    : return "OP_MAX";
+    case OP_WITHIN                 : return "OP_WITHIN";
+
+    // crypto
+    case OP_RIPEMD160              : return "OP_RIPEMD160";
+    case OP_SHA1                   : return "OP_SHA1";
+    case OP_SHA256                 : return "OP_SHA256";
+    case OP_HASH160                : return "OP_HASH160";
+    case OP_HASH256                : return "OP_HASH256";
+    case OP_CODESEPARATOR          : return "OP_CODESEPARATOR";
+    case OP_CHECKSIG               : return "OP_CHECKSIG";
+    case OP_CHECKSIGVERIFY         : return "OP_CHECKSIGVERIFY";
+    case OP_CHECKMULTISIG          : return "OP_CHECKMULTISIG";
+    case OP_CHECKMULTISIGVERIFY    : return "OP_CHECKMULTISIGVERIFY";
+
+    // meta
+    case OP_EVAL                   : return "OP_EVAL";
+
+    // expanson
+    case OP_NOP2                   : return "OP_NOP2";
+    case OP_NOP3                   : return "OP_NOP3";
+    case OP_NOP4                   : return "OP_NOP4";
+    case OP_NOP5                   : return "OP_NOP5";
+    case OP_NOP6                   : return "OP_NOP6";
+    case OP_NOP7                   : return "OP_NOP7";
+    case OP_NOP8                   : return "OP_NOP8";
+    case OP_NOP9                   : return "OP_NOP9";
+    case OP_NOP10                  : return "OP_NOP10";
+
+
+
+    // template matching params
+    case OP_SCRIPTHASH             : return "OP_SCRIPTHASH";
+    case OP_PUBKEYHASH             : return "OP_PUBKEYHASH";
+    case OP_PUBKEY                 : return "OP_PUBKEY";
+
+    case OP_INVALIDOPCODE          : return "OP_INVALIDOPCODE";
+    default:
+        return "OP_UNKNOWN";
+    }
+}
+
+//
+// Returns true if script is valid.
+//
+bool EvalScriptInner(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType,
+                     CScript::const_iterator pbegincodehash, CScript::const_iterator pendcodehash, int& nOpCount, int& nSigOpCount,
+                     bool fStrictOpEval, int nRecurseDepth)
 {
     CAutoBN_CTX pctx;
     CScript::const_iterator pc = script.begin();
     CScript::const_iterator pend = script.end();
-    CScript::const_iterator pbegincodehash = script.begin();
     opcodetype opcode;
     valtype vchPushValue;
     vector<bool> vfExec;
     vector<valtype> altstack;
     if (script.size() > 10000)
         return false;
-    int nOpCount = 0;
 
+    // Limit OP_EVAL recursion
+    if (nRecurseDepth > 2)
+        return false;
 
     try
     {
@@ -155,7 +321,7 @@
                 // Control
                 //
                 case OP_NOP:
-                case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
+                case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
                 case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
                 break;
 
@@ -751,12 +917,13 @@
                     //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n");
 
                     // Subset of script starting at the most recent codeseparator
-                    CScript scriptCode(pbegincodehash, pend);
+                    CScript scriptCode(pbegincodehash, pendcodehash);
 
                     // Drop the signature, since there's no way for a signature to sign itself
                     scriptCode.FindAndDelete(CScript(vchSig));
 
                     bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType);
+                    nSigOpCount++;
 
                     popstack(stack);
                     popstack(stack);
@@ -800,7 +967,7 @@
                         return false;
 
                     // Subset of script starting at the most recent codeseparator
-                    CScript scriptCode(pbegincodehash, pend);
+                    CScript scriptCode(pbegincodehash, pendcodehash);
 
                     // Drop the signatures, since there's no way for a signature to sign itself
                     for (int k = 0; k < nSigsCount; k++)
@@ -823,6 +990,7 @@
                         }
                         ikey++;
                         nKeysCount--;
+                        nSigOpCount++;
 
                         // If there are more signatures left than keys left,
                         // then too many signatures have failed
@@ -844,6 +1012,32 @@
                 }
                 break;
 
+                case OP_EVAL:
+                {
+                    if (!fStrictOpEval)
+                        break; // Act as a NO_OP
+
+
+                    // Evaluate the top item on the stack as a Script
+                    // [serialized script ] -- [result(s) of executing script]
+                    if (stack.size() < 1)
+                        return false;
+                    valtype& vchScript = stacktop(-1);
+                    CScript subscript(vchScript.begin(), vchScript.end());
+                    popstack(stack);
+
+                    // Codeseparators not allowed; they don't make sense 'inside' an OP_EVAL, because
+                    // their purpose is to change which parts of the scriptPubKey script is copied
+                    // and signed by OP_CHECKSIG, but OP_EVAl'ed code is in the scriptSig, not the scriptPubKey.
+                    if (subscript.Find(OP_CODESEPARATOR))
+                        return false;
+
+                    if (!EvalScriptInner(stack, subscript, txTo, nIn, nHashType,
+                                         pbegincodehash, pendcodehash, nOpCount, nSigOpCount, fStrictOpEval, nRecurseDepth++))
+                        return false;
+                }
+                break;
+
                 default:
                     return false;
             }
@@ -865,6 +1059,18 @@
     return true;
 }
 
+bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script,
+                const CTransaction& txTo, unsigned int nIn, int nHashType,
+                bool fStrictOpEval, int& nSigOpCountRet)
+{
+    CScript::const_iterator pbegincodehash = script.begin();
+    CScript::const_iterator pendcodehash = script.end();
+
+    int nOpCount = 0;
+    return EvalScriptInner(stack, script, txTo, nIn, nHashType, pbegincodehash, pendcodehash,
+                           nOpCount, nSigOpCountRet, fStrictOpEval, 0);
+}
+
 
 
 
@@ -963,25 +1169,36 @@
 
 
 
-
-bool Solver(const CScript& scriptPubKey, vector<pair<opcodetype, valtype> >& vSolutionRet)
+//
+// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
+//
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
 {
     // Templates
-    static vector<CScript> vTemplates;
-    if (vTemplates.empty())
+    static map<txnouttype, CScript> mTemplates;
+    if (mTemplates.empty())
     {
         // Standard tx, sender provides pubkey, receiver adds signature
-        vTemplates.push_back(CScript() << OP_PUBKEY << OP_CHECKSIG);
+        mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
 
         // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
-        vTemplates.push_back(CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG);
+        mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
+
+        // Sender provides N pubkeys, receivers provides M signatures
+        mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+
+        // Sender provides script hash, receiver provides script and
+        // as many signatures as required to satisfy script
+        mTemplates.insert(make_pair(TX_SCRIPTHASH, CScript() << OP_DUP << OP_HASH160 << OP_SCRIPTHASH << OP_EQUALVERIFY << OP_EVAL));
     }
 
     // Scan templates
     const CScript& script1 = scriptPubKey;
-    BOOST_FOREACH(const CScript& script2, vTemplates)
+    BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
     {
-        vSolutionRet.clear();
+        const CScript& script2 = tplate.second;
+        vSolutionsRet.clear();
+
         opcodetype opcode1, opcode2;
         vector<unsigned char> vch1, vch2;
 
@@ -993,170 +1210,318 @@
             if (pc1 == script1.end() && pc2 == script2.end())
             {
                 // Found a match
-                reverse(vSolutionRet.begin(), vSolutionRet.end());
+                typeRet = tplate.first;
+                if (typeRet == TX_MULTISIG)
+                {
+                    // Additional checks for TX_MULTISIG:
+                    unsigned char m = vSolutionsRet.front()[0];
+                    unsigned char n = vSolutionsRet.back()[0];
+                    if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
+                        return false;
+                }
                 return true;
             }
             if (!script1.GetOp(pc1, opcode1, vch1))
                 break;
             if (!script2.GetOp(pc2, opcode2, vch2))
                 break;
+
+            // Template matching opcodes:
+            if (opcode2 == OP_PUBKEYS)
+            {
+                while (vch1.size() >= 33 && vch1.size() <= 120)
+                {
+                    vSolutionsRet.push_back(vch1);
+                    if (!script1.GetOp(pc1, opcode1, vch1))
+                        break;
+                }
+                if (!script2.GetOp(pc2, opcode2, vch2))
+                    break;
+                // Normal situation is to fall through
+                // to other if/else statments
+            }
+
             if (opcode2 == OP_PUBKEY)
             {
                 if (vch1.size() < 33 || vch1.size() > 120)
                     break;
-                vSolutionRet.push_back(make_pair(opcode2, vch1));
+                vSolutionsRet.push_back(vch1);
             }
             else if (opcode2 == OP_PUBKEYHASH)
             {
                 if (vch1.size() != sizeof(uint160))
                     break;
-                vSolutionRet.push_back(make_pair(opcode2, vch1));
+                vSolutionsRet.push_back(vch1);
+            }
+            else if (opcode2 == OP_SCRIPTHASH)
+            {
+                if (vch1.size() != sizeof(uint160))
+                    break;
+                vSolutionsRet.push_back(vch1);
+            }
+            else if (opcode2 == OP_SMALLINTEGER)
+            {   // Single-byte small integer pushed onto vSolutions
+                if (opcode1 == OP_0 ||
+                    (opcode1 >= OP_1 && opcode1 <= OP_16))
+                {
+                    char n = (char)CScript::DecodeOP_N(opcode1);
+                    vSolutionsRet.push_back(valtype(1, n));
+                }
+                else
+                    break;
             }
             else if (opcode1 != opcode2 || vch1 != vch2)
             {
+                // Others must match exactly
                 break;
             }
         }
     }
 
-    vSolutionRet.clear();
+    vSolutionsRet.clear();
+    typeRet = TX_NONSTANDARD;
     return false;
 }
 
 
+bool Sign1(const CBitcoinAddress& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+{
+    CKey key;
+    if (!keystore.GetKey(address, key))
+        return false;
+
+    vector<unsigned char> vchSig;
+    if (!key.Sign(hash, vchSig))
+        return false;
+    vchSig.push_back((unsigned char)nHashType);
+    scriptSigRet << vchSig;
+
+    return true;
+}
+
+bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+{
+    int nSigned = 0;
+    int nRequired = multisigdata.front()[0];
+    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))
+        {
+            ++nSigned;
+            if (nSigned == nRequired) break;
+        }
+    }
+    return nSigned==nRequired;
+}
+
+//
+// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
+// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed).
+// Returns true if scriptPubKey could be completely satisified.
+//
 bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet)
 {
     scriptSigRet.clear();
 
-    vector<pair<opcodetype, valtype> > vSolution;
-    if (!Solver(scriptPubKey, vSolution))
+    txnouttype whichType;
+    vector<valtype> vSolutions;
+    if (!Solver(scriptPubKey, whichType, vSolutions))
         return false;
 
-    // Compile solution
-    BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+    CBitcoinAddress address;
+    CScript subscript;
+    switch (whichType)
     {
-        if (item.first == OP_PUBKEY)
-        {
-            // Sign
-            const valtype& vchPubKey = item.second;
-            CKey key;
-            if (!keystore.GetKey(Hash160(vchPubKey), key))
-                return false;
-            if (key.GetPubKey() != vchPubKey)
-                return false;
-            if (hash != 0)
-            {
-                vector<unsigned char> vchSig;
-                if (!key.Sign(hash, vchSig))
-                    return false;
-                vchSig.push_back((unsigned char)nHashType);
-                scriptSigRet << vchSig;
-            }
-        }
-        else if (item.first == OP_PUBKEYHASH)
-        {
-            // Sign and give pubkey
-            CKey key;
-            if (!keystore.GetKey(uint160(item.second), key))
-                return false;
-            if (hash != 0)
-            {
-                vector<unsigned char> vchSig;
-                if (!key.Sign(hash, vchSig))
-                    return false;
-                vchSig.push_back((unsigned char)nHashType);
-                scriptSigRet << vchSig << key.GetPubKey();
-            }
-        }
+    case TX_NONSTANDARD:
+        return false;
+    case TX_PUBKEY:
+        address.SetPubKey(vSolutions[0]);
+        return Sign1(address, keystore, hash, nHashType, scriptSigRet);
+    case TX_PUBKEYHASH:
+        address.SetHash160(uint160(vSolutions[0]));
+        if (!Sign1(address, keystore, hash, nHashType, scriptSigRet))
+            return false;
         else
         {
-            return false;
+            valtype vch;
+            keystore.GetPubKey(address, vch);
+            scriptSigRet << vch;
         }
+        break;
+    case TX_SCRIPTHASH:
+        if (!keystore.GetCScript(uint160(vSolutions[0]), subscript))
+            return false;
+        if (!Solver(keystore, subscript, hash, nHashType, scriptSigRet))
+            return false;
+        if (hash != 0)
+            // static_cast to get vector.operator<< instead of CScript.operator<<
+            scriptSigRet << static_cast<valtype>(subscript); // signatures AND serialized script
+        break;
+    case TX_MULTISIG:
+        scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
+        return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
     }
-
     return true;
 }
 
 
 bool IsStandard(const CScript& scriptPubKey)
 {
-    vector<pair<opcodetype, valtype> > vSolution;
-    return Solver(scriptPubKey, vSolution);
+    vector<valtype> vSolutions;
+    txnouttype whichType;
+    if (!Solver(scriptPubKey, whichType, vSolutions))
+        return false;
+
+    if (whichType == TX_MULTISIG)
+    {
+        unsigned char m = vSolutions.front()[0];
+        unsigned char n = vSolutions.back()[0];
+        // Support up to x-of-3 multisig txns as standard
+        if (n < 1 || n > 3)
+            return false;
+        if (m < 1 || m > n)
+            return false;
+    }
+
+    return whichType != TX_NONSTANDARD;
 }
 
 
+int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
+{
+    int nResult = 0;
+    BOOST_FOREACH(const valtype& pubkey, pubkeys)
+    {
+        CBitcoinAddress address;
+        address.SetPubKey(pubkey);
+        if (keystore.HaveKey(address))
+            ++nResult;
+    }
+    return nResult;
+}
+
 bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
 {
-    vector<pair<opcodetype, valtype> > vSolution;
-    if (!Solver(scriptPubKey, vSolution))
+    vector<valtype> vSolutions;
+    txnouttype whichType;
+    if (!Solver(scriptPubKey, whichType, vSolutions))
+        return false;
+
+    CBitcoinAddress address;
+    switch (whichType)
+    {
+    case TX_NONSTANDARD:
+        return false;
+    case TX_PUBKEY:
+        address.SetPubKey(vSolutions[0]);
+        return keystore.HaveKey(address);
+    case TX_PUBKEYHASH:
+        address.SetHash160(uint160(vSolutions[0]));
+        return keystore.HaveKey(address);
+    case TX_SCRIPTHASH:
+    {
+        CScript subscript;
+        if (!keystore.GetCScript(uint160(vSolutions[0]), subscript))
+            return false;
+        return IsMine(keystore, subscript);
+    }
+    case TX_MULTISIG:
+    {
+        // Only consider transactions "mine" if we own ALL the
+        // keys involved. multi-signature transactions that are
+        // partially owned (somebody else has a key that can spend
+        // them) enable spend-out-from-under-you attacks, especially
+        // in shared-wallet situations.
+        vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
+        return HaveKeys(vSolutions, keystore);
+    }
+    }
+    return false;
+}
+
+bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
+{
+    vector<valtype> vSolutions;
+    txnouttype whichType;
+    if (!Solver(scriptPubKey, whichType, vSolutions))
         return false;
 
-    // Compile solution
-    BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+    if (whichType == TX_PUBKEY)
+    {
+        addressRet.SetPubKey(vSolutions[0]);
+        return true;
+    }
+    else if (whichType == TX_PUBKEYHASH)
+    {
+        addressRet.SetHash160(uint160(vSolutions[0]));
+        return true;
+    }
+    else if (whichType == TX_SCRIPTHASH)
     {
-        if (item.first == OP_PUBKEY)
+        addressRet.SetScriptHash160(uint160(vSolutions[0]));
+        return true;
+    }
+    // Multisig txns have more than one address...
+    return false;
+}
+
+bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* keystore, txnouttype& typeRet, vector<CBitcoinAddress>& addressRet, int& nRequiredRet)
+{
+    addressRet.clear();
+    typeRet = TX_NONSTANDARD;
+    vector<valtype> vSolutions;
+    if (!Solver(scriptPubKey, typeRet, vSolutions))
+        return false;
+
+    if (typeRet == TX_MULTISIG)
+    {
+        nRequiredRet = vSolutions.front()[0];
+        int n = vSolutions.back()[0];
+        for (int i = 1; i < vSolutions.size()-1; i++)
         {
-            const valtype& vchPubKey = item.second;
-            vector<unsigned char> vchPubKeyFound;
-            if (!keystore.GetPubKey(Hash160(vchPubKey), vchPubKeyFound))
-                return false;
-            if (vchPubKeyFound != vchPubKey)
-                return false;
+            CBitcoinAddress address;
+            address.SetPubKey(vSolutions[i]);
+            addressRet.push_back(address);
         }
-        else if (item.first == OP_PUBKEYHASH)
-        {
-            if (!keystore.HaveKey(uint160(item.second)))
-                return false;
-        }
-        else
-        {
-            return false;
-        }
+    }
+    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());
+        addressRet.push_back(address);
     }
 
     return true;
 }
 
-bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
-{
-    vector<pair<opcodetype, valtype> > vSolution;
-    if (!Solver(scriptPubKey, vSolution))
-        return false;
-
-    BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
-    {
-        if (item.first == OP_PUBKEY)
-            addressRet.SetPubKey(item.second);
-        else if (item.first == OP_PUBKEYHASH)
-            addressRet.SetHash160((uint160)item.second);
-        if (keystore == NULL || keystore->HaveKey(addressRet))
-            return true;
-    }
-
-    return false;
-}
-
-
-bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
-{
-    if (keystore)
-        return ExtractAddressInner(scriptPubKey, keystore, addressRet);
-    else
-        return ExtractAddressInner(scriptPubKey, NULL, addressRet);
-    return false;
-}
-
-
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType)
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOpCountRet,
+                  int nHashType, bool fStrictOpEval)
 {
     vector<vector<unsigned char> > stack;
-    if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType))
+    if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType, fStrictOpEval, nSigOpCountRet))
         return false;
-    if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType))
+    if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType, fStrictOpEval, nSigOpCountRet))
         return false;
     if (stack.empty())
         return false;
-    return CastToBool(stack.back());
+    bool fResult = CastToBool(stack.back());
+
+    // This code should be removed when a compatibility-breaking block chain split has passed.
+    // Special check for OP_EVAL backwards-compatibility: if scriptPubKey or scriptSig contains
+    // OP_EVAL, then result must be identical if OP_EVAL is treated as a no-op:
+    if (fResult && fStrictOpEval && (scriptPubKey.Find(OP_EVAL) || scriptSig.Find(OP_EVAL)))
+        return VerifyScript(scriptSig, scriptPubKey, txTo, nIn, nSigOpCountRet, nHashType, false);
+
+    return fResult;
 }
 
 
@@ -1177,15 +1542,16 @@
     txin.scriptSig = scriptPrereq + txin.scriptSig;
 
     // Test solution
+    int nUnused = 0;
     if (scriptPrereq.empty())
-        if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, 0))
+        if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nUnused, 0, true))
             return false;
 
     return true;
 }
 
 
-bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType)
+bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int& nSigOpCountRet, int nHashType, bool fStrictOpEval)
 {
     assert(nIn < txTo.vin.size());
     const CTxIn& txin = txTo.vin[nIn];
@@ -1196,8 +1562,35 @@
     if (txin.prevout.hash != txFrom.GetHash())
         return false;
 
-    if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nHashType))
+    if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nSigOpCountRet, nHashType, fStrictOpEval))
         return false;
 
     return true;
 }
+
+void CScript::SetBitcoinAddress(const CBitcoinAddress& address)
+{
+    this->clear();
+    if (address.IsScript())
+        *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_EVAL;
+    else
+        *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_CHECKSIG;
+}
+
+void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
+{
+    this->clear();
+
+    *this << EncodeOP_N(nRequired);
+    BOOST_FOREACH(const CKey& key, keys)
+        *this << key.GetPubKey();
+    *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
+}
+
+void CScript::SetEval(const CScript& subscript)
+{
+    assert(!subscript.empty());
+    uint160 subscriptHash = Hash160(subscript);
+    this->clear();
+    *this << OP_DUP << OP_HASH160 << subscriptHash << OP_EQUALVERIFY << OP_EVAL;
+}
--- a/src/script.h
+++ b/src/script.h
@@ -6,7 +6,6 @@
 #define H_BITCOIN_SCRIPT
 
 #include "base58.h"
-#include "keystore.h"
 
 #include <string>
 #include <vector>
@@ -14,6 +13,7 @@
 #include <boost/foreach.hpp>
 
 class CTransaction;
+class CKeyStore;
 
 enum
 {
@@ -24,6 +24,17 @@
 };
 
 
+enum txnouttype
+{
+    TX_NONSTANDARD,
+    // 'standard' transaction types:
+    TX_PUBKEY,
+    TX_PUBKEYHASH,
+    TX_SCRIPTHASH,
+    TX_MULTISIG,
+};
+
+const char* GetTxnOutputType(txnouttype t);
 
 enum opcodetype
 {
@@ -147,8 +158,10 @@
     OP_CHECKMULTISIG,
     OP_CHECKMULTISIGVERIFY,
 
+    // meta
+    OP_EVAL, // Was OP_NOP1
+
     // expansion
-    OP_NOP1,
     OP_NOP2,
     OP_NOP3,
     OP_NOP4,
@@ -162,162 +175,16 @@
 
 
     // template matching params
+    OP_SMALLINTEGER = 0xfa,
+    OP_PUBKEYS = 0xfb,
+    OP_SCRIPTHASH = 0xfc,
     OP_PUBKEYHASH = 0xfd,
     OP_PUBKEY = 0xfe,
 
     OP_INVALIDOPCODE = 0xff,
 };
 
-
-
-
-
-
-
-
-inline const char* GetOpName(opcodetype opcode)
-{
-    switch (opcode)
-    {
-    // push value
-    case OP_0                      : return "0";
-    case OP_PUSHDATA1              : return "OP_PUSHDATA1";
-    case OP_PUSHDATA2              : return "OP_PUSHDATA2";
-    case OP_PUSHDATA4              : return "OP_PUSHDATA4";
-    case OP_1NEGATE                : return "-1";
-    case OP_RESERVED               : return "OP_RESERVED";
-    case OP_1                      : return "1";
-    case OP_2                      : return "2";
-    case OP_3                      : return "3";
-    case OP_4                      : return "4";
-    case OP_5                      : return "5";
-    case OP_6                      : return "6";
-    case OP_7                      : return "7";
-    case OP_8                      : return "8";
-    case OP_9                      : return "9";
-    case OP_10                     : return "10";
-    case OP_11                     : return "11";
-    case OP_12                     : return "12";
-    case OP_13                     : return "13";
-    case OP_14                     : return "14";
-    case OP_15                     : return "15";
-    case OP_16                     : return "16";
-
-    // control
-    case OP_NOP                    : return "OP_NOP";
-    case OP_VER                    : return "OP_VER";
-    case OP_IF                     : return "OP_IF";
-    case OP_NOTIF                  : return "OP_NOTIF";
-    case OP_VERIF                  : return "OP_VERIF";
-    case OP_VERNOTIF               : return "OP_VERNOTIF";
-    case OP_ELSE                   : return "OP_ELSE";
-    case OP_ENDIF                  : return "OP_ENDIF";
-    case OP_VERIFY                 : return "OP_VERIFY";
-    case OP_RETURN                 : return "OP_RETURN";
-
-    // stack ops
-    case OP_TOALTSTACK             : return "OP_TOALTSTACK";
-    case OP_FROMALTSTACK           : return "OP_FROMALTSTACK";
-    case OP_2DROP                  : return "OP_2DROP";
-    case OP_2DUP                   : return "OP_2DUP";
-    case OP_3DUP                   : return "OP_3DUP";
-    case OP_2OVER                  : return "OP_2OVER";
-    case OP_2ROT                   : return "OP_2ROT";
-    case OP_2SWAP                  : return "OP_2SWAP";
-    case OP_IFDUP                  : return "OP_IFDUP";
-    case OP_DEPTH                  : return "OP_DEPTH";
-    case OP_DROP                   : return "OP_DROP";
-    case OP_DUP                    : return "OP_DUP";
-    case OP_NIP                    : return "OP_NIP";
-    case OP_OVER                   : return "OP_OVER";
-    case OP_PICK                   : return "OP_PICK";
-    case OP_ROLL                   : return "OP_ROLL";
-    case OP_ROT                    : return "OP_ROT";
-    case OP_SWAP                   : return "OP_SWAP";
-    case OP_TUCK                   : return "OP_TUCK";
-
-    // splice ops
-    case OP_CAT                    : return "OP_CAT";
-    case OP_SUBSTR                 : return "OP_SUBSTR";
-    case OP_LEFT                   : return "OP_LEFT";
-    case OP_RIGHT                  : return "OP_RIGHT";
-    case OP_SIZE                   : return "OP_SIZE";
-
-    // bit logic
-    case OP_INVERT                 : return "OP_INVERT";
-    case OP_AND                    : return "OP_AND";
-    case OP_OR                     : return "OP_OR";
-    case OP_XOR                    : return "OP_XOR";
-    case OP_EQUAL                  : return "OP_EQUAL";
-    case OP_EQUALVERIFY            : return "OP_EQUALVERIFY";
-    case OP_RESERVED1              : return "OP_RESERVED1";
-    case OP_RESERVED2              : return "OP_RESERVED2";
-
-    // numeric
-    case OP_1ADD                   : return "OP_1ADD";
-    case OP_1SUB                   : return "OP_1SUB";
-    case OP_2MUL                   : return "OP_2MUL";
-    case OP_2DIV                   : return "OP_2DIV";
-    case OP_NEGATE                 : return "OP_NEGATE";
-    case OP_ABS                    : return "OP_ABS";
-    case OP_NOT                    : return "OP_NOT";
-    case OP_0NOTEQUAL              : return "OP_0NOTEQUAL";
-    case OP_ADD                    : return "OP_ADD";
-    case OP_SUB                    : return "OP_SUB";
-    case OP_MUL                    : return "OP_MUL";
-    case OP_DIV                    : return "OP_DIV";
-    case OP_MOD                    : return "OP_MOD";
-    case OP_LSHIFT                 : return "OP_LSHIFT";
-    case OP_RSHIFT                 : return "OP_RSHIFT";
-    case OP_BOOLAND                : return "OP_BOOLAND";
-    case OP_BOOLOR                 : return "OP_BOOLOR";
-    case OP_NUMEQUAL               : return "OP_NUMEQUAL";
-    case OP_NUMEQUALVERIFY         : return "OP_NUMEQUALVERIFY";
-    case OP_NUMNOTEQUAL            : return "OP_NUMNOTEQUAL";
-    case OP_LESSTHAN               : return "OP_LESSTHAN";
-    case OP_GREATERTHAN            : return "OP_GREATERTHAN";
-    case OP_LESSTHANOREQUAL        : return "OP_LESSTHANOREQUAL";
-    case OP_GREATERTHANOREQUAL     : return "OP_GREATERTHANOREQUAL";
-    case OP_MIN                    : return "OP_MIN";
-    case OP_MAX                    : return "OP_MAX";
-    case OP_WITHIN                 : return "OP_WITHIN";
-
-    // crypto
-    case OP_RIPEMD160              : return "OP_RIPEMD160";
-    case OP_SHA1                   : return "OP_SHA1";
-    case OP_SHA256                 : return "OP_SHA256";
-    case OP_HASH160                : return "OP_HASH160";
-    case OP_HASH256                : return "OP_HASH256";
-    case OP_CODESEPARATOR          : return "OP_CODESEPARATOR";
-    case OP_CHECKSIG               : return "OP_CHECKSIG";
-    case OP_CHECKSIGVERIFY         : return "OP_CHECKSIGVERIFY";
-    case OP_CHECKMULTISIG          : return "OP_CHECKMULTISIG";
-    case OP_CHECKMULTISIGVERIFY    : return "OP_CHECKMULTISIGVERIFY";
-
-    // expanson
-    case OP_NOP1                   : return "OP_NOP1";
-    case OP_NOP2                   : return "OP_NOP2";
-    case OP_NOP3                   : return "OP_NOP3";
-    case OP_NOP4                   : return "OP_NOP4";
-    case OP_NOP5                   : return "OP_NOP5";
-    case OP_NOP6                   : return "OP_NOP6";
-    case OP_NOP7                   : return "OP_NOP7";
-    case OP_NOP8                   : return "OP_NOP8";
-    case OP_NOP9                   : return "OP_NOP9";
-    case OP_NOP10                  : return "OP_NOP10";
-
-
-
-    // template matching params
-    case OP_PUBKEYHASH             : return "OP_PUBKEYHASH";
-    case OP_PUBKEY                 : return "OP_PUBKEY";
-
-    case OP_INVALIDOPCODE          : return "OP_INVALIDOPCODE";
-    default:
-        return "OP_UNKNOWN";
-    }
-};
-
+const char* GetOpName(opcodetype opcode);
 
 
 
@@ -574,22 +441,52 @@
         return true;
     }
 
-
-    void FindAndDelete(const CScript& b)
+    // Encode/decode small integers:
+    static int DecodeOP_N(opcodetype opcode)
+    {
+        if (opcode == OP_0)
+            return 0;
+        assert(opcode >= OP_1 && opcode <= OP_16);
+        return (int)opcode - (int)(OP_1 - 1);
+    }
+    static opcodetype EncodeOP_N(int n)
     {
+        assert(n >= 0 && n <= 16);
+        if (n == 0)
+            return OP_0;
+        return (opcodetype)(OP_1+n-1);
+    }
+
+    int FindAndDelete(const CScript& b)
+    {
+        int nFound = 0;
         if (b.empty())
-            return;
+            return nFound;
         iterator pc = begin();
         opcodetype opcode;
         do
         {
             while (end() - pc >= b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
+            {
                 erase(pc, pc + b.size());
+                ++nFound;
+            }
         }
         while (GetOp(pc, opcode));
+        return nFound;
+    }
+    int Find(opcodetype op) const
+    {
+        int nFound = 0;
+        opcodetype opcode;
+        for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);)
+            if (opcode == op)
+                ++nFound;
+        return nFound;
     }
 
-
+    // This method should be removed when a compatibility-breaking block chain split has passed.
+    // Compatibility method for old clients that count sigops differently:
     int GetSigOpCount() const
     {
         int n = 0;
@@ -607,11 +504,9 @@
         return n;
     }
 
-
+    // Called by CTransaction::IsStandard
     bool IsPushOnly() const
     {
-        if (size() > 200)
-            return false;
         const_iterator pc = begin();
         while (pc < end())
         {
@@ -625,31 +520,13 @@
     }
 
 
-    CBitcoinAddress GetBitcoinAddress() const
-    {
-        opcodetype opcode;
-        std::vector<unsigned char> vch;
-        CScript::const_iterator pc = begin();
-        if (!GetOp(pc, opcode, vch) || opcode != OP_DUP) return 0;
-        if (!GetOp(pc, opcode, vch) || opcode != OP_HASH160) return 0;
-        if (!GetOp(pc, opcode, vch) || vch.size() != sizeof(uint160)) return 0;
-        uint160 hash160 = uint160(vch);
-        if (!GetOp(pc, opcode, vch) || opcode != OP_EQUALVERIFY) return 0;
-        if (!GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG) return 0;
-        if (pc != end()) return 0;
-        return CBitcoinAddress(hash160);
-    }
-
-    void SetBitcoinAddress(const CBitcoinAddress& address)
-    {
-        this->clear();
-        *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_CHECKSIG;
-    }
-
+    void SetBitcoinAddress(const CBitcoinAddress& address);
     void SetBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
     {
         SetBitcoinAddress(CBitcoinAddress(vchPubKey));
     }
+    void SetMultisig(int nRequired, const std::vector<CKey>& keys);
+    void SetEval(const CScript& subscript);
 
 
     void PrintHex() const
@@ -690,14 +567,14 @@
 
 
 
-
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType, bool fStrictOpEval, int& nSigOpCountRet);
 
-bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType);
-
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
 bool IsStandard(const CScript& scriptPubKey);
 bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
 bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* pkeystore, CBitcoinAddress& addressRet);
+bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* pkeystore, txnouttype& typeRet, std::vector<CBitcoinAddress>& addressRet, int& nRequiredRet);
 bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript());
-bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType=0);
+bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int& nSigOpCountRet, int nHashType=0, bool fStrictOpEval=true);
 
 #endif
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -5,9 +5,10 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/foreach.hpp>
 
-#include "../main.h"
-#include "../net.h"
-#include "../util.h"
+#include "main.h"
+#include "wallet.h"
+#include "net.h"
+#include "util.h"
 
 using namespace std;
 
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -1,6 +1,8 @@
 #include <boost/test/unit_test.hpp>
 
-#include "../util.h"
+#include "main.h"
+#include "wallet.h"
+#include "util.h"
 
 BOOST_AUTO_TEST_SUITE(base58_tests)
 
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -1,18 +1,20 @@
 #include <boost/test/unit_test.hpp>
 
-#include "../util.h"
+#include "main.h"
+#include "wallet.h"
+#include "util.h"
 
 BOOST_AUTO_TEST_SUITE(base64_tests)
 
 BOOST_AUTO_TEST_CASE(base64_testvectors)
 {
-    static const string vstrIn[]  = {"","f","fo","foo","foob","fooba","foobar"};
-    static const string vstrOut[] = {"","Zg==","Zm8=","Zm9v","Zm9vYg==","Zm9vYmE=","Zm9vYmFy"};
+    static const std::string vstrIn[]  = {"","f","fo","foo","foob","fooba","foobar"};
+    static const std::string vstrOut[] = {"","Zg==","Zm8=","Zm9v","Zm9vYg==","Zm9vYmE=","Zm9vYmFy"};
     for (int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
     {
-        string strEnc = EncodeBase64(vstrIn[i]);
+        std::string strEnc = EncodeBase64(vstrIn[i]);
         BOOST_CHECK(strEnc == vstrOut[i]);
-        string strDec = DecodeBase64(strEnc);
+        std::string strDec = DecodeBase64(strEnc);
         BOOST_CHECK(strDec == vstrIn[i]);
     }
 }
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -1,6 +1,6 @@
 #include <boost/test/unit_test.hpp>
 
-#include "../uint256.h"
+#include "uint256.h"
 
 extern void SHA256Transform(void* pstate, void* pinput, const void* pinit);
 
new file mode 100644
--- /dev/null
+++ b/src/test/multisig_tests.cpp
@@ -0,0 +1,294 @@
+#include <boost/assert.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/assign/list_inserter.hpp>
+#include <boost/assign/std/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#include <openssl/ec.h>
+#include <openssl/err.h>
+
+#include "keystore.h"
+#include "main.h"
+#include "script.h"
+#include "wallet.h"
+
+using namespace std;
+using namespace boost::assign;
+
+typedef vector<unsigned char> valtype;
+
+extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOpCount,
+                         int nHashType, bool fStrictOpEval);
+
+BOOST_AUTO_TEST_SUITE(multisig_tests)
+
+CScript
+sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn)
+{
+    uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL);
+
+    CScript result;
+    result << OP_0; // CHECKMULTISIG bug workaround
+    BOOST_FOREACH(CKey key, keys)
+    {
+        vector<unsigned char> vchSig;
+        BOOST_CHECK(key.Sign(hash, vchSig));
+        vchSig.push_back((unsigned char)SIGHASH_ALL);
+        result << vchSig;
+    }
+    return result;
+}
+
+BOOST_AUTO_TEST_CASE(multisig_verify)
+{
+    CKey key[4];
+    for (int i = 0; i < 4; i++)
+        key[i].MakeNewKey();
+
+    CScript a_and_b;
+    a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+
+    CScript a_or_b;
+    a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+
+    CScript escrow;
+    escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+
+    CTransaction txFrom;  // Funding transaction
+    txFrom.vout.resize(3);
+    txFrom.vout[0].scriptPubKey = a_and_b;
+    txFrom.vout[1].scriptPubKey = a_or_b;
+    txFrom.vout[2].scriptPubKey = escrow;
+
+    CTransaction txTo[3]; // Spending transaction
+    for (int i = 0; i < 3; i++)
+    {
+        txTo[i].vin.resize(1);
+        txTo[i].vout.resize(1);
+        txTo[i].vin[0].prevout.n = i;
+        txTo[i].vin[0].prevout.hash = txFrom.GetHash();
+        txTo[i].vout[0].nValue = 1;
+    }
+
+    vector<CKey> keys;
+    CScript s;
+    int nUnused = 0;
+
+    // Test a AND b:
+    keys.clear();
+    keys += key[0],key[1]; // magic operator+= from boost.assign
+    s = sign_multisig(a_and_b, keys, txTo[0], 0);
+    BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, nUnused, 0, true));
+
+    for (int i = 0; i < 4; i++)
+    {
+        keys.clear();
+        keys += key[i];
+        s = sign_multisig(a_and_b, keys, txTo[0], 0);
+        BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, nUnused, 0, true), strprintf("a&b 1: %d", i));
+
+        keys.clear();
+        keys += key[1],key[i];
+        s = sign_multisig(a_and_b, keys, txTo[0], 0);
+        BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, nUnused, 0, true), strprintf("a&b 2: %d", i));
+    }
+
+    // Test a OR b:
+    for (int i = 0; i < 4; i++)
+    {
+        keys.clear();
+        keys += key[i];
+        s = sign_multisig(a_or_b, keys, txTo[1], 0);
+        if (i == 0 || i == 1)
+            BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true), strprintf("a|b: %d", i));
+        else
+            BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true), strprintf("a|b: %d", i));
+    }
+    s.clear();
+    s << OP_0 << OP_0;
+    BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true));
+    s.clear();
+    s << OP_0 << OP_1;
+    BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true));
+
+
+    for (int i = 0; i < 4; i++)
+        for (int j = 0; j < 4; j++)
+        {
+            keys.clear();
+            keys += key[i],key[j];
+            s = sign_multisig(escrow, keys, txTo[2], 0);
+            if (i < j && i < 3 && j < 3)
+                BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, nUnused, 0, true), strprintf("escrow 1: %d %d", i, j));
+            else
+                BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, nUnused, 0, true), strprintf("escrow 2: %d %d", i, j));
+        }
+}
+
+BOOST_AUTO_TEST_CASE(multisig_IsStandard)
+{
+    CKey key[4];
+    for (int i = 0; i < 4; i++)
+        key[i].MakeNewKey();
+
+    CScript a_and_b;
+    a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+    BOOST_CHECK(::IsStandard(a_and_b));
+
+    CScript a_or_b;
+    a_or_b  << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+    BOOST_CHECK(::IsStandard(a_or_b));
+
+    CScript escrow;
+    escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+    BOOST_CHECK(::IsStandard(escrow));
+
+    CScript one_of_four;
+    one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG;
+    BOOST_CHECK(!::IsStandard(one_of_four));
+
+    CScript malformed[6];
+    malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+    malformed[1] << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+    malformed[2] << OP_0 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+    malformed[3] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_0 << OP_CHECKMULTISIG;
+    malformed[4] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_CHECKMULTISIG;
+    malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey();
+
+    for (int i = 0; i < 6; i++)
+        BOOST_CHECK(!::IsStandard(malformed[i]));
+}
+
+BOOST_AUTO_TEST_CASE(multisig_Solver1)
+{
+    // Tests Solver() that returns lists of keys that are
+    // required to satisfy a ScriptPubKey
+    //
+    // Also tests IsMine() and ExtractAddress()
+    //
+    // Note: ExtractAddress for the multisignature transactions
+    // always returns false for this release, even if you have
+    // one key that would satisfy an (a|b) or 2-of-3 keys needed
+    // to spend an escrow transaction.
+    //
+    CBasicKeyStore keystore, emptykeystore;
+    CKey key[3];
+    CBitcoinAddress keyaddr[3];
+    for (int i = 0; i < 3; i++)
+    {
+        key[i].MakeNewKey();
+        keystore.AddKey(key[i]);
+        keyaddr[i].SetPubKey(key[i].GetPubKey());
+    }
+
+    {
+        vector<valtype> solutions;
+        txnouttype whichType;
+        CScript s;
+        s << key[0].GetPubKey() << OP_CHECKSIG;
+        BOOST_CHECK(Solver(s, whichType, solutions));
+        BOOST_CHECK(solutions.size() == 1);
+        CBitcoinAddress addr;
+        BOOST_CHECK(ExtractAddress(s, &keystore, addr));
+        BOOST_CHECK(addr == keyaddr[0]);
+        BOOST_CHECK(IsMine(keystore, s));
+        BOOST_CHECK(!IsMine(emptykeystore, s));
+    }
+    {
+        vector<valtype> solutions;
+        txnouttype whichType;
+        CScript s;
+        s << OP_DUP << OP_HASH160 << Hash160(key[0].GetPubKey()) << OP_EQUALVERIFY << OP_CHECKSIG;
+        BOOST_CHECK(Solver(s, whichType, solutions));
+        BOOST_CHECK(solutions.size() == 1);
+        CBitcoinAddress addr;
+        BOOST_CHECK(ExtractAddress(s, &keystore, addr));
+        BOOST_CHECK(addr == keyaddr[0]);
+        BOOST_CHECK(IsMine(keystore, s));
+        BOOST_CHECK(!IsMine(emptykeystore, s));
+    }
+    {
+        vector<valtype> solutions;
+        txnouttype whichType;
+        CScript s;
+        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, &keystore, addr));
+        BOOST_CHECK(IsMine(keystore, s));
+        BOOST_CHECK(!IsMine(emptykeystore, s));
+    }
+    {
+        vector<valtype> solutions;
+        txnouttype whichType;
+        CScript s;
+        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;
+        int nRequired;
+        BOOST_CHECK(ExtractAddresses(s, &keystore, whichType, addrs, nRequired));
+        BOOST_CHECK(addrs[0] == keyaddr[0]);
+        BOOST_CHECK(addrs[1] == keyaddr[1]);
+        BOOST_CHECK(nRequired = 1);
+        BOOST_CHECK(IsMine(keystore, s));
+        BOOST_CHECK(!IsMine(emptykeystore, s));
+    }
+    {
+        vector<valtype> solutions;
+        txnouttype whichType;
+        CScript s;
+        s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+        BOOST_CHECK(Solver(s, whichType, solutions));
+        BOOST_CHECK(solutions.size() == 5);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(multisig_Sign)
+{
+    // Test SignSignature() (and therefore the version of Solver() that signs transactions)
+    CBasicKeyStore keystore;
+    CKey key[4];
+    for (int i = 0; i < 4; i++)
+    {
+        key[i].MakeNewKey();
+        keystore.AddKey(key[i]);
+    }
+
+    CScript a_and_b;
+    a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+
+    CScript a_or_b;
+    a_or_b  << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+
+    CScript escrow;
+    escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+
+    CTransaction txFrom;  // Funding transaction
+    txFrom.vout.resize(3);
+    txFrom.vout[0].scriptPubKey = a_and_b;
+    txFrom.vout[1].scriptPubKey = a_or_b;
+    txFrom.vout[2].scriptPubKey = escrow;
+
+    CTransaction txTo[3]; // Spending transaction
+    for (int i = 0; i < 3; i++)
+    {
+        txTo[i].vin.resize(1);
+        txTo[i].vout.resize(1);
+        txTo[i].vin[0].prevout.n = i;
+        txTo[i].vin[0].prevout.hash = txFrom.GetHash();
+        txTo[i].vout[0].nValue = 1;
+    }
+
+    for (int i = 0; i < 3; i++)
+    {
+        BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
+    }
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
new file mode 100644
--- /dev/null
+++ b/src/test/script_op_eval_tests.cpp
@@ -0,0 +1,234 @@
+#include <boost/assert.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/assign/list_inserter.hpp>
+#include <boost/assign/std/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+
+#include "../main.h"
+#include "../script.h"
+#include "../wallet.h"
+
+using namespace std;
+
+// Test routines internal to script.cpp:
+extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOps,
+                         int nHashType, bool fStrictOpEval);
+
+BOOST_AUTO_TEST_SUITE(script_op_eval_tests)
+
+BOOST_AUTO_TEST_CASE(script_op_eval1)
+{
+    // OP_EVAL looks like this:
+    // scriptSig:    <sig> <sig...> <serialized_script>
+    // scriptPubKey: DUP HASH160 <hash> EQUALVERIFY EVAL
+
+    // Test SignSignature() (and therefore the version of Solver() that signs transactions)
+    CBasicKeyStore keystore;
+    CKey key[4];
+    for (int i = 0; i < 4; i++)
+    {
+        key[i].MakeNewKey();
+        keystore.AddKey(key[i]);
+    }
+
+    // 8 Scripts: checking all combinations of
+    // different keys, straight/EVAL, pubkey/pubkeyhash
+    CScript standardScripts[4];
+    standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG;
+    standardScripts[1].SetBitcoinAddress(key[1].GetPubKey());
+    standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG;
+    standardScripts[3].SetBitcoinAddress(key[2].GetPubKey());
+    CScript evalScripts[4];
+    uint160 sigScriptHashes[4];
+    for (int i = 0; i < 4; i++)
+    {
+        sigScriptHashes[i] = Hash160(standardScripts[i]);
+        keystore.AddCScript(sigScriptHashes[i], standardScripts[i]);
+        evalScripts[i] << OP_DUP << OP_HASH160 << sigScriptHashes[i] << OP_EQUALVERIFY << OP_EVAL;
+    }
+
+    CTransaction txFrom;  // Funding transaction:
+    txFrom.vout.resize(8);
+    for (int i = 0; i < 4; i++)
+    {
+        txFrom.vout[i].scriptPubKey = evalScripts[i];
+        txFrom.vout[i+4].scriptPubKey = standardScripts[i];
+    }
+    BOOST_CHECK(txFrom.IsStandard());
+
+    CTransaction txTo[8]; // Spending transactions
+    for (int i = 0; i < 8; i++)
+    {
+        txTo[i].vin.resize(1);
+        txTo[i].vout.resize(1);
+        txTo[i].vin[0].prevout.n = i;
+        txTo[i].vin[0].prevout.hash = txFrom.GetHash();
+        txTo[i].vout[0].nValue = 1;
+        BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
+    }
+    for (int i = 0; i < 8; i++)
+    {
+        BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
+    }
+    // All of the above should be OK, and the txTos have valid signatures
+    // Check to make sure signature verification fails if we use the wrong ScriptSig:
+    for (int i = 0; i < 8; i++)
+        for (int j = 0; j < 8; j++)
+        {
+            CScript sigSave = txTo[i].vin[0].scriptSig;
+            txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
+            int nUnused = 0;
+            bool sigOK = VerifySignature(txFrom, txTo[i], 0, nUnused);
+            if (i == j)
+                BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
+            else
+                BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
+            txTo[i].vin[0].scriptSig = sigSave;
+        }
+}
+
+BOOST_AUTO_TEST_CASE(script_op_eval2)
+{
+    // Test OP_EVAL edge cases
+
+    CScript recurse;
+    recurse << OP_DUP << OP_EVAL;
+
+    uint160 recurseHash = Hash160(recurse);
+
+    CScript fund;
+    fund << OP_DUP << OP_HASH160 << recurseHash << OP_EQUALVERIFY << OP_EVAL;
+
+    CTransaction txFrom;  // Funding transaction:
+    txFrom.vout.resize(1);
+    txFrom.vout[0].scriptPubKey = fund;
+
+    BOOST_CHECK(txFrom.IsStandard()); // Looks like a standard transaction until you try to spend it
+
+    CTransaction txTo;
+    txTo.vin.resize(1);
+    txTo.vout.resize(1);
+    txTo.vin[0].prevout.n = 0;
+    txTo.vin[0].prevout.hash = txFrom.GetHash();
+    txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(recurse);
+    txTo.vout[0].nValue = 1;
+
+    int nUnused = 0;
+    BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, true));
+    BOOST_CHECK(!VerifySignature(txFrom, txTo, 0, nUnused, true));
+}
+
+BOOST_AUTO_TEST_CASE(script_op_eval3)
+{
+    // Test the CScript::Set* methods
+    CBasicKeyStore keystore;
+    CKey key[4];
+    std::vector<CKey> keys;
+    for (int i = 0; i < 4; i++)
+    {
+        key[i].MakeNewKey();
+        keystore.AddKey(key[i]);
+        keys.push_back(key[i]);
+    }
+
+    CScript inner[4];
+    inner[0].SetBitcoinAddress(key[0].GetPubKey());
+    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));
+
+    CScript outer[4];
+    for (int i = 0; i < 4; i++)
+    {
+        outer[i].SetEval(inner[i]);
+        keystore.AddCScript(Hash160(inner[i]), inner[i]);
+    }
+
+    CTransaction txFrom;  // Funding transaction:
+    txFrom.vout.resize(4);
+    for (int i = 0; i < 4; i++)
+    {
+        txFrom.vout[i].scriptPubKey = outer[i];
+    }
+    BOOST_CHECK(txFrom.IsStandard());
+
+    CTransaction txTo[4]; // Spending transactions
+    for (int i = 0; i < 4; i++)
+    {
+        txTo[i].vin.resize(1);
+        txTo[i].vout.resize(1);
+        txTo[i].vin[0].prevout.n = i;
+        txTo[i].vin[0].prevout.hash = txFrom.GetHash();
+        txTo[i].vout[0].nValue = 1;
+        txTo[i].vout[0].scriptPubKey = inner[i];
+        BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
+    }
+    for (int i = 0; i < 4; i++)
+    {
+        BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
+        BOOST_CHECK_MESSAGE(txTo[i].IsStandard(), strprintf("txTo[%d].IsStandard", i));
+    }
+}
+
+BOOST_AUTO_TEST_CASE(script_op_eval_backcompat1)
+{
+    // Check backwards-incompatibility-testing code
+    CScript returnsEleven;
+    returnsEleven << OP_11;
+
+    // This should validate on new clients, but will
+    // be invalid on old clients (that interpret OP_EVAL as a no-op)
+    //  ... except there's a special rule that makes new clients reject
+    // it.
+    CScript fund;
+    fund << OP_EVAL << OP_11 << OP_EQUAL;
+
+    CTransaction txFrom;  // Funding transaction:
+    txFrom.vout.resize(1);
+    txFrom.vout[0].scriptPubKey = fund;
+
+    CTransaction txTo;
+    txTo.vin.resize(1);
+    txTo.vout.resize(1);
+    txTo.vin[0].prevout.n = 0;
+    txTo.vin[0].prevout.hash = txFrom.GetHash();
+    txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(returnsEleven);
+    txTo.vout[0].nValue = 1;
+
+    int nUnused = 0;
+    BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, true));
+    BOOST_CHECK(!VerifySignature(txFrom, txTo, 0, nUnused, true));
+}
+
+BOOST_AUTO_TEST_CASE(script_op_eval_switchover)
+{
+    // Test OP_EVAL switchover code
+    CScript notValid;
+    notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
+
+    // This will be valid under old rules, invalid under new:
+    CScript fund;
+    fund << OP_EVAL;
+
+    CTransaction txFrom;  // Funding transaction:
+    txFrom.vout.resize(1);
+    txFrom.vout[0].scriptPubKey = fund;
+
+    CTransaction txTo;
+    txTo.vin.resize(1);
+    txTo.vout.resize(1);
+    txTo.vin[0].prevout.n = 0;
+    txTo.vin[0].prevout.hash = txFrom.GetHash();
+    txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(notValid);
+    txTo.vout[0].nValue = 1;
+
+    int nUnused = 0;
+    BOOST_CHECK(VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, false));
+
+    // Under strict op_eval switchover, it should be considered invalid:
+    BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, true));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -2,13 +2,13 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/foreach.hpp>
 
-#include "../main.h"
-#include "../wallet.h"
+#include "main.h"
+#include "wallet.h"
 
 using namespace std;
 extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
-extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType);
-extern bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType);
+extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOps,
+                         int nHashType, bool fStrictOpEval);
 
 BOOST_AUTO_TEST_SUITE(script_tests)
 
@@ -21,19 +21,21 @@
     static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a };
     static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a };
 
+    int nUnused = 0;
+
     vector<vector<unsigned char> > directStack;
-    BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0));
+    BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0, true, nUnused));
 
     vector<vector<unsigned char> > pushdata1Stack;
-    BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0));
+    BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0, true, nUnused));
     BOOST_CHECK(pushdata1Stack == directStack);
 
     vector<vector<unsigned char> > pushdata2Stack;
-    BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0));
+    BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0, true, nUnused));
     BOOST_CHECK(pushdata2Stack == directStack);
 
     vector<vector<unsigned char> > pushdata4Stack;
-    BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0));
+    BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0, true, nUnused));
     BOOST_CHECK(pushdata4Stack == directStack);
 }
 
@@ -71,6 +73,7 @@
 
 BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
 {
+    int nUnused = 0;
     CKey key1, key2, key3;
     key1.MakeNewKey();
     key2.MakeNewKey();
@@ -91,19 +94,20 @@
     txTo12.vout[0].nValue = 1;
 
     CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
-    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, 0));
+    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, nUnused, 0, true));
     txTo12.vout[0].nValue = 2;
-    BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, 0));
+    BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, nUnused, 0, true));
 
     CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
-    BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, 0));
+    BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, nUnused, 0, true));
 
     CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
-    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, 0));
+    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, nUnused, 0, true));
 }
 
 BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
 {
+    int nUnused = 0;
     CKey key1, key2, key3, key4;
     key1.MakeNewKey();
     key2.MakeNewKey();
@@ -127,46 +131,46 @@
     std::vector<CKey> keys;
     keys.push_back(key1); keys.push_back(key2);
     CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 
     keys.clear();
     keys.push_back(key1); keys.push_back(key3);
     CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 
     keys.clear();
     keys.push_back(key2); keys.push_back(key3);
     CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 
     keys.clear();
     keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
     CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 
     keys.clear();
     keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
     CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 
     keys.clear();
     keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
     CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 
     keys.clear();
     keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
     CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 
     keys.clear();
     keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
     CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 
     keys.clear(); // Must have signatures
     CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
-    BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, 0));
+    BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 }    
 
 
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -1,19 +1,18 @@
 #define BOOST_TEST_MODULE Bitcoin Test Suite
 #include <boost/test/unit_test.hpp>
 
-#include "../main.h"
-#include "../wallet.h"
+#include "main.h"
+#include "wallet.h"
 
-#include "uint160_tests.cpp"
-#include "uint256_tests.cpp"
-#include "script_tests.cpp"
-#include "transaction_tests.cpp"
-#include "DoS_tests.cpp"
-#include "base64_tests.cpp"
-#include "util_tests.cpp"
-#include "base58_tests.cpp"
-#include "miner_tests.cpp"
-#include "Checkpoints_tests.cpp"
+extern bool fPrintToConsole;
+struct TestingSetup {
+    TestingSetup() {
+        fPrintToConsole = true; // don't want to write to debug.log file
+    }
+    ~TestingSetup() { }
+};
+
+BOOST_GLOBAL_FIXTURE(TestingSetup);
 
 CWallet* pwalletMain;
 
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -1,7 +1,7 @@
 #include <boost/test/unit_test.hpp>
 
-#include "../main.h"
-#include "../wallet.h"
+#include "main.h"
+#include "wallet.h"
 
 using namespace std;
 
--- a/src/test/uint160_tests.cpp
+++ b/src/test/uint160_tests.cpp
@@ -1,6 +1,6 @@
 #include <boost/test/unit_test.hpp>
 
-#include "../uint256.h"
+#include "uint256.h"
 
 BOOST_AUTO_TEST_SUITE(uint160_tests)
 
--- a/src/test/uint256_tests.cpp
+++ b/src/test/uint256_tests.cpp
@@ -1,6 +1,6 @@
 #include <boost/test/unit_test.hpp>
 
-#include "../uint256.h"
+#include "uint256.h"
 
 BOOST_AUTO_TEST_SUITE(uint256_tests)
 
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -2,7 +2,9 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/foreach.hpp>
 
-#include "../util.h"
+#include "main.h"
+#include "wallet.h"
+#include "util.h"
 
 using namespace std;
 
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -42,6 +42,15 @@
     return false;
 }
 
+bool CWallet::AddCScript(const uint160 &hash, const CScript& redeemScript)
+{
+    if (!CCryptoKeyStore::AddCScript(hash, redeemScript))
+        return false;
+    if (!fFileBacked)
+        return true;
+    return CWalletDB(strWalletFile).WriteCScript(hash, redeemScript);
+}
+
 bool CWallet::Unlock(const SecureString& strWalletPassphrase)
 {
     if (!IsLocked())
@@ -374,6 +383,24 @@
     return 0;
 }
 
+bool CWallet::IsChange(const CTxOut& txout) const
+{
+    CBitcoinAddress 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
+    // is change. That assumption is likely to break when we implement multisignature
+    // wallets that return change back into a multi-signature-protected address;
+    // 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, this, address))
+        CRITICAL_BLOCK(cs_wallet)
+            if (!mapAddressBook.count(address))
+                return true;
+    return false;
+}
+
 int64 CWalletTx::GetTxTime() const
 {
     return nTimeReceived;
@@ -443,8 +470,7 @@
         nFee = nDebit - nValueOut;
     }
 
-    // Sent/received.  Standard client will never generate a send-to-multiple-recipients,
-    // but non-standard clients might (so return a list of address/amount pairs)
+    // Sent/received.
     BOOST_FOREACH(const CTxOut& txout, vout)
     {
         CBitcoinAddress address;
@@ -997,12 +1023,11 @@
                     vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
                     // assert(mapKeys.count(vchPubKey));
 
-                    // Fill a vout to ourself, using same address type as the payment
+                    // Fill a vout to ourself
+                    // TODO: pass in scriptChange instead of reservekey so
+                    // change transaction isn't always pay-to-bitcoin-address
                     CScript scriptChange;
-                    if (vecSend[0].first.GetBitcoinAddress().IsValid())
-                        scriptChange.SetBitcoinAddress(vchPubKey);
-                    else
-                        scriptChange << vchPubKey << OP_CHECKSIG;
+                    scriptChange.SetBitcoinAddress(vchPubKey);
 
                     // Insert change txn at random position:
                     vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -7,6 +7,7 @@
 
 #include "bignum.h"
 #include "key.h"
+#include "keystore.h"
 #include "script.h"
 
 class CWalletTx;
@@ -69,6 +70,8 @@
     bool AddCryptedKey(const std::vector<unsigned char> &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) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
+    bool AddCScript(const uint160& hash, const CScript& redeemScript);
+    bool LoadCScript(const uint160& hash, const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(hash, redeemScript); }
 
     bool Unlock(const SecureString& strWalletPassphrase);
     bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
@@ -114,15 +117,7 @@
             throw std::runtime_error("CWallet::GetCredit() : value out of range");
         return (IsMine(txout) ? txout.nValue : 0);
     }
-    bool IsChange(const CTxOut& txout) const
-    {
-        CBitcoinAddress address;
-        if (ExtractAddress(txout.scriptPubKey, this, address))
-            CRITICAL_BLOCK(cs_wallet)
-                if (!mapAddressBook.count(address))
-                    return true;
-        return false;
-    }
+    bool IsChange(const CTxOut& txout) const;
     int64 GetChange(const CTxOut& txout) const
     {
         if (!MoneyRange(txout.nValue))