X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fscript.cpp;h=c0da405b215322cb886082b854282649b86efc6c;hb=09bb63d7438ad8550288b852695dea78cff3babc;hp=ebf378e56941ca332f1b52f24300d2f0bffa1735;hpb=d335d83d0e8f72e274be8e05829f6063d7ecc3e7;p=novacoin.git diff --git a/src/script.cpp b/src/script.cpp index ebf378e..c0da405 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -99,6 +99,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 +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"; @@ -229,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"; @@ -293,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]; @@ -421,7 +422,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; @@ -480,6 +481,80 @@ bool EvalScript(vector >& stack, const CScript& script, co } break; + case OP_CHECKLOCKTIMEVERIFY: + { + // CHECKLOCKTIMEVERIFY + // + // (nLockTime -- nLockTime) + if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) + break; // treat as a NOP is not enabled + if (stack.size() < 1) + return false; + const CBigNum nLockTime = CastToBigNum(stacktop(-1)); + if (nLockTime < 0) + return false; // Negative argument is senseless. + + if (!( // We can have either lock-by-blockheight or lock-by-blocktime. + (txTo.nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) || + (txTo.nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD) + )) + return false; + + // Now we can perform a simple numerical comparison + 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; + break; + } + + case OP_CHECKSEQUENCEVERIFY: + { + if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) + // treat as a NOP if not enabled + break; + if (stack.size() < 1) + return false; + const CBigNum nInvSequence = 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 (nInvSequence < 0) + return false; // negative nSequence is senseless + + // Relative lock times are supported by comparing the passed + // in lock time to the sequence number of the input. All other + // logic is the same, all that differs is what we are comparing + // the lock time to. + int64_t txToLockTime = (int64_t)~txTo.vin[nIn].nSequence; + if (txToLockTime >= SEQUENCE_THRESHOLD) + return false; + + if (!( + (txToLockTime < SEQUENCE_THRESHOLD && nInvSequence < SEQUENCE_THRESHOLD) || + (txToLockTime >= SEQUENCE_THRESHOLD && nInvSequence >= SEQUENCE_THRESHOLD) + )) + return false; + + // Now that we know we're comparing apples-to-apples, the + // comparison is a simple numeric one. + if (nInvSequence > txToLockTime) + return false; + + break; + } // // Stack ops @@ -1194,6 +1269,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector SMALLDATA_SWITCH_TIME) + { + // 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)); @@ -1204,6 +1285,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) @@ -1286,10 +1379,24 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector 80) + // small pushdata, <= 1024 bytes + if (vch1.size() > (GetTime() > SMALLDATA_SWITCH_TIME ? 1024 : 80)) break; } else if (opcode1 != opcode2 || vch1 != vch2) @@ -1321,6 +1428,21 @@ bool Sign1(const CKeyID& address, const CKeyStore& keystore, const uint256& hash return true; } +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; + + vector vchSig; + if (!key.Sign(hash, vchSig)) + return false; + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig; + + return true; +} + bool SignN(const vector& multisigdata, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet) { int nSigned = 0; @@ -1359,6 +1481,12 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, const uint25 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)) @@ -1389,6 +1517,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vectorclear(); + *this << pubKeyVariant << R << OP_DROP << OP_CHECKSIG; +} + + void CScript::SetMultisig(int nRequired, const std::vector& keys) { this->clear();