X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fscript.cpp;h=ceacdc38466ef8114b4672b15f614633b820a159;hb=1ebe5b92ef18395cdae9b88fc38b0ed6166c3243;hp=c7c2b29e7d0a56c6831ddc921938e2cd1e8535c9;hpb=311c10210ed8edca195066a9fdd09036db31f89a;p=novacoin.git diff --git a/src/script.cpp b/src/script.cpp index c7c2b29..ceacdc3 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -148,6 +148,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"; @@ -230,8 +232,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"; @@ -294,7 +294,7 @@ bool IsDERSignature(const valtype &vchSig, bool fWithHashType, bool fCheckLow) { if (5 + nLenR >= vchSig.size()) return error("Non-canonical signature: S length misplaced"); unsigned int nLenS = vchSig[5+nLenR]; - if ((unsigned long)(nLenR + nLenS + (fWithHashType ? 7 : 6)) != 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]; @@ -338,6 +338,83 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { 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(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { CAutoBN_CTX pctx; @@ -422,7 +499,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; @@ -481,6 +558,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 @@ -1211,6 +1349,8 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector= 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) @@ -1293,6 +1443,20 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vectorclear(); - *this << pubKeyVariant << R << OP_DROP << OP_CHECKSIG; + 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();