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<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
{
CAutoBN_CTX pctx;
// CHECKLOCKTIMEVERIFY
//
// (nLockTime -- nLockTime)
- if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY))
- break; // treat as a NOP is not enabled
+ if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
+ // treat as a NOP2 if not enabled
+ break;
+ }
+
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;
+ CBigNum nLockTime = CastToBigNum(stacktop(-1));
- // Now we can perform a simple numerical comparison
- if (nLockTime > (int64_t)txTo.nLockTime)
+ // 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;
- // 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())
+ // 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 NOP if not enabled
+ if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
+ // treat as a NOP3 not enabled
break;
+ }
+
if (stack.size() < 1)
return false;
- const CBigNum nInvSequence = CastToBigNum(stacktop(-1));
+
+ // 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 (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)
+ if (nSequence < 0)
return false;
- if (!(
- (txToLockTime < LOCKTIME_THRESHOLD && nInvSequence < LOCKTIME_THRESHOLD) ||
- (txToLockTime >= LOCKTIME_THRESHOLD && nInvSequence >= LOCKTIME_THRESHOLD)
- ))
- 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;
- // Now that we know we're comparing apples-to-apples, the
- // comparison is a simple numeric one.
- if (nInvSequence > txToLockTime)
+ // Compare the specified sequence number with the input.
+ if (!CheckSequence(nSequence.getuint64(), txTo, nIn))
return false;
break;
{
static CSignatureCache signatureCache;
- CKey key;
- if (!key.SetPubKey(vchPubKey))
- return false;
- CPubKey pubkey = key.GetPubKey();
+ CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
return false;
if (signatureCache.Get(sighash, vchSig, pubkey))
return true;
- if (!key.Verify(sighash, vchSig))
+ if (!pubkey.Verify(sighash, vchSig))
return false;
if (!(flags & SCRIPT_VERIFY_NOCACHE))
}
-
-
-
-
-
-
//
// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
//
// Standard tx, sender provides pubkey, receiver adds signature
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
- 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));
- }
+ // 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));
// Compare
CScript::const_iterator pc1 = script1.begin();
CScript::const_iterator pc2 = script2.begin();
- while (true)
+ for ( ; ; )
{
if (pc1 == script1.end() && pc2 == script2.end())
{
else if (opcode2 == OP_SMALLDATA)
{
// small pushdata, <= 1024 bytes
- if (vch1.size() > (GetTime() > SMALLDATA_SWITCH_TIME ? 1024 : 80))
+ if (vch1.size() > 1024)
break;
}
else if (opcode1 != opcode2 || vch1 != vch2)
bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
};
+/*
isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
{
CScript script;
script.SetDestination(dest);
return IsMine(keystore, script);
+}*/
+
+isminetype IsMine(const CKeyStore &keystore, const CBitcoinAddress& dest)
+{
+ CScript script;
+ script.SetAddress(dest);
+ return IsMine(keystore, script);
}
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
return false;
}
+bool ExtractAddress(const CKeyStore &keystore, const CScript& scriptPubKey, CBitcoinAddress& addressRet)
+{
+ vector<valtype> vSolutions;
+ txnouttype whichType;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
+ return false;
+
+ if (whichType == TX_PUBKEY)
+ {
+ addressRet = CBitcoinAddress(CPubKey(vSolutions[0]).GetID());
+ return true;
+ }
+ if (whichType == TX_PUBKEY_DROP)
+ {
+ // Pay-to-Pubkey-R
+ CMalleableKeyView view;
+ if (!keystore.CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view))
+ return false;
+
+ addressRet = CBitcoinAddress(view.GetMalleablePubKey());
+ return true;
+ }
+ else if (whichType == TX_PUBKEYHASH)
+ {
+ addressRet = CBitcoinAddress(CKeyID(uint160(vSolutions[0])));
+ return true;
+ }
+ else if (whichType == TX_SCRIPTHASH)
+ {
+ addressRet = CBitcoinAddress(CScriptID(uint160(vSolutions[0])));
+ return true;
+ }
+ // Multisig txns have more than one address...
+ return false;
+}
+
class CAffectedKeysVisitor : public boost::static_visitor<void> {
private:
const CKeyStore &keystore;
boost::apply_visitor(CScriptVisitor(this), dest);
}
-void CScript::SetDestination(const CPubKey& R, CPubKey& pubKeyVariant)
+void CScript::SetAddress(const CBitcoinAddress& dest)
{
this->clear();
- *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<CKey>& keys)
+void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
{
this->clear();
*this << EncodeOP_N(nRequired);
- BOOST_FOREACH(const CKey& key, keys)
- *this << key.GetPubKey();
+ BOOST_FOREACH(const CPubKey& key, keys)
+ *this << key;
*this << EncodeOP_N((int)(keys.size())) << OP_CHECKMULTISIG;
}