X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fscript.cpp;h=0909c8fa4584d51a1b2ae09209996a10e769a2b1;hb=06c7b792fed77e00e06abba85c84bd589311f315;hp=8a66750e2a03dac20e6cda7eecf7db7348d5ef92;hpb=7a255170a850961f78c4011ddb63df50c5a40950;p=novacoin.git diff --git a/src/script.cpp b/src/script.cpp index 8a66750..0909c8f 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -2,11 +2,6 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include - -using namespace std; -using namespace boost; #include "script.h" #include "keystore.h" @@ -16,7 +11,7 @@ using namespace boost; #include "sync.h" #include "util.h" -bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); +bool CheckSig(std::vector vchSig, const std::vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); static const valtype vchFalse(0); static const valtype vchZero(0); @@ -31,7 +26,7 @@ static const size_t nMaxNumSize = 4; CBigNum CastToBigNum(const valtype& vch) { if (vch.size() > nMaxNumSize) - throw runtime_error("CastToBigNum() : overflow"); + throw std::runtime_error("CastToBigNum() : overflow"); // Get rid of extra leading zeros return CBigNum(CBigNum(vch).getvch()); } @@ -85,10 +80,10 @@ void MakeSameSize(valtype& vch1, valtype& vch2) // #define stacktop(i) (stack.at(stack.size()+(i))) #define altstacktop(i) (altstack.at(altstack.size()+(i))) -static inline void popstack(vector& stack) +static inline void popstack(std::vector& stack) { if (stack.empty()) - throw runtime_error("popstack() : stack empty"); + throw std::runtime_error("popstack() : stack empty"); stack.pop_back(); } @@ -99,6 +94,7 @@ const char* GetTxnOutputType(txnouttype t) { case TX_NONSTANDARD: return "nonstandard"; case TX_PUBKEY: return "pubkey"; + case TX_PUBKEY_DROP: return "pubkeydrop"; case TX_PUBKEYHASH: return "pubkeyhash"; case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; @@ -147,6 +143,8 @@ const char* GetOpName(opcodetype opcode) case OP_ENDIF : return "OP_ENDIF"; case OP_VERIFY : return "OP_VERIFY"; case OP_RETURN : return "OP_RETURN"; + case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY"; + case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY"; // stack ops case OP_TOALTSTACK : return "OP_TOALTSTACK"; @@ -229,8 +227,6 @@ const char* GetOpName(opcodetype opcode) // expanson case OP_NOP1 : return "OP_NOP1"; - 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"; @@ -270,10 +266,7 @@ bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) { return true; } -bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { - if (!(flags & SCRIPT_VERIFY_STRICTENC)) - return true; - +bool IsDERSignature(const valtype &vchSig, bool fWithHashType, bool fCheckLow) { // See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 // A canonical signature exists of: <30> <02> <02> // Where R and S are not negative (their first byte has its highest bit not set), and not @@ -283,18 +276,20 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { return error("Non-canonical signature: too short"); if (vchSig.size() > 73) return error("Non-canonical signature: too long"); - unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); - if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) - return error("Non-canonical signature: unknown hashtype byte"); if (vchSig[0] != 0x30) return error("Non-canonical signature: wrong type"); - if (vchSig[1] != vchSig.size()-3) + if (vchSig[1] != vchSig.size() - (fWithHashType ? 3 : 2)) return error("Non-canonical signature: wrong length marker"); + if (fWithHashType) { + unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); + if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) + return error("Non-canonical signature: unknown hashtype byte"); + } unsigned int nLenR = vchSig[3]; if (5 + nLenR >= vchSig.size()) return error("Non-canonical signature: S length misplaced"); unsigned int nLenS = vchSig[5+nLenR]; - if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) + if ((nLenR + nLenS + (fWithHashType ? 7 : 6)) != vchSig.size()) return error("Non-canonical signature: R+S length mismatch"); const unsigned char *R = &vchSig[4]; @@ -317,15 +312,105 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) return error("Non-canonical signature: S value excessively padded"); - if (flags & SCRIPT_VERIFY_EVEN_S) { - if (S[nLenS-1] & 1) - return error("Non-canonical signature: S value odd"); + if (fCheckLow) { + unsigned int nLenR = vchSig[3]; + unsigned int nLenS = vchSig[5+nLenR]; + const unsigned char *S = &vchSig[6+nLenR]; + // If the S value is above the order of the curve divided by two, its + // complement modulo the order could have been used instead, which is + // one byte shorter when encoded correctly. + if (!CKey::CheckSignatureElement(S, nLenS, true)) + return error("Non-canonical signature: S value is unnecessarily high"); } return true; } -bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) +bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { + if (!(flags & SCRIPT_VERIFY_STRICTENC)) + return true; + + return IsDERSignature(vchSig, true, (flags & SCRIPT_VERIFY_LOW_S) != 0); +} + +bool CheckLockTime(const int64_t& nLockTime, const CTransaction &txTo, unsigned int nIn) +{ + // There are two kinds of nLockTime: lock-by-blockheight + // and lock-by-blocktime, distinguished by whether + // nLockTime < LOCKTIME_THRESHOLD. + // + // We want to compare apples to apples, so fail the script + // unless the type of nLockTime being tested is the same as + // the nLockTime in the transaction. + if (!( + (txTo.nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) || + (txTo.nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD) + )) + return false; + + // Now that we know we're comparing apples-to-apples, the + // comparison is a simple numeric one. + if (nLockTime > (int64_t)txTo.nLockTime) + return false; + + // Finally the nLockTime feature can be disabled and thus + // CHECKLOCKTIMEVERIFY bypassed if every txin has been + // finalized by setting nSequence to maxint. The + // transaction would be allowed into the blockchain, making + // the opcode ineffective. + // + // Testing if this vin is not final is sufficient to + // prevent this condition. Alternatively we could test all + // inputs, but testing just this input minimizes the data + // required to prove correct CHECKLOCKTIMEVERIFY execution. + if (SEQUENCE_FINAL == txTo.vin[nIn].nSequence) + return false; + + return true; +} + +bool CheckSequence(const int64_t& nSequence, const CTransaction &txTo, unsigned int nIn) +{ + // Relative lock times are supported by comparing the passed + // in operand to the sequence number of the input. + const int64_t txToSequence = (int64_t)txTo.vin[nIn].nSequence; + + // Sequence numbers with their most significant bit set are not + // consensus constrained. Testing that the transaction's sequence + // number do not have this bit set prevents using this property + // to get around a CHECKSEQUENCEVERIFY check. + if (txToSequence & SEQUENCE_LOCKTIME_DISABLE_FLAG) + return false; + + // Mask off any bits that do not have consensus-enforced meaning + // before doing the integer comparisons + const uint32_t nLockTimeMask = SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK; + const int64_t txToSequenceMasked = txToSequence & nLockTimeMask; + const int64_t nSequenceMasked = nSequence & nLockTimeMask; + + // There are two kinds of nSequence: lock-by-blockheight + // and lock-by-blocktime, distinguished by whether + // nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG. + // + // We want to compare apples to apples, so fail the script + // unless the type of nSequenceMasked being tested is the same as + // the nSequenceMasked in the transaction. + if (!( + (txToSequenceMasked < SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < SEQUENCE_LOCKTIME_TYPE_FLAG) || + (txToSequenceMasked >= SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= SEQUENCE_LOCKTIME_TYPE_FLAG) + )) { + return false; + } + + // Now that we know we're comparing apples-to-apples, the + // comparison is a simple numeric one. + if (nSequenceMasked > txToSequenceMasked) + return false; + + return true; +} + +bool EvalScript(std::vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); @@ -333,8 +418,8 @@ bool EvalScript(vector >& stack, const CScript& script, co CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; - vector vfExec; - vector altstack; + std::vector vfExec; + std::vector altstack; if (script.size() > 10000) return false; int nOpCount = 0; @@ -409,7 +494,7 @@ bool EvalScript(vector >& 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_NOP1: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: break; @@ -468,6 +553,67 @@ bool EvalScript(vector >& stack, const CScript& script, co } break; + case OP_CHECKLOCKTIMEVERIFY: + { + // CHECKLOCKTIMEVERIFY + // + // (nLockTime -- nLockTime) + if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { + // treat as a NOP2 if not enabled + break; + } + + if (stack.size() < 1) + return false; + + CBigNum nLockTime = CastToBigNum(stacktop(-1)); + + // In the rare event that the argument may be < 0 due to + // some arithmetic being done first, you can always use + // 0 MAX CHECKLOCKTIMEVERIFY. + if (nLockTime < 0) + return false; + + // Actually compare the specified lock time with the transaction. + if (!CheckLockTime(nLockTime.getuint64(), txTo, nIn)) + return false; + + break; + } + + case OP_CHECKSEQUENCEVERIFY: + { + if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) { + // treat as a NOP3 not enabled + break; + } + + if (stack.size() < 1) + return false; + + // nSequence, like nLockTime, is a 32-bit unsigned integer + // field. See the comment in CHECKLOCKTIMEVERIFY regarding + // 5-byte numeric operands. + CBigNum nSequence = CastToBigNum(stacktop(-1)); + + // In the rare event that the argument may be < 0 due to + // some arithmetic being done first, you can always use + // 0 MAX CHECKSEQUENCEVERIFY. + if (nSequence < 0) + return false; + + // To provide for future soft-fork extensibility, if the + // operand has the disabled lock-time flag set, + // CHECKSEQUENCEVERIFY behaves as a NOP. + if ((nSequence.getint32() & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) + break; + + // Compare the specified sequence number with the input. + if (!CheckSequence(nSequence.getuint64(), txTo, nIn)) + return false; + + break; + } // // Stack ops @@ -575,7 +721,7 @@ bool EvalScript(vector >& stack, const CScript& script, co case OP_DEPTH: { // -- stacksize - CBigNum bn(stack.size()); + CBigNum bn((uint16_t) stack.size()); stack.push_back(bn.getvch()); } break; @@ -625,7 +771,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; - int n = CastToBigNum(stacktop(-1)).getint(); + int n = CastToBigNum(stacktop(-1)).getint32(); popstack(stack); if (n < 0 || n >= (int)stack.size()) return false; @@ -673,7 +819,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // (in -- in size) if (stack.size() < 1) return false; - CBigNum bn(stacktop(-1).size()); + CBigNum bn((uint16_t) stacktop(-1).size()); stack.push_back(bn.getvch()); } break; @@ -901,7 +1047,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nKeysCount = CastToBigNum(stacktop(-i)).getint(); + int nKeysCount = CastToBigNum(stacktop(-i)).getint32(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; @@ -912,7 +1058,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nSigsCount = CastToBigNum(stacktop(-i)).getint(); + int nSigsCount = CastToBigNum(stacktop(-i)).getint32(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; @@ -1080,15 +1226,15 @@ class CSignatureCache { private: // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple, CPubKey > sigdata_type; + typedef std::tuple, CPubKey > sigdata_type; std::set< sigdata_type> setValid; - CCriticalSection cs_sigcache; + boost::shared_mutex cs_sigcache; public: bool Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { - LOCK(cs_sigcache); + boost::shared_lock lock(cs_sigcache); sigdata_type k(hash, vchSig, pubKey); std::set::iterator mi = setValid.find(k); @@ -1103,12 +1249,12 @@ public: // (~200 bytes per cache entry times 50,000 entries) // Since there are a maximum of 20,000 signature operations per block // 50,000 is a reasonable default. - int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); if (nMaxCacheSize <= 0) return; - LOCK(cs_sigcache); + boost::shared_lock lock(cs_sigcache); - while (static_cast(setValid.size()) > nMaxCacheSize) + while (static_cast(setValid.size()) > nMaxCacheSize) { // Evict a random entry. Random because that helps // foil would-be DoS attackers who might try to pre-generate @@ -1128,15 +1274,12 @@ public: } }; -bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, +bool CheckSig(std::vector vchSig, const std::vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags) { static CSignatureCache signatureCache; - CKey key; - if (!key.SetPubKey(vchPubKey)) - return false; - CPubKey pubkey = key.GetPubKey(); + CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; @@ -1154,7 +1297,7 @@ bool CheckSig(vector vchSig, const vector &vchPubK if (signatureCache.Get(sighash, vchSig, pubkey)) return true; - if (!key.Verify(sighash, vchSig)) + if (!pubkey.Verify(sighash, vchSig)) return false; if (!(flags & SCRIPT_VERIFY_NOCACHE)) @@ -1164,24 +1307,21 @@ bool CheckSig(vector vchSig, const vector &vchPubK } - - - - - - // // Return public keys or hashes from scriptPubKey, for 'standard' transaction types. // -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector >& vSolutionsRet) +bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet) { // Templates - static map mTemplates; + static std::map mTemplates; if (mTemplates.empty()) { // Standard tx, sender provides pubkey, receiver adds signature mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); + // Malleable pubkey tx hack, sender provides generated pubkey combined with R parameter. The R parameter is dropped before checking a signature. + mTemplates.insert(make_pair(TX_PUBKEY_DROP, CScript() << OP_PUBKEY << OP_PUBKEY << OP_DROP << OP_CHECKSIG)); + // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); @@ -1192,30 +1332,42 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); + std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); return true; } + // Provably prunable, data-carrying output + // + // So long as script passes the IsUnspendable() test and all but the first + // byte passes the IsPushOnly() test we don't care what exactly is in the + // script. + if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) { + typeRet = TX_NULL_DATA; + return true; + } + // Scan templates const CScript& script1 = scriptPubKey; - BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) + for (const auto& tplate : mTemplates) { const CScript& script2 = tplate.second; vSolutionsRet.clear(); opcodetype opcode1, opcode2; - vector vch1, vch2; + std::vector vch1, vch2; // Compare CScript::const_iterator pc1 = script1.begin(); CScript::const_iterator pc2 = script2.begin(); - while (true) + for ( ; ; ) { if (pc1 == script1.end() && pc2 == script2.end()) { @@ -1274,10 +1426,24 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector 80) + // small pushdata, <= 1024 bytes + if (vch1.size() > 1024) break; } else if (opcode1 != opcode2 || vch1 != vch2) @@ -1294,13 +1460,13 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector vchSig; + std::vector vchSig; if (!key.Sign(hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); @@ -1309,7 +1475,22 @@ bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int n return true; } -bool SignN(const vector& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) +bool SignR(const CPubKey& pubKey, const CPubKey& R, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet) +{ + CKey key; + if (!keystore.CreatePrivKey(pubKey, R, key)) + return false; + + std::vector vchSig; + if (!key.Sign(hash, vchSig)) + return false; + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig; + + return true; +} + +bool SignN(const std::vector& multisigdata, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet) { int nSigned = 0; int nRequired = multisigdata.front()[0]; @@ -1329,12 +1510,12 @@ bool SignN(const vector& multisigdata, const CKeyStore& keystore, uint2 // unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. // Returns false if scriptPubKey could not be completely satisfied. // -bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, +bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, const uint256& hash, int nHashType, CScript& scriptSigRet, txnouttype& whichTypeRet) { scriptSigRet.clear(); - vector vSolutions; + std::vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; @@ -1347,6 +1528,12 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); + case TX_PUBKEY_DROP: + { + CPubKey key = CPubKey(vSolutions[0]); + CPubKey R = CPubKey(vSolutions[1]); + return SignR(key, R, keystore, hash, nHashType, scriptSigRet); + } case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) @@ -1377,6 +1564,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector vSolutions; + std::vector vSolutions; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; @@ -1411,10 +1599,10 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) } -unsigned int HaveKeys(const vector& pubkeys, const CKeyStore& keystore) +unsigned int HaveKeys(const std::vector& pubkeys, const CKeyStore& keystore) { unsigned int nResult = 0; - BOOST_FOREACH(const valtype& pubkey, pubkeys) + for (const valtype& pubkey : pubkeys) { CKeyID keyID = CPubKey(pubkey).GetID(); if (keystore.HaveKey(keyID)) @@ -1435,36 +1623,65 @@ public: bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); } }; -bool IsMine(const CKeyStore &keystore, const CTxDestination &dest) +/* +isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest) +{ + CScript script; + script.SetDestination(dest); + return IsMine(keystore, script); +}*/ + +isminetype IsMine(const CKeyStore &keystore, const CBitcoinAddress& dest) { - return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest); + CScript script; + script.SetAddress(dest); + return IsMine(keystore, script); } -bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) +isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { - vector vSolutions; + std::vector vSolutions; txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; + if (!Solver(scriptPubKey, whichType, vSolutions)) { + if (keystore.HaveWatchOnly(scriptPubKey)) + return MINE_WATCH_ONLY; + return MINE_NO; + } CKeyID keyID; switch (whichType) { case TX_NONSTANDARD: case TX_NULL_DATA: - return false; + break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - return keystore.HaveKey(keyID); + if (keystore.HaveKey(keyID)) + return MINE_SPENDABLE; + break; + case TX_PUBKEY_DROP: + { + CPubKey key = CPubKey(vSolutions[0]); + CPubKey R = CPubKey(vSolutions[1]); + if (keystore.CheckOwnership(key, R)) + return MINE_SPENDABLE; + } + break; case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - return keystore.HaveKey(keyID); + if (keystore.HaveKey(keyID)) + return MINE_SPENDABLE; + break; case TX_SCRIPTHASH: { + CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; - if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript)) - return false; - return IsMine(keystore, subscript); + if (keystore.GetCScript(scriptID, subscript)) { + isminetype ret = IsMine(keystore, subscript); + if (ret == MINE_SPENDABLE) + return ret; + } + break; } case TX_MULTISIG: { @@ -1473,16 +1690,21 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) // partially owned (somebody else has a key that can spend // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. - vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); - return HaveKeys(keys, keystore) == keys.size(); + std::vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); + if (HaveKeys(keys, keystore) == keys.size()) + return MINE_SPENDABLE; + break; } } - return false; + + if (keystore.HaveWatchOnly(scriptPubKey)) + return MINE_WATCH_ONLY; + return MINE_NO; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { - vector vSolutions; + std::vector vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; @@ -1506,9 +1728,46 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) return false; } +bool ExtractAddress(const CKeyStore &keystore, const CScript& scriptPubKey, CBitcoinAddress& addressRet) +{ + std::vector vSolutions; + txnouttype whichType; + if (!Solver(scriptPubKey, whichType, vSolutions)) + return false; + + if (whichType == TX_PUBKEY) + { + addressRet = CBitcoinAddress(CPubKey(vSolutions[0]).GetID()); + return true; + } + if (whichType == TX_PUBKEY_DROP) + { + // Pay-to-Pubkey-R + CMalleableKeyView view; + if (!keystore.CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view)) + return false; + + addressRet = CBitcoinAddress(view.GetMalleablePubKey()); + return true; + } + else if (whichType == TX_PUBKEYHASH) + { + addressRet = CBitcoinAddress(CKeyID(uint160(vSolutions[0]))); + return true; + } + else if (whichType == TX_SCRIPTHASH) + { + addressRet = CBitcoinAddress(CScriptID(uint160(vSolutions[0]))); + return true; + } + // Multisig txns have more than one address... + return false; +} + class CAffectedKeysVisitor : public boost::static_visitor { private: const CKeyStore &keystore; + CAffectedKeysVisitor& operator=(CAffectedKeysVisitor const&); std::vector &vKeys; public: @@ -1519,7 +1778,7 @@ public: std::vector vDest; int nRequired; if (ExtractDestinations(script, type, vDest, nRequired)) { - BOOST_FOREACH(const CTxDestination &dest, vDest) + for (const CTxDestination &dest : vDest) boost::apply_visitor(*this, dest); } } @@ -1543,15 +1802,18 @@ void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey); } -bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector& addressRet, int& nRequiredRet) +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet) { addressRet.clear(); typeRet = TX_NONSTANDARD; - vector vSolutions; + std::vector vSolutions; if (!Solver(scriptPubKey, typeRet, vSolutions)) return false; if (typeRet == TX_NULL_DATA) + { + nRequiredRet = 0; return true; + } if (typeRet == TX_MULTISIG) { @@ -1565,6 +1827,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto else { nRequiredRet = 1; + if (typeRet == TX_PUBKEY_DROP) + return true; CTxDestination address; if (!ExtractDestination(scriptPubKey, address)) return false; @@ -1577,7 +1841,7 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { - vector > stack, stackCopy; + std::vector > stack, stackCopy; if (!EvalScript(stack, scriptSig, txTo, nIn, flags, nHashType)) return false; if (flags & SCRIPT_VERIFY_P2SH) @@ -1647,7 +1911,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0); + return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STRICT_FLAGS, 0); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) @@ -1661,26 +1925,26 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); } -static CScript PushAll(const vector& values) +static CScript PushAll(const std::vector& values) { CScript result; - BOOST_FOREACH(const valtype& v, values) + for (const valtype& v : values) result << v; return result; } -static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, - const vector& vSolutions, - vector& sigs1, vector& sigs2) +static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, + const std::vector& vSolutions, + std::vector& sigs1, std::vector& sigs2) { // Combine all the signatures we've got: - set allsigs; - BOOST_FOREACH(const valtype& v, sigs1) + std::set allsigs; + for (const valtype& v : sigs1) { if (!v.empty()) allsigs.insert(v); } - BOOST_FOREACH(const valtype& v, sigs2) + for (const valtype& v : sigs2) { if (!v.empty()) allsigs.insert(v); @@ -1689,9 +1953,9 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u // Build a map of pubkey -> signature by matching sigs to pubkeys: assert(vSolutions.size() > 1); unsigned int nSigsRequired = vSolutions.front()[0]; - unsigned int nPubKeys = vSolutions.size()-2; - map sigs; - BOOST_FOREACH(const valtype& sig, allsigs) + unsigned int nPubKeys = (unsigned int)(vSolutions.size()-2); + std::map sigs; + for (const valtype& sig : allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) { @@ -1724,9 +1988,9 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u return result; } -static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, - const txnouttype txType, const vector& vSolutions, - vector& sigs1, vector& sigs2) +static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, + const txnouttype txType, const std::vector& vSolutions, + std::vector& sigs1, std::vector& sigs2) { switch (txType) { @@ -1737,6 +2001,7 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, return PushAll(sigs1); return PushAll(sigs2); case TX_PUBKEY: + case TX_PUBKEY_DROP: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: if (sigs1.empty() || sigs1[0].empty()) @@ -1754,7 +2019,7 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; - vector > vSolutions2; + std::vector > vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.pop_back(); sigs2.pop_back(); @@ -1769,16 +2034,16 @@ static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, return CScript(); } -CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, +CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2) { txnouttype txType; - vector > vSolutions; + std::vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); - vector stack1; + std::vector stack1; EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); - vector stack2; + std::vector stack2; EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); @@ -1898,12 +2163,31 @@ void CScript::SetDestination(const CTxDestination& dest) boost::apply_visitor(CScriptVisitor(this), dest); } -void CScript::SetMultisig(int nRequired, const std::vector& keys) +void CScript::SetAddress(const CBitcoinAddress& dest) +{ + this->clear(); + if (dest.IsScript()) + *this << OP_HASH160 << dest.GetData() << OP_EQUAL; + else if (dest.IsPubKey()) + *this << OP_DUP << OP_HASH160 << dest.GetData() << OP_EQUALVERIFY << OP_CHECKSIG; + else if (dest.IsPair()) { + // Pubkey pair address, going to generate + // new one-time public key. + CMalleablePubKey mpk; + if (!mpk.setvch(dest.GetData())) + return; + CPubKey R, pubKeyVariant; + mpk.GetVariant(R, pubKeyVariant); + *this << pubKeyVariant << R << OP_DROP << OP_CHECKSIG; + } +} + +void CScript::SetMultisig(int nRequired, const std::vector& keys) { this->clear(); *this << EncodeOP_N(nRequired); - BOOST_FOREACH(const CKey& key, keys) - *this << key.GetPubKey(); - *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; + for (const CPubKey& key : keys) + *this << key; + *this << EncodeOP_N((int)(keys.size())) << OP_CHECKMULTISIG; }