diff options
Diffstat (limited to 'src/script')
| -rw-r--r-- | src/script/bitcoinconsensus.cpp | 14 | ||||
| -rw-r--r-- | src/script/bitcoinconsensus.h | 4 | ||||
| -rw-r--r-- | src/script/interpreter.cpp | 84 | ||||
| -rw-r--r-- | src/script/interpreter.h | 38 | ||||
| -rw-r--r-- | src/script/ismine.cpp | 36 | ||||
| -rw-r--r-- | src/script/ismine.h | 16 | ||||
| -rw-r--r-- | src/script/script.cpp | 8 | ||||
| -rw-r--r-- | src/script/script.h | 10 | ||||
| -rw-r--r-- | src/script/script_error.cpp | 4 | ||||
| -rw-r--r-- | src/script/sigcache.cpp | 16 | ||||
| -rw-r--r-- | src/script/sigcache.h | 4 | ||||
| -rw-r--r-- | src/script/sign.cpp | 63 | ||||
| -rw-r--r-- | src/script/sign.h | 11 | ||||
| -rw-r--r-- | src/script/standard.cpp | 23 | ||||
| -rw-r--r-- | src/script/standard.h | 28 |
15 files changed, 205 insertions, 154 deletions
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index 03128917f..8cc44b675 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -1,14 +1,14 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "bitcoinconsensus.h" +#include <script/bitcoinconsensus.h> -#include "primitives/transaction.h" -#include "pubkey.h" -#include "script/interpreter.h" -#include "version.h" +#include <primitives/transaction.h> +#include <pubkey.h> +#include <script/interpreter.h> +#include <version.h> namespace { @@ -40,7 +40,7 @@ public: } template<typename T> - TxInputStream& operator>>(T& obj) + TxInputStream& operator>>(T&& obj) { ::Unserialize(*this, obj); return *this; diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h index 33bf80e5a..bb94c1752 100644 --- a/src/script/bitcoinconsensus.h +++ b/src/script/bitcoinconsensus.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,7 @@ #include <stdint.h> #if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" +#include <config/bitcoin-config.h> #if defined(_WIN32) #if defined(DLL_EXPORT) #if defined(HAVE_FUNC_ATTRIBUTE_DLLEXPORT) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 77314e8cb..07b2292d4 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,17 +1,16 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "interpreter.h" +#include <script/interpreter.h> -#include "primitives/transaction.h" -#include "crypto/ripemd160.h" -#include "crypto/sha1.h" -#include "crypto/sha256.h" -#include "pubkey.h" -#include "script/script.h" -#include "uint256.h" +#include <crypto/ripemd160.h> +#include <crypto/sha1.h> +#include <crypto/sha256.h> +#include <pubkey.h> +#include <script/script.h> +#include <uint256.h> typedef std::vector<unsigned char> valtype; @@ -111,7 +110,7 @@ bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) { // excluding the sighash byte. // * R-length: 1-byte length descriptor of the R value that follows. // * R: arbitrary-length big-endian encoded R value. It must use the shortest - // possible encoding for a positive integers (which means no null bytes at + // possible encoding for a positive integer (which means no null bytes at // the start, except a single one when the next byte has its highest bit set). // * S-length: 1-byte length descriptor of the S value that follows. // * S: arbitrary-length big-endian encoded S value. The same rules apply. @@ -174,7 +173,13 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { if (!IsValidSignatureEncoding(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } + // https://bitcoin.stackexchange.com/a/12556: + // Also note that inside transaction signatures, an extra hashtype byte + // follows the actual signature data. std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1); + // 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 (!CPubKey::CheckLowS(vchSigCopy)) { return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); } @@ -214,30 +219,32 @@ bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, co return set_error(serror, SCRIPT_ERR_PUBKEYTYPE); } // Only compressed keys are accepted in segwit - if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SIGVERSION_WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) { + if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SigVersion::WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) { return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE); } return true; } bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { + // Excludes OP_1NEGATE, OP_1-16 since they are by definition minimal + assert(0 <= opcode && opcode <= OP_PUSHDATA4); if (data.size() == 0) { - // Could have used OP_0. + // Should have used OP_0. return opcode == OP_0; } else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) { - // Could have used OP_1 .. OP_16. - return opcode == OP_1 + (data[0] - 1); + // Should have used OP_1 .. OP_16. + return false; } else if (data.size() == 1 && data[0] == 0x81) { - // Could have used OP_1NEGATE. - return opcode == OP_1NEGATE; + // Should have used OP_1NEGATE. + return false; } else if (data.size() <= 75) { - // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). + // Must have used a direct push (opcode indicating number of bytes pushed + those bytes). return opcode == data.size(); } else if (data.size() <= 255) { - // Could have used OP_PUSHDATA. + // Must have used OP_PUSHDATA. return opcode == OP_PUSHDATA1; } else if (data.size() <= 65535) { - // Could have used OP_PUSHDATA2. + // Must have used OP_PUSHDATA2. return opcode == OP_PUSHDATA2; } return true; @@ -349,9 +356,6 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& { if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { // not enabled; treat as a NOP2 - if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { - return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); - } break; } @@ -391,9 +395,6 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& { if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) { // not enabled; treat as a NOP3 - if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { - return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); - } break; } @@ -442,7 +443,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& if (stack.size() < 1) return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); valtype& vch = stacktop(-1); - if (sigversion == SIGVERSION_WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) { + if (sigversion == SigVersion::WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) { if (vch.size() > 1) return set_error(serror, SCRIPT_ERR_MINIMALIF); if (vch.size() == 1 && vch[0] != 1) @@ -889,7 +890,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& CScript scriptCode(pbegincodehash, pend); // Drop the signature in pre-segwit scripts but not segwit scripts - if (sigversion == SIGVERSION_BASE) { + if (sigversion == SigVersion::BASE) { scriptCode.FindAndDelete(CScript(vchSig)); } @@ -953,7 +954,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& for (int k = 0; k < nSigsCount; k++) { valtype& vchSig = stacktop(-isig-k); - if (sigversion == SIGVERSION_BASE) { + if (sigversion == SigVersion::BASE) { scriptCode.FindAndDelete(CScript(vchSig)); } } @@ -1168,31 +1169,36 @@ uint256 GetOutputsHash(const CTransaction& txTo) { PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) { - hashPrevouts = GetPrevoutHash(txTo); - hashSequence = GetSequenceHash(txTo); - hashOutputs = GetOutputsHash(txTo); + // Cache is calculated only for transactions with witness + if (txTo.HasWitness()) { + hashPrevouts = GetPrevoutHash(txTo); + hashSequence = GetSequenceHash(txTo); + hashOutputs = GetOutputsHash(txTo); + ready = true; + } } uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { assert(nIn < txTo.vin.size()); - if (sigversion == SIGVERSION_WITNESS_V0) { + if (sigversion == SigVersion::WITNESS_V0) { uint256 hashPrevouts; uint256 hashSequence; uint256 hashOutputs; + const bool cacheready = cache && cache->ready; if (!(nHashType & SIGHASH_ANYONECANPAY)) { - hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo); + hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo); } if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo); + hashSequence = cacheready ? cache->hashSequence : GetSequenceHash(txTo); } if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo); + hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo); } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { CHashWriter ss(SER_GETHASH, 0); ss << txTo.vout[nIn]; @@ -1390,7 +1396,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } - if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_WITNESS_V0, serror)) { + if (!EvalScript(stack, scriptPubKey, flags, checker, SigVersion::WITNESS_V0, serror)) { return false; } @@ -1417,12 +1423,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C } std::vector<std::vector<unsigned char> > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, scriptSig, flags, checker, SigVersion::BASE, serror)) // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, scriptPubKey, flags, checker, SigVersion::BASE, serror)) // serror is set return false; if (stack.empty()) @@ -1468,7 +1474,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); - if (!EvalScript(stack, pubKey2, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, pubKey2, flags, checker, SigVersion::BASE, serror)) // serror is set return false; if (stack.empty()) diff --git a/src/script/interpreter.h b/src/script/interpreter.h index f845e1943..bb7750d78 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -1,13 +1,13 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_INTERPRETER_H #define BITCOIN_SCRIPT_INTERPRETER_H -#include "script_error.h" -#include "primitives/transaction.h" +#include <script/script_error.h> +#include <primitives/transaction.h> #include <vector> #include <stdint.h> @@ -27,37 +27,40 @@ enum SIGHASH_ANYONECANPAY = 0x80, }; -/** Script verification flags */ +/** Script verification flags. + * + * All flags are intended to be soft forks: the set of acceptable scripts under + * flags (A | B) is a subset of the acceptable scripts under flag (A). + */ enum { SCRIPT_VERIFY_NONE = 0, - // Evaluate P2SH subscripts (softfork safe, BIP16). + // Evaluate P2SH subscripts (BIP16). SCRIPT_VERIFY_P2SH = (1U << 0), // Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure. // Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure. - // (softfork safe, but not used or intended as a consensus rule). + // (not used or intended as a consensus rule). SCRIPT_VERIFY_STRICTENC = (1U << 1), - // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1) + // Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1) SCRIPT_VERIFY_DERSIG = (1U << 2), // Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure - // (softfork safe, BIP62 rule 5). + // (BIP62 rule 5). SCRIPT_VERIFY_LOW_S = (1U << 3), - // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7). + // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7). SCRIPT_VERIFY_NULLDUMMY = (1U << 4), - // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2). + // Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2). SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5), // Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct // pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating // any other push causes the script to fail (BIP62 rule 3). // In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4). - // (softfork safe) SCRIPT_VERIFY_MINIMALDATA = (1U << 6), // Discourage use of NOPs reserved for upgrades (NOP1-10) @@ -68,12 +71,14 @@ enum // discouraged NOPs fails the script. This verification flag will never be // a mandatory flag applied to scripts in a block. NOPs that are not // executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. + // NOPs that have associated forks to give them new meaning (CLTV, CSV) + // are not subject to this rule. SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7), // Require that only a single stack element remains after evaluation. This changes the success criterion from // "At least one stack element must remain, and when interpreted as a boolean, it must be true" to // "Exactly one stack element must remain, and when interpreted as a boolean, it must be true". - // (softfork safe, BIP62 rule 6) + // (BIP62 rule 6) // Note: CLEANSTACK should never be used without P2SH or WITNESS. SCRIPT_VERIFY_CLEANSTACK = (1U << 8), @@ -99,7 +104,7 @@ enum // SCRIPT_VERIFY_MINIMALIF = (1U << 13), - // Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed + // Signature(s) must be empty vector if a CHECK(MULTI)SIG operation failed // SCRIPT_VERIFY_NULLFAIL = (1U << 14), @@ -113,14 +118,15 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i struct PrecomputedTransactionData { uint256 hashPrevouts, hashSequence, hashOutputs; + bool ready = false; explicit PrecomputedTransactionData(const CTransaction& tx); }; -enum SigVersion +enum class SigVersion { - SIGVERSION_BASE = 0, - SIGVERSION_WITNESS_V0 = 1, + BASE = 0, + WITNESS_V0 = 1, }; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 6b68f0679..05bc5e9bd 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -1,29 +1,25 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "ismine.h" +#include <script/ismine.h> -#include "key.h" -#include "keystore.h" -#include "script/script.h" -#include "script/standard.h" -#include "script/sign.h" +#include <key.h> +#include <keystore.h> +#include <script/script.h> +#include <script/sign.h> typedef std::vector<unsigned char> valtype; -unsigned int HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore) +static bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore) { - unsigned int nResult = 0; - for (const valtype& pubkey : pubkeys) - { + for (const valtype& pubkey : pubkeys) { CKeyID keyID = CPubKey(pubkey).GetID(); - if (keystore.HaveKey(keyID)) - ++nResult; + if (!keystore.HaveKey(keyID)) return false; } - return nResult; + return true; } isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion sigversion) @@ -65,7 +61,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - if (sigversion != SIGVERSION_BASE && vSolutions[0].size() != 33) { + if (sigversion != SigVersion::BASE && vSolutions[0].size() != 33) { isInvalid = true; return ISMINE_NO; } @@ -80,14 +76,14 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& // This also applies to the P2WSH case. break; } - isminetype ret = ::IsMine(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, SIGVERSION_WITNESS_V0); + isminetype ret = ::IsMine(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, SigVersion::WITNESS_V0); if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) return ret; break; } case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - if (sigversion != SIGVERSION_BASE) { + if (sigversion != SigVersion::BASE) { CPubKey pubkey; if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) { isInvalid = true; @@ -118,7 +114,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& CScriptID scriptID = CScriptID(hash); CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { - isminetype ret = IsMine(keystore, subscript, isInvalid, SIGVERSION_WITNESS_V0); + isminetype ret = IsMine(keystore, subscript, isInvalid, SigVersion::WITNESS_V0); if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) return ret; } @@ -133,7 +129,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); - if (sigversion != SIGVERSION_BASE) { + if (sigversion != SigVersion::BASE) { for (size_t i = 0; i < keys.size(); i++) { if (keys[i].size() != 33) { isInvalid = true; @@ -141,7 +137,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& } } } - if (HaveKeys(keys, keystore) == keys.size()) + if (HaveKeys(keys, keystore)) return ISMINE_SPENDABLE; break; } diff --git a/src/script/ismine.h b/src/script/ismine.h index 1aa5937b3..f93a66e35 100644 --- a/src/script/ismine.h +++ b/src/script/ismine.h @@ -1,12 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_ISMINE_H #define BITCOIN_SCRIPT_ISMINE_H -#include "script/standard.h" +#include <script/standard.h> #include <stdint.h> @@ -29,13 +29,13 @@ enum isminetype typedef uint8_t isminefilter; /* isInvalid becomes true when the script is found invalid by consensus or policy. This will terminate the recursion - * and return a ISMINE_NO immediately, as an invalid script should never be considered as "mine". This is needed as + * and return ISMINE_NO immediately, as an invalid script should never be considered as "mine". This is needed as * different SIGVERSION may have different network rules. Currently the only use of isInvalid is indicate uncompressed - * keys in SIGVERSION_WITNESS_V0 script, but could also be used in similar cases in the future + * keys in SigVersion::WITNESS_V0 script, but could also be used in similar cases in the future */ -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion = SIGVERSION_BASE); -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion = SIGVERSION_BASE); -isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, bool& isInvalid, SigVersion = SIGVERSION_BASE); -isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion = SIGVERSION_BASE); +isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion = SigVersion::BASE); +isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion = SigVersion::BASE); +isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, bool& isInvalid, SigVersion = SigVersion::BASE); +isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion = SigVersion::BASE); #endif // BITCOIN_SCRIPT_ISMINE_H diff --git a/src/script/script.cpp b/src/script/script.cpp index a10b619f7..65e5405eb 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -1,12 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "script.h" +#include <script/script.h> -#include "tinyformat.h" -#include "utilstrencodings.h" +#include <tinyformat.h> +#include <utilstrencodings.h> const char* GetOpName(opcodetype opcode) { diff --git a/src/script/script.h b/src/script/script.h index 2a9206054..591777672 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -1,14 +1,14 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_SCRIPT_H #define BITCOIN_SCRIPT_SCRIPT_H -#include "crypto/common.h" -#include "prevector.h" -#include "serialize.h" +#include <crypto/common.h> +#include <prevector.h> +#include <serialize.h> #include <assert.h> #include <climits> @@ -568,7 +568,7 @@ public: pc += nSize; } - opcodeRet = (opcodetype)opcode; + opcodeRet = static_cast<opcodetype>(opcode); return true; } diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index 6c590f53e..dbceb1f74 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -1,9 +1,9 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "script_error.h" +#include <script/script_error.h> const char* ScriptErrorString(const ScriptError serror) { diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 4cc7afa2f..9638b12f9 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -1,17 +1,17 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "sigcache.h" +#include <script/sigcache.h> -#include "memusage.h" -#include "pubkey.h" -#include "random.h" -#include "uint256.h" -#include "util.h" +#include <memusage.h> +#include <pubkey.h> +#include <random.h> +#include <uint256.h> +#include <util.h> -#include "cuckoocache.h" +#include <cuckoocache.h> #include <boost/thread.hpp> namespace { diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 5832b264b..1309d57cc 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -1,12 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_SIGCACHE_H #define BITCOIN_SCRIPT_SIGCACHE_H -#include "script/interpreter.h" +#include <script/interpreter.h> #include <vector> diff --git a/src/script/sign.cpp b/src/script/sign.cpp index ac58b690a..598f7acd8 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,16 +1,16 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "script/sign.h" +#include <script/sign.h> -#include "key.h" -#include "keystore.h" -#include "policy/policy.h" -#include "primitives/transaction.h" -#include "script/standard.h" -#include "uint256.h" +#include <key.h> +#include <keystore.h> +#include <policy/policy.h> +#include <primitives/transaction.h> +#include <script/standard.h> +#include <uint256.h> typedef std::vector<unsigned char> valtype; @@ -24,7 +24,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, return false; // Signing with uncompressed keys is disabled in witness scripts - if (sigversion == SIGVERSION_WITNESS_V0 && !key.IsCompressed()) + if (sigversion == SigVersion::WITNESS_V0 && !key.IsCompressed()) return false; uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); @@ -140,10 +140,9 @@ static CScript PushAll(const std::vector<valtype>& values) bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata) { - CScript script = fromPubKey; std::vector<valtype> result; txnouttype whichType; - bool solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE); + bool solved = SignStep(creator, fromPubKey, result, whichType, SigVersion::BASE); bool P2SH = false; CScript subscript; sigdata.scriptWitness.stack.clear(); @@ -153,8 +152,8 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu // Solver returns the subscript that needs to be evaluated; // the final scriptSig is the signatures from that // and then the serialized subscript: - script = subscript = CScript(result[0].begin(), result[0].end()); - solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH; + subscript = CScript(result[0].begin(), result[0].end()); + solved = solved && SignStep(creator, subscript, result, whichType, SigVersion::BASE) && whichType != TX_SCRIPTHASH; P2SH = true; } @@ -163,7 +162,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu CScript witnessscript; witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG; txnouttype subType; - solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0); + solved = solved && SignStep(creator, witnessscript, result, subType, SigVersion::WITNESS_V0); sigdata.scriptWitness.stack = result; result.clear(); } @@ -171,7 +170,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu { CScript witnessscript(result[0].begin(), result[0].end()); txnouttype subType; - solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; + solved = solved && SignStep(creator, witnessscript, result, subType, SigVersion::WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end())); sigdata.scriptWitness.stack = result; result.clear(); @@ -195,11 +194,16 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI return data; } +void UpdateInput(CTxIn& input, const SignatureData& data) +{ + input.scriptSig = data.scriptSig; + input.scriptWitness = data.scriptWitness; +} + void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data) { assert(tx.vin.size() > nIn); - tx.vin[nIn].scriptSig = data.scriptSig; - tx.vin[nIn].scriptWitness = data.scriptWitness; + UpdateInput(tx.vin[nIn], data); } bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType) @@ -290,7 +294,7 @@ struct Stacks Stacks() {} explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_), witness() {} explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) { - EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); + EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SigVersion::BASE); } SignatureData Output() const { @@ -366,7 +370,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature sigs2.witness.pop_back(); sigs2.script = sigs2.witness; sigs2.witness.clear(); - Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SIGVERSION_WITNESS_V0); + Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SigVersion::WITNESS_V0); result.witness = result.script; result.script.clear(); result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end())); @@ -384,7 +388,7 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature std::vector<std::vector<unsigned char> > vSolutions; Solver(scriptPubKey, txType, vSolutions); - return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output(); + return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SigVersion::BASE).Output(); } namespace { @@ -422,3 +426,22 @@ bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const vchSig[6 + 33 + 32] = SIGHASH_ALL; return true; } + +bool IsSolvable(const CKeyStore& store, const CScript& script) +{ + // This check is to make sure that the script we created can actually be solved for and signed by us + // if we were to have the private keys. This is just to make sure that the script is valid and that, + // if found in a transaction, we would still accept and relay that transaction. In particular, + // it will reject witness outputs that require signing with an uncompressed public key. + DummySignatureCreator creator(&store); + SignatureData sigs; + // Make sure that STANDARD_SCRIPT_VERIFY_FLAGS includes SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, the most + // important property this function is designed to test for. + static_assert(STANDARD_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, "IsSolvable requires standard script flags to include WITNESS_PUBKEYTYPE"); + if (ProduceSignature(creator, script, sigs)) { + // VerifyScript check is just defensive, and should never fail. + assert(VerifyScript(sigs.scriptSig, script, &sigs.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker())); + return true; + } + return false; +} diff --git a/src/script/sign.h b/src/script/sign.h index a0d8ee4ff..2c749521c 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -1,12 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_SIGN_H #define BITCOIN_SCRIPT_SIGN_H -#include "script/interpreter.h" +#include <script/interpreter.h> class CKeyID; class CKeyStore; @@ -80,5 +80,12 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature /** Extract signature data from a transaction, and insert it. */ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data); +void UpdateInput(CTxIn& input, const SignatureData& data); + +/* Check whether we know how to sign for an output like this, assuming we + * have all private keys. While this function does not need private keys, the passed + * keystore is used to look up public keys and redeemscripts by hash. + * Solvability is unrelated to whether we consider this output to be ours. */ +bool IsSolvable(const CKeyStore& store, const CScript& script); #endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/script/standard.cpp b/src/script/standard.cpp index f57f1f61b..cfb3c5858 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -1,14 +1,14 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "script/standard.h" +#include <script/standard.h> -#include "pubkey.h" -#include "script/script.h" -#include "util.h" -#include "utilstrencodings.h" +#include <pubkey.h> +#include <script/script.h> +#include <util.h> +#include <utilstrencodings.h> typedef std::vector<unsigned char> valtype; @@ -348,19 +348,14 @@ CScript GetScriptForWitness(const CScript& redeemscript) std::vector<std::vector<unsigned char> > vSolutions; if (Solver(redeemscript, typ, vSolutions)) { if (typ == TX_PUBKEY) { - unsigned char h160[20]; - CHash160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160); - ret << OP_0 << std::vector<unsigned char>(&h160[0], &h160[20]); - return ret; + return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); } else if (typ == TX_PUBKEYHASH) { - ret << OP_0 << vSolutions[0]; - return ret; + return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); } } uint256 hash; CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin()); - ret << OP_0 << ToByteVector(hash); - return ret; + return GetScriptForDestination(WitnessV0ScriptHash(hash)); } bool IsValidDestination(const CTxDestination& dest) { diff --git a/src/script/standard.h b/src/script/standard.h index fa07ea88c..3b2838a5b 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -1,13 +1,13 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCRIPT_STANDARD_H #define BITCOIN_SCRIPT_STANDARD_H -#include "script/interpreter.h" -#include "uint256.h" +#include <script/interpreter.h> +#include <uint256.h> #include <boost/variant.hpp> @@ -73,8 +73,19 @@ public: friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } }; -struct WitnessV0ScriptHash : public uint256 {}; -struct WitnessV0KeyHash : public uint160 {}; +struct WitnessV0ScriptHash : public uint256 +{ + WitnessV0ScriptHash() : uint256() {} + explicit WitnessV0ScriptHash(const uint256& hash) : uint256(hash) {} + using uint256::uint256; +}; + +struct WitnessV0KeyHash : public uint160 +{ + WitnessV0KeyHash() : uint160() {} + explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {} + using uint160::uint160; +}; //! CTxDestination subtype to encode any future Witness version struct WitnessUnknown @@ -144,6 +155,10 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) * addressRet is populated with a single value and nRequiredRet is set to 1. * Returns true if successful. Currently does not extract address from * pay-to-witness scripts. + * + * Note: this function confuses destinations (a subset of CScripts that are + * encodable as an address) with key identifiers (of keys involved in a + * CScript), and its use should be phased out. */ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); @@ -164,6 +179,9 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys); * Generate a pay-to-witness script for the given redeem script. If the redeem * script is P2PK or P2PKH, this returns a P2WPKH script, otherwise it returns a * P2WSH script. + * + * TODO: replace calls to GetScriptForWitness with GetScriptForDestination using + * the various witness-specific CTxDestination subtypes. */ CScript GetScriptForWitness(const CScript& redeemscript); |