Update License in File Headers
[novacoin.git] / src / script.cpp
index b92f7b0..e7664d2 100644 (file)
@@ -1,6 +1,7 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2011 The Bitcoin developers
 // Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
 #include "headers.h"
 
 using namespace std;
@@ -1032,48 +1033,45 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
         return false;
 
     // Compile solution
-    CRITICAL_BLOCK(keystore.cs_KeyStore)
+    BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
     {
-        BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+        if (item.first == OP_PUBKEY)
         {
-            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)
             {
-                // Sign
-                const valtype& vchPubKey = item.second;
-                CKey key;
-                if (!keystore.GetKey(Hash160(vchPubKey), key))
-                    return false;
-                if (key.GetPubKey() != vchPubKey)
+                vector<unsigned char> vchSig;
+                if (!key.Sign(hash, vchSig))
                     return false;
-                if (hash != 0)
-                {
-                    vector<unsigned char> vchSig;
-                    if (!key.Sign(hash, vchSig))
-                        return false;
-                    vchSig.push_back((unsigned char)nHashType);
-                    scriptSigRet << vchSig;
-                }
+                vchSig.push_back((unsigned char)nHashType);
+                scriptSigRet << vchSig;
             }
-            else if (item.first == OP_PUBKEYHASH)
+        }
+        else if (item.first == OP_PUBKEYHASH)
+        {
+            // Sign and give pubkey
+            CKey key;
+            if (!keystore.GetKey(uint160(item.second), key))
+                return false;
+            if (hash != 0)
             {
-                // Sign and give pubkey
-                CKey key;
-                if (!keystore.GetKey(uint160(item.second), key))
+                vector<unsigned char> vchSig;
+                if (!key.Sign(hash, vchSig))
                     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();
-                }
-            }
-            else
-            {
-                return false;
+                vchSig.push_back((unsigned char)nHashType);
+                scriptSigRet << vchSig << key.GetPubKey();
             }
         }
+        else
+        {
+            return false;
+        }
     }
 
     return true;
@@ -1094,75 +1092,94 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
         return false;
 
     // Compile solution
-    CRITICAL_BLOCK(keystore.cs_KeyStore)
+    BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
     {
-        BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+        if (item.first == OP_PUBKEY)
         {
-            if (item.first == OP_PUBKEY)
-            {
-                const valtype& vchPubKey = item.second;
-                vector<unsigned char> vchPubKeyFound;
-                if (!keystore.GetPubKey(Hash160(vchPubKey), vchPubKeyFound))
-                    return false;
-                if (vchPubKeyFound != vchPubKey)
-                    return false;
-            }
-            else if (item.first == OP_PUBKEYHASH)
-            {
-                if (!keystore.HaveKey(uint160(item.second)))
-                    return false;
-            }
-            else
-            {
+            const valtype& vchPubKey = item.second;
+            vector<unsigned char> vchPubKeyFound;
+            if (!keystore.GetPubKey(Hash160(vchPubKey), vchPubKeyFound))
+                return false;
+            if (vchPubKeyFound != vchPubKey)
                 return false;
-            }
+        }
+        else if (item.first == OP_PUBKEYHASH)
+        {
+            if (!keystore.HaveKey(uint160(item.second)))
+                return false;
+        }
+        else
+        {
+            return false;
         }
     }
 
     return true;
 }
 
-
-bool ExtractHash160(const CScript& scriptPubKey, const CKeyStore* keystore, uint160& hash160Ret)
+bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
 {
     vector<pair<opcodetype, valtype> > vSolution;
     if (!Solver(scriptPubKey, vSolution))
         return false;
 
-    CRITICAL_BLOCK(keystore->cs_KeyStore)
+    BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
     {
-        BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
-        {
-            uint160 hash160;
-            if (item.first == OP_PUBKEY)
-            {
-                hash160 = Hash160(item.second);
-            }
-            else if (item.first == OP_PUBKEYHASH)
-            {
-                hash160 = uint160(item.second);
-            }
-            if (keystore == NULL || keystore->HaveKey(hash160))
-            {
-                hash160Ret = hash160;
-                return true;
-            }
-        }
+        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 VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType)
+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,
+                  bool fValidatePayToScriptHash, int nHashType)
 {
-    vector<vector<unsigned char> > stack;
+    vector<vector<unsigned char> > stack, stackCopy;
     if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType))
         return false;
+    if (fValidatePayToScriptHash)
+        stackCopy = stack;
     if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType))
         return false;
     if (stack.empty())
         return false;
-    return CastToBool(stack.back());
+
+    if (CastToBool(stack.back()) == false)
+        return false;
+
+    // Additional validation for spend-to-script-hash transactions:
+    if (fValidatePayToScriptHash && scriptPubKey.IsPayToScriptHash())
+    {
+        if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only
+            return false;            // or validation fails
+
+        const valtype& pubKeySerialized = stackCopy.back();
+        CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
+        popstack(stackCopy);
+
+        if (!EvalScript(stackCopy, pubKey2, txTo, nIn, nHashType))
+            return false;
+        if (stackCopy.empty())
+            return false;
+        return CastToBool(stackCopy.back());
+    }
+
+    return true;
 }
 
 
@@ -1184,14 +1201,14 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans
 
     // Test solution
     if (scriptPrereq.empty())
-        if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, 0))
+        if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, true, 0))
             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, bool fValidatePayToScriptHash, int nHashType)
 {
     assert(nIn < txTo.vin.size());
     const CTxIn& txin = txTo.vin[nIn];
@@ -1202,8 +1219,65 @@ 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, nHashType))
+    if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, nHashType))
         return false;
 
     return true;
 }
+
+int CScript::GetSigOpCount(bool fAccurate) const
+{
+    int n = 0;
+    const_iterator pc = begin();
+    opcodetype lastOpcode = OP_INVALIDOPCODE;
+    while (pc < end())
+    {
+        opcodetype opcode;
+        if (!GetOp(pc, opcode))
+            break;
+        if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
+            n++;
+        else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
+        {
+            if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
+                n += DecodeOP_N(lastOpcode);
+            else
+                n += 20;
+        }
+        lastOpcode = opcode;
+    }
+    return n;
+}
+
+int CScript::GetSigOpCount(const CScript& scriptSig) const
+{
+    if (!IsPayToScriptHash())
+        return GetSigOpCount(true);
+
+    // This is a pay-to-script-hash scriptPubKey;
+    // get the last item that the scriptSig
+    // pushes onto the stack:
+    const_iterator pc = scriptSig.begin();
+    vector<unsigned char> data;
+    while (pc < scriptSig.end())
+    {
+        opcodetype opcode;
+        if (!scriptSig.GetOp(pc, opcode, data))
+            return 0;
+        if (opcode > OP_16)
+            return 0;
+    }
+
+    /// ... and return it's opcount:
+    CScript subscript(data.begin(), data.end());
+    return subscript.GetSigOpCount(true);
+}
+
+bool CScript::IsPayToScriptHash() const
+{
+    // Extra-fast test for pay-to-script-hash CScripts:
+    return (this->size() == 23 &&
+            this->at(0) == OP_HASH160 &&
+            this->at(1) == 0x14 &&
+            this->at(22) == OP_EQUAL);
+}