case OP_ENDIF : return "OP_ENDIF";
case OP_VERIFY : return "OP_VERIFY";
case OP_RETURN : return "OP_RETURN";
+ case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
// stack ops
case OP_TOALTSTACK : return "OP_TOALTSTACK";
// 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";
// Control
//
case OP_NOP:
- 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:
break;
}
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;
+ }
//
// Stack ops
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
}
+ vSolutionsRet.clear();
+
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
if (scriptPubKey.IsPayToScriptHash())
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)