diff options
Diffstat (limited to 'src/script.cpp')
-rw-r--r-- | src/script.cpp | 607 |
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; +} |