aboutsummaryrefslogtreecommitdiff
path: root/src/script.cpp
diff options
context:
space:
mode:
authorGavin Andresen <gavinandresen@gmail.com>2011-11-08 13:20:29 -0500
committerGavin Andresen <gavinandresen@gmail.com>2011-12-19 13:24:48 -0500
commit2a45a494b0bec6a0f1fc6ab7f26c260b85e7ff3e (patch)
treea6c8ad492ea81d6f1c2b8694351a7b7bfa785ae6 /src/script.cpp
parenta0871afb2b1d6d358c833fd08bca2f13c840fd4d (diff)
Use block times for 'hard' OP_EVAL switchover, and refactored EvalScript
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.
Diffstat (limited to 'src/script.cpp')
-rw-r--r--src/script.cpp95
1 files changed, 38 insertions, 57 deletions
diff --git a/src/script.cpp b/src/script.cpp
index e60399120f..5487c01fab 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -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;