aboutsummaryrefslogtreecommitdiff
path: root/src/script.cpp
diff options
context:
space:
mode:
authorLuke Dashjr <luke-jr+git@utopios.org>2012-03-21 13:39:57 -0400
committerLuke Dashjr <luke-jr+git@utopios.org>2012-03-21 13:49:00 -0400
commit2ac8af4534ad026cec5e281852d2e42616d15610 (patch)
treea64210f65e7453d40b66eed290128c8682e7ed33 /src/script.cpp
parent17a5fd9248ce62ca412f7098ca261d4b4271cc99 (diff)
parentcdc6b8d6a6ee4f0bfa721561c340cf8f6b81bc6a (diff)
downloadbitcoin-2ac8af4534ad026cec5e281852d2e42616d15610.tar.xz
Merge branch '0.4.x' into 0.5.0.x
Conflicts: src/main.cpp
Diffstat (limited to 'src/script.cpp')
-rw-r--r--src/script.cpp93
1 files changed, 87 insertions, 6 deletions
diff --git a/src/script.cpp b/src/script.cpp
index 12d3f9e83a..a7e4d3e280 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -1147,16 +1147,40 @@ bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBit
}
-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,
+ 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;
}
@@ -1178,14 +1202,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];
@@ -1196,8 +1220,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);
+}