Use block times for 'hard' OP_EVAL switchover, and refactored EvalScript
authorGavin Andresen <gavinandresen@gmail.com>
Tue, 8 Nov 2011 18:20:29 +0000 (13:20 -0500)
committerGavin Andresen <gavinandresen@gmail.com>
Mon, 19 Dec 2011 18:24:48 +0000 (13:24 -0500)
so it takes a flag for how to interpret OP_EVAL.
Also increased IsStandard size of scriptSigs to 500 bytes, so
a 3-of-3 multisig transaction IsStandard.

14 files changed:
src/bitcoinrpc.cpp
src/db.cpp
src/db.h
src/keystore.cpp
src/keystore.h
src/main.cpp
src/main.h
src/script.cpp
src/script.h
src/test/multisig_tests.cpp
src/test/script_op_eval_tests.cpp
src/test/script_tests.cpp
src/wallet.cpp
src/wallet.h

index 47fd983..1a1c991 100644 (file)
@@ -1674,10 +1674,10 @@ Value validateaddress(const Array& params, bool fHelp)
             pwalletMain->GetCScript(address.GetHash160(), subscript);
             ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
             std::vector<CBitcoinAddress> addresses;
-            txntype whichType;
+            txnouttype whichType;
             int nRequired;
             ExtractAddresses(subscript, pwalletMain, whichType, addresses, nRequired);
-            ret.push_back(Pair("script", GetTxnTypeName(whichType)));
+            ret.push_back(Pair("script", GetTxnOutputType(whichType)));
             Array a;
             BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
                 a.push_back(addr.ToString());
index 52ad695..f43b2a5 100644 (file)
@@ -938,7 +938,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
             {
                 uint160 hash;
                 ssKey >> hash;
-                std::vector<unsigned char> script;
+                CScript script;
                 ssValue >> script;
                 if (!pwallet->LoadCScript(hash, script))
                     return DB_CORRUPT;
index 99dd88b..e593ae2 100644 (file)
--- a/src/db.h
+++ b/src/db.h
 
 #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,16 +420,17 @@ public:
         return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
     }
 
-    bool ReadCScript(const uint160 &hash, std::vector<unsigned char>& data)
+    // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
+    bool ReadCScript(const uint160 &hash, CScript& redeemScript)
     {
-        data.clear();
-        return Read(std::make_pair(std::string("cscript"), hash), data);
+        redeemScript.clear();
+        return Read(std::make_pair(std::string("cscript"), hash), redeemScript);
     }
 
-    bool WriteCScript(const uint160& hash, const std::vector<unsigned char>& data)
+    bool WriteCScript(const uint160& hash, const CScript& redeemScript)
     {
         nWalletDBUpdated++;
-        return Write(std::make_pair(std::string("cscript"), hash), data, false);
+        return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
     }
 
     bool WriteBestBlock(const CBlockLocator& locator)
index c9b9b4a..21fb0f9 100644 (file)
@@ -4,8 +4,9 @@
 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
 
 #include "headers.h"
-#include "db.h"
 #include "crypter.h"
+#include "db.h"
+#include "script.h"
 
 std::vector<unsigned char> CKeyStore::GenerateNewKey()
 {
@@ -33,10 +34,10 @@ bool CBasicKeyStore::AddKey(const CKey& key)
     return true;
 }
 
-bool CBasicKeyStore::AddCScript(const uint160 &hash, const std::vector<unsigned char>& data)
+bool CBasicKeyStore::AddCScript(const uint160 &hash, const CScript& redeemScript)
 {
     CRITICAL_BLOCK(cs_KeyStore)
-        mapData[hash] = data;
+        mapScripts[hash] = redeemScript;
     return true;
 }
 
@@ -44,19 +45,19 @@ bool CBasicKeyStore::HaveCScript(const uint160& hash) const
 {
     bool result;
     CRITICAL_BLOCK(cs_KeyStore)
-        result = (mapData.count(hash) > 0);
+        result = (mapScripts.count(hash) > 0);
     return result;
 }
 
 
-bool CBasicKeyStore::GetCScript(const uint160 &hash, std::vector<unsigned char>& dataOut) const
+bool CBasicKeyStore::GetCScript(const uint160 &hash, CScript& redeemScriptOut) const
 {
     CRITICAL_BLOCK(cs_KeyStore)
     {
-        DataMap::const_iterator mi = mapData.find(hash);
-        if (mi != mapData.end())
+        ScriptMap::const_iterator mi = mapScripts.find(hash);
+        if (mi != mapScripts.end())
         {
-            dataOut = (*mi).second;
+            redeemScriptOut = (*mi).second;
             return true;
         }
     }
index 942fb9a..669bf90 100644 (file)
@@ -6,6 +6,7 @@
 #define BITCOIN_KEYSTORE_H
 
 #include "crypter.h"
+#include "script.h"
 
 // A virtual base class for key stores
 class CKeyStore
@@ -31,9 +32,10 @@ public:
     virtual void GetKeys(std::set<CBitcoinAddress> &setAddress) const =0;
     virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
 
-    virtual bool AddCScript(const uint160 &hash, const std::vector<unsigned char>& data) =0;
+    // 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, std::vector<unsigned char>& dataOut) 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();
@@ -48,14 +50,14 @@ public:
 };
 
 typedef std::map<CBitcoinAddress, CSecret> KeyMap;
-typedef std::map<uint160, std::vector<unsigned char> > DataMap;
+typedef std::map<uint160, CScript > ScriptMap;
 
 // Basic key store, that keeps keys in an address->secret map
 class CBasicKeyStore : public CKeyStore
 {
 protected:
     KeyMap mapKeys;
-    DataMap mapData;
+    ScriptMap mapScripts;
 
 public:
     bool AddKey(const CKey& key);
@@ -92,9 +94,9 @@ public:
         }
         return false;
     }
-    virtual bool AddCScript(const uint160 &hash, const std::vector<unsigned char>& data);
+    virtual bool AddCScript(const uint160 &hash, const CScript& redeemScript);
     virtual bool HaveCScript(const uint160 &hash) const;
-    virtual bool GetCScript(const uint160 &hash, std::vector<unsigned char>& dataOut) 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;
index 1b5bf52..81dd76f 100644 (file)
@@ -250,13 +250,13 @@ bool CTransaction::IsStandard() const
 {
     BOOST_FOREACH(const CTxIn& txin, vin)
     {
-        // Biggest 'standard' txin is a 2-signature 2-of-3 escrow
-        // in an OP_EVAL, which is 2 ~80-byte signatures, 3
+        // 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() > 400)
-            return error("nonstandard txin, size %d\n", txin.scriptSig.size());
+        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: %s", txin.scriptSig.ToString().c_str());
+            return error("nonstandard txin (opcodes other than PUSH): %s", txin.scriptSig.ToString().c_str());
     }
     BOOST_FOREACH(const CTxOut& txout, vout)
         if (!::IsStandard(txout.scriptPubKey))
@@ -275,7 +275,7 @@ bool CTransaction::IsStandard() const
 // expensive-to-check-upon-redemption script like:
 //   DUP CHECKSIG DROP ... repeated 100 times... OP_1
 //
-bool CTransaction::IsStandardInputs(std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs) const
+bool CTransaction::AreInputsStandard(std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs) const
 {
     if (fTestNet)
         return true; // Allow non-standard on testnet
@@ -287,18 +287,20 @@ bool CTransaction::IsStandardInputs(std::map<uint256, std::pair<CTxIndex, CTrans
         CTransaction& txPrev = mapInputs[prevout.hash].second;
 
         vector<vector<unsigned char> > vSolutions;
-        txntype whichType;
-        if (!Solver(txPrev.vout[vin[i].prevout.n].scriptPubKey, whichType, vSolutions))
-            return false;
+        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, nUnused))
-                return false;
-            const vector<unsigned char>& subscript = stack.back();
-            if (!::IsStandard(CScript(subscript.begin(), subscript.end())))
+            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());
         }
     }
 
@@ -481,7 +483,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
         }
 
         // Check for non-standard OP_EVALs in inputs
-        if (!IsStandardInputs(mapInputs))
+        if (!AreInputsStandard(mapInputs))
             return error("AcceptToMemoryPool() : nonstandard transaction input");
 
         // Check against previous transactions
@@ -978,9 +980,27 @@ bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inp
             // (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, nSigOpsRet))
+                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
@@ -1054,7 +1074,7 @@ bool CTransaction::ClientConnectInputs()
 
             // Verify signature
             int nUnused = 0;
-            if (!VerifySignature(txPrev, *this, i, nUnused))
+            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
index bf31234..26d14b0 100644 (file)
@@ -494,7 +494,7 @@ public:
     }
 
     bool IsStandard() const;
-    bool IsStandardInputs(std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs) const;
+    bool AreInputsStandard(std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs) const;
 
     int64 GetValueOut() const
     {
@@ -622,6 +622,8 @@ public:
     bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
     bool ReadFromDisk(COutPoint prevout);
     bool DisconnectInputs(CTxDB& txdb);
+
+    // 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,
index e603991..5487c01 100644 (file)
@@ -70,7 +70,7 @@ static inline void popstack(vector<valtype>& stack)
 }
 
 
-const char* GetTxnTypeName(txntype t)
+const char* GetTxnOutputType(txnouttype t)
 {
     switch (t)
     {
@@ -230,12 +230,12 @@ const char* GetOpName(opcodetype opcode)
     }
 }
 
-
 //
 // 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, int nRecurseDepth)
+                     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();
@@ -1014,17 +1014,9 @@ bool EvalScriptInner(vector<vector<unsigned char> >& stack, const CScript& scrip
 
                 case OP_EVAL:
                 {
-                    // This code should be removed when OP_EVAL has
-                    // a majority of hashing power on the network.
-                    // OP_EVAL behaves just like OP_NOP until
-                    // opevaltime :
-                    if (!fTestNet || fDebug)
-                    {
-                        // 1328054400 is Feb 1, 2012
-                        int64 nEvalSwitchTime = GetArg("opevaltime", 1328054400);
-                        if (GetTime() < nEvalSwitchTime)
-                            break;
-                    }
+                    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]
@@ -1034,12 +1026,14 @@ bool EvalScriptInner(vector<vector<unsigned char> >& stack, const CScript& scrip
                     CScript subscript(vchScript.begin(), vchScript.end());
                     popstack(stack);
                     
-                    // Codeseparators not allowed
+                    // 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, nRecurseDepth++))
+                                         pbegincodehash, pendcodehash, nOpCount, nSigOpCount, fStrictOpEval, nRecurseDepth++))
                         return false;
                 }
                 break;
@@ -1066,14 +1060,15 @@ bool EvalScriptInner(vector<vector<unsigned char> >& stack, const CScript& scrip
 }
 
 bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script,
-                const CTransaction& txTo, unsigned int nIn, int nHashType, int& nSigOpCountRet)
+                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, 0);
+                           nOpCount, nSigOpCountRet, fStrictOpEval, 0);
 }
 
 
@@ -1177,10 +1172,10 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc
 //
 // Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
 //
-bool Solver(const CScript& scriptPubKey, txntype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
 {
     // Templates
-    static map<txntype, CScript> mTemplates;
+    static map<txnouttype, CScript> mTemplates;
     if (mTemplates.empty())
     {
         // Standard tx, sender provides pubkey, receiver adds signature
@@ -1199,7 +1194,7 @@ bool Solver(const CScript& scriptPubKey, txntype& typeRet, vector<vector<unsigne
 
     // Scan templates
     const CScript& script1 = scriptPubKey;
-    BOOST_FOREACH(const PAIRTYPE(txntype, CScript)& tplate, mTemplates)
+    BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
     {
         const CScript& script2 = tplate.second;
         vSolutionsRet.clear();
@@ -1331,13 +1326,13 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
 {
     scriptSigRet.clear();
 
-    txntype whichType;
+    txnouttype whichType;
     vector<valtype> vSolutions;
     if (!Solver(scriptPubKey, whichType, vSolutions))
         return false;
 
     CBitcoinAddress address;
-    valtype subscript;
+    CScript subscript;
     switch (whichType)
     {
     case TX_NONSTANDARD:
@@ -1359,10 +1354,11 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
     case TX_SCRIPTHASH:
         if (!keystore.GetCScript(uint160(vSolutions[0]), subscript))
             return false;
-        if (!Solver(keystore, CScript(subscript.begin(), subscript.end()), hash, nHashType, scriptSigRet))
+        if (!Solver(keystore, subscript, hash, nHashType, scriptSigRet))
             return false;
         if (hash != 0)
-            scriptSigRet << subscript; // signatures AND serialized script
+            // 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
@@ -1375,7 +1371,7 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
 bool IsStandard(const CScript& scriptPubKey)
 {
     vector<valtype> vSolutions;
-    txntype whichType;
+    txnouttype whichType;
     if (!Solver(scriptPubKey, whichType, vSolutions))
         return false;
 
@@ -1410,7 +1406,7 @@ int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
 bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
 {
     vector<valtype> vSolutions;
-    txntype whichType;
+    txnouttype whichType;
     if (!Solver(scriptPubKey, whichType, vSolutions))
         return false;
 
@@ -1427,10 +1423,10 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
         return keystore.HaveKey(address);
     case TX_SCRIPTHASH:
     {
-        valtype subscript;
+        CScript subscript;
         if (!keystore.GetCScript(uint160(vSolutions[0]), subscript))
             return false;
-        return IsMine(keystore, CScript(subscript.begin(), subscript.end()));
+        return IsMine(keystore, subscript);
     }
     case TX_MULTISIG:
     {
@@ -1449,7 +1445,7 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
 bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
 {
     vector<valtype> vSolutions;
-    txntype whichType;
+    txnouttype whichType;
     if (!Solver(scriptPubKey, whichType, vSolutions))
         return false;
 
@@ -1472,7 +1468,7 @@ bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBit
     return false;
 }
 
-bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* keystore, txntype& typeRet, vector<CBitcoinAddress>& addressRet, int& nRequiredRet)
+bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* keystore, txnouttype& typeRet, vector<CBitcoinAddress>& addressRet, int& nRequiredRet)
 {
     addressRet.clear();
     typeRet = TX_NONSTANDARD;
@@ -1484,10 +1480,10 @@ bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* keystore, tx
     {
         nRequiredRet = vSolutions.front()[0];
         int n = vSolutions.back()[0];
-        for (vector<valtype>::const_iterator it = vSolutions.begin()+1; it != vSolutions.begin()+vSolutions.size()-1; it++)
+        for (int i = 1; i < vSolutions.size()-1; i++)
         {
             CBitcoinAddress address;
-            address.SetPubKey(*it);
+            address.SetPubKey(vSolutions[i]);
             addressRet.push_back(address);
         }
     }
@@ -1507,12 +1503,13 @@ bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* keystore, tx
     return true;
 }
 
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOpCountRet, 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, nSigOpCountRet))
+    if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType, fStrictOpEval, nSigOpCountRet))
         return false;
-    if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType, nSigOpCountRet))
+    if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType, fStrictOpEval, nSigOpCountRet))
         return false;
     if (stack.empty())
         return false;
@@ -1521,24 +1518,8 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
     // 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 (scriptSig.Find(OP_EVAL)+scriptPubKey.Find(OP_EVAL) > 0)
-    {
-        int nUnused = 0;
-        stack.clear();
-        CScript sigCopy = scriptSig;
-        sigCopy.FindAndDelete(CScript(OP_EVAL));
-        CScript pubKeyCopy = scriptPubKey;
-        pubKeyCopy.FindAndDelete(CScript(OP_EVAL));
-
-        if (!EvalScript(stack, sigCopy, txTo, nIn, nHashType, nUnused))
-            return false;
-        if (!EvalScript(stack, pubKeyCopy, txTo, nIn, nHashType, nUnused))
-            return false;
-        if (stack.empty())
-            return false;
-        if (fResult != CastToBool(stack.back()))
-            return false;
-    }
+    if (fResult && fStrictOpEval && (scriptPubKey.Find(OP_EVAL) || scriptSig.Find(OP_EVAL)))
+        return VerifyScript(scriptSig, scriptPubKey, txTo, nIn, nSigOpCountRet, nHashType, false);
 
     return fResult;
 }
@@ -1563,14 +1544,14 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans
     // Test solution
     int nUnused = 0;
     if (scriptPrereq.empty())
-        if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nUnused, 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& nSigOpCountRet, 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];
@@ -1581,7 +1562,7 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig
     if (txin.prevout.hash != txFrom.GetHash())
         return false;
 
-    if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nSigOpCountRet, nHashType))
+    if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nSigOpCountRet, nHashType, fStrictOpEval))
         return false;
 
     return true;
index ee0be02..b671e15 100644 (file)
@@ -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,7 +24,7 @@ enum
 };
 
 
-enum txntype
+enum txnouttype
 {
     TX_NONSTANDARD,
     // 'standard' transaction types:
@@ -34,7 +34,7 @@ enum txntype
     TX_MULTISIG,
 };
 
-const char* GetTxnTypeName(txntype t);
+const char* GetTxnOutputType(txnouttype t);
 
 enum opcodetype
 {
@@ -567,14 +567,14 @@ public:
 
 
 
-bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType, int& nSigOpCountRet);
+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 Solver(const CScript& scriptPubKey, txntype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+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, txntype& typeRet, std::vector<CBitcoinAddress>& addressRet, int& nRequiredRet);
+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& nSigOpCountRet, int nHashType=0);
+bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int& nSigOpCountRet, int nHashType=0, bool fStrictOpEval=true);
 
 #endif
index 75c764d..58f62b9 100644 (file)
@@ -20,7 +20,8 @@ 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);
+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)
 
@@ -80,19 +81,19 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
     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));
+    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), strprintf("a&b 1: %d", i));
+        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), strprintf("a&b 2: %d", i));
+        BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, nUnused, 0, true), strprintf("a&b 2: %d", i));
     }
 
     // Test a OR b:
@@ -102,16 +103,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
         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), strprintf("a|b: %d", i));
+            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), strprintf("a|b: %d", i));
+            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));
+    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));
+    BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true));
 
 
     for (int i = 0; i < 4; i++)
@@ -121,9 +122,9 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
             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), strprintf("escrow 1: %d %d", i, j));
+                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), strprintf("escrow 2: %d %d", i, j));
+                BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, nUnused, 0, true), strprintf("escrow 2: %d %d", i, j));
         }
 }
 
@@ -185,7 +186,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
 
     {
         vector<valtype> solutions;
-        txntype whichType;
+        txnouttype whichType;
         CScript s;
         s << key[0].GetPubKey() << OP_CHECKSIG;
         BOOST_CHECK(Solver(s, whichType, solutions));
@@ -198,7 +199,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
     }
     {
         vector<valtype> solutions;
-        txntype whichType;
+        txnouttype whichType;
         CScript s;
         s << OP_DUP << OP_HASH160 << Hash160(key[0].GetPubKey()) << OP_EQUALVERIFY << OP_CHECKSIG;
         BOOST_CHECK(Solver(s, whichType, solutions));
@@ -211,7 +212,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
     }
     {
         vector<valtype> solutions;
-        txntype whichType;
+        txnouttype whichType;
         CScript s;
         s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
         BOOST_CHECK(Solver(s, whichType, solutions));
@@ -223,7 +224,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
     }
     {
         vector<valtype> solutions;
-        txntype whichType;
+        txnouttype whichType;
         CScript s;
         s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
         BOOST_CHECK(Solver(s, whichType, solutions));
@@ -239,7 +240,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
     }
     {
         vector<valtype> solutions;
-        txntype whichType;
+        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));
index 6c683b5..c44642c 100644 (file)
@@ -13,24 +13,10 @@ 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);
+extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOps,
+                         int nHashType, bool fStrictOpEval);
 
-static const int64 nEvalSwitchover = 1328054400;
-
-struct CEvalFixture {
-    CEvalFixture()
-    {
-        // Set mock time to AFTER OP_EVAL deployed
-        SetMockTime(nEvalSwitchover+1);
-    }
-    ~CEvalFixture()
-    {
-        // Reset back to use-real-time
-        SetMockTime(0);
-    }
-};
-
-BOOST_FIXTURE_TEST_SUITE(script_op_eval_tests, CEvalFixture)
+BOOST_AUTO_TEST_SUITE(script_op_eval_tests)
 
 BOOST_AUTO_TEST_CASE(script_op_eval1)
 {
@@ -130,8 +116,8 @@ BOOST_AUTO_TEST_CASE(script_op_eval2)
     txTo.vout[0].nValue = 1;
 
     int nUnused = 0;
-    BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0));
-    BOOST_CHECK(!VerifySignature(txFrom, txTo, 0, nUnused));
+    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)
@@ -212,13 +198,13 @@ BOOST_AUTO_TEST_CASE(script_op_eval_backcompat1)
     txTo.vout[0].nValue = 1;
 
     int nUnused = 0;
-    BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0));
-    BOOST_CHECK(!VerifySignature(txFrom, txTo, 0, nUnused));
+    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)
 {
-    // Use SetMockTime to test OP_EVAL switchover code
+    // Test OP_EVAL switchover code
     CScript notValid;
     notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
 
@@ -238,14 +224,11 @@ BOOST_AUTO_TEST_CASE(script_op_eval_switchover)
     txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(notValid);
     txTo.vout[0].nValue = 1;
 
-    SetMockTime(nEvalSwitchover-1);
-
     int nUnused = 0;
-    BOOST_CHECK(VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0));
+    BOOST_CHECK(VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, false));
 
-    // After eval switchover time, it should validate:
-    SetMockTime(nEvalSwitchover);
-    BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0));
+    // 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()
index 3d1c218..22885a6 100644 (file)
@@ -7,8 +7,8 @@
 
 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& nSigOps, 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)
 
@@ -24,18 +24,18 @@ BOOST_AUTO_TEST_CASE(script_PushData)
     int nUnused = 0;
 
     vector<vector<unsigned char> > directStack;
-    BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0, nUnused));
+    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, nUnused));
+    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, nUnused));
+    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, nUnused));
+    BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0, true, nUnused));
     BOOST_CHECK(pushdata4Stack == directStack);
 }
 
@@ -94,15 +94,15 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
     txTo12.vout[0].nValue = 1;
 
     CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
-    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, nUnused, 0));
+    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, nUnused, 0, true));
     txTo12.vout[0].nValue = 2;
-    BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, nUnused, 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, nUnused, 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, nUnused, 0));
+    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, nUnused, 0, true));
 }
 
 BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
@@ -131,46 +131,46 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
     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, nUnused, 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, nUnused, 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, nUnused, 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, nUnused, 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, nUnused, 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, nUnused, 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, nUnused, 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, nUnused, 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, nUnused, 0));
+    BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, nUnused, 0, true));
 }    
 
 
index 5d44b1f..25eb624 100644 (file)
@@ -42,13 +42,13 @@ bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector
     return false;
 }
 
-bool CWallet::AddCScript(const uint160 &hash, const std::vector<unsigned char>& data)
+bool CWallet::AddCScript(const uint160 &hash, const CScript& redeemScript)
 {
-    if (!CCryptoKeyStore::AddCScript(hash, data))
+    if (!CCryptoKeyStore::AddCScript(hash, redeemScript))
         return false;
     if (!fFileBacked)
         return true;
-    return CWalletDB(strWalletFile).WriteCScript(hash, data);
+    return CWalletDB(strWalletFile).WriteCScript(hash, redeemScript);
 }
 
 bool CWallet::Unlock(const SecureString& strWalletPassphrase)
@@ -386,6 +386,14 @@ int64 CWallet::GetDebit(const CTxIn &txin) const
 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) && !address.IsScript())
         CRITICAL_BLOCK(cs_wallet)
             if (!mapAddressBook.count(address))
index 34090ec..a7d07c9 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "bignum.h"
 #include "key.h"
+#include "keystore.h"
 #include "script.h"
 
 class CWalletTx;
@@ -69,8 +70,8 @@ public:
     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 std::vector<unsigned char>& data);
-    bool LoadCScript(const uint160& hash, const std::vector<unsigned char>& data) { return CCryptoKeyStore::AddCScript(hash, data); }
+    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);