Skip to content

Commit

Permalink
Merge bitcoin#9283: A few more CTransactionRef optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
laanwj authored and CryptoCentric committed Feb 26, 2019
1 parent 0b5e4f5 commit f7e30fe
Show file tree
Hide file tree
Showing 16 changed files with 68 additions and 78 deletions.
2 changes: 1 addition & 1 deletion src/bench/mempool_eviction.cpp
Expand Up @@ -18,7 +18,7 @@ static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
unsigned int sigOpCost = 4;
LockPoints lp;
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight,
MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight, pool.HasNoInputsOf(tx),
tx.GetValueOut(), spendsCoinbase, sigOpCost, lp));
}

Expand Down
36 changes: 19 additions & 17 deletions src/net_processing.cpp
Expand Up @@ -63,7 +63,7 @@ struct IteratorComparator
};
struct COrphanTx {
// When modifying, adapt the copy of this definition in tests/DoS_tests.
CTransaction tx;
CTransactionRef tx;
NodeId fromPeer;
int64_t nTimeExpire;
};
Expand Down Expand Up @@ -525,9 +525,9 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals)
// mapOrphanTransactions
//

bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
uint256 hash = tx.GetHash();
const uint256& hash = tx->GetHash();
if (mapOrphanTransactions.count(hash))
return false;

Expand All @@ -538,7 +538,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c
// have been mined or received.
// 100 orphans, each of which is at most 99,999 bytes big is
// at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
unsigned int sz = GetSerializeSize(tx, SER_NETWORK, CTransaction::CURRENT_VERSION);
unsigned int sz = GetSerializeSize(*tx, SER_NETWORK, CTransaction::CURRENT_VERSION);
if (sz > MAX_STANDARD_TX_SIZE)
{
LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
Expand All @@ -547,7 +547,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c

auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME});
assert(ret.second);
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
BOOST_FOREACH(const CTxIn& txin, tx->vin) {
mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first);
}

Expand All @@ -561,7 +561,7 @@ int EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end())
return 0;
BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin)
BOOST_FOREACH(const CTxIn& txin, it->second.tx->vin)
{
auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout);
if (itPrev == mapOrphanTransactionsByPrev.end())
Expand All @@ -583,7 +583,7 @@ void EraseOrphansFor(NodeId peer)
map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer)
{
nErased += EraseOrphanTx(maybeErase->second.tx.GetHash());
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());
}
}
if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer);
Expand All @@ -604,7 +604,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE
{
map<uint256, COrphanTx>::iterator maybeErase = iter++;
if (maybeErase->second.nTimeExpire <= nNow) {
nErased += EraseOrphanTx(maybeErase->second.tx.GetHash());
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());
} else {
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);
}
Expand Down Expand Up @@ -675,7 +675,7 @@ void PeerLogicValidation::SyncTransaction(const CTransaction& tx, const CBlockIn
auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout);
if (itByPrev == mapOrphanTransactionsByPrev.end()) continue;
for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
const CTransaction& orphanTx = (*mi)->second.tx;
const CTransaction& orphanTx = *(*mi)->second.tx;
const uint256& orphanHash = orphanTx.GetHash();
vOrphanErase.push_back(orphanHash);
}
Expand Down Expand Up @@ -1613,23 +1613,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,

deque<COutPoint> vWorkQueue;
vector<uint256> vEraseQueue;
CTransaction tx;
CTransactionRef ptx;
CTxLockRequest txLockRequest;
CDarksendBroadcastTx dstx;
int nInvType = MSG_TX;

// Read data and assign inv type
if(strCommand == NetMsgType::TX) {
vRecv >> tx;
vRecv >> ptx;
} else if(strCommand == NetMsgType::TXLOCKREQUEST) {
vRecv >> txLockRequest;
tx = txLockRequest;
ptx = txLockRequest.tx;
nInvType = MSG_TXLOCK_REQUEST;
} else if (strCommand == NetMsgType::DSTX) {
vRecv >> dstx;
tx = dstx.tx;
ptx = dstx.tx;
nInvType = MSG_DSTX;
}
const CTransaction& tx = *ptx;

CInv inv(nInvType, tx.GetHash());
pfrom->AddInventoryKnown(inv);
Expand Down Expand Up @@ -1679,7 +1680,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,

mapAlreadyAskedFor.erase(inv.hash);

if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) {
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, ptx, true, &fMissingInputs)) {
// Process custom txes, this changes AlreadyHave to "true"
if (strCommand == NetMsgType::DSTX) {
LogPrintf("DSTX -- Masternode transaction accepted, txid=%s, peer=%d\n",
Expand Down Expand Up @@ -1716,7 +1717,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
mi != itByPrev->second.end();
++mi)
{
const CTransaction& orphanTx = (*mi)->second.tx;
const CTransactionRef& porphanTx = (*mi)->second.tx;
const CTransaction& orphanTx = *porphanTx;
const uint256& orphanHash = orphanTx.GetHash();
NodeId fromPeer = (*mi)->second.fromPeer;
bool fMissingInputs2 = false;
Expand All @@ -1728,7 +1730,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,

if (setMisbehaving.count(fromPeer))
continue;
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, true, &fMissingInputs2))
{
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
connman.RelayTransaction(orphanTx);
Expand Down Expand Up @@ -1776,7 +1778,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->AddInventoryKnown(_inv);
if (!AlreadyHave(_inv)) pfrom->AskFor(_inv);
}
AddOrphanTx(tx, pfrom->GetId());
AddOrphanTx(ptx, pfrom->GetId());

// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
Expand Down
2 changes: 0 additions & 2 deletions src/primitives/transaction.h
Expand Up @@ -348,8 +348,6 @@ struct CMutableTransaction
typedef std::shared_ptr<const CTransaction> CTransactionRef;
static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
static inline CTransactionRef MakeTransactionRef(const CTransactionRef& txIn) { return txIn; }
static inline CTransactionRef MakeTransactionRef(CTransactionRef&& txIn) { return std::move(txIn); }

/** Implementation of BIP69
* https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki
Expand Down
2 changes: 1 addition & 1 deletion src/privatesend-client.cpp
Expand Up @@ -421,7 +421,7 @@ bool CPrivateSendClient::SendDenominate(const std::vector<CTxDSIn>& vecTxDSIn, c

mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), 1000, 0.1*COIN);
TRY_LOCK(cs_main, lockMain);
if(!lockMain || !AcceptToMemoryPool(mempool, validationState, CTransaction(tx), false, NULL, false, maxTxFee, true)) {
if(!lockMain || !AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(tx), false, NULL, false, maxTxFee, true)) {
LogPrintf("CPrivateSendClient::SendDenominate -- AcceptToMemoryPool() failed! tx=%s", tx.ToString());
UnlockCoins();
keyHolderStorage.ReturnAll();
Expand Down
8 changes: 4 additions & 4 deletions src/privatesend-server.cpp
Expand Up @@ -218,7 +218,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C
LOCK(cs_main);
CValidationState validationState;
mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), 1000, 0.1*COIN);
if(!AcceptToMemoryPool(mempool, validationState, CTransaction(tx), false, NULL, false, maxTxFee, true)) {
if(!AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(tx), false, NULL, false, maxTxFee, true)) {
LogPrintf("DSVIN -- transaction not valid! tx=%s", tx.ToString());
PushStatus(pfrom, STATUS_REJECTED, ERR_INVALID_TX, connman);
return;
Expand Down Expand Up @@ -335,10 +335,10 @@ void CPrivateSendServer::CommitFinalTransaction(CConnman& connman)
{
if(!fMasterNode) return; // check and relay final tx only on masternode

CTransaction finalTransaction = CTransaction(finalMutableTransaction);
uint256 hashTx = finalTransaction.GetHash();
CTransactionRef finalTransaction = MakeTransactionRef(finalMutableTransaction);
uint256 hashTx = finalTransaction->GetHash();

LogPrint("privatesend", "CPrivateSendServer::CommitFinalTransaction -- finalTransaction=%s", finalTransaction.ToString());
LogPrint("privatesend", "CPrivateSendServer::CommitFinalTransaction -- finalTransaction=%s", finalTransaction->ToString());

{
// See if the transaction is valid
Expand Down
2 changes: 1 addition & 1 deletion src/privatesend.cpp
Expand Up @@ -217,7 +217,7 @@ bool CPrivateSend::IsCollateralValid(const CTransaction& txCollateral)
{
LOCK(cs_main);
CValidationState validationState;
if(!AcceptToMemoryPool(mempool, validationState, txCollateral, false, NULL, false, maxTxFee, true)) {
if(!AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(txCollateral), false, NULL, false, maxTxFee, true)) {
LogPrint("privatesend", "CPrivateSend::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n");
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions src/privatesend.h
Expand Up @@ -230,10 +230,10 @@ class CDarksendBroadcastTx
sigTime(0)
{}

CDarksendBroadcastTx(CTransaction tx, COutPoint outpoint, int64_t sigTime) :
CDarksendBroadcastTx(const CTransactionRef& _tx, COutPoint _outpoint, int64_t _sigTime) :
nConfirmedHeight(-1),
tx(tx),
vin(CTxIn(outpoint)),
tx(_tx),
vin(CTxIn(_outpoint)),
vchSig(),
sigTime(sigTime)
{}
Expand Down
11 changes: 6 additions & 5 deletions src/rpc/rawtransaction.cpp
Expand Up @@ -898,7 +898,8 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
CTransaction tx;
if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
const uint256& hashTx = tx->GetHash();

bool fLimitFree = false;
CAmount nMaxRawTxFee = maxTxFee;
Expand All @@ -911,19 +912,19 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)

CCoinsViewCache &view = *pcoinsTip;
bool fHaveChain = false;
for (size_t o = 0; !fHaveChain && o < tx.vout.size(); o++) {
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
fHaveChain = !existingCoin.IsSpent();
}
bool fHaveMempool = mempool.exists(hashTx);
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
if (fInstantSend && !instantsend.ProcessTxLockRequest(tx, *g_connman)) {
if (fInstantSend && !instantsend.ProcessTxLockRequest(*tx, *g_connman)) {
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Not a valid InstantSend transaction, see debug.log for more info");
}
CValidationState state;
bool fMissingInputs;
if (!AcceptToMemoryPool(mempool, state, tx, fLimitFree, &fMissingInputs, false, nMaxRawTxFee)) {
if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
Expand All @@ -939,7 +940,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");

g_connman->RelayTransaction(tx);
g_connman->RelayTransaction(*tx);

return hashTx.GetHex();
}
Expand Down
24 changes: 12 additions & 12 deletions src/test/DoS_tests.cpp
Expand Up @@ -24,11 +24,11 @@
#include <boost/test/unit_test.hpp>

// Tests this internal-to-main.cpp method:
extern bool AddOrphanTx(const CTransaction& tx, NodeId peer);
extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);
extern void EraseOrphansFor(NodeId peer);
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
struct COrphanTx {
CTransaction tx;
CTransactionRef tx;
NodeId fromPeer;
int64_t nTimeExpire;
};
Expand Down Expand Up @@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
BOOST_CHECK(!connman->IsBanned(addr));
}

CTransaction RandomOrphan()
CTransactionRef RandomOrphan()
{
std::map<uint256, COrphanTx>::iterator it;
it = mapOrphanTransactions.lower_bound(GetRandHash());
Expand Down Expand Up @@ -154,30 +154,30 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());

AddOrphanTx(tx, i);
AddOrphanTx(MakeTransactionRef(tx), i);
}

// ... and 50 that depend on other orphans:
for (int i = 0; i < 50; i++)
{
CTransaction txPrev = RandomOrphan();
CTransactionRef txPrev = RandomOrphan();

CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = txPrev.GetHash();
tx.vin[0].prevout.hash = txPrev->GetHash();
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
SignSignature(keystore, txPrev, tx, 0);
SignSignature(keystore, *txPrev, tx, 0);

AddOrphanTx(tx, i);
AddOrphanTx(MakeTransactionRef(tx), i);
}

// This really-big orphan should be ignored:
for (int i = 0; i < 10; i++)
{
CTransaction txPrev = RandomOrphan();
CTransactionRef txPrev = RandomOrphan();

CMutableTransaction tx;
tx.vout.resize(1);
Expand All @@ -187,15 +187,15 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
for (unsigned int j = 0; j < tx.vin.size(); j++)
{
tx.vin[j].prevout.n = j;
tx.vin[j].prevout.hash = txPrev.GetHash();
tx.vin[j].prevout.hash = txPrev->GetHash();
}
SignSignature(keystore, txPrev, tx, 0);
SignSignature(keystore, *txPrev, tx, 0);
// Re-use same signature for other inputs
// (they don't have to be valid for this test)
for (unsigned int j = 1; j < tx.vin.size(); j++)
tx.vin[j].scriptSig = tx.vin[0].scriptSig;

BOOST_CHECK(!AddOrphanTx(tx, i));
BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i));
}

// Test EraseOrphansFor:
Expand Down
2 changes: 1 addition & 1 deletion src/test/test_absolute.cpp
Expand Up @@ -144,7 +144,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CT
CAmount inChainValue = pool && pool->HasNoInputsOf(txn) ? txn.GetValueOut() : 0;

return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight,
inChainValue, spendsCoinbase, sigOpCount, lp);
hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp);
}

void Shutdown(void* parg)
Expand Down
2 changes: 1 addition & 1 deletion src/test/txvalidationcache_tests.cpp
Expand Up @@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx)
LOCK(cs_main);

CValidationState state;
return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0);
return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), false, NULL, true, 0);
}

BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
Expand Down
10 changes: 5 additions & 5 deletions src/txmempool.cpp
Expand Up @@ -21,22 +21,22 @@

using namespace std;

CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
CAmount _inChainInputValue,
bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp):
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
inChainInputValue(_inChainInputValue),
hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue),
spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp)
{
nTxSize = ::GetSerializeSize(_tx, SER_NETWORK, PROTOCOL_VERSION);
nModSize = _tx.CalculateModifiedSize(nTxSize);
nTxSize = ::GetSerializeSize(*_tx, SER_NETWORK, PROTOCOL_VERSION);
nModSize = _tx->CalculateModifiedSize(nTxSize);
nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);

nCountWithDescendants = 1;
nSizeWithDescendants = nTxSize;
nModFeesWithDescendants = nFee;
CAmount nValueIn = _tx.GetValueOut()+nFee;
CAmount nValueIn = tx->GetValueOut()+nFee;
assert(inChainInputValue <= nValueIn);

feeDelta = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/txmempool.h
Expand Up @@ -112,10 +112,11 @@ class CTxMemPoolEntry
CAmount nModFeesWithAncestors;
unsigned int nSigOpCountWithAncestors;
public:
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
CAmount _inChainInputValue, bool spendsCoinbase,
unsigned int nSigOps, LockPoints lp);

CTxMemPoolEntry(const CTxMemPoolEntry& other);

const CTransaction& GetTx() const { return *this->tx; }
Expand Down

0 comments on commit f7e30fe

Please sign in to comment.