// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <boost/foreach.hpp>
-#include <boost/tuple/tuple.hpp>
-
-using namespace std;
-using namespace boost;
#include "script.h"
#include "keystore.h"
#include "sync.h"
#include "util.h"
+using namespace std;
+
bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
static const valtype vchFalse(0);
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";
// expanson
case OP_NOP1 : return "OP_NOP1";
- case OP_NOP3 : return "OP_NOP3";
case OP_NOP4 : return "OP_NOP4";
case OP_NOP5 : return "OP_NOP5";
case OP_NOP6 : return "OP_NOP6";
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];
return IsDERSignature(vchSig, true, (flags & SCRIPT_VERIFY_LOW_S) != 0);
}
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
+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, uint32_t nIn, unsigned int flags, int nHashType)
{
CAutoBN_CTX pctx;
- CScript::const_iterator pc = script.begin();
- CScript::const_iterator pend = script.end();
- CScript::const_iterator pbegincodehash = script.begin();
+ auto pc = script.begin();
+ auto pend = script.end();
+ auto pbegincodehash = script.begin();
opcodetype opcode;
valtype vchPushValue;
vector<bool> vfExec;
opcode == OP_RSHIFT)
return false; // Disabled opcodes.
- if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4)
+ if (fExec && opcode <= OP_PUSHDATA4)
stack.push_back(vchPushValue);
else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
switch (opcode)
case OP_16:
{
// ( -- value)
- CBigNum bn((int)opcode - (int)(OP_1 - 1));
+ CBigNum bn(opcode - (OP_1 - 1));
stack.push_back(bn.getvch());
}
break;
// Control
//
case OP_NOP:
- case OP_NOP1: 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;
{
if (stack.size() < 1)
return false;
- valtype& vch = stacktop(-1);
+ auto& vch = stacktop(-1);
fValue = CastToBool(vch);
if (opcode == OP_NOTIF)
fValue = !fValue;
// 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));
+
+ auto 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; // Negative argument is senseless.
+ return false;
- 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)
- ))
+ // Actually compare the specified lock time with the transaction.
+ if (!CheckLockTime(nLockTime.getuint64(), txTo, nIn))
return false;
- // Now we can perform a simple numerical comparison
- if (nLockTime > (int64_t)txTo.nLockTime)
+ break;
+ }
+
+ case OP_CHECKSEQUENCEVERIFY:
+ {
+ if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
+ // treat as a NOP3 not enabled
+ break;
+ }
+
+ if (stack.size() < 1)
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())
+ // nSequence, like nLockTime, is a 32-bit unsigned integer
+ // field. See the comment in CHECKLOCKTIMEVERIFY regarding
+ // 5-byte numeric operands.
+ auto 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;
}
// (x1 x2 -- x1 x2 x1 x2)
if (stack.size() < 2)
return false;
- valtype vch1 = stacktop(-2);
- valtype vch2 = stacktop(-1);
+ auto vch1 = stacktop(-2);
+ auto vch2 = stacktop(-1);
stack.push_back(vch1);
stack.push_back(vch2);
}
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
if (stack.size() < 3)
return false;
- valtype vch1 = stacktop(-3);
- valtype vch2 = stacktop(-2);
- valtype vch3 = stacktop(-1);
+ auto vch1 = stacktop(-3);
+ auto vch2 = stacktop(-2);
+ auto vch3 = stacktop(-1);
stack.push_back(vch1);
stack.push_back(vch2);
stack.push_back(vch3);
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
if (stack.size() < 4)
return false;
- valtype vch1 = stacktop(-4);
- valtype vch2 = stacktop(-3);
+ auto vch1 = stacktop(-4);
+ auto vch2 = stacktop(-3);
stack.push_back(vch1);
stack.push_back(vch2);
}
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
if (stack.size() < 6)
return false;
- valtype vch1 = stacktop(-6);
- valtype vch2 = stacktop(-5);
+ auto vch1 = stacktop(-6);
+ auto vch2 = stacktop(-5);
stack.erase(stack.end()-6, stack.end()-4);
stack.push_back(vch1);
stack.push_back(vch2);
// (x - 0 | x x)
if (stack.size() < 1)
return false;
- valtype vch = stacktop(-1);
+ auto vch = stacktop(-1);
if (CastToBool(vch))
stack.push_back(vch);
}
// (x -- x x)
if (stack.size() < 1)
return false;
- valtype vch = stacktop(-1);
+ auto vch = stacktop(-1);
stack.push_back(vch);
}
break;
// (x1 x2 -- x1 x2 x1)
if (stack.size() < 2)
return false;
- valtype vch = stacktop(-2);
+ auto vch = stacktop(-2);
stack.push_back(vch);
}
break;
popstack(stack);
if (n < 0 || n >= (int)stack.size())
return false;
- valtype vch = stacktop(-n-1);
+ auto vch = stacktop(-n-1);
if (opcode == OP_ROLL)
stack.erase(stack.end()-n-1);
stack.push_back(vch);
// (x1 x2 -- x2 x1 x2)
if (stack.size() < 2)
return false;
- valtype vch = stacktop(-1);
+ auto vch = stacktop(-1);
stack.insert(stack.end()-2, vch);
}
break;
// (x1 x2 - bool)
if (stack.size() < 2)
return false;
- valtype& vch1 = stacktop(-2);
- valtype& vch2 = stacktop(-1);
+ auto& vch1 = stacktop(-2);
+ auto& vch2 = stacktop(-1);
bool fEqual = (vch1 == vch2);
// OP_NOTEQUAL is disabled because it would be too easy to say
// something like n != 1 and have some wiseguy pass in 1 with extra
// (in -- out)
if (stack.size() < 1)
return false;
- CBigNum bn = CastToBigNum(stacktop(-1));
+ auto bn = CastToBigNum(stacktop(-1));
switch (opcode)
{
case OP_1ADD: bn += bnOne; break;
// (x1 x2 -- out)
if (stack.size() < 2)
return false;
- CBigNum bn1 = CastToBigNum(stacktop(-2));
- CBigNum bn2 = CastToBigNum(stacktop(-1));
+ auto bn1 = CastToBigNum(stacktop(-2));
+ auto bn2 = CastToBigNum(stacktop(-1));
CBigNum bn;
switch (opcode)
{
// (x min max -- out)
if (stack.size() < 3)
return false;
- CBigNum bn1 = CastToBigNum(stacktop(-3));
- CBigNum bn2 = CastToBigNum(stacktop(-2));
- CBigNum bn3 = CastToBigNum(stacktop(-1));
+ auto bn1 = CastToBigNum(stacktop(-3));
+ auto bn2 = CastToBigNum(stacktop(-2));
+ auto bn3 = CastToBigNum(stacktop(-1));
bool fValue = (bn2 <= bn1 && bn1 < bn3);
popstack(stack);
popstack(stack);
// (in -- hash)
if (stack.size() < 1)
return false;
- valtype& vch = stacktop(-1);
+ auto& vch = stacktop(-1);
valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
if (opcode == OP_RIPEMD160)
RIPEMD160(&vch[0], vch.size(), &vchHash[0]);
SHA256(&vch[0], vch.size(), &vchHash[0]);
else if (opcode == OP_HASH160)
{
- uint160 hash160 = Hash160(vch);
+ auto hash160 = Hash160(vch);
memcpy(&vchHash[0], &hash160, sizeof(hash160));
}
else if (opcode == OP_HASH256)
{
- uint256 hash = Hash(vch.begin(), vch.end());
+ auto hash = Hash(vch.begin(), vch.end());
memcpy(&vchHash[0], &hash, sizeof(hash));
}
popstack(stack);
if (stack.size() < 2)
return false;
- valtype& vchSig = stacktop(-2);
- valtype& vchPubKey = stacktop(-1);
+ auto& vchSig = stacktop(-2);
+ auto& vchPubKey = stacktop(-1);
////// debug print
//PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n");
// Drop the signatures, since there's no way for a signature to sign itself
for (int k = 0; k < nSigsCount; k++)
{
- valtype& vchSig = stacktop(-isig-k);
+ auto& vchSig = stacktop(-isig-k);
scriptCode.FindAndDelete(CScript(vchSig));
}
bool fSuccess = true;
while (fSuccess && nSigsCount > 0)
{
- valtype& vchSig = stacktop(-isig);
- valtype& vchPubKey = stacktop(-ikey);
+ auto& vchSig = stacktop(-isig);
+ auto& vchPubKey = stacktop(-ikey);
// Check signature
bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
-uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
+uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, uint32_t nIn, int nHashType)
{
if (nIn >= txTo.vin.size())
{
- printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
+ printf("ERROR: SignatureHash() : nIn=%" PRIu32 " out of range\n", nIn);
return 1;
}
CTransaction txTmp(txTo);
else if ((nHashType & 0x1f) == SIGHASH_SINGLE)
{
// Only lock-in the txout payee at same index as txin
- unsigned int nOut = nIn;
+ uint32_t nOut = nIn;
if (nOut >= txTmp.vout.size())
{
- printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut);
+ printf("ERROR: SignatureHash() : nOut=%" PRIu32 " out of range\n", nOut);
return 1;
}
txTmp.vout.resize(nOut+1);
{
private:
// sigdata_type is (signature hash, signature, public key):
- typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey > sigdata_type;
- std::set< sigdata_type> setValid;
+ typedef tuple<uint256, std::vector<unsigned char>, CPubKey > sigdata_type;
+ set< sigdata_type> setValid;
boost::shared_mutex cs_sigcache;
public:
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
sigdata_type k(hash, vchSig, pubKey);
- std::set<sigdata_type>::iterator mi = setValid.find(k);
+ auto mi = setValid.find(k);
if (mi != setValid.end())
return true;
return false;
// foil would-be DoS attackers who might try to pre-generate
// and re-use a set of valid signatures just-slightly-greater
// than our cache size.
- uint256 randomHash = GetRandHash();
+ auto randomHash = GetRandHash();
std::vector<unsigned char> unused;
- std::set<sigdata_type>::iterator it =
- setValid.lower_bound(sigdata_type(randomHash, unused, unused));
+ auto it = setValid.lower_bound(sigdata_type(randomHash, unused, unused));
if (it == setValid.end())
it = setValid.begin();
setValid.erase(*it);
{
static CSignatureCache signatureCache;
- CKey key;
- if (!key.SetPubKey(vchPubKey))
- return false;
- CPubKey pubkey = key.GetPubKey();
+ CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
return false;
return false;
vchSig.pop_back();
- uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
+ auto sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
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.
//
if (mTemplates.empty())
{
// Standard tx, sender provides pubkey, receiver adds signature
- mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
+ mTemplates.insert({ 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({ 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));
+ mTemplates.insert({ TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG });
// Sender provides N pubkeys, receivers provides M signatures
- mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+ mTemplates.insert({ TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG });
// Empty, provably prunable, data-carrying output
- mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
+ mTemplates.insert({ 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)
+ const auto& script1 = scriptPubKey;
+ for(const auto& tplate : mTemplates)
{
- const CScript& script2 = tplate.second;
+ const auto& script2 = tplate.second;
vSolutionsRet.clear();
opcodetype opcode1, opcode2;
vector<unsigned char> vch1, vch2;
// Compare
- CScript::const_iterator pc1 = script1.begin();
- CScript::const_iterator pc2 = script2.begin();
- while (true)
+ auto pc1 = script1.begin();
+ auto pc2 = script2.begin();
+ for ( ; ; )
{
if (pc1 == script1.end() && pc2 == script2.end())
{
if (typeRet == TX_MULTISIG)
{
// Additional checks for TX_MULTISIG:
- unsigned char m = vSolutionsRet.front()[0];
- unsigned char n = vSolutionsRet.back()[0];
+ auto m = vSolutionsRet.front()[0];
+ auto n = vSolutionsRet.back()[0];
if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
return false;
}
else
break;
}
+ else if (opcode2 == OP_INTEGER)
+ { // Up to four-byte integer pushed onto vSolutions
+ try
+ {
+ auto 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
- if (vch1.size() > (GetTime() > SMALLDATA_SWITCH_TIME ? 1024 : 80))
+ if (vch1.size() > 1024)
break;
}
else if (opcode1 != opcode2 || vch1 != vch2)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
- for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
+ for (uint32_t i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
{
- const valtype& pubkey = multisigdata[i];
- CKeyID keyID = CPubKey(pubkey).GetID();
+ const auto& pubkey = multisigdata[i];
+ auto keyID = CPubKey(pubkey).GetID();
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
++nSigned;
}
return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
case TX_PUBKEY_DROP:
{
- CPubKey key = CPubKey(vSolutions[0]);
- CPubKey R = CPubKey(vSolutions[1]);
+ auto key = CPubKey(vSolutions[0]);
+ auto R = CPubKey(vSolutions[1]);
return SignR(key, R, keystore, hash, nHashType, scriptSigRet);
}
case TX_PUBKEYHASH:
unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
{
- unsigned int nResult = 0;
- BOOST_FOREACH(const valtype& pubkey, pubkeys)
+ uint32_t nResult = 0;
+ for(const auto& pubkey : pubkeys)
{
- CKeyID keyID = CPubKey(pubkey).GetID();
+ auto keyID = CPubKey(pubkey).GetID();
if (keystore.HaveKey(keyID))
++nResult;
}
bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
};
-isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
+isminetype IsMine(const CKeyStore &keystore, const CBitcoinAddress& dest)
{
CScript script;
- script.SetDestination(dest);
+ script.SetAddress(dest);
return IsMine(keystore, script);
}
break;
case TX_PUBKEY_DROP:
{
- CPubKey key = CPubKey(vSolutions[0]);
- CPubKey R = CPubKey(vSolutions[1]);
+ auto key = CPubKey(vSolutions[0]);
+ auto R = CPubKey(vSolutions[1]);
if (keystore.CheckOwnership(key, R))
return MINE_SPENDABLE;
}
break;
case TX_SCRIPTHASH:
{
- CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
+ auto scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) {
- isminetype ret = IsMine(keystore, subscript);
+ auto ret = IsMine(keystore, subscript);
if (ret == MINE_SPENDABLE)
return ret;
}
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;
std::vector<CTxDestination> vDest;
int nRequired;
if (ExtractDestinations(script, type, vDest, nRequired)) {
- BOOST_FOREACH(const CTxDestination &dest, vDest)
+ for(const CTxDestination &dest : vDest)
boost::apply_visitor(*this, dest);
}
}
return true;
}
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- unsigned int flags, int nHashType)
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, uint32_t nIn, unsigned int flags, int nHashType)
{
vector<vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, txTo, nIn, flags, nHashType))
// an empty stack and the EvalScript above would return false.
assert(!stackCopy.empty());
- const valtype& pubKeySerialized = stackCopy.back();
+ const auto& pubKeySerialized = stackCopy.back();
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stackCopy);
return true;
}
-bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType)
+bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, uint32_t nIn, int nHashType)
{
assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
+ auto& txin = txTo.vin[nIn];
// Leave out the signature from the hash, since a signature can't sign itself.
// The checksig op will also drop the signatures from its hash.
- uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
+ auto hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
txnouttype whichType;
if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
// Solver returns the subscript that need to be evaluated;
// the final scriptSig is the signatures from that
// and then the serialized subscript:
- CScript subscript = txin.scriptSig;
+ auto subscript = txin.scriptSig;
// Recompute txn hash using subscript in place of scriptPubKey:
- uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
+ auto hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
txnouttype subType;
- bool fSolved =
- Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
+ bool fSolved = Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
// Append serialized subscript whether or not it is completely signed:
txin.scriptSig << static_cast<valtype>(subscript);
if (!fSolved) return false;
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STRICT_FLAGS, 0);
}
-bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType)
+bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, uint32_t nIn, int nHashType)
{
assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
+ auto& txin = txTo.vin[nIn];
assert(txin.prevout.n < txFrom.vout.size());
assert(txin.prevout.hash == txFrom.GetHash());
- const CTxOut& txout = txFrom.vout[txin.prevout.n];
+ const auto& txout = txFrom.vout[txin.prevout.n];
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
}
static CScript PushAll(const vector<valtype>& values)
{
CScript result;
- BOOST_FOREACH(const valtype& v, values)
+ for(const auto& v : values)
result << v;
return result;
}
{
// Combine all the signatures we've got:
set<valtype> allsigs;
- BOOST_FOREACH(const valtype& v, sigs1)
+ for(const auto& v : sigs1)
{
if (!v.empty())
allsigs.insert(v);
}
- BOOST_FOREACH(const valtype& v, sigs2)
+ for(const auto& v : sigs2)
{
if (!v.empty())
allsigs.insert(v);
// Build a map of pubkey -> signature by matching sigs to pubkeys:
assert(vSolutions.size() > 1);
- unsigned int nSigsRequired = vSolutions.front()[0];
- unsigned int nPubKeys = (unsigned int)(vSolutions.size()-2);
+ auto nSigsRequired = (uint32_t)vSolutions.front()[0];
+ auto nPubKeys = (uint32_t)(vSolutions.size()-2);
+
map<valtype, valtype> sigs;
- BOOST_FOREACH(const valtype& sig, allsigs)
+ for(const auto& sig : allsigs)
{
for (unsigned int i = 0; i < nPubKeys; i++)
{
- const valtype& pubkey = vSolutions[i+1];
+ const auto& pubkey = vSolutions[i+1];
if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey
}
}
// Now build a merged CScript:
- unsigned int nSigsHave = 0;
+ uint32_t nSigsHave = 0;
CScript result; result << OP_0; // pop-one-too-many workaround
- for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
+ for (uint32_t i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
{
if (sigs.count(vSolutions[i+1]))
{
}
}
// Fill any missing with OP_0:
- for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
+ for (auto i = nSigsHave; i < nSigsRequired; i++)
result << OP_0;
return result;
else
{
// Recur to combine:
- valtype spk = sigs1.back();
+ auto spk = sigs1.back();
CScript pubKey2(spk.begin(), spk.end());
txnouttype txType2;
Solver(pubKey2, txType2, vSolutions2);
sigs1.pop_back();
sigs2.pop_back();
- CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
+ auto result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
result << spk;
return result;
}
return CScript();
}
-CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, uint32_t nIn,
const CScript& scriptSig1, const CScript& scriptSig2)
{
txnouttype txType;
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
}
+//
+//CScript
+//
+
+CScript& CScript::push_int64(int64_t n)
+{
+ if (n == -1 || (n >= 1 && n <= 16))
+ {
+ push_back((uint8_t)n + (OP_1 - 1));
+ }
+ else
+ {
+ CBigNum bn(n);
+ *this << bn.getvch();
+ }
+ return *this;
+}
+
+CScript& CScript::push_uint64(uint64_t n)
+{
+ if (n >= 1 && n <= 16)
+ {
+ push_back((uint8_t)n + (OP_1 - 1));
+ }
+ else
+ {
+ CBigNum bn(n);
+ *this << bn.getvch();
+ }
+ return *this;
+}
+
+CScript& CScript::operator+=(const CScript& b)
+{
+ insert(end(), b.begin(), b.end());
+ return *this;
+}
+
+CScript& CScript::operator<<(opcodetype opcode)
+{
+ insert(end(), opcode);
+ return *this;
+}
+
+CScript& CScript::operator<<(const uint160& b)
+{
+ insert(end(), sizeof(b));
+ insert(end(), (uint8_t*)&b, (uint8_t*)&b + sizeof(b));
+ return *this;
+}
+
+CScript& CScript::operator<<(const uint256& b)
+{
+ insert(end(), sizeof(b));
+ insert(end(), (uint8_t*)&b, (uint8_t*)&b + sizeof(b));
+ return *this;
+}
+
+CScript& CScript::operator<<(const CPubKey& key)
+{
+ std::vector<uint8_t> vchKey(key.begin(), key.end());
+ return (*this) << vchKey;
+}
+
+CScript& CScript::operator<<(const CBigNum& b)
+{
+ *this << b.getvch();
+ return *this;
+}
+
+CScript& CScript::operator<<(const std::vector<uint8_t>& b)
+{
+ if (b.size() < OP_PUSHDATA1)
+ {
+ insert(end(), (uint8_t)b.size());
+ }
+ else if (b.size() <= 0xff)
+ {
+ insert(end(), OP_PUSHDATA1);
+ insert(end(), (uint8_t)b.size());
+ }
+ else if (b.size() <= 0xffff)
+ {
+ insert(end(), OP_PUSHDATA2);
+ uint16_t nSize = (uint16_t) b.size();
+ insert(end(), (uint8_t*)&nSize, (uint8_t*)&nSize + sizeof(nSize));
+ }
+ else
+ {
+ insert(end(), OP_PUSHDATA4);
+ uint32_t nSize = (uint32_t) b.size();
+ insert(end(), (uint8_t*)&nSize, (uint8_t*)&nSize + sizeof(nSize));
+ }
+ insert(end(), b.begin(), b.end());
+ return *this;
+}
+
+CScript& CScript::operator<<(const CScript& b)
+{
+ // I'm not sure if this should push the script or concatenate scripts.
+ // If there's ever a use for pushing a script onto a script, delete this member fn
+ assert(!"Warning: Pushing a CScript onto a CScript with << is probably not intended, use + to concatenate!");
+ return *this;
+}
+
+bool CScript::GetOp(iterator& pc, opcodetype& opcodeRet, std::vector<uint8_t>& vchRet)
+{
+ // Wrapper so it can be called with either iterator or const_iterator
+ const_iterator pc2 = pc;
+ bool fRet = GetOp2(pc2, opcodeRet, &vchRet);
+ pc = begin() + (pc2 - begin());
+ return fRet;
+}
+
+bool CScript::GetOp(iterator& pc, opcodetype& opcodeRet)
+{
+ const_iterator pc2 = pc;
+ bool fRet = GetOp2(pc2, opcodeRet, NULL);
+ pc = begin() + (pc2 - begin());
+ return fRet;
+}
+
+bool CScript::GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<uint8_t>& vchRet) const
+{
+ return GetOp2(pc, opcodeRet, &vchRet);
+}
+
+bool CScript::GetOp(const_iterator& pc, opcodetype& opcodeRet) const
+{
+ return GetOp2(pc, opcodeRet, NULL);
+}
+
+bool CScript::GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<uint8_t>* pvchRet) const
+{
+ opcodeRet = OP_INVALIDOPCODE;
+ if (pvchRet)
+ pvchRet->clear();
+ if (pc >= end())
+ return false;
+
+ // Read instruction
+ if (end() - pc < 1)
+ return false;
+ uint32_t opcode = *pc++;
+
+ // Immediate operand
+ if (opcode <= OP_PUSHDATA4)
+ {
+ uint32_t nSize = OP_0;
+ if (opcode < OP_PUSHDATA1)
+ {
+ nSize = opcode;
+ }
+ else if (opcode == OP_PUSHDATA1)
+ {
+ if (end() - pc < 1)
+ return false;
+ nSize = *pc++;
+ }
+ else if (opcode == OP_PUSHDATA2)
+ {
+ if (end() - pc < 2)
+ return false;
+ memcpy(&nSize, &pc[0], 2);
+ pc += 2;
+ }
+ else if (opcode == OP_PUSHDATA4)
+ {
+ if (end() - pc < 4)
+ return false;
+ memcpy(&nSize, &pc[0], 4);
+ pc += 4;
+ }
+ if (end() - pc < 0 || (uint32_t)(end() - pc) < nSize)
+ return false;
+ if (pvchRet)
+ pvchRet->assign(pc, pc + nSize);
+ pc += nSize;
+ }
+
+ opcodeRet = (opcodetype)opcode;
+ return true;
+}
+
+int CScript::DecodeOP_N(opcodetype opcode)
+{
+ if (opcode == OP_0)
+ return 0;
+ assert(opcode >= OP_1 && opcode <= OP_16);
+ return (opcode - (OP_1 - 1));
+}
+
+opcodetype CScript::EncodeOP_N(int n)
+{
+ assert(n >= 0 && n <= 16);
+ if (n == 0)
+ return OP_0;
+ return (opcodetype)(OP_1+n-1);
+}
+
+int CScript::FindAndDelete(const CScript& b)
+{
+ int nFound = 0;
+ if (b.empty())
+ return nFound;
+ CScript result;
+ iterator pc = begin(), pc2 = begin();
+ opcodetype opcode;
+ do
+ {
+ result.insert(result.end(), pc2, pc);
+ while (static_cast<size_t>(end() - pc) >= b.size() && equal(b.begin(), b.end(), pc))
+ {
+ pc = pc + b.size();
+ ++nFound;
+ }
+ pc2 = pc;
+ }
+ while (GetOp(pc, opcode));
+
+ if (nFound > 0) {
+ result.insert(result.end(), pc2, end());
+ *this = result;
+ }
+ return nFound;
+}
+
+int CScript::Find(opcodetype op) const
+{
+ int nFound = 0;
+ opcodetype opcode;
+ for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);)
+ if (opcode == op)
+ ++nFound;
+ return nFound;
+}
+
unsigned int CScript::GetSigOpCount(bool fAccurate) const
{
- unsigned int n = 0;
- const_iterator pc = begin();
- opcodetype lastOpcode = OP_INVALIDOPCODE;
+ uint32_t n = 0;
+ auto pc = begin();
+ auto lastOpcode = OP_INVALIDOPCODE;
while (pc < end())
{
opcodetype opcode;
// This is a pay-to-script-hash scriptPubKey;
// get the last item that the scriptSig
// pushes onto the stack:
- const_iterator pc = scriptSig.begin();
+ auto pc = scriptSig.begin();
vector<unsigned char> data;
while (pc < scriptSig.end())
{
this->at(22) == OP_EQUAL);
}
+bool CScript::IsPushOnly(const_iterator pc) const
+{
+ while (pc < end())
+ {
+ opcodetype opcode;
+ if (!GetOp(pc, opcode))
+ return false;
+ if (opcode > OP_16)
+ return false;
+ }
+ return true;
+}
+
+// Called by CTransaction::IsStandard and P2SH VerifyScript (which makes it consensus-critical).
+bool CScript::IsPushOnly() const
+{
+ return this->IsPushOnly(begin());
+}
+
bool CScript::HasCanonicalPushes() const
{
- const_iterator pc = begin();
+ auto pc = begin();
while (pc < end())
{
opcodetype opcode;
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();
+ for(const auto& key : keys)
+ *this << key;
*this << EncodeOP_N((int)(keys.size())) << OP_CHECKMULTISIG;
}
+
+void CScript::PrintHex() const
+{
+ printf("CScript(%s)\n", HexStr(begin(), end(), true).c_str());
+}
+
+std::string CScript::ToString(bool fShort) const
+{
+ std::string str;
+ opcodetype opcode;
+ std::vector<uint8_t> vch;
+ const_iterator pc = begin();
+ while (pc < end())
+ {
+ if (!str.empty())
+ str += " ";
+ if (!GetOp(pc, opcode, vch))
+ {
+ str += "[error]";
+ return str;
+ }
+ if (opcode <= OP_PUSHDATA4)
+ str += fShort? ValueString(vch).substr(0, 10) : ValueString(vch);
+ else
+ str += GetOpName(opcode);
+ }
+ return str;
+}
+
+void CScript::print() const
+{
+ printf("%s\n", ToString().c_str());
+}
+
+CScriptID CScript::GetID() const
+{
+ return CScriptID(Hash160(*this));
+}