Split main.cpp (8,217 lines) into four focused translation units

- tx_validation.cpp (1,012 lines): transaction validation functions
  (IsStandardTx, CheckTransaction, ContextualCheckInputs, etc.)
- mempool_accept.cpp (524 lines): mempool acceptance and orphan management
  (AcceptToMemoryPool, AddOrphanTx, GetMinRelayFee, etc.)
- block_processing.cpp (4,064 lines): block processing, chain management,
  and disk I/O (ConnectBlock, DisconnectBlock, ActivateBestChain, CheckBlock,
  LoadBlockIndex, FlushStateToDisk, etc.)
- main_internal.h (83 lines): shared internal state declarations formerly in
  anonymous namespace (CBlockIndexWorkComparator, setBlockIndexCandidates,
  vinfoBlockFile, setDirtyBlockIndex, etc.)

main.cpp retains NET message handling (ProcessMessage, SendMessages),
peer state management, and utility functions (2,821 lines).
This commit is contained in:
dan_s
2026-02-27 01:01:22 -06:00
parent a918136a7c
commit 0083cd26bb
7 changed files with 5791 additions and 5489 deletions

View File

@@ -281,6 +281,9 @@ libbitcoin_server_a_SOURCES = \
hush_impl.cpp \
hush_nSPV_impl.cpp \
main.cpp \
tx_validation.cpp \
mempool_accept.cpp \
block_processing.cpp \
merkleblock.cpp \
metrics.h \
miner.cpp \

4064
src/block_processing.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -289,6 +289,14 @@ void PruneAndFlush();
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectAbsurdFee=false, int dosLevel=-1);
bool CCTxFixAcceptToMemPoolUnchecked(CTxMemPool& pool, const CTransaction &tx);
bool myAddtomempool(CTransaction &tx, CValidationState *pstate, bool fSkipExpiry);
/** Orphan transaction management */
bool AddOrphanTx(const CTransaction& tx, NodeId peer);
void EraseOrphanTx(uint256 hash);
void EraseOrphansFor(NodeId peer);
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
struct CNodeStateStats {
@@ -708,6 +716,8 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde
bool (*isInitBlockDownload)() = IsInitialBlockDownload,int32_t validateprices=1);
/** Apply the effects of this transaction on the UTXO set represented by view */
class CTxUndo;
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
/** Transaction validation functions */

83
src/main_internal.h Normal file
View File

@@ -0,0 +1,83 @@
// Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
//
// Internal shared state for main.cpp and block_processing.cpp
// These variables were previously in an anonymous namespace in main.cpp
// but need to be shared across translation units after splitting.
#ifndef HUSH_MAIN_INTERNAL_H
#define HUSH_MAIN_INTERNAL_H
#include "chain.h"
#include "sync.h"
#include "bloom.h"
#include "primitives/block.h"
#include "chainparams.h"
#include <set>
#include <map>
#include <list>
#include <vector>
#include <boost/smart_ptr/scoped_ptr.hpp>
struct CBlockIndexWorkComparator
{
bool operator()(CBlockIndex *pa, const CBlockIndex *pb) const {
// First sort by most total work, ...
if (pa->chainPower.chainWork > pb->chainPower.chainWork) return false;
if (pa->chainPower.chainWork < pb->chainPower.chainWork) return true;
// ... then by earliest time received, ...
if (pa->nSequenceId < pb->nSequenceId) return false;
if (pa->nSequenceId > pb->nSequenceId) return true;
// Use pointer address as tie breaker (should only happen with blocks
// loaded from disk, as those all have id 0).
if (pa < pb) return false;
if (pa > pb) return true;
// Identical blocks.
return false;
}
};
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
uint256 hash;
CBlockIndex *pindex; //! Optional.
int64_t nTime; //! Time of "getdata" request in microseconds.
bool fValidatedHeaders; //! Whether this block has validated headers at the time of request.
int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer)
};
// Shared block-processing state — defined in main.cpp
extern CBlockIndex *pindexBestInvalid;
extern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
extern int nSyncStarted;
extern std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
extern CCriticalSection cs_LastBlockFile;
extern std::vector<CBlockFileInfo> vinfoBlockFile, tmpBlockFiles;
extern int nLastBlockFile;
extern int nLastTmpFile;
extern unsigned int maxTempFileSize0;
extern unsigned int maxTempFileSize1;
extern bool fCheckForPruning;
extern CCriticalSection cs_nBlockSequenceId;
extern uint32_t nBlockSequenceId;
extern std::map<uint256, NodeId> mapBlockSource;
extern boost::scoped_ptr<CRollingBloomFilter> recentRejects;
extern uint256 hashRecentRejectsChainTip;
extern std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight;
extern int nQueuedValidatedHeaders;
extern int nPreferredDownload;
extern std::set<CBlockIndex*> setDirtyBlockIndex;
extern std::set<int> setDirtyFileInfo;
#endif // HUSH_MAIN_INTERNAL_H

524
src/mempool_accept.cpp Normal file
View File

@@ -0,0 +1,524 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2016-2024 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
//
// Mempool acceptance and orphan transaction management — extracted from main.cpp
// Functions: AddOrphanTx, EraseOrphanTx, EraseOrphansFor, LimitOrphanTxSize,
// GetMinRelayFee, AcceptToMemoryPool, CCTxFixAcceptToMemPoolUnchecked, myAddtomempool
#include "main.h"
#include "sodium.h"
#include "arith_uint256.h"
#include "chainparams.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
#include "key_io.h"
#include "metrics.h"
#include "net.h"
#include "script/interpreter.h"
#include "timedata.h"
#include "txdb.h"
#include "txmempool.h"
#include "undo.h"
#include "util.h"
#include "utilmoneystr.h"
#include "validationinterface.h"
#include "hush_defs.h"
#include "hush.h"
#include "librustzcash.h"
#include <cstring>
#include <algorithm>
#include <atomic>
#include <sstream>
#include <map>
#include <unordered_map>
#include <vector>
using namespace std;
extern int32_t HUSH_LOADINGBLOCKS,HUSH_LONGESTCHAIN,HUSH_INSYNC,HUSH_CONNECTING,HUSH_EXTRASATOSHI;
extern unsigned int expiryDelta;
extern CFeeRate minRelayTxFee;
extern bool fAddressIndex;
extern bool fSpentIndex;
extern const bool ishush3;
#define ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE 10000
// Orphan transaction data — defined in main.cpp
struct COrphanTx {
CTransaction tx;
NodeId fromPeer;
};
extern map<uint256, COrphanTx> mapOrphanTransactions;
extern map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
return false;
// Ignore big transactions, to avoid a
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// large transaction with a missing parent then we assume
// it will rebroadcast it later, after the parent transaction(s)
// have been mined or received.
// 10,000 orphans, each of which is at most 5,000 bytes big is
// at most 500 megabytes of orphans:
unsigned int sz = GetSerializeSize(tx, SER_NETWORK, tx.nVersion);
if (sz > 5000)
{
LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
return false;
}
mapOrphanTransactions[hash].tx = tx;
mapOrphanTransactions[hash].fromPeer = peer;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash);
LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(),
mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size());
return true;
}
void EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end())
return;
BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin)
{
map<uint256, set<uint256> >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash);
if (itPrev == mapOrphanTransactionsByPrev.end())
continue;
itPrev->second.erase(hash);
if (itPrev->second.empty())
mapOrphanTransactionsByPrev.erase(itPrev);
}
mapOrphanTransactions.erase(it);
}
void EraseOrphansFor(NodeId peer)
{
int nErased = 0;
map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
while (iter != mapOrphanTransactions.end())
{
map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer)
{
EraseOrphanTx(maybeErase->second.tx.GetHash());
++nErased;
}
}
if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer);
}
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans)
{
// Evict a random orphan:
uint256 randomhash = GetRandHash();
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
EraseOrphanTx(it->first);
++nEvicted;
}
return nEvicted;
}
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
{
{
LOCK(mempool.cs);
uint256 hash = tx.GetHash();
double dPriorityDelta = 0;
CAmount nFeeDelta = 0;
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
if (dPriorityDelta > 0 || nFeeDelta > 0)
return 0;
}
CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes);
if (fAllowFree)
{
// There is a free transaction area in blocks created by most miners,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
// to be considered to fall into this category. We don't want to encourage sending
// multiple transactions instead of one big transaction to avoid fees.
if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
nMinFee = 0;
}
if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
return nMinFee;
}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, int dosLevel)
{
AssertLockHeld(cs_main);
const uint32_t z2zTransitionWindow = 10;
const uint32_t z2zTransitionStart = 340000 - z2zTransitionWindow;
const uint32_t nHeight = chainActive.Height();
// This only applies to HUSH3, other chains can start off z2z via ac_private=1
if(ishush3) {
if((nHeight >= z2zTransitionStart) || (nHeight <= 340000)) {
// During the z2z transition window, only coinbase tx's as part of blocks are allowed
// Theory: We want an empty mempool at our fork block height, and the only way to assure that
// is to have an empty mempool for a few previous blocks, to take care of potential re-orgs
// and edge cases. This empty mempool assures there will be no transactions involving taddrs
// stuck in the mempool, when the z2z rule takes effect.
// Thanks to jl777 for helping design this
fprintf(stderr,"%s: rejecting all tx's during z2z transition window. Please retry after Block %d !!!\n", __func__,nHeight);
return false;
}
}
if (pfMissingInputs)
*pfMissingInputs = false;
uint32_t tiptime;
int flag=0,nextBlockHeight = chainActive.Height() + 1;
auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus());
if ( nextBlockHeight <= 1 || chainActive.LastTip() == 0 )
tiptime = (uint32_t)time(NULL);
else tiptime = (uint32_t)chainActive.LastTip()->nTime;
auto verifier = libzcash::ProofVerifier::Strict();
if (!CheckTransaction(tiptime,tx, state, verifier, 0, 0))
{
return error("AcceptToMemoryPool: CheckTransaction failed");
}
// Reject duplicate output proofs in a single ztx in mempool
// Migrate this to CheckTransaction() to make it a consensus requirement
{
set<libzcash::GrothProof> vSaplingOutputProof;
BOOST_FOREACH(const OutputDescription& output, tx.vShieldedOutput)
{
if (vSaplingOutputProof.count(output.zkproof))
return state.Invalid(error("AcceptToMemoryPool: duplicate output proof"),REJECT_DUPLICATE_OUTPUT_PROOF, "bad-txns-duplicate-output-proof");
vSaplingOutputProof.insert(output.zkproof);
}
}
// Reject duplicate spend proofs in a single ztx in mempool
// Migrate this to CheckTransaction() to make it a consensus requirement
{
set<libzcash::GrothProof> vSaplingSpendProof;
BOOST_FOREACH(const SpendDescription& spend, tx.vShieldedSpend)
{
if (vSaplingSpendProof.count(spend.zkproof))
return state.Invalid(error("AcceptToMemoryPool: duplicate spend proof"),REJECT_DUPLICATE_SPEND_PROOF, "bad-txns-duplicate-spend-proof");
vSaplingSpendProof.insert(spend.zkproof);
}
}
// DoS level set to 10 to be more forgiving.
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
if (!ContextualCheckTransaction(0,0,0,tx, state, nextBlockHeight, (dosLevel == -1) ? 10 : dosLevel))
{
return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
}
//fprintf(stderr,"addmempool 2\n");
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
{
fprintf(stderr,"AcceptToMemoryPool coinbase as individual tx\n");
return state.DoS(100, error("AcceptToMemoryPool: coinbase as individual tx"),REJECT_INVALID, "coinbase");
}
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
string reason;
if (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight))
{
//
//fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\nscriptPubKey: %s\n",reason.c_str(),tx.vout[0].scriptPubKey.ToString().c_str());
return state.DoS(0,error("AcceptToMemoryPool: nonstandard transaction: %s", reason),REJECT_NONSTANDARD, reason);
}
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
{
//fprintf(stderr,"AcceptToMemoryPool reject non-final\n");
return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
}
// is it already in the memory pool?
uint256 hash = tx.GetHash();
if (pool.exists(hash))
{
//fprintf(stderr,"already in mempool\n");
return state.Invalid(false, REJECT_DUPLICATE, "already in mempool");
}
// Check for conflicts with in-memory transactions
{
LOCK(pool.cs); // protect pool.mapNextTx
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
COutPoint outpoint = tx.vin[i].prevout;
if (pool.mapNextTx.count(outpoint))
{
// Disable replacement feature for now
return false;
}
}
for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
if (pool.nullifierExists(spendDescription.nullifier, SAPLING)) {
return false;
}
}
}
{
CCoinsView dummy;
CCoinsViewCache view(&dummy);
int64_t interest;
CAmount nValueIn = 0;
{
LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
// do we already have it?
if (view.HaveCoins(hash)) {
//fprintf(stderr,"view.HaveCoins(hash) error\n");
return state.Invalid(false, REJECT_DUPLICATE, "already have coins");
}
{
// do all inputs exist?
// Note that this does not check for the presence of actual outputs (see the next check for that),
// and only helps with filling in pfMissingInputs (to determine missing vs spent).
BOOST_FOREACH(const CTxIn txin, tx.vin)
{
if (!view.HaveCoins(txin.prevout.hash)) {
if (pfMissingInputs)
*pfMissingInputs = true;
//fprintf(stderr,"missing inputs\n");
return false;
// https://github.com/zcash/zcash/blob/master/src/main.cpp#L1490
// state.DoS(0, error("AcceptToMemoryPool: tx inputs not found"),REJECT_INVALID, "bad-txns-inputs-missing");
}
}
// are the actual inputs available?
if (!view.HaveInputs(tx)) {
//fprintf(stderr,"accept failure. inputs-spent\n");
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),REJECT_DUPLICATE, "bad-txns-inputs-spent");
}
}
// are the zaddr requirements met?
if (!view.HaveShieldedRequirements(tx)) {
//fprintf(stderr,"accept failure. ztx reqs not met\n");
return state.Invalid(error("AcceptToMemoryPool: shielded requirements not met"),REJECT_DUPLICATE, "bad-txns-shielded-requirements-not-met");
}
// Bring the best block into scope
view.GetBestBlock();
nValueIn = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime);
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
}
// Check for non-standard pay-to-script-hash in inputs
if (Params().RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId))
return error("AcceptToMemoryPool: reject nonstandard transaction input");
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
// MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
// merely non-standard transaction.
unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
{
fprintf(stderr,"accept failure.4\n");
return state.DoS(1, error("AcceptToMemoryPool: too many sigops %s, %d > %d", hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
}
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
double dPriority = view.GetPriority(tx, chainActive.Height());
if ( nValueOut > 777777*COIN && HUSH_VALUETOOBIG(nValueOut - 777777*COIN) != 0 ) // some room for blockreward and txfees
return state.DoS(100, error("AcceptToMemoryPool: GetValueOut too big"),REJECT_INVALID,"tx valueout is too big");
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
bool fSpendsCoinbase = false;
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
const CCoins *coins = view.AccessCoins(txin.prevout.hash);
if (coins->IsCoinBase()) {
fSpendsCoinbase = true;
break;
}
}
// Grab the branch ID we expect this transaction to commit to. We don't
// yet know if it does, but if the entry gets added to the mempool, then
// it has passed ContextualCheckInputs and therefore this is correct.
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx), fSpendsCoinbase, consensusBranchId);
unsigned int nSize = entry.GetTxSize();
// Accept a tx if it contains zspends and has at least the default fee specified by z_sendmany.
if (tx.vShieldedSpend.size() > 0 && nFees >= ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE) {
// In future we will we have more accurate and dynamic computation of fees, derpz
} else {
// Don't accept it if it can't get into a block, yallz
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee) {
//fprintf(stderr,"accept failure.5\n");
return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",hash.ToString(), nFees, txMinFee),REJECT_INSUFFICIENTFEE, "insufficient fee");
}
}
// Require that free transactions have sufficient priority to be mined in the next block.
if (GetBoolArg("-relaypriority", false) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
fprintf(stderr,"accept failure.6\n");
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) )
{
static CCriticalSection csFreeLimiter;
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();
LOCK(csFreeLimiter);
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
{
fprintf(stderr,"accept failure.7\n");
return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"), REJECT_INSUFFICIENTFEE, "rate limited free transaction");
}
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}
fRejectAbsurdFee = false;
if ( fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000 && nFees > nValueOut/19)
// Disable checks for absurd fees when adding to the mempool. Instead, this check is done
// when a user attempts to make a transaction with an absurd fee and only rejects absurd
// fees when OP_RETURN data is NOT being used. This means users making normal financial
// transactions (z2z) are protected from absurd fees, it is only users who are storing
// arbitrary data via a z2t transaction are allowed to (or potentially required) to pay high fees
// It would be nice to detect the use of OP_RETURN right here but it seems to only be known
// inside of IsStandard() inside of IsStandardTx() and we want to avoid doing expensive checks
// multiple times.
{
string errmsg = strprintf("absurdly high fees %s, %d > %d",
hash.ToString(),
nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
LogPrint("mempool", errmsg.c_str());
return state.Error("AcceptToMemoryPool: " + errmsg);
}
//fprintf(stderr,"addmempool 6\n");
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata(tx);
if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
{
//fprintf(stderr,"accept failure.9\n");
return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
}
// Check again against just the consensus-critical mandatory script
// verification flags, in case of bugs in the standard flags that cause
// transactions to pass as valid when they're actually invalid. For
// instance the STRICTENC flag was incorrectly allowing certain
// CHECKSIG NOT scripts to pass, even though they were invalid.
//
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
// XXX: is this neccesary for CryptoConditions?
if ( HUSH_CONNECTING <= 0 && chainActive.LastTip() != 0 )
{
flag = 1;
HUSH_CONNECTING = (1<<30) + (int32_t)chainActive.LastTip()->GetHeight() + 1;
}
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
{
if ( flag != 0 )
HUSH_CONNECTING = -1;
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
}
if ( flag != 0 )
HUSH_CONNECTING = -1;
{
LOCK(pool.cs);
// Store transaction in memory
pool.addUnchecked(hash, entry, !IsInitialBlockDownload());
// Add memory address index
if (fAddressIndex) {
pool.addAddressIndex(entry, view);
}
// Add memory spent index
if (fSpentIndex) {
pool.addSpentIndex(entry, view);
}
}
}
return true;
}
bool CCTxFixAcceptToMemPoolUnchecked(CTxMemPool& pool, const CTransaction &tx)
{
// called from CheckBlock which is in cs_main and mempool.cs locks already.
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
CTxMemPoolEntry entry(tx, 0, GetTime(), 0, chainActive.Height(), mempool.HasNoInputsOf(tx), false, consensusBranchId);
//fprintf(stderr, "adding %s to mempool from block %d\n",tx.GetHash().ToString().c_str(),chainActive.GetHeight());
pool.addUnchecked(tx.GetHash(), entry, false);
return true;
}
bool myAddtomempool(CTransaction &tx, CValidationState *pstate, bool fSkipExpiry)
{
CValidationState state;
if (!pstate)
pstate = &state;
CTransaction Ltx; bool fMissingInputs,fOverrideFees = false;
if ( mempool.lookup(tx.GetHash(),Ltx) == 0 )
{
if ( !fSkipExpiry )
return(AcceptToMemoryPool(mempool, *pstate, tx, false, &fMissingInputs, !fOverrideFees, -1));
else
return(CCTxFixAcceptToMemPoolUnchecked(mempool,tx));
}
else return(true);
}

1012
src/tx_validation.cpp Normal file

File diff suppressed because it is too large Load Diff