diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/interpreter.cpp | 83 | ||||
-rw-r--r-- | src/script/interpreter.h | 11 | ||||
-rw-r--r-- | src/script/script.h | 21 | ||||
-rw-r--r-- | src/script/script_error.cpp | 4 | ||||
-rw-r--r-- | src/script/script_error.h | 4 | ||||
-rw-r--r-- | src/script/sign.cpp | 39 | ||||
-rw-r--r-- | src/script/sign.h | 8 | ||||
-rw-r--r-- | src/script/standard.cpp | 20 | ||||
-rw-r--r-- | src/script/standard.h | 17 |
9 files changed, 164 insertions, 43 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 84a7432fdb..0b78fdf5a8 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -335,9 +335,51 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un // Control // case OP_NOP: - break; + break; + + case OP_CHECKLOCKTIMEVERIFY: + { + 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; + } + + if (stack.size() < 1) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + // Note that elsewhere numeric opcodes are limited to + // operands in the range -2**31+1 to 2**31-1, however it is + // legal for opcodes to produce results exceeding that + // range. This limitation is implemented by CScriptNum's + // default 4-byte limit. + // + // If we kept to that limit we'd have a year 2038 problem, + // even though the nLockTime field in transactions + // themselves is uint32 which only becomes meaningless + // after the year 2106. + // + // Thus as a special case we tell CScriptNum to accept up + // to 5-byte bignums, which are good until 2**39-1, well + // beyond the 2**32-1 limit of the nLockTime field itself. + const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5); + + // 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 set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); + + // Actually compare the specified lock time with the transaction. + if (!checker.CheckLockTime(nLockTime)) + return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME); + + break; + } - case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: + case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) @@ -1084,6 +1126,43 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn return true; } +bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const +{ + // There are two times 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 (txTo->vin[nIn].IsFinal()) + return false; + + return true; +} + + bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); diff --git a/src/script/interpreter.h b/src/script/interpreter.h index fc64438f68..35d572f0ad 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -76,6 +76,11 @@ enum // (softfork safe, BIP62 rule 6) // Note: CLEANSTACK should never be used without P2SH. SCRIPT_VERIFY_CLEANSTACK = (1U << 8), + + // Verify CHECKLOCKTIMEVERIFY + // + // See BIP65 for details. + SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), }; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); @@ -88,6 +93,11 @@ public: return false; } + virtual bool CheckLockTime(const CScriptNum& nLockTime) const + { + return false; + } + virtual ~BaseSignatureChecker() {} }; @@ -103,6 +113,7 @@ protected: public: TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const; + bool CheckLockTime(const CScriptNum& nLockTime) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/script.h b/src/script/script.h index d5045005be..e39ca57f4f 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -19,6 +19,10 @@ static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes +// Threshold for nLockTime: below this value it is interpreted as block number, +// otherwise as UNIX timestamp. +static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC + template <typename T> std::vector<unsigned char> ToByteVector(const T& in) { @@ -151,6 +155,7 @@ enum opcodetype // expansion OP_NOP1 = 0xb0, OP_NOP2 = 0xb1, + OP_CHECKLOCKTIMEVERIFY = OP_NOP2, OP_NOP3 = 0xb2, OP_NOP4 = 0xb3, OP_NOP5 = 0xb4, @@ -196,7 +201,10 @@ public: m_value = n; } - explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal) + static const size_t nDefaultMaxNumSize = 4; + + explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal, + const size_t nMaxNumSize = nDefaultMaxNumSize) { if (vch.size() > nMaxNumSize) { throw scriptnum_error("script number overflow"); @@ -319,8 +327,6 @@ public: return result; } - static const size_t nMaxNumSize = 4; - private: static int64_t set_vch(const std::vector<unsigned char>& vch) { @@ -603,4 +609,13 @@ public: } }; +class CReserveScript +{ +public: + CScript reserveScript; + virtual void KeepScript() {} + CReserveScript() {} + virtual ~CReserveScript() {} +}; + #endif // BITCOIN_SCRIPT_SCRIPT_H diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index d8ecfde1d7..f1aa1fb408 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -47,6 +47,10 @@ const char* ScriptErrorString(const ScriptError serror) return "OP_RETURN was encountered"; case SCRIPT_ERR_UNBALANCED_CONDITIONAL: return "Invalid OP_IF construction"; + case SCRIPT_ERR_NEGATIVE_LOCKTIME: + return "Negative locktime"; + case SCRIPT_ERR_UNSATISFIED_LOCKTIME: + return "Locktime requirement not satisfied"; case SCRIPT_ERR_SIG_HASHTYPE: return "Signature hash type missing or not understood"; case SCRIPT_ERR_SIG_DER: diff --git a/src/script/script_error.h b/src/script/script_error.h index 6365680b29..bb10b8a293 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -35,6 +35,10 @@ typedef enum ScriptError_t SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, SCRIPT_ERR_UNBALANCED_CONDITIONAL, + /* OP_CHECKLOCKTIMEVERIFY */ + SCRIPT_ERR_NEGATIVE_LOCKTIME, + SCRIPT_ERR_UNSATISFIED_LOCKTIME, + /* BIP62 */ SCRIPT_ERR_SIG_HASHTYPE, SCRIPT_ERR_SIG_DER, diff --git a/src/script/sign.cpp b/src/script/sign.cpp index eab629cd91..8b43183b6d 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -5,9 +5,10 @@ #include "script/sign.h" -#include "primitives/transaction.h" #include "key.h" #include "keystore.h" +#include "policy/policy.h" +#include "primitives/transaction.h" #include "script/standard.h" #include "uint256.h" @@ -275,3 +276,39 @@ CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecke return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2); } + +namespace { +/** Dummy signature checker which accepts all signatures. */ +class DummySignatureChecker : public BaseSignatureChecker +{ +public: + DummySignatureChecker() {} + + bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const + { + return true; + } +}; +const DummySignatureChecker dummyChecker; +} + +const BaseSignatureChecker& DummySignatureCreator::Checker() const +{ + return dummyChecker; +} + +bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const +{ + // Create a dummy signature that is a valid DER-encoding + vchSig.assign(72, '\000'); + vchSig[0] = 0x30; + vchSig[1] = 69; + vchSig[2] = 0x02; + vchSig[3] = 33; + vchSig[4] = 0x01; + vchSig[4 + 33] = 0x02; + vchSig[5 + 33] = 32; + vchSig[6 + 33] = 0x01; + vchSig[6 + 33 + 32] = SIGHASH_ALL; + return true; +} diff --git a/src/script/sign.h b/src/script/sign.h index 0c4cf61e5e..13f45007dd 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -43,6 +43,14 @@ public: bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const; }; +/** A signature creator that just produces 72-byte empty signatyres. */ +class DummySignatureCreator : public BaseSignatureCreator { +public: + DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {} + const BaseSignatureChecker& Checker() const; + bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const; +}; + /** Produce a script signature using a generic signature creator. */ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index ce50e3aad8..66657127ab 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -180,26 +180,6 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c return -1; } -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) -{ - vector<valtype> vSolutions; - 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; -} - bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { vector<valtype> vSolutions; diff --git a/src/script/standard.h b/src/script/standard.h index a8b0acc981..46ae5f9f10 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -39,22 +39,6 @@ extern unsigned nMaxDatacarrierBytes; */ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH; -/** - * Standard script verification flags that standard transactions will comply - * with. However scripts violating these flags may still be present in valid - * blocks and we must accept those blocks. - */ -static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | - SCRIPT_VERIFY_DERSIG | - SCRIPT_VERIFY_STRICTENC | - SCRIPT_VERIFY_MINIMALDATA | - SCRIPT_VERIFY_NULLDUMMY | - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | - SCRIPT_VERIFY_CLEANSTACK; - -/** For convenience, standard but not mandatory verify flags. */ -static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; - enum txnouttype { TX_NONSTANDARD, @@ -85,7 +69,6 @@ const char* GetTxnOutputType(txnouttype t); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet); int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions); -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); |