diff --git a/src/bloom.cpp b/src/bloom.cpp index da30e6f355..6268eeb767 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -163,7 +163,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) if (fFound) return true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { // Match if the filter contains an outpoint tx spends if (contains(txin.prevout)) diff --git a/src/coins.cpp b/src/coins.cpp index daeb6b6a1b..b7c8866661 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -265,9 +265,11 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces unsigned char *p = vchData.data(); if (!tx.IsCoinBase()) { - for (size_t i = 0; i < tx.vin.size(); ++i) + // The first input is null for asset definition transactions + FOREACH_TXIN(txin, tx) { - const CTxOutValue& val = GetOutputFor(tx.vin[i]).nValue; + const CTxOut& txOut = GetOutputFor(txin); + const CTxOutValue& val = txOut.nValue; if (val.IsAmount()) nPlainAmount -= val.GetAmount(); else @@ -331,8 +333,9 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx) const bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const { if (!tx.IsCoinBase()) { - for (unsigned int i = 0; i < tx.vin.size(); i++) { - const COutPoint &prevout = tx.vin[i].prevout; + // Don't check the null input in asset defintion transactions + FOREACH_TXIN(txin, tx) { + const COutPoint &prevout = txin.prevout; const CCoins* coins = AccessCoins(prevout.hash); if (!coins || !coins->IsAvailable(prevout.n)) { return false; @@ -347,7 +350,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const if (tx.IsCoinBase()) return 0.0; double dResult = 0.0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { const CCoins* coins = AccessCoins(txin.prevout.hash); assert(coins); diff --git a/src/core_write.cpp b/src/core_write.cpp index c3982dfa00..73b632d8c9 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -100,7 +100,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) entry.pushKV("locktime", (int64_t)tx.nLockTime); UniValue vin(UniValue::VARR); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + FOREACH_TXIN(txin, tx) { UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); diff --git a/src/main.cpp b/src/main.cpp index ccfa77f56e..d0938660f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -574,7 +574,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) mapOrphanTransactions[hash].tx = tx; mapOrphanTransactions[hash].fromPeer = peer; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), @@ -587,7 +587,7 @@ void static EraseOrphanTx(uint256 hash) map::iterator it = mapOrphanTransactions.find(hash); if (it == mapOrphanTransactions.end()) return; - BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) + FOREACH_TXIN(txin, it->second.tx) { map >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); if (itPrev == mapOrphanTransactionsByPrev.end()) @@ -666,7 +666,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) return false; } - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { if (!txin.scriptSig.IsPushOnly()) { reason = "scriptsig-not-pushonly"; @@ -717,7 +717,7 @@ int64_t LockTime(const CTransaction &tx, int flags, const CCoinsView* pCoinsView // Will remain equal to true if all inputs are finalized (MAX_INT). bool fFinalized = true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + FOREACH_TXIN(txin, tx) { // The relative lock-time is the inverted sequence number so // as to preserve the semantics MAX_INT means an input is // finalized (0 relative lock-time). @@ -895,7 +895,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) unsigned int GetLegacySigOpCount(const CTransaction& tx) { unsigned int nSigOps = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { nSigOps += txin.scriptSig.GetSigOpCount(false); } @@ -912,11 +912,11 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in return 0; unsigned int nSigOps = 0; - for (unsigned int i = 0; i < tx.vin.size(); i++) + FOREACH_TXIN(txin, tx) { - const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]); + const CTxOut &prevout = inputs.GetOutputFor(txin); if (prevout.scriptPubKey.IsPayToScriptHash()) - nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); + nSigOps += prevout.scriptPubKey.GetSigOpCount(txin.scriptSig); } return nSigOps; } @@ -967,7 +967,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) // Check for duplicate inputs set vInOutPoints; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { if (vInOutPoints.count(txin.prevout)) return state.DoS(100, error("CheckTransaction() : duplicate inputs"), @@ -983,9 +983,10 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) } else { - BOOST_FOREACH(const CTxIn& txin, tx.vin) + // The first input is null for asset definition transactions + FOREACH_TXIN(txin, tx) if (txin.prevout.IsNull()) - return state.DoS(10, error("CheckTransaction() : prevout is null"), + return state.DoS(10, error("CheckTransaction(): prevout is null"), REJECT_INVALID, "bad-txns-prevout-null"); } @@ -1080,8 +1081,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), // only helps filling in pfMissingInputs (to determine missing vs spent). - BOOST_FOREACH(const CTxIn txin, tx.vin) { - if (!view.HaveCoins(txin.prevout.hash)) { + // Don't check the null input in asset defintion transactions + for (unsigned int i = tx.GetFirstInputPos(); i < tx.vin.size(); i++) { + if (!view.HaveCoins(tx.vin[i].prevout.hash)) { if (pfMissingInputs) *pfMissingInputs = true; return false; @@ -1517,7 +1519,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach // mark inputs spent if (!tx.IsCoinBase()) { txundo.vprevout.reserve(tx.vin.size()); - for (unsigned int i = 0; i < tx.vin.size(); i++) { + for (unsigned int i = tx.GetFirstInputPos(); i < tx.vin.size(); i++) { const CTxIn &txin = tx.vin[i]; txundo.vprevout.push_back(CTxInUndo()); CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash); @@ -1561,9 +1563,9 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // This is also true for mempool checks. CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; int nSpendHeight = pindexPrev->nHeight + 1; - for (unsigned int i = 0; i < tx.vin.size(); i++) + FOREACH_TXIN(txin, tx) { - const COutPoint &prevout = tx.vin[i].prevout; + const COutPoint &prevout = txin.prevout; const CCoins *coins = inputs.AccessCoins(prevout.hash); assert(coins); @@ -1599,7 +1601,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // still computed and checked, and any change will be caught at the next checkpoint. if (fScriptChecks) { CTxOutValue prevValueIn = -1; - for (unsigned int i = 0; i < tx.vin.size(); i++) { + for (unsigned int i = tx.GetFirstInputPos(); i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; const CCoins* coins = inputs.AccessCoins(prevout.hash); assert(coins); diff --git a/src/miner.cpp b/src/miner.cpp index 5f90d37bdd..592d3a0b74 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -181,7 +181,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) COrphan* porphan = NULL; bool fMissingInputs = false; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { // Read prev transaction if (!view.HaveCoins(txin.prevout.hash)) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index a54af3ad58..61c577db8a 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -318,6 +318,11 @@ public: return (vin.size() > 1 && vin[0].prevout.IsNull()); } + unsigned int GetFirstInputPos() const + { + return IsAssetDefinition() ? 1 : 0; + } + friend bool operator==(const CTransaction& a, const CTransaction& b) { return a.hash == b.hash; @@ -370,4 +375,11 @@ struct CMutableTransaction uint256 GetHash() const; }; +#define FOREACH_TXIN(VAR, TX) \ + for (unsigned int __txin_i = (TX).GetFirstInputPos(); \ + __txin_i < (TX).vin.size(); \ + ++__txin_i) \ + if (bool __txin_finish = false) {} else \ + for (const CTxIn& VAR = (TX).vin[__txin_i]; !__txin_finish; __txin_finish = true) + #endif // BITCOIN_PRIMITIVES_TRANSACTION_H diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 9abc7988ef..d60248dd41 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -151,7 +151,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco else { isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) { isminetype mine = wallet->IsMine(txin); if(fAllFromMe > mine) fAllFromMe = mine; @@ -220,7 +220,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Mixed debit transaction // - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) if (wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; for (unsigned int i = 0; i < wtx.vout.size(); i++) @@ -273,7 +273,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (fDebug) { strHTML += "

" + tr("Debug information") + "

"; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) if(wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; for (unsigned int i = 0; i < wtx.vout.size(); i++) @@ -286,7 +286,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "
" + tr("Inputs") + ":"; strHTML += "
    "; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) { COutPoint prevout = txin.prevout; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 2cc35ff422..5ff77065c4 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -80,7 +80,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * { bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) { isminetype mine = wallet->IsMine(txin); if(mine == ISMINE_WATCH_ONLY) involvesWatchAddress = true; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 2230ba5ccd..a06afa8fab 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -178,7 +178,7 @@ Value getrawmempool(const Array& params, bool fHelp) info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); const CTransaction& tx = e.GetTx(); set setDepends; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { if (mempool.exists(txin.prevout.hash)) setDepends.insert(txin.prevout.hash.ToString()); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 51de5e3eb7..7edc06fbd1 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -476,7 +476,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem txToRemove.push_back(it->second.ptx->GetHash()); } } - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) mapNextTx.erase(txin.prevout); removed.push_back(tx); @@ -494,7 +494,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in list transactionsToRemove; for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->second.GetTx(); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + FOREACH_TXIN(txin, tx) { std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) continue; @@ -517,7 +517,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list // Remove transactions which depend on inputs of tx, recursively list result; LOCK(cs); - BOOST_FOREACH(const CTxIn &txin, tx.vin) { + FOREACH_TXIN(txin, tx) { std::map::iterator it = mapNextTx.find(txin.prevout); if (it != mapNextTx.end()) { const CTransaction &txConflict = *it->second.ptx; @@ -577,11 +577,11 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const LOCK(cs); list waitingOnDependants; for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { - unsigned int i = 0; checkTotal += it->second.GetTxSize(); const CTransaction& tx = it->second.GetTx(); + unsigned int i = tx.GetFirstInputPos(); bool fDependsWait = false; - BOOST_FOREACH(const CTxIn &txin, tx.vin) { + FOREACH_TXIN(txin, tx) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) { diff --git a/src/wallet.cpp b/src/wallet.cpp index e8e0fd5717..e6aaccdbba 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -333,7 +333,7 @@ set CWallet::GetConflicts(const uint256& txid) const std::pair range; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) { if (mapTxSpends.count(txin.prevout) <= 1) continue; // No conflict if zero or one spends @@ -417,7 +417,7 @@ void CWallet::AddToSpends(const uint256& wtxid) if (thisTx.IsCoinBase()) // Coinbases don't spend anything! return; - BOOST_FOREACH(const CTxIn& txin, thisTx.vin) + FOREACH_TXIN(txin, thisTx) AddToSpends(txin.prevout, wtxid); } @@ -712,7 +712,7 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) // If a transaction changes 'conflicted' state, that changes the balance // available of the outputs it spends. So force those to be // recomputed, also: - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { if (mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); @@ -1756,7 +1756,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // Notify that old coins are spent set setCoins; - BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) + FOREACH_TXIN(txin, wtxNew) { CWalletTx &coin = mapWallet[txin.prevout.hash]; coin.BindWallet(this); diff --git a/src/wallet.h b/src/wallet.h index 1a3758126e..e393cd4ddd 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -363,7 +363,7 @@ public: CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const { CAmount nDebit = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { nDebit += GetDebit(txin, filter); if (!MoneyRange(nDebit)) @@ -922,7 +922,7 @@ public: return false; // Trusted if all inputs are from us and are in the mempool: - BOOST_FOREACH(const CTxIn& txin, vin) + FOREACH_TXIN(txin, *this) { // Transactions not sent by us: not trusted const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);