aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include4
-rw-r--r--src/addrman.cpp10
-rw-r--r--src/addrman.h14
-rw-r--r--src/bitcoin-tx.cpp21
-rw-r--r--src/init.cpp3
-rw-r--r--src/main.cpp89
-rw-r--r--src/memusage.h24
-rw-r--r--src/net.cpp20
-rw-r--r--src/net.h2
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp14
-rw-r--r--src/test/data/bitcoin-util-test.json13
-rw-r--r--src/test/data/txcreatedata_seq0.hex1
-rw-r--r--src/test/data/txcreatedata_seq1.hex1
-rw-r--r--src/test/policyestimator_tests.cpp18
-rw-r--r--src/torcontrol.cpp18
-rw-r--r--src/txmempool.cpp86
-rw-r--r--src/txmempool.h29
18 files changed, 247 insertions, 122 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 77cf1001e1..2d7791232d 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -17,7 +17,9 @@ EXTRA_DIST += \
test/data/txcreate2.hex \
test/data/txcreatedata1.hex \
test/data/txcreatedata2.hex \
- test/data/txcreatesign.hex
+ test/data/txcreatesign.hex \
+ test/data/txcreatedata_seq0.hex \
+ test/data/txcreatedata_seq1.hex
JSON_TEST_FILES = \
test/data/script_tests.json \
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 6c54cfa4cd..00f6fe99e0 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -197,6 +197,9 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId)
void CAddrMan::Good_(const CService& addr, int64_t nTime)
{
int nId;
+
+ nLastGood = nTime;
+
CAddrInfo* pinfo = Find(addr, &nId);
// if not found, bail out
@@ -311,7 +314,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
return fNew;
}
-void CAddrMan::Attempt_(const CService& addr, int64_t nTime)
+void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
{
CAddrInfo* pinfo = Find(addr);
@@ -327,7 +330,10 @@ void CAddrMan::Attempt_(const CService& addr, int64_t nTime)
// update info
info.nLastTry = nTime;
- info.nAttempts++;
+ if (fCountFailure && info.nLastCountAttempt < nLastGood) {
+ info.nLastCountAttempt = nTime;
+ info.nAttempts++;
+ }
}
CAddrInfo CAddrMan::Select_(bool newOnly)
diff --git a/src/addrman.h b/src/addrman.h
index 3085450450..c5923e9417 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -29,6 +29,9 @@ public:
//! last try whatsoever by us (memory only)
int64_t nLastTry;
+ //! last counted attempt (memory only)
+ int64_t nLastCountAttempt;
+
private:
//! where knowledge about this address first came from
CNetAddr source;
@@ -66,6 +69,7 @@ public:
{
nLastSuccess = 0;
nLastTry = 0;
+ nLastCountAttempt = 0;
nAttempts = 0;
nRefCount = 0;
fInTried = false;
@@ -200,6 +204,9 @@ private:
//! list of "new" buckets
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
+ //! last time Good was called (memory only)
+ int64_t nLastGood;
+
protected:
//! secret key to randomize bucket select with
uint256 nKey;
@@ -230,7 +237,7 @@ protected:
bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty);
//! Mark an entry as attempted to connect.
- void Attempt_(const CService &addr, int64_t nTime);
+ void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime);
//! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
CAddrInfo Select_(bool newOnly);
@@ -458,6 +465,7 @@ public:
nIdCount = 0;
nTried = 0;
nNew = 0;
+ nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
}
CAddrMan()
@@ -532,12 +540,12 @@ public:
}
//! Mark an entry as connection attempted to.
- void Attempt(const CService &addr, int64_t nTime = GetAdjustedTime())
+ void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
{
{
LOCK(cs);
Check();
- Attempt_(addr, nTime);
+ Attempt_(addr, fCountFailure, nTime);
Check();
}
}
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 95d7a085a0..f9ea94b9f4 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -71,7 +71,7 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage = HelpMessageGroup(_("Commands:"));
strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX"));
strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX"));
- strUsage += HelpMessageOpt("in=TXID:VOUT", _("Add input to TX"));
+ strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX"));
strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
@@ -181,15 +181,15 @@ static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
{
+ std::vector<std::string> vStrInputParts;
+ boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+
// separate TXID:VOUT in string
- size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
- (pos == 0) ||
- (pos == (strInput.size() - 1)))
+ if (vStrInputParts.size()<2)
throw runtime_error("TX input missing separator");
// extract and validate TXID
- string strTxid = strInput.substr(0, pos);
+ string strTxid = vStrInputParts[0];
if ((strTxid.size() != 64) || !IsHex(strTxid))
throw runtime_error("invalid TX input txid");
uint256 txid(uint256S(strTxid));
@@ -198,13 +198,18 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz;
// extract and validate vout
- string strVout = strInput.substr(pos + 1, string::npos);
+ string strVout = vStrInputParts[1];
int vout = atoi(strVout);
if ((vout < 0) || (vout > (int)maxVout))
throw runtime_error("invalid TX input vout");
+ // extract the optional sequence number
+ uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();
+ if (vStrInputParts.size() > 2)
+ nSequenceIn = std::stoul(vStrInputParts[2]);
+
// append to transaction input list
- CTxIn txin(txid, vout);
+ CTxIn txin(txid, vout, CScript(), nSequenceIn);
tx.vin.push_back(txin);
}
diff --git a/src/init.cpp b/src/init.cpp
index 9a22501859..3a260d16db 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -319,7 +319,8 @@ std::string HelpMessage(HelpMessageMode mode)
}
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
- strUsage += HelpMessageOpt("-feefilter", strprintf(_("Tell other nodes to filter invs to us by our mempool min fee (default: %u)"), DEFAULT_FEEFILTER));
+ if (showDebug)
+ strUsage += HelpMessageOpt("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER));
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup"));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
diff --git a/src/main.cpp b/src/main.cpp
index fc8e72a7db..bd028fefba 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -81,9 +81,6 @@ uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
-std::map<uint256, CTransaction> mapRelay;
-std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
-CCriticalSection cs_mapRelay;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
@@ -216,6 +213,12 @@ namespace {
/** Number of peers from which we're downloading blocks. */
int nPeersWithValidatedDownloads = 0;
+
+ /** Relay map, protected by cs_main. */
+ typedef std::map<uint256, std::shared_ptr<const CTransaction>> MapRelay;
+ MapRelay mapRelay;
+ /** Expiration-time ordered list of (expire time, relay map entry) pairs, protected by cs_main). */
+ std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration;
} // anon namespace
//////////////////////////////////////////////////////////////////////////////
@@ -1443,8 +1446,10 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
LOCK(cs_main);
- if (mempool.lookup(hash, txOut))
+ std::shared_ptr<const CTransaction> ptx = mempool.get(hash);
+ if (ptx)
{
+ txOut = *ptx;
return true;
}
@@ -3883,10 +3888,18 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
CValidationState state;
+ int reportDone = 0;
+ LogPrintf("[0%]...");
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{
boost::this_thread::interruption_point();
- uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))));
+ int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
+ if (reportDone < percentageDone/10) {
+ // report every 10% step
+ LogPrintf("[%d%%]...", percentageDone);
+ reportDone = percentageDone/10;
+ }
+ uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone);
if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
@@ -3944,6 +3957,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
}
}
+ LogPrintf("[DONE].\n");
LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions);
return true;
@@ -4512,30 +4526,24 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
}
}
- else if (inv.IsKnownType())
+ else if (inv.type == MSG_TX)
{
- CTransaction tx;
// Send stream from relay memory
bool push = false;
- {
- LOCK(cs_mapRelay);
- map<uint256, CTransaction>::iterator mi = mapRelay.find(inv.hash);
- if (mi != mapRelay.end()) {
- tx = (*mi).second;
- push = true;
- }
- }
- if (!push && inv.type == MSG_TX) {
- int64_t txtime;
+ auto mi = mapRelay.find(inv.hash);
+ if (mi != mapRelay.end()) {
+ pfrom->PushMessage(NetMsgType::TX, *mi->second);
+ push = true;
+ } else if (pfrom->timeLastMempoolReq) {
+ auto txinfo = mempool.info(inv.hash);
// To protect privacy, do not answer getdata using the mempool when
// that TX couldn't have been INVed in reply to a MEMPOOL request.
- if (mempool.lookup(inv.hash, tx, txtime) && txtime <= pfrom->timeLastMempoolReq) {
+ if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) {
+ pfrom->PushMessage(NetMsgType::TX, *txinfo.tx);
push = true;
}
}
- if (push) {
- pfrom->PushMessage(inv.GetCommand(), tx);
- } else {
+ if (!push) {
vNotFound.push_back(inv);
}
}
@@ -5310,6 +5318,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == NetMsgType::MEMPOOL)
{
+ if (!(nLocalServices & NODE_BLOOM) && !pfrom->fWhitelisted)
+ {
+ LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
+ return true;
+ }
+
if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted)
{
LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
@@ -5907,8 +5922,7 @@ bool SendMessages(CNode* pto)
// Respond to BIP35 mempool requests
if (fSendTrickle && pto->fSendMempool) {
- std::vector<uint256> vtxid;
- mempool.queryHashes(vtxid);
+ auto vtxinfo = mempool.infoAll();
pto->fSendMempool = false;
CAmount filterrate = 0;
{
@@ -5918,20 +5932,16 @@ bool SendMessages(CNode* pto)
LOCK(pto->cs_filter);
- BOOST_FOREACH(const uint256& hash, vtxid) {
+ for (const auto& txinfo : vtxinfo) {
+ const uint256& hash = txinfo.tx->GetHash();
CInv inv(MSG_TX, hash);
pto->setInventoryTxToSend.erase(hash);
if (filterrate) {
- CFeeRate feeRate;
- mempool.lookupFeeRate(hash, feeRate);
- if (feeRate.GetFeePerK() < filterrate)
+ if (txinfo.feeRate.GetFeePerK() < filterrate)
continue;
}
if (pto->pfilter) {
- CTransaction tx;
- bool fInMemPool = mempool.lookup(hash, tx);
- if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
- if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
+ if (!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
}
pto->filterInventoryKnown.insert(hash);
vInv.push_back(inv);
@@ -5977,31 +5987,28 @@ bool SendMessages(CNode* pto)
continue;
}
// Not in the mempool anymore? don't bother sending it.
- CFeeRate feeRate;
- if (!mempool.lookupFeeRate(hash, feeRate)) {
+ auto txinfo = mempool.info(hash);
+ if (!txinfo.tx) {
continue;
}
- if (filterrate && feeRate.GetFeePerK() < filterrate) {
+ if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) {
continue;
}
- CTransaction tx;
- if (!mempool.lookup(hash, tx)) continue;
- if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(tx)) continue;
+ if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
// Send
vInv.push_back(CInv(MSG_TX, hash));
nRelayedTransactions++;
{
- LOCK(cs_mapRelay);
// Expire old relay messages
- while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
+ while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow)
{
mapRelay.erase(vRelayExpiration.front().second);
vRelayExpiration.pop_front();
}
- auto ret = mapRelay.insert(std::make_pair(hash, tx));
+ auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx)));
if (ret.second) {
- vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, hash));
+ vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first));
}
}
if (vInv.size() == MAX_INV_SZ) {
diff --git a/src/memusage.h b/src/memusage.h
index 9c98e5c2cf..3810bfad07 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -72,6 +72,15 @@ private:
X x;
};
+struct stl_shared_counter
+{
+ /* Various platforms use different sized counters here.
+ * Conservatively assume that they won't be larger than size_t. */
+ void* class_type;
+ size_t use_count;
+ size_t weak_count;
+};
+
template<typename X>
static inline size_t DynamicUsage(const std::vector<X>& v)
{
@@ -122,6 +131,21 @@ static inline size_t IncrementalDynamicUsage(const indirectmap<X, Y>& m)
return MallocUsage(sizeof(stl_tree_node<std::pair<const X*, Y> >));
}
+template<typename X>
+static inline size_t DynamicUsage(const std::unique_ptr<X>& p)
+{
+ return p ? MallocUsage(sizeof(X)) : 0;
+}
+
+template<typename X>
+static inline size_t DynamicUsage(const std::shared_ptr<X>& p)
+{
+ // A shared_ptr can either use a single continuous memory block for both
+ // the counter and the storage (when using std::make_shared), or separate.
+ // We can't observe the difference, however, so assume the worst.
+ return p ? MallocUsage(sizeof(X)) + MallocUsage(sizeof(stl_shared_counter)) : 0;
+}
+
// Boost data structures
template<typename X>
diff --git a/src/net.cpp b/src/net.cpp
index c09e3aedb6..be426236e4 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -365,7 +365,7 @@ CNode* FindNode(const CService& addr)
return NULL;
}
-CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
+CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
{
if (pszDest == NULL) {
if (IsLocal(addrConnect))
@@ -397,7 +397,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
return NULL;
}
- addrman.Attempt(addrConnect);
+ addrman.Attempt(addrConnect, fCountFailure);
// Add node
CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
@@ -414,7 +414,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
} else if (!proxyConnectionFailed) {
// If connecting to the node failed, and failure is not caused by a problem connecting to
// the proxy, mark this as an attempt.
- addrman.Attempt(addrConnect);
+ addrman.Attempt(addrConnect, fCountFailure);
}
return NULL;
@@ -1531,7 +1531,7 @@ void static ProcessOneShot()
CAddress addr;
CSemaphoreGrant grant(*semOutbound, true);
if (grant) {
- if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true))
+ if (!OpenNetworkConnection(addr, false, &grant, strDest.c_str(), true))
AddOneShot(strDest);
}
}
@@ -1547,7 +1547,7 @@ void ThreadOpenConnections()
BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"])
{
CAddress addr;
- OpenNetworkConnection(addr, NULL, strAddr.c_str());
+ OpenNetworkConnection(addr, false, NULL, strAddr.c_str());
for (int i = 0; i < 10 && i < nLoop; i++)
{
MilliSleep(500);
@@ -1631,7 +1631,7 @@ void ThreadOpenConnections()
}
if (addrConnect.IsValid())
- OpenNetworkConnection(addrConnect, &grant);
+ OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant);
}
}
@@ -1653,7 +1653,7 @@ void ThreadOpenAddedConnections()
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
CAddress addr;
CSemaphoreGrant grant(*semOutbound);
- OpenNetworkConnection(addr, &grant, strAddNode.c_str());
+ OpenNetworkConnection(addr, false, &grant, strAddNode.c_str());
MilliSleep(500);
}
MilliSleep(120000); // Retry every 2 minutes
@@ -1692,7 +1692,7 @@ void ThreadOpenAddedConnections()
BOOST_FOREACH(std::vector<CService>& vserv, lservAddressesToAdd)
{
CSemaphoreGrant grant(*semOutbound);
- OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
+ OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), false, &grant);
MilliSleep(500);
}
MilliSleep(120000); // Retry every 2 minutes
@@ -1700,7 +1700,7 @@ void ThreadOpenAddedConnections()
}
// if successful, this moves the passed grant to the constructed node
-bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
{
//
// Initiate outbound network connection
@@ -1714,7 +1714,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
} else if (FindNode(std::string(pszDest)))
return false;
- CNode* pnode = ConnectNode(addrConnect, pszDest);
+ CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure);
boost::this_thread::interruption_point();
if (!pnode)
diff --git a/src/net.h b/src/net.h
index 403653e8c8..e744af21ec 100644
--- a/src/net.h
+++ b/src/net.h
@@ -84,7 +84,7 @@ CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
-bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 36178bfb4c..cae964e46d 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -219,7 +219,7 @@ UniValue addnode(const UniValue& params, bool fHelp)
if (strCommand == "onetry")
{
CAddress addr;
- OpenNetworkConnection(addr, NULL, strNode.c_str());
+ OpenNetworkConnection(addr, false, NULL, strNode.c_str());
return NullUniValue;
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index f92ddb282e..992914f88c 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -334,6 +334,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
" {\n"
" \"txid\":\"id\", (string, required) The transaction id\n"
" \"vout\":n (numeric, required) The output number\n"
+ " \"sequence\":n (numeric, optional) The sequence number\n"
" }\n"
" ,...\n"
" ]\n"
@@ -384,6 +385,12 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max());
+
+ // set the sequence number if passed in the parameters object
+ const UniValue& sequenceObj = find_value(o, "sequence");
+ if (sequenceObj.isNum())
+ nSequence = sequenceObj.get_int();
+
CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
rawTx.vin.push_back(in);
@@ -754,6 +761,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
// Script verification errors
UniValue vErrors(UniValue::VARR);
+ // Use CTransaction for the constant parts of the
+ // transaction to avoid rehashing.
+ const CTransaction txConst(mergedTx);
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
@@ -771,10 +781,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
// ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
- txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
+ txin.scriptSig = CombineSignatures(prevPubKey, txConst, i, txin.scriptSig, txv.vin[i].scriptSig);
}
ScriptError serror = SCRIPT_ERR_OK;
- if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) {
+ if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i), &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}
diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json
index 3bf80ca434..5cb383de85 100644
--- a/src/test/data/bitcoin-util-test.json
+++ b/src/test/data/bitcoin-util-test.json
@@ -86,5 +86,18 @@
"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
"outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
"output_cmp": "txcreatedata2.hex"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967293",
+ "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"],
+ "output_cmp": "txcreatedata_seq0.hex"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:1"],
+ "output_cmp": "txcreatedata_seq1.hex"
}
]
diff --git a/src/test/data/txcreatedata_seq0.hex b/src/test/data/txcreatedata_seq0.hex
new file mode 100644
index 0000000000..db02b5e4a4
--- /dev/null
+++ b/src/test/data/txcreatedata_seq0.hex
@@ -0,0 +1 @@
+01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000
diff --git a/src/test/data/txcreatedata_seq1.hex b/src/test/data/txcreatedata_seq1.hex
new file mode 100644
index 0000000000..4cedcd975c
--- /dev/null
+++ b/src/test/data/txcreatedata_seq1.hex
@@ -0,0 +1 @@
+01000000021f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff1f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000010000000180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 644c3da213..2b00e6f567 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -74,9 +74,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// 9/10 blocks add 2nd highest and so on until ...
// 1/10 blocks add lowest fee/pri transactions
while (txHashes[9-h].size()) {
- CTransaction btx;
- if (mpool.lookup(txHashes[9-h].back(), btx))
- block.push_back(btx);
+ std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[9-h].back());
+ if (ptx)
+ block.push_back(*ptx);
txHashes[9-h].pop_back();
}
}
@@ -160,9 +160,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// Estimates should still not be below original
for (int j = 0; j < 10; j++) {
while(txHashes[j].size()) {
- CTransaction btx;
- if (mpool.lookup(txHashes[j].back(), btx))
- block.push_back(btx);
+ std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[j].back());
+ if (ptx)
+ block.push_back(*ptx);
txHashes[j].pop_back();
}
}
@@ -181,9 +181,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash();
mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool));
- CTransaction btx;
- if (mpool.lookup(hash, btx))
- block.push_back(btx);
+ std::shared_ptr<const CTransaction> ptx = mpool.get(hash);
+ if (ptx)
+ block.push_back(*ptx);
}
}
mpool.removeForBlock(block, ++blocknum, dummyConflicted);
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 47d834c7b4..0d6b655675 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -574,7 +574,15 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl
* password: "password"
*/
std::string torpassword = GetArg("-torpassword", "");
- if (methods.count("NULL")) {
+ if (!torpassword.empty()) {
+ if (methods.count("HASHEDPASSWORD")) {
+ LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n");
+ boost::replace_all(torpassword, "\"", "\\\"");
+ conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2));
+ } else {
+ LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n");
+ }
+ } else if (methods.count("NULL")) {
LogPrint("tor", "tor: Using NULL authentication\n");
conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2));
} else if (methods.count("SAFECOOKIE")) {
@@ -595,13 +603,7 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl
}
}
} else if (methods.count("HASHEDPASSWORD")) {
- if (!torpassword.empty()) {
- LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n");
- boost::replace_all(torpassword, "\"", "\\\"");
- conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2));
- } else {
- LogPrintf("tor: Password authentication required, but no password provided with -torpassword\n");
- }
+ LogPrintf("tor: The only supported authentication mechanism left is password, but no password provided with -torpassword\n");
} else {
LogPrintf("tor: No supported authentication method\n");
}
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index f44e450363..205ffd6379 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -23,18 +23,18 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
bool poolHasNoInputsOf, CAmount _inChainInputValue,
bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp):
- tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
+ tx(std::make_shared<CTransaction>(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue),
spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp)
{
- nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- nModSize = tx.CalculateModifiedSize(nTxSize);
- nUsageSize = RecursiveDynamicUsage(tx);
+ 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;
@@ -768,50 +768,76 @@ bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb
namespace {
class DepthAndScoreComparator
{
- CTxMemPool *mp;
public:
- DepthAndScoreComparator(CTxMemPool *mempool) : mp(mempool) {}
- bool operator()(const uint256& a, const uint256& b) { return mp->CompareDepthAndScore(a, b); }
+ bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b)
+ {
+ uint64_t counta = a->GetCountWithAncestors();
+ uint64_t countb = b->GetCountWithAncestors();
+ if (counta == countb) {
+ return CompareTxMemPoolEntryByScore()(*a, *b);
+ }
+ return counta < countb;
+ }
};
}
-void CTxMemPool::queryHashes(vector<uint256>& vtxid)
+std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const
{
- vtxid.clear();
+ std::vector<indexed_transaction_set::const_iterator> iters;
+ AssertLockHeld(cs);
+
+ iters.reserve(mapTx.size());
+ for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) {
+ iters.push_back(mi);
+ }
+ std::sort(iters.begin(), iters.end(), DepthAndScoreComparator());
+ return iters;
+}
+
+void CTxMemPool::queryHashes(vector<uint256>& vtxid)
+{
LOCK(cs);
+ auto iters = GetSortedDepthAndScore();
+
+ vtxid.clear();
vtxid.reserve(mapTx.size());
- for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
- vtxid.push_back(mi->GetTx().GetHash());
- std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this));
+ for (auto it : iters) {
+ vtxid.push_back(it->GetTx().GetHash());
+ }
}
-
-bool CTxMemPool::lookup(uint256 hash, CTransaction& result, int64_t& time) const
+std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
{
LOCK(cs);
- indexed_transaction_set::const_iterator i = mapTx.find(hash);
- if (i == mapTx.end()) return false;
- result = i->GetTx();
- time = i->GetTime();
- return true;
+ auto iters = GetSortedDepthAndScore();
+
+ std::vector<TxMempoolInfo> ret;
+ ret.reserve(mapTx.size());
+ for (auto it : iters) {
+ ret.push_back(TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize())});
+ }
+
+ return ret;
}
-bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
+std::shared_ptr<const CTransaction> CTxMemPool::get(const uint256& hash) const
{
- int64_t time;
- return CTxMemPool::lookup(hash, result, time);
+ LOCK(cs);
+ indexed_transaction_set::const_iterator i = mapTx.find(hash);
+ if (i == mapTx.end())
+ return nullptr;
+ return i->GetSharedTx();
}
-bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const
+TxMempoolInfo CTxMemPool::info(const uint256& hash) const
{
LOCK(cs);
indexed_transaction_set::const_iterator i = mapTx.find(hash);
if (i == mapTx.end())
- return false;
- feeRate = CFeeRate(i->GetFee(), i->GetTxSize());
- return true;
+ return TxMempoolInfo();
+ return TxMempoolInfo{i->GetSharedTx(), i->GetTime(), CFeeRate(i->GetFee(), i->GetTxSize())};
}
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
@@ -924,9 +950,9 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
// conflict with the underlying cache, and it cannot have pruned entries (as it contains full)
// transactions. First checking the underlying cache risks returning a pruned entry instead.
- CTransaction tx;
- if (mempool.lookup(txid, tx)) {
- coins = CCoins(tx, MEMPOOL_HEIGHT);
+ shared_ptr<const CTransaction> ptx = mempool.get(txid);
+ if (ptx) {
+ coins = CCoins(*ptx, MEMPOOL_HEIGHT);
return true;
}
return (base->GetCoins(txid, coins) && !coins.IsPruned());
diff --git a/src/txmempool.h b/src/txmempool.h
index 3cf84159cc..f0e9b2e2c6 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -7,6 +7,7 @@
#define BITCOIN_TXMEMPOOL_H
#include <list>
+#include <memory>
#include <set>
#include "amount.h"
@@ -75,7 +76,7 @@ class CTxMemPool;
class CTxMemPoolEntry
{
private:
- CTransaction tx;
+ std::shared_ptr<const CTransaction> tx;
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
size_t nTxSize; //!< ... and avoid recomputing tx size
size_t nModSize; //!< ... and modified size for priority
@@ -112,7 +113,8 @@ public:
unsigned int nSigOps, LockPoints lp);
CTxMemPoolEntry(const CTxMemPoolEntry& other);
- const CTransaction& GetTx() const { return this->tx; }
+ const CTransaction& GetTx() const { return *this->tx; }
+ std::shared_ptr<const CTransaction> GetSharedTx() const { return this->tx; }
/**
* Fast calculation of lower bound of current priority as update
* from entry priority. Only inputs that were originally in-chain will age.
@@ -308,6 +310,21 @@ struct ancestor_score {};
class CBlockPolicyEstimator;
/**
+ * Information about a mempool transaction.
+ */
+struct TxMempoolInfo
+{
+ /** The transaction itself */
+ std::shared_ptr<const CTransaction> tx;
+
+ /** Time the transaction entered the mempool. */
+ int64_t nTime;
+
+ /** Feerate of the transaction. */
+ CFeeRate feeRate;
+};
+
+/**
* CTxMemPool stores valid-according-to-the-current-best-chain
* transactions that may be included in the next block.
*
@@ -464,6 +481,8 @@ private:
void UpdateParent(txiter entry, txiter parent, bool add);
void UpdateChild(txiter entry, txiter child, bool add);
+ std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const;
+
public:
indirectmap<COutPoint, const CTransaction*> mapNextTx;
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
@@ -588,9 +607,9 @@ public:
return (mapTx.count(hash) != 0);
}
- bool lookup(uint256 hash, CTransaction& result) const;
- bool lookup(uint256 hash, CTransaction& result, int64_t& time) const;
- bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const;
+ std::shared_ptr<const CTransaction> get(const uint256& hash) const;
+ TxMempoolInfo info(const uint256& hash) const;
+ std::vector<TxMempoolInfo> infoAll() const;
/** Estimate fee rate needed to get into the next nBlocks
* If no answer can be given at nBlocks, return an estimate