aboutsummaryrefslogtreecommitdiff
path: root/src/script.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/script.cpp')
-rw-r--r--src/script.cpp607
1 files changed, 500 insertions, 107 deletions
diff --git a/src/script.cpp b/src/script.cpp
index 12d3f9e83a..467cb2f0df 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -70,20 +70,186 @@ static inline void popstack(vector<valtype>& stack)
}
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType)
+const char* GetTxnOutputType(txnouttype t)
+{
+ switch (t)
+ {
+ case TX_NONSTANDARD: return "nonstandard";
+ case TX_PUBKEY: return "pubkey";
+ case TX_PUBKEYHASH: return "pubkeyhash";
+ case TX_SCRIPTHASH: return "scripthash";
+ case TX_MULTISIG: return "multisig";
+ }
+ return NULL;
+}
+
+
+const char* GetOpName(opcodetype opcode)
+{
+ switch (opcode)
+ {
+ // push value
+ case OP_0 : return "0";
+ case OP_PUSHDATA1 : return "OP_PUSHDATA1";
+ case OP_PUSHDATA2 : return "OP_PUSHDATA2";
+ case OP_PUSHDATA4 : return "OP_PUSHDATA4";
+ case OP_1NEGATE : return "-1";
+ case OP_RESERVED : return "OP_RESERVED";
+ case OP_1 : return "1";
+ case OP_2 : return "2";
+ case OP_3 : return "3";
+ case OP_4 : return "4";
+ case OP_5 : return "5";
+ case OP_6 : return "6";
+ case OP_7 : return "7";
+ case OP_8 : return "8";
+ case OP_9 : return "9";
+ case OP_10 : return "10";
+ case OP_11 : return "11";
+ case OP_12 : return "12";
+ case OP_13 : return "13";
+ case OP_14 : return "14";
+ case OP_15 : return "15";
+ case OP_16 : return "16";
+
+ // control
+ case OP_NOP : return "OP_NOP";
+ case OP_VER : return "OP_VER";
+ case OP_IF : return "OP_IF";
+ case OP_NOTIF : return "OP_NOTIF";
+ case OP_VERIF : return "OP_VERIF";
+ case OP_VERNOTIF : return "OP_VERNOTIF";
+ case OP_ELSE : return "OP_ELSE";
+ case OP_ENDIF : return "OP_ENDIF";
+ case OP_VERIFY : return "OP_VERIFY";
+ case OP_RETURN : return "OP_RETURN";
+
+ // stack ops
+ case OP_TOALTSTACK : return "OP_TOALTSTACK";
+ case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
+ case OP_2DROP : return "OP_2DROP";
+ case OP_2DUP : return "OP_2DUP";
+ case OP_3DUP : return "OP_3DUP";
+ case OP_2OVER : return "OP_2OVER";
+ case OP_2ROT : return "OP_2ROT";
+ case OP_2SWAP : return "OP_2SWAP";
+ case OP_IFDUP : return "OP_IFDUP";
+ case OP_DEPTH : return "OP_DEPTH";
+ case OP_DROP : return "OP_DROP";
+ case OP_DUP : return "OP_DUP";
+ case OP_NIP : return "OP_NIP";
+ case OP_OVER : return "OP_OVER";
+ case OP_PICK : return "OP_PICK";
+ case OP_ROLL : return "OP_ROLL";
+ case OP_ROT : return "OP_ROT";
+ case OP_SWAP : return "OP_SWAP";
+ case OP_TUCK : return "OP_TUCK";
+
+ // splice ops
+ case OP_CAT : return "OP_CAT";
+ case OP_SUBSTR : return "OP_SUBSTR";
+ case OP_LEFT : return "OP_LEFT";
+ case OP_RIGHT : return "OP_RIGHT";
+ case OP_SIZE : return "OP_SIZE";
+
+ // bit logic
+ case OP_INVERT : return "OP_INVERT";
+ case OP_AND : return "OP_AND";
+ case OP_OR : return "OP_OR";
+ case OP_XOR : return "OP_XOR";
+ case OP_EQUAL : return "OP_EQUAL";
+ case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
+ case OP_RESERVED1 : return "OP_RESERVED1";
+ case OP_RESERVED2 : return "OP_RESERVED2";
+
+ // numeric
+ case OP_1ADD : return "OP_1ADD";
+ case OP_1SUB : return "OP_1SUB";
+ case OP_2MUL : return "OP_2MUL";
+ case OP_2DIV : return "OP_2DIV";
+ case OP_NEGATE : return "OP_NEGATE";
+ case OP_ABS : return "OP_ABS";
+ case OP_NOT : return "OP_NOT";
+ case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
+ case OP_ADD : return "OP_ADD";
+ case OP_SUB : return "OP_SUB";
+ case OP_MUL : return "OP_MUL";
+ case OP_DIV : return "OP_DIV";
+ case OP_MOD : return "OP_MOD";
+ case OP_LSHIFT : return "OP_LSHIFT";
+ case OP_RSHIFT : return "OP_RSHIFT";
+ case OP_BOOLAND : return "OP_BOOLAND";
+ case OP_BOOLOR : return "OP_BOOLOR";
+ case OP_NUMEQUAL : return "OP_NUMEQUAL";
+ case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
+ case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
+ case OP_LESSTHAN : return "OP_LESSTHAN";
+ case OP_GREATERTHAN : return "OP_GREATERTHAN";
+ case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
+ case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
+ case OP_MIN : return "OP_MIN";
+ case OP_MAX : return "OP_MAX";
+ case OP_WITHIN : return "OP_WITHIN";
+
+ // crypto
+ case OP_RIPEMD160 : return "OP_RIPEMD160";
+ case OP_SHA1 : return "OP_SHA1";
+ case OP_SHA256 : return "OP_SHA256";
+ case OP_HASH160 : return "OP_HASH160";
+ case OP_HASH256 : return "OP_HASH256";
+ case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
+ case OP_CHECKSIG : return "OP_CHECKSIG";
+ case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
+ case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
+ case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
+
+ // meta
+ case OP_EVAL : return "OP_EVAL";
+
+ // expanson
+ case OP_NOP2 : return "OP_NOP2";
+ case OP_NOP3 : return "OP_NOP3";
+ case OP_NOP4 : return "OP_NOP4";
+ case OP_NOP5 : return "OP_NOP5";
+ case OP_NOP6 : return "OP_NOP6";
+ case OP_NOP7 : return "OP_NOP7";
+ case OP_NOP8 : return "OP_NOP8";
+ case OP_NOP9 : return "OP_NOP9";
+ case OP_NOP10 : return "OP_NOP10";
+
+
+
+ // template matching params
+ case OP_SCRIPTHASH : return "OP_SCRIPTHASH";
+ case OP_PUBKEYHASH : return "OP_PUBKEYHASH";
+ case OP_PUBKEY : return "OP_PUBKEY";
+
+ case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
+ default:
+ return "OP_UNKNOWN";
+ }
+}
+
+//
+// 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,
+ bool fStrictOpEval, int nRecurseDepth)
{
CAutoBN_CTX pctx;
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
- CScript::const_iterator pbegincodehash = script.begin();
opcodetype opcode;
valtype vchPushValue;
vector<bool> vfExec;
vector<valtype> altstack;
if (script.size() > 10000)
return false;
- int nOpCount = 0;
+ // Limit OP_EVAL recursion
+ if (nRecurseDepth > 2)
+ return false;
try
{
@@ -155,7 +321,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
// Control
//
case OP_NOP:
- case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
+ case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
break;
@@ -751,12 +917,13 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
//PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n");
// Subset of script starting at the most recent codeseparator
- CScript scriptCode(pbegincodehash, pend);
+ CScript scriptCode(pbegincodehash, pendcodehash);
// Drop the signature, since there's no way for a signature to sign itself
scriptCode.FindAndDelete(CScript(vchSig));
bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType);
+ nSigOpCount++;
popstack(stack);
popstack(stack);
@@ -800,7 +967,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
return false;
// Subset of script starting at the most recent codeseparator
- CScript scriptCode(pbegincodehash, pend);
+ CScript scriptCode(pbegincodehash, pendcodehash);
// Drop the signatures, since there's no way for a signature to sign itself
for (int k = 0; k < nSigsCount; k++)
@@ -823,6 +990,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
}
ikey++;
nKeysCount--;
+ nSigOpCount++;
// If there are more signatures left than keys left,
// then too many signatures have failed
@@ -844,6 +1012,32 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
}
break;
+ case OP_EVAL:
+ {
+ 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]
+ if (stack.size() < 1)
+ return false;
+ valtype& vchScript = stacktop(-1);
+ CScript subscript(vchScript.begin(), vchScript.end());
+ popstack(stack);
+
+ // 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, fStrictOpEval, nRecurseDepth++))
+ return false;
+ }
+ break;
+
default:
return false;
}
@@ -865,6 +1059,18 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
return true;
}
+bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script,
+ 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, fStrictOpEval, 0);
+}
+
@@ -963,25 +1169,36 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc
-
-bool Solver(const CScript& scriptPubKey, vector<pair<opcodetype, valtype> >& vSolutionRet)
+//
+// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
+//
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
{
// Templates
- static vector<CScript> vTemplates;
- if (vTemplates.empty())
+ static map<txnouttype, CScript> mTemplates;
+ if (mTemplates.empty())
{
// Standard tx, sender provides pubkey, receiver adds signature
- vTemplates.push_back(CScript() << OP_PUBKEY << OP_CHECKSIG);
+ mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
- vTemplates.push_back(CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG);
+ mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
+
+ // Sender provides N pubkeys, receivers provides M signatures
+ mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+
+ // Sender provides script hash, receiver provides script and
+ // as many signatures as required to satisfy script
+ mTemplates.insert(make_pair(TX_SCRIPTHASH, CScript() << OP_DUP << OP_HASH160 << OP_SCRIPTHASH << OP_EQUALVERIFY << OP_EVAL));
}
// Scan templates
const CScript& script1 = scriptPubKey;
- BOOST_FOREACH(const CScript& script2, vTemplates)
+ BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
{
- vSolutionRet.clear();
+ const CScript& script2 = tplate.second;
+ vSolutionsRet.clear();
+
opcodetype opcode1, opcode2;
vector<unsigned char> vch1, vch2;
@@ -993,170 +1210,318 @@ bool Solver(const CScript& scriptPubKey, vector<pair<opcodetype, valtype> >& vSo
if (pc1 == script1.end() && pc2 == script2.end())
{
// Found a match
- reverse(vSolutionRet.begin(), vSolutionRet.end());
+ typeRet = tplate.first;
+ if (typeRet == TX_MULTISIG)
+ {
+ // Additional checks for TX_MULTISIG:
+ unsigned char m = vSolutionsRet.front()[0];
+ unsigned char n = vSolutionsRet.back()[0];
+ if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
+ return false;
+ }
return true;
}
if (!script1.GetOp(pc1, opcode1, vch1))
break;
if (!script2.GetOp(pc2, opcode2, vch2))
break;
+
+ // Template matching opcodes:
+ if (opcode2 == OP_PUBKEYS)
+ {
+ while (vch1.size() >= 33 && vch1.size() <= 120)
+ {
+ vSolutionsRet.push_back(vch1);
+ if (!script1.GetOp(pc1, opcode1, vch1))
+ break;
+ }
+ if (!script2.GetOp(pc2, opcode2, vch2))
+ break;
+ // Normal situation is to fall through
+ // to other if/else statments
+ }
+
if (opcode2 == OP_PUBKEY)
{
if (vch1.size() < 33 || vch1.size() > 120)
break;
- vSolutionRet.push_back(make_pair(opcode2, vch1));
+ vSolutionsRet.push_back(vch1);
}
else if (opcode2 == OP_PUBKEYHASH)
{
if (vch1.size() != sizeof(uint160))
break;
- vSolutionRet.push_back(make_pair(opcode2, vch1));
+ vSolutionsRet.push_back(vch1);
+ }
+ else if (opcode2 == OP_SCRIPTHASH)
+ {
+ if (vch1.size() != sizeof(uint160))
+ break;
+ vSolutionsRet.push_back(vch1);
+ }
+ else if (opcode2 == OP_SMALLINTEGER)
+ { // Single-byte small integer pushed onto vSolutions
+ if (opcode1 == OP_0 ||
+ (opcode1 >= OP_1 && opcode1 <= OP_16))
+ {
+ char n = (char)CScript::DecodeOP_N(opcode1);
+ vSolutionsRet.push_back(valtype(1, n));
+ }
+ else
+ break;
}
else if (opcode1 != opcode2 || vch1 != vch2)
{
+ // Others must match exactly
break;
}
}
}
- vSolutionRet.clear();
+ vSolutionsRet.clear();
+ typeRet = TX_NONSTANDARD;
return false;
}
-bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet)
+bool Sign1(const CBitcoinAddress& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
{
- scriptSigRet.clear();
+ CKey key;
+ if (!keystore.GetKey(address, key))
+ return false;
- vector<pair<opcodetype, valtype> > vSolution;
- if (!Solver(scriptPubKey, vSolution))
+ vector<unsigned char> vchSig;
+ if (!key.Sign(hash, vchSig))
return false;
+ vchSig.push_back((unsigned char)nHashType);
+ scriptSigRet << vchSig;
+
+ return true;
+}
- // Compile solution
- BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+{
+ int nSigned = 0;
+ int nRequired = multisigdata.front()[0];
+ for (vector<valtype>::const_iterator it = multisigdata.begin()+1; it != multisigdata.begin()+multisigdata.size()-1; it++)
{
- 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)
- {
- vector<unsigned char> vchSig;
- if (!key.Sign(hash, vchSig))
- return false;
- vchSig.push_back((unsigned char)nHashType);
- scriptSigRet << vchSig;
- }
- }
- else if (item.first == OP_PUBKEYHASH)
+ const valtype& pubkey = *it;
+ CBitcoinAddress address;
+ address.SetPubKey(pubkey);
+ if (Sign1(address, keystore, hash, nHashType, scriptSigRet))
{
- // Sign and give pubkey
- CKey key;
- if (!keystore.GetKey(uint160(item.second), key))
- 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();
- }
+ ++nSigned;
+ if (nSigned == nRequired) break;
}
+ }
+ return nSigned==nRequired;
+}
+
+//
+// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
+// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed).
+// Returns true if scriptPubKey could be completely satisified.
+//
+bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet)
+{
+ scriptSigRet.clear();
+
+ txnouttype whichType;
+ vector<valtype> vSolutions;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
+ return false;
+
+ CBitcoinAddress address;
+ CScript subscript;
+ switch (whichType)
+ {
+ case TX_NONSTANDARD:
+ return false;
+ case TX_PUBKEY:
+ address.SetPubKey(vSolutions[0]);
+ return Sign1(address, keystore, hash, nHashType, scriptSigRet);
+ case TX_PUBKEYHASH:
+ address.SetHash160(uint160(vSolutions[0]));
+ if (!Sign1(address, keystore, hash, nHashType, scriptSigRet))
+ return false;
else
{
- return false;
+ valtype vch;
+ keystore.GetPubKey(address, vch);
+ scriptSigRet << vch;
}
+ break;
+ case TX_SCRIPTHASH:
+ if (!keystore.GetCScript(uint160(vSolutions[0]), subscript))
+ return false;
+ if (!Solver(keystore, subscript, hash, nHashType, scriptSigRet))
+ return false;
+ if (hash != 0)
+ // 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
+ return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
}
-
return true;
}
bool IsStandard(const CScript& scriptPubKey)
{
- vector<pair<opcodetype, valtype> > vSolution;
- return Solver(scriptPubKey, vSolution);
+ vector<valtype> vSolutions;
+ txnouttype whichType;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
+ return false;
+
+ if (whichType == TX_MULTISIG)
+ {
+ unsigned char m = vSolutions.front()[0];
+ unsigned char n = vSolutions.back()[0];
+ // Support up to x-of-3 multisig txns as standard
+ if (n < 1 || n > 3)
+ return false;
+ if (m < 1 || m > n)
+ return false;
+ }
+
+ return whichType != TX_NONSTANDARD;
}
+int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
+{
+ int nResult = 0;
+ BOOST_FOREACH(const valtype& pubkey, pubkeys)
+ {
+ CBitcoinAddress address;
+ address.SetPubKey(pubkey);
+ if (keystore.HaveKey(address))
+ ++nResult;
+ }
+ return nResult;
+}
+
bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
- vector<pair<opcodetype, valtype> > vSolution;
- if (!Solver(scriptPubKey, vSolution))
+ vector<valtype> vSolutions;
+ txnouttype whichType;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
- // Compile solution
- BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+ CBitcoinAddress address;
+ switch (whichType)
{
- 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
- {
+ case TX_NONSTANDARD:
+ return false;
+ case TX_PUBKEY:
+ address.SetPubKey(vSolutions[0]);
+ return keystore.HaveKey(address);
+ case TX_PUBKEYHASH:
+ address.SetHash160(uint160(vSolutions[0]));
+ return keystore.HaveKey(address);
+ case TX_SCRIPTHASH:
+ {
+ CScript subscript;
+ if (!keystore.GetCScript(uint160(vSolutions[0]), subscript))
return false;
- }
+ return IsMine(keystore, subscript);
}
-
- return true;
+ case TX_MULTISIG:
+ {
+ // Only consider transactions "mine" if we own ALL the
+ // keys involved. multi-signature transactions that are
+ // partially owned (somebody else has a key that can spend
+ // them) enable spend-out-from-under-you attacks, especially
+ // in shared-wallet situations.
+ vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
+ return HaveKeys(vSolutions, keystore);
+ }
+ }
+ return false;
}
-bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
+bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
{
- vector<pair<opcodetype, valtype> > vSolution;
- if (!Solver(scriptPubKey, vSolution))
+ vector<valtype> vSolutions;
+ txnouttype whichType;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
- BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+ if (whichType == TX_PUBKEY)
{
- 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;
+ addressRet.SetPubKey(vSolutions[0]);
+ return true;
}
-
+ else if (whichType == TX_PUBKEYHASH)
+ {
+ addressRet.SetHash160(uint160(vSolutions[0]));
+ return true;
+ }
+ else if (whichType == TX_SCRIPTHASH)
+ {
+ addressRet.SetScriptHash160(uint160(vSolutions[0]));
+ return true;
+ }
+ // Multisig txns have more than one address...
return false;
}
-
-bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
+bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* keystore, txnouttype& typeRet, vector<CBitcoinAddress>& addressRet, int& nRequiredRet)
{
- if (keystore)
- return ExtractAddressInner(scriptPubKey, keystore, addressRet);
+ addressRet.clear();
+ typeRet = TX_NONSTANDARD;
+ vector<valtype> vSolutions;
+ if (!Solver(scriptPubKey, typeRet, vSolutions))
+ return false;
+
+ if (typeRet == TX_MULTISIG)
+ {
+ nRequiredRet = vSolutions.front()[0];
+ int n = vSolutions.back()[0];
+ for (int i = 1; i < vSolutions.size()-1; i++)
+ {
+ CBitcoinAddress address;
+ address.SetPubKey(vSolutions[i]);
+ addressRet.push_back(address);
+ }
+ }
else
- return ExtractAddressInner(scriptPubKey, NULL, addressRet);
- return false;
-}
+ {
+ nRequiredRet = 1;
+ CBitcoinAddress address;
+ if (typeRet == TX_PUBKEYHASH)
+ address.SetHash160(uint160(vSolutions.front()));
+ else if (typeRet == TX_SCRIPTHASH)
+ address.SetScriptHash160(uint160(vSolutions.front()));
+ else if (typeRet == TX_PUBKEY)
+ address.SetPubKey(vSolutions.front());
+ addressRet.push_back(address);
+ }
+ return true;
+}
-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, int& nSigOpCountRet,
+ int nHashType, bool fStrictOpEval)
{
vector<vector<unsigned char> > stack;
- if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType))
+ if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType, fStrictOpEval, nSigOpCountRet))
return false;
- if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType))
+ if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType, fStrictOpEval, nSigOpCountRet))
return false;
if (stack.empty())
return false;
- return CastToBool(stack.back());
+ bool fResult = CastToBool(stack.back());
+
+ // 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 (fResult && fStrictOpEval && (scriptPubKey.Find(OP_EVAL) || scriptSig.Find(OP_EVAL)))
+ return VerifyScript(scriptSig, scriptPubKey, txTo, nIn, nSigOpCountRet, nHashType, false);
+
+ return fResult;
}
@@ -1177,15 +1542,16 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans
txin.scriptSig = scriptPrereq + txin.scriptSig;
// Test solution
+ int nUnused = 0;
if (scriptPrereq.empty())
- if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, 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 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];
@@ -1196,8 +1562,35 @@ 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, nSigOpCountRet, nHashType, fStrictOpEval))
return false;
return true;
}
+
+void CScript::SetBitcoinAddress(const CBitcoinAddress& address)
+{
+ this->clear();
+ if (address.IsScript())
+ *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_EVAL;
+ else
+ *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_CHECKSIG;
+}
+
+void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
+{
+ this->clear();
+
+ *this << EncodeOP_N(nRequired);
+ BOOST_FOREACH(const CKey& key, keys)
+ *this << key.GetPubKey();
+ *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
+}
+
+void CScript::SetEval(const CScript& subscript)
+{
+ assert(!subscript.empty());
+ uint160 subscriptHash = Hash160(subscript);
+ this->clear();
+ *this << OP_DUP << OP_HASH160 << subscriptHash << OP_EQUALVERIFY << OP_EVAL;
+}