}
-const char* GetTxnTypeName(txntype t)
+const char* GetTxnOutputType(txnouttype t)
{
switch (t)
{
}
}
-
//
// 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();
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]
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;
}
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);
}
//
// 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
// 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();
{
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:
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
bool IsStandard(const CScript& scriptPubKey)
{
vector<valtype> vSolutions;
- txntype whichType;
+ txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
vector<valtype> vSolutions;
- txntype whichType;
+ txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
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:
{
bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
{
vector<valtype> vSolutions;
- txntype whichType;
+ txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
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;
{
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);
}
}
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;
// 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;
}
// 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];
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;