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";
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];
// 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
// Standard tx, sender provides pubkey, receiver adds signature
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
- if (GetTime() > SMALLDATA_SWITCH_TIME)
+ if (fTestNet || GetTime() > 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));
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)
else
break;
}
+ else if (opcode2 == OP_INTEGER)
+ { // Up to four-byte integer pushed onto vSolutions
+ try
+ {
+ CBigNum bnVal = CastToBigNum(vch1);
+ if (bnVal <= 16)
+ break; // It's better to use OP_0 ... OP_16 for small integers.
+ vSolutionsRet.push_back(vch1);
+ }
+ catch(...)
+ {
+ break;
+ }
+ }
else if (opcode2 == OP_SMALLDATA)
{
// small pushdata, <= 1024 bytes
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<unsigned char> vchSig;
+ if (!key.Sign(hash, vchSig))
+ return false;
+ vchSig.push_back((unsigned char)nHashType);
+ scriptSigRet << vchSig;
+
+ return true;
+}
+
bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet)
{
int nSigned = 0;
case TX_NULL_DATA:
return false;
case TX_PUBKEY:
- case TX_PUBKEY_DROP:
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))
case TX_NULL_DATA:
break;
case TX_PUBKEY:
- case TX_PUBKEY_DROP:
keyID = CPubKey(vSolutions[0]).GetID();
if (keystore.HaveKey(keyID))
return MINE_SPENDABLE;
break;
+ case TX_PUBKEY_DROP:
+ {
+ CPubKey key = CPubKey(vSolutions[0]);
+ CPubKey R = CPubKey(vSolutions[1]);
+ if (keystore.CheckOwnership(key, R))
+ return MINE_SPENDABLE;
+ }
+ break;
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
if (keystore.HaveKey(keyID))
if (!Solver(scriptPubKey, typeRet, vSolutions))
return false;
if (typeRet == TX_NULL_DATA)
+ {
+ nRequiredRet = 0;
return true;
+ }
if (typeRet == TX_MULTISIG)
{
else
{
nRequiredRet = 1;
+ if (typeRet == TX_PUBKEY_DROP)
+ return true;
CTxDestination address;
if (!ExtractDestination(scriptPubKey, address))
return false;
boost::apply_visitor(CScriptVisitor(this), dest);
}
+void CScript::SetDestination(const CPubKey& R, CPubKey& pubKeyVariant)
+{
+ this->clear();
+ *this << pubKeyVariant << R << OP_DROP << OP_CHECKSIG;
+}
+
+
void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
{
this->clear();