X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fscript.cpp;h=e7664d2cfcf0676c1dd9e6d5862655e567a719b0;hb=58ac600b2c94f12309fc5e18933891590dc1eb4c;hp=bd1b5b3c5f4782e820b9f62c878cca5a4cca5c6a;hpb=98705aa51cbfee81ecd2498a014c285ac677ba69;p=novacoin.git diff --git a/src/script.cpp b/src/script.cpp index bd1b5b3..e7664d2 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2011 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" using namespace std; @@ -580,6 +581,7 @@ bool EvalScript(vector >& stack, const CScript& script, co case OP_ABS: if (bn < bnZero) bn = -bn; break; case OP_NOT: bn = (bn == bnZero); break; case OP_0NOTEQUAL: bn = (bn != bnZero); break; + default: assert(!"invalid opcode"); break; } popstack(stack); stack.push_back(bn.getvch()); @@ -659,6 +661,7 @@ bool EvalScript(vector >& stack, const CScript& script, co case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; + default: assert(!"invalid opcode"); break; } popstack(stack); popstack(stack); @@ -1030,50 +1033,45 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash return false; // Compile solution - CRITICAL_BLOCK(keystore.cs_mapKeys) + BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) { - BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) + if (item.first == OP_PUBKEY) { - 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) { - // Sign - const valtype& vchPubKey = item.second; - CPrivKey privkey; - if (!keystore.GetPrivKey(vchPubKey, privkey)) + vector vchSig; + if (!key.Sign(hash, vchSig)) return false; - if (hash != 0) - { - vector vchSig; - if (!CKey::Sign(privkey, hash, vchSig)) - return false; - vchSig.push_back((unsigned char)nHashType); - scriptSigRet << vchSig; - } + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig; } - else if (item.first == OP_PUBKEYHASH) + } + else if (item.first == OP_PUBKEYHASH) + { + // Sign and give pubkey + CKey key; + if (!keystore.GetKey(uint160(item.second), key)) + return false; + if (hash != 0) { - // Sign and give pubkey - map::iterator mi = mapPubKeys.find(uint160(item.second)); - if (mi == mapPubKeys.end()) + vector vchSig; + if (!key.Sign(hash, vchSig)) return false; - const vector& vchPubKey = (*mi).second; - CPrivKey privkey; - if (!keystore.GetPrivKey(vchPubKey, privkey)) - return false; - if (hash != 0) - { - vector vchSig; - if (!CKey::Sign(privkey, hash, vchSig)) - return false; - vchSig.push_back((unsigned char)nHashType); - scriptSigRet << vchSig << vchPubKey; - } - } - else - { - return false; + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig << key.GetPubKey(); } } + else + { + return false; + } } return true; @@ -1089,76 +1087,99 @@ bool IsStandard(const CScript& scriptPubKey) bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { - CScript scriptSig; - return Solver(keystore, scriptPubKey, 0, 0, scriptSig); -} - - -bool ExtractPubKey(const CScript& scriptPubKey, const CKeyStore* keystore, vector& vchPubKeyRet) -{ - vchPubKeyRet.clear(); - vector > vSolution; if (!Solver(scriptPubKey, vSolution)) return false; - CRITICAL_BLOCK(cs_mapPubKeys) + // Compile solution + BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) { - BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) + if (item.first == OP_PUBKEY) { - valtype vchPubKey; - if (item.first == OP_PUBKEY) - { - vchPubKey = item.second; - } - else if (item.first == OP_PUBKEYHASH) - { - map::iterator mi = mapPubKeys.find(uint160(item.second)); - if (mi == mapPubKeys.end()) - continue; - vchPubKey = (*mi).second; - } - if (keystore == NULL || keystore->HaveKey(vchPubKey)) - { - vchPubKeyRet = vchPubKey; - return true; - } + const valtype& vchPubKey = item.second; + vector 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 + { + return false; } } - return false; -} + return true; +} -bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret) +bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet) { - hash160Ret = 0; - vector > vSolution; if (!Solver(scriptPubKey, vSolution)) return false; BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) { - if (item.first == OP_PUBKEYHASH) - { - hash160Ret = uint160(item.second); + 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; - } } return false; } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType) +bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet) { - vector > stack; + if (keystore) + return ExtractAddressInner(scriptPubKey, keystore, addressRet); + else + return ExtractAddressInner(scriptPubKey, NULL, addressRet); + return false; +} + + +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, + bool fValidatePayToScriptHash, int nHashType) +{ + vector > 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; } @@ -1180,14 +1201,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]; @@ -1198,8 +1219,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 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); +}