Page MenuHomePhabricator

No OneTemporary

diff --git a/src/net_processing.h b/src/net_processing.h
index 47d106756..f09a1f7e4 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -1,131 +1,131 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NET_PROCESSING_H
#define BITCOIN_NET_PROCESSING_H
#include <consensus/params.h>
#include <net.h>
#include <validationinterface.h>
class Config;
/**
* Default for -maxorphantx, maximum number of orphan transactions kept in
* memory.
*/
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
/**
* Default number of orphan+recently-replaced txn to keep around for block
* reconstruction.
*/
static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100;
/** Default for BIP61 (sending reject messages) */
static constexpr bool DEFAULT_ENABLE_BIP61 = true;
class PeerLogicValidation final : public CValidationInterface,
public NetEventsInterface {
private:
CConnman *const connman;
BanMan *const m_banman;
bool SendRejectsAndCheckIfBanned(CNode *pnode, bool enable_bip61)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
public:
PeerLogicValidation(CConnman *connman, BanMan *banman,
CScheduler &scheduler, bool enable_bip61);
/**
* Overridden from CValidationInterface.
*/
void
BlockConnected(const std::shared_ptr<const CBlock> &pblock,
const CBlockIndex *pindexConnected,
const std::vector<CTransactionRef> &vtxConflicted) override;
/**
* Overridden from CValidationInterface.
*/
void UpdatedBlockTip(const CBlockIndex *pindexNew,
const CBlockIndex *pindexFork,
bool fInitialDownload) override;
/**
* Overridden from CValidationInterface.
*/
void BlockChecked(const CBlock &block,
const CValidationState &state) override;
/**
* Overridden from CValidationInterface.
*/
void NewPoWValidBlock(const CBlockIndex *pindex,
const std::shared_ptr<const CBlock> &pblock) override;
/**
* Initialize a peer by adding it to mapNodeState and pushing a message
* requesting its version.
*/
void InitializeNode(const Config &config, CNode *pnode) override;
/**
* Handle removal of a peer by updating various state and removing it from
* mapNodeState.
*/
void FinalizeNode(const Config &config, NodeId nodeid,
bool &fUpdateConnectionTime) override;
/**
* Process protocol messages received from a given node.
*/
bool ProcessMessages(const Config &config, CNode *pfrom,
std::atomic<bool> &interrupt) override;
/**
* Send queued protocol messages to be sent to a give node.
*
* @param[in] pto The node which we are sending messages to.
* @param[in] interrupt Interrupt condition for processing threads
* @return True if there is more work to be done
*/
bool SendMessages(const Config &config, CNode *pto,
std::atomic<bool> &interrupt) override
EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
/**
* Consider evicting an outbound peer based on the amount of time they've
* been behind our tip.
*/
void ConsiderEviction(CNode *pto, int64_t time_in_seconds)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Evict extra outbound peers. If we think our tip may be stale, connect to
* an extra outbound.
*/
void
CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams);
/**
* If we have extra outbound peers, try to disconnect the one with the
* oldest block announcement.
*/
void EvictExtraOutboundPeers(int64_t time_in_seconds);
private:
- //! Next time to check for stale tip
+ //!< Next time to check for stale tip
int64_t m_stale_tip_check_time;
/** Enable BIP61 (sending reject messages) */
const bool m_enable_bip61;
};
struct CNodeStateStats {
int nMisbehavior = 0;
int nSyncHeight = -1;
int nCommonHeight = -1;
std::vector<int> vHeightInFlight;
};
/** Get statistics from node state */
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
/** Increase a node's misbehavior score. */
void Misbehaving(NodeId nodeid, int howmuch, const std::string &reason = "");
#endif // BITCOIN_NET_PROCESSING_H
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 7b9abcdbd..4715d100f 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -1,805 +1,805 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <netbase.h>
#include <hash.h>
#include <random.h>
#include <sync.h>
#include <uint256.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <tinyformat.h>
#include <atomic>
#ifndef WIN32
#include <fcntl.h>
#endif
#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
// Settings
static CCriticalSection cs_proxyInfos;
static proxyType proxyInfo[NET_MAX] GUARDED_BY(cs_proxyInfos);
static proxyType nameProxy GUARDED_BY(cs_proxyInfos);
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
bool fNameLookup = DEFAULT_NAME_LOOKUP;
// Need ample time for negotiation for very slow proxies such as Tor
// (milliseconds)
static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
static std::atomic<bool> interruptSocks5Recv(false);
enum Network ParseNetwork(std::string net) {
Downcase(net);
if (net == "ipv4") {
return NET_IPV4;
}
if (net == "ipv6") {
return NET_IPV6;
}
if (net == "onion") {
return NET_ONION;
}
if (net == "tor") {
LogPrintf("Warning: net name 'tor' is deprecated and will be removed "
"in the future. You should use 'onion' instead.\n");
return NET_ONION;
}
return NET_UNROUTABLE;
}
std::string GetNetworkName(enum Network net) {
switch (net) {
case NET_IPV4:
return "ipv4";
case NET_IPV6:
return "ipv6";
case NET_ONION:
return "onion";
default:
return "";
}
}
static bool LookupIntern(const char *pszName, std::vector<CNetAddr> &vIP,
unsigned int nMaxSolutions, bool fAllowLookup) {
vIP.clear();
{
CNetAddr addr;
if (addr.SetSpecial(std::string(pszName))) {
vIP.push_back(addr);
return true;
}
}
struct addrinfo aiHint;
memset(&aiHint, 0, sizeof(struct addrinfo));
aiHint.ai_socktype = SOCK_STREAM;
aiHint.ai_protocol = IPPROTO_TCP;
aiHint.ai_family = AF_UNSPEC;
#ifdef WIN32
aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
#else
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
#endif
struct addrinfo *aiRes = nullptr;
int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes);
if (nErr) {
return false;
}
struct addrinfo *aiTrav = aiRes;
while (aiTrav != nullptr &&
(nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) {
CNetAddr resolved;
if (aiTrav->ai_family == AF_INET) {
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
resolved =
CNetAddr(reinterpret_cast<struct sockaddr_in *>(aiTrav->ai_addr)
->sin_addr);
}
if (aiTrav->ai_family == AF_INET6) {
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
struct sockaddr_in6 *s6 =
reinterpret_cast<struct sockaddr_in6 *>(aiTrav->ai_addr);
resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
}
// Never allow resolving to an internal address. Consider any such
// result invalid.
if (!resolved.IsInternal()) {
vIP.push_back(resolved);
}
aiTrav = aiTrav->ai_next;
}
freeaddrinfo(aiRes);
return (vIP.size() > 0);
}
bool LookupHost(const char *pszName, std::vector<CNetAddr> &vIP,
unsigned int nMaxSolutions, bool fAllowLookup) {
std::string strHost(pszName);
if (strHost.empty()) {
return false;
}
if (strHost.front() == '[' && strHost.back() == ']') {
strHost = strHost.substr(1, strHost.size() - 2);
}
return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup);
}
bool LookupHost(const char *pszName, CNetAddr &addr, bool fAllowLookup) {
std::vector<CNetAddr> vIP;
LookupHost(pszName, vIP, 1, fAllowLookup);
if (vIP.empty()) {
return false;
}
addr = vIP.front();
return true;
}
bool Lookup(const char *pszName, std::vector<CService> &vAddr, int portDefault,
bool fAllowLookup, unsigned int nMaxSolutions) {
if (pszName[0] == 0) {
return false;
}
int port = portDefault;
std::string hostname;
SplitHostPort(std::string(pszName), port, hostname);
std::vector<CNetAddr> vIP;
bool fRet =
LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup);
if (!fRet) {
return false;
}
vAddr.resize(vIP.size());
for (unsigned int i = 0; i < vIP.size(); i++) {
vAddr[i] = CService(vIP[i], port);
}
return true;
}
bool Lookup(const char *pszName, CService &addr, int portDefault,
bool fAllowLookup) {
std::vector<CService> vService;
bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1);
if (!fRet) {
return false;
}
addr = vService[0];
return true;
}
CService LookupNumeric(const char *pszName, int portDefault) {
CService addr;
// "1.2:345" will fail to resolve the ip, but will still set the port.
// If the ip fails to resolve, re-init the result.
if (!Lookup(pszName, addr, portDefault, false)) {
addr = CService();
}
return addr;
}
struct timeval MillisToTimeval(int64_t nTimeout) {
struct timeval timeout;
timeout.tv_sec = nTimeout / 1000;
timeout.tv_usec = (nTimeout % 1000) * 1000;
return timeout;
}
/** SOCKS version */
enum SOCKSVersion : uint8_t { SOCKS4 = 0x04, SOCKS5 = 0x05 };
/** Values defined for METHOD in RFC1928 */
enum SOCKS5Method : uint8_t {
- NOAUTH = 0x00, //! No authentication required
- GSSAPI = 0x01, //! GSSAPI
- USER_PASS = 0x02, //! Username/password
- NO_ACCEPTABLE = 0xff, //! No acceptable methods
+ NOAUTH = 0x00, //!< No authentication required
+ GSSAPI = 0x01, //!< GSSAPI
+ USER_PASS = 0x02, //!< Username/password
+ NO_ACCEPTABLE = 0xff, //!< No acceptable methods
};
/** Values defined for CMD in RFC1928 */
enum SOCKS5Command : uint8_t {
CONNECT = 0x01,
BIND = 0x02,
UDP_ASSOCIATE = 0x03
};
/** Values defined for REP in RFC1928 */
enum SOCKS5Reply : uint8_t {
- SUCCEEDED = 0x00, //! Succeeded
- GENFAILURE = 0x01, //! General failure
- NOTALLOWED = 0x02, //! Connection not allowed by ruleset
- NETUNREACHABLE = 0x03, //! Network unreachable
- HOSTUNREACHABLE = 0x04, //! Network unreachable
- CONNREFUSED = 0x05, //! Connection refused
- TTLEXPIRED = 0x06, //! TTL expired
- CMDUNSUPPORTED = 0x07, //! Command not supported
- ATYPEUNSUPPORTED = 0x08, //! Address type not supported
+ SUCCEEDED = 0x00, //!< Succeeded
+ GENFAILURE = 0x01, //!< General failure
+ NOTALLOWED = 0x02, //!< Connection not allowed by ruleset
+ NETUNREACHABLE = 0x03, //!< Network unreachable
+ HOSTUNREACHABLE = 0x04, //!< Network unreachable
+ CONNREFUSED = 0x05, //!< Connection refused
+ TTLEXPIRED = 0x06, //!< TTL expired
+ CMDUNSUPPORTED = 0x07, //!< Command not supported
+ ATYPEUNSUPPORTED = 0x08, //!< Address type not supported
};
/** Values defined for ATYPE in RFC1928 */
enum SOCKS5Atyp : uint8_t {
IPV4 = 0x01,
DOMAINNAME = 0x03,
IPV6 = 0x04,
};
/** Status codes that can be returned by InterruptibleRecv */
enum class IntrRecvError {
OK,
Timeout,
Disconnected,
NetworkError,
Interrupted
};
/**
* Read bytes from socket. This will either read the full number of bytes
* requested or return False on error or timeout.
* This function can be interrupted by calling InterruptSocks5()
*
* @param data Buffer to receive into
* @param len Length of data to receive
* @param timeout Timeout in milliseconds for receive operation
*
* @note This function requires that hSocket is in non-blocking mode.
*/
static IntrRecvError InterruptibleRecv(uint8_t *data, size_t len, int timeout,
const SOCKET &hSocket) {
int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout;
// Maximum time to wait in one select call. It will take up until this time
// (in millis) to break off in case of an interruption.
const int64_t maxWait = 1000;
while (len > 0 && curTime < endTime) {
// Optimistically try the recv first
ssize_t ret = recv(hSocket, (char *)data, len, 0);
if (ret > 0) {
len -= ret;
data += ret;
} else if (ret == 0) {
// Unexpected disconnection
return IntrRecvError::Disconnected;
} else {
// Other error or blocking
int nErr = WSAGetLastError();
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK ||
nErr == WSAEINVAL) {
if (!IsSelectableSocket(hSocket)) {
return IntrRecvError::NetworkError;
}
struct timeval tval =
MillisToTimeval(std::min(endTime - curTime, maxWait));
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
if (nRet == SOCKET_ERROR) {
return IntrRecvError::NetworkError;
}
} else {
return IntrRecvError::NetworkError;
}
}
if (interruptSocks5Recv) {
return IntrRecvError::Interrupted;
}
curTime = GetTimeMillis();
}
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
}
/** Credentials for proxy authentication */
struct ProxyCredentials {
std::string username;
std::string password;
};
/** Convert SOCKS5 reply to an error message */
static std::string Socks5ErrorString(uint8_t err) {
switch (err) {
case SOCKS5Reply::GENFAILURE:
return "general failure";
case SOCKS5Reply::NOTALLOWED:
return "connection not allowed";
case SOCKS5Reply::NETUNREACHABLE:
return "network unreachable";
case SOCKS5Reply::HOSTUNREACHABLE:
return "host unreachable";
case SOCKS5Reply::CONNREFUSED:
return "connection refused";
case SOCKS5Reply::TTLEXPIRED:
return "TTL expired";
case SOCKS5Reply::CMDUNSUPPORTED:
return "protocol error";
case SOCKS5Reply::ATYPEUNSUPPORTED:
return "address type not supported";
default:
return "unknown";
}
}
/** Connect using SOCKS5 (as described in RFC1928) */
static bool Socks5(const std::string &strDest, int port,
const ProxyCredentials *auth, const SOCKET &hSocket) {
IntrRecvError recvr;
LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255) {
return error("Hostname too long");
}
// Accepted authentication methods
std::vector<uint8_t> vSocks5Init;
vSocks5Init.push_back(SOCKSVersion::SOCKS5);
if (auth) {
vSocks5Init.push_back(0x02); // Number of methods
vSocks5Init.push_back(SOCKS5Method::NOAUTH);
vSocks5Init.push_back(SOCKS5Method::USER_PASS);
} else {
vSocks5Init.push_back(0x01); // Number of methods
vSocks5Init.push_back(SOCKS5Method::NOAUTH);
}
ssize_t ret = send(hSocket, (const char *)vSocks5Init.data(),
vSocks5Init.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5Init.size()) {
return error("Error sending to proxy");
}
uint8_t pchRet1[2];
if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) !=
IntrRecvError::OK) {
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() "
"timeout or other failure\n",
strDest, port);
return false;
}
if (pchRet1[0] != SOCKSVersion::SOCKS5) {
return error("Proxy failed to initialize");
}
if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
// Perform username/password authentication (as described in RFC1929)
std::vector<uint8_t> vAuth;
// Current (and only) version of user/pass subnegotiation
vAuth.push_back(0x01);
if (auth->username.size() > 255 || auth->password.size() > 255) {
return error("Proxy username or password too long");
}
vAuth.push_back(auth->username.size());
vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
vAuth.push_back(auth->password.size());
vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
ret = send(hSocket, (const char *)vAuth.data(), vAuth.size(),
MSG_NOSIGNAL);
if (ret != (ssize_t)vAuth.size()) {
return error("Error sending authentication to proxy");
}
LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n",
auth->username, auth->password);
uint8_t pchRetA[2];
if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT,
hSocket)) != IntrRecvError::OK) {
return error("Error reading proxy authentication response");
}
if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
return error("Proxy authentication unsuccessful");
}
} else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
// Perform no authentication
} else {
return error("Proxy requested wrong authentication method %02x",
pchRet1[1]);
}
std::vector<uint8_t> vSocks5;
// VER protocol version
vSocks5.push_back(SOCKSVersion::SOCKS5);
// CMD CONNECT
vSocks5.push_back(SOCKS5Command::CONNECT);
// RSV Reserved must be 0
vSocks5.push_back(0x00);
// ATYP DOMAINNAME
vSocks5.push_back(SOCKS5Atyp::DOMAINNAME);
// Length<=255 is checked at beginning of function
vSocks5.push_back(strDest.size());
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
vSocks5.push_back((port >> 8) & 0xFF);
vSocks5.push_back((port >> 0) & 0xFF);
ret = send(hSocket, (const char *)vSocks5.data(), vSocks5.size(),
MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5.size()) {
return error("Error sending to proxy");
}
uint8_t pchRet2[4];
if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) !=
IntrRecvError::OK) {
if (recvr == IntrRecvError::Timeout) {
/**
* If a timeout happens here, this effectively means we timed out
* while connecting to the remote node. This is very common for Tor,
* so do not print an error message.
*/
return false;
} else {
return error("Error while reading proxy response");
}
}
if (pchRet2[0] != SOCKSVersion::SOCKS5) {
return error("Proxy failed to accept request");
}
if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
// Failures to connect to a peer that are not proxy errors
LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port,
Socks5ErrorString(pchRet2[1]));
return false;
}
// Reserved field must be 0
if (pchRet2[2] != 0x00) {
return error("Error: malformed proxy response");
}
uint8_t pchRet3[256];
switch (pchRet2[3]) {
case SOCKS5Atyp::IPV4:
recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket);
break;
case SOCKS5Atyp::IPV6:
recvr =
InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket);
break;
case SOCKS5Atyp::DOMAINNAME: {
recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
if (recvr != IntrRecvError::OK) {
return error("Error reading from proxy");
}
int nRecv = pchRet3[0];
recvr =
InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
break;
}
default:
return error("Error: malformed proxy response");
}
if (recvr != IntrRecvError::OK) {
return error("Error reading from proxy");
}
if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) !=
IntrRecvError::OK) {
return error("Error reading from proxy");
}
LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
return true;
}
SOCKET CreateSocket(const CService &addrConnect) {
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
if (!addrConnect.GetSockAddr((struct sockaddr *)&sockaddr, &len)) {
LogPrintf("Cannot create socket for %s: unsupported network\n",
addrConnect.ToString());
return INVALID_SOCKET;
}
SOCKET hSocket = socket(((struct sockaddr *)&sockaddr)->sa_family,
SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET) {
return INVALID_SOCKET;
}
if (!IsSelectableSocket(hSocket)) {
CloseSocket(hSocket);
LogPrintf("Cannot create connection: non-selectable socket created (fd "
">= FD_SETSIZE ?)\n");
return INVALID_SOCKET;
}
#ifdef SO_NOSIGPIPE
int set = 1;
// Different way of disabling SIGPIPE on BSD
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (sockopt_arg_type)&set,
sizeof(int));
#endif
// Disable Nagle's algorithm
SetSocketNoDelay(hSocket);
// Set to non-blocking
if (!SetSocketNonBlocking(hSocket, true)) {
CloseSocket(hSocket);
LogPrintf("ConnectSocketDirectly: Setting socket to non-blocking "
"failed, error %s\n",
NetworkErrorString(WSAGetLastError()));
}
return hSocket;
}
template <typename... Args>
static void LogConnectFailure(bool manual_connection, const char *fmt,
const Args &... args) {
std::string error_message = tfm::format(fmt, args...);
if (manual_connection) {
LogPrintf("%s\n", error_message);
} else {
LogPrint(BCLog::NET, "%s\n", error_message);
}
}
bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET &hSocket,
int nTimeout, bool manual_connection) {
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
if (hSocket == INVALID_SOCKET) {
LogPrintf("Cannot connect to %s: invalid socket\n",
addrConnect.ToString());
return false;
}
if (!addrConnect.GetSockAddr((struct sockaddr *)&sockaddr, &len)) {
LogPrintf("Cannot connect to %s: unsupported network\n",
addrConnect.ToString());
return false;
}
if (connect(hSocket, (struct sockaddr *)&sockaddr, len) == SOCKET_ERROR) {
int nErr = WSAGetLastError();
// WSAEINVAL is here because some legacy version of winsock uses it
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK ||
nErr == WSAEINVAL) {
struct timeval timeout = MillisToTimeval(nTimeout);
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
if (nRet == 0) {
LogPrint(BCLog::NET, "connection to %s timeout\n",
addrConnect.ToString());
return false;
}
if (nRet == SOCKET_ERROR) {
LogPrintf("select() for %s failed: %s\n",
addrConnect.ToString(),
NetworkErrorString(WSAGetLastError()));
return false;
}
socklen_t nRetSize = sizeof(nRet);
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR,
(sockopt_arg_type)&nRet,
&nRetSize) == SOCKET_ERROR) {
LogPrintf("getsockopt() for %s failed: %s\n",
addrConnect.ToString(),
NetworkErrorString(WSAGetLastError()));
return false;
}
if (nRet != 0) {
LogConnectFailure(manual_connection,
"connect() to %s failed after select(): %s",
addrConnect.ToString(),
NetworkErrorString(nRet));
return false;
}
}
#ifdef WIN32
else if (WSAGetLastError() != WSAEISCONN)
#else
else
#endif
{
LogConnectFailure(manual_connection, "connect() to %s failed: %s",
addrConnect.ToString(),
NetworkErrorString(WSAGetLastError()));
return false;
}
}
return true;
}
bool SetProxy(enum Network net, const proxyType &addrProxy) {
assert(net >= 0 && net < NET_MAX);
if (!addrProxy.IsValid()) {
return false;
}
LOCK(cs_proxyInfos);
proxyInfo[net] = addrProxy;
return true;
}
bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
assert(net >= 0 && net < NET_MAX);
LOCK(cs_proxyInfos);
if (!proxyInfo[net].IsValid()) {
return false;
}
proxyInfoOut = proxyInfo[net];
return true;
}
bool SetNameProxy(const proxyType &addrProxy) {
if (!addrProxy.IsValid()) {
return false;
}
LOCK(cs_proxyInfos);
nameProxy = addrProxy;
return true;
}
bool GetNameProxy(proxyType &nameProxyOut) {
LOCK(cs_proxyInfos);
if (!nameProxy.IsValid()) {
return false;
}
nameProxyOut = nameProxy;
return true;
}
bool HaveNameProxy() {
LOCK(cs_proxyInfos);
return nameProxy.IsValid();
}
bool IsProxy(const CNetAddr &addr) {
LOCK(cs_proxyInfos);
for (int i = 0; i < NET_MAX; i++) {
if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy)) {
return true;
}
}
return false;
}
bool ConnectThroughProxy(const proxyType &proxy, const std::string &strDest,
int port, const SOCKET &hSocket, int nTimeout,
bool *outProxyConnectionFailed) {
// first connect to proxy server
if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) {
if (outProxyConnectionFailed) {
*outProxyConnectionFailed = true;
}
return false;
}
// do socks negotiation
if (proxy.randomize_credentials) {
ProxyCredentials random_auth;
static std::atomic_int counter(0);
random_auth.username = random_auth.password =
strprintf("%i", counter++);
if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket)) {
return false;
}
} else if (!Socks5(strDest, (unsigned short)port, 0, hSocket)) {
return false;
}
return true;
}
bool LookupSubNet(const char *pszName, CSubNet &ret) {
std::string strSubnet(pszName);
size_t slash = strSubnet.find_last_of('/');
std::vector<CNetAddr> vIP;
std::string strAddress = strSubnet.substr(0, slash);
if (LookupHost(strAddress.c_str(), vIP, 1, false)) {
CNetAddr network = vIP[0];
if (slash != strSubnet.npos) {
std::string strNetmask = strSubnet.substr(slash + 1);
int32_t n;
// IPv4 addresses start at offset 12, and first 12 bytes must match,
// so just offset n
if (ParseInt32(strNetmask, &n)) {
// If valid number, assume /24 syntax
ret = CSubNet(network, n);
return ret.IsValid();
} else {
// If not a valid number, try full netmask syntax
// Never allow lookup for netmask
if (LookupHost(strNetmask.c_str(), vIP, 1, false)) {
ret = CSubNet(network, vIP[0]);
return ret.IsValid();
}
}
} else {
ret = CSubNet(network);
return ret.IsValid();
}
}
return false;
}
#ifdef WIN32
std::string NetworkErrorString(int err) {
char buf[256];
buf[0] = 0;
if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, sizeof(buf), nullptr)) {
return strprintf("%s (%d)", buf, err);
} else {
return strprintf("Unknown error (%d)", err);
}
}
#else
std::string NetworkErrorString(int err) {
char buf[256];
buf[0] = 0;
/**
* Too bad there are two incompatible implementations of the
* thread-safe strerror.
*/
const char *s;
#ifdef STRERROR_R_CHAR_P
/* GNU variant can return a pointer outside the passed buffer */
s = strerror_r(err, buf, sizeof(buf));
#else
s = buf;
/* POSIX variant always returns message in buffer */
if (strerror_r(err, buf, sizeof(buf))) {
buf[0] = 0;
}
#endif
return strprintf("%s (%d)", s, err);
}
#endif
bool CloseSocket(SOCKET &hSocket) {
if (hSocket == INVALID_SOCKET) {
return false;
}
#ifdef WIN32
int ret = closesocket(hSocket);
#else
int ret = close(hSocket);
#endif
if (ret) {
LogPrintf("Socket close failed: %d. Error: %s\n", hSocket,
NetworkErrorString(WSAGetLastError()));
}
hSocket = INVALID_SOCKET;
return ret != SOCKET_ERROR;
}
bool SetSocketNonBlocking(const SOCKET &hSocket, bool fNonBlocking) {
if (fNonBlocking) {
#ifdef WIN32
u_long nOne = 1;
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
#else
int fFlags = fcntl(hSocket, F_GETFL, 0);
if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
#endif
return false;
}
} else {
#ifdef WIN32
u_long nZero = 0;
if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {
#else
int fFlags = fcntl(hSocket, F_GETFL, 0);
if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
#endif
return false;
}
}
return true;
}
bool SetSocketNoDelay(const SOCKET &hSocket) {
int set = 1;
int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY,
(sockopt_arg_type)&set, sizeof(int));
return rc == 0;
}
void InterruptSocks5(bool interrupt) {
interruptSocks5Recv = interrupt;
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 3d6b81343..ffd38da8d 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -1,948 +1,948 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_TXMEMPOOL_H
#define BITCOIN_TXMEMPOOL_H
#include <amount.h>
#include <coins.h>
#include <crypto/siphash.h>
#include <indirectmap.h>
#include <primitives/transaction.h>
#include <random.h>
#include <sync.h>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/signals2/signal.hpp>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
class CBlockIndex;
class Config;
extern CCriticalSection cs_main;
inline double AllowFreeThreshold() {
return (144 * COIN) / (250 * SATOSHI);
}
inline bool AllowFree(double dPriority) {
// Large (in bytes) low-priority (new, small-coin) transactions need a fee.
return dPriority > AllowFreeThreshold();
}
/**
* Fake height value used in Coins to signify they are only in the memory
* pool(since 0.8)
*/
static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF;
struct LockPoints {
// Will be set to the blockchain height and median time past values that
// would be necessary to satisfy all relative locktime constraints (BIP68)
// of this tx given our view of block chain history
int height;
int64_t time;
// As long as the current chain descends from the highest height block
// containing one of the inputs used in the calculation, then the cached
// values are still valid even after a reorg.
CBlockIndex *maxInputBlock;
LockPoints() : height(0), time(0), maxInputBlock(nullptr) {}
};
class CTxMemPool;
/** \class CTxMemPoolEntry
*
* CTxMemPoolEntry stores data about the corresponding transaction, as well as
* data about all in-mempool transactions that depend on the transaction
* ("descendant" transactions).
*
* When a new entry is added to the mempool, we update the descendant state
* (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants)
* for all ancestors of the newly added transaction.
*/
class CTxMemPoolEntry {
private:
CTransactionRef tx;
//!< Cached to avoid expensive parent-transaction lookups
Amount nFee;
//!< ... and avoid recomputing tx size
size_t nTxSize;
//!< ... and modified size for priority
size_t nModSize;
//!< ... and total memory usage
size_t nUsageSize;
//!< Local time when entering the mempool
int64_t nTime;
//!< Priority when entering the mempool
double entryPriority;
//!< Chain height when entering the mempool
unsigned int entryHeight;
//!< Sum of all txin values that are already in blockchain
Amount inChainInputValue;
//!< keep track of transactions that spend a coinbase
bool spendsCoinbase;
//!< Total sigop plus P2SH sigops count
int64_t sigOpCount;
//!< Used for determining the priority of the transaction for mining in a
//! block
Amount feeDelta;
//!< Track the height and time at which tx was final
LockPoints lockPoints;
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
// descendants as well.
//!< number of descendant transactions
uint64_t nCountWithDescendants;
//!< ... and size
uint64_t nSizeWithDescendants;
//!< ... and total fees (all including us)
Amount nModFeesWithDescendants;
// Analogous statistics for ancestor transactions
uint64_t nCountWithAncestors;
uint64_t nSizeWithAncestors;
Amount nModFeesWithAncestors;
int64_t nSigOpCountWithAncestors;
public:
CTxMemPoolEntry(const CTransactionRef &_tx, const Amount _nFee,
int64_t _nTime, double _entryPriority,
unsigned int _entryHeight, Amount _inChainInputValue,
bool spendsCoinbase, int64_t nSigOpsCost, LockPoints lp);
const CTransaction &GetTx() const { return *this->tx; }
CTransactionRef 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.
*/
double GetPriority(unsigned int currentHeight) const;
const Amount GetFee() const { return nFee; }
size_t GetTxSize() const { return nTxSize; }
int64_t GetTime() const { return nTime; }
unsigned int GetHeight() const { return entryHeight; }
int64_t GetSigOpCount() const { return sigOpCount; }
Amount GetModifiedFee() const { return nFee + feeDelta; }
size_t DynamicMemoryUsage() const { return nUsageSize; }
const LockPoints &GetLockPoints() const { return lockPoints; }
// Adjusts the descendant state.
void UpdateDescendantState(int64_t modifySize, Amount modifyFee,
int64_t modifyCount);
// Adjusts the ancestor state
void UpdateAncestorState(int64_t modifySize, Amount modifyFee,
int64_t modifyCount, int modifySigOps);
// Updates the fee delta used for mining priority score, and the
// modified fees with descendants.
void UpdateFeeDelta(Amount feeDelta);
// Update the LockPoints after a reorg
void UpdateLockPoints(const LockPoints &lp);
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
Amount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
bool GetSpendsCoinbase() const { return spendsCoinbase; }
uint64_t GetCountWithAncestors() const { return nCountWithAncestors; }
uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
Amount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
int64_t GetSigOpCountWithAncestors() const {
return nSigOpCountWithAncestors;
}
//!< Index in mempool's vTxHashes
mutable size_t vTxHashesIdx;
};
// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
struct update_descendant_state {
update_descendant_state(int64_t _modifySize, Amount _modifyFee,
int64_t _modifyCount)
: modifySize(_modifySize), modifyFee(_modifyFee),
modifyCount(_modifyCount) {}
void operator()(CTxMemPoolEntry &e) {
e.UpdateDescendantState(modifySize, modifyFee, modifyCount);
}
private:
int64_t modifySize;
Amount modifyFee;
int64_t modifyCount;
};
struct update_ancestor_state {
update_ancestor_state(int64_t _modifySize, Amount _modifyFee,
int64_t _modifyCount, int64_t _modifySigOpsCost)
: modifySize(_modifySize), modifyFee(_modifyFee),
modifyCount(_modifyCount), modifySigOpsCost(_modifySigOpsCost) {}
void operator()(CTxMemPoolEntry &e) {
e.UpdateAncestorState(modifySize, modifyFee, modifyCount,
modifySigOpsCost);
}
private:
int64_t modifySize;
Amount modifyFee;
int64_t modifyCount;
int64_t modifySigOpsCost;
};
struct update_fee_delta {
explicit update_fee_delta(Amount _feeDelta) : feeDelta(_feeDelta) {}
void operator()(CTxMemPoolEntry &e) { e.UpdateFeeDelta(feeDelta); }
private:
Amount feeDelta;
};
struct update_lock_points {
explicit update_lock_points(const LockPoints &_lp) : lp(_lp) {}
void operator()(CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); }
private:
const LockPoints &lp;
};
// extracts a transaction hash from CTxMempoolEntry or CTransactionRef
struct mempoolentry_txid {
typedef uint256 result_type;
result_type operator()(const CTxMemPoolEntry &entry) const {
return entry.GetTx().GetId();
}
result_type operator()(const CTransactionRef &tx) const {
return tx->GetId();
}
};
/** \class CompareTxMemPoolEntryByDescendantScore
*
* Sort an entry by max(score/size of entry's tx, score/size with all
* descendants).
*/
class CompareTxMemPoolEntryByDescendantScore {
public:
bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const {
double a_mod_fee, a_size, b_mod_fee, b_size;
GetModFeeAndSize(a, a_mod_fee, a_size);
GetModFeeAndSize(b, b_mod_fee, b_size);
// Avoid division by rewriting (a/b > c/d) as (a*d > c*b).
double f1 = a_mod_fee * b_size;
double f2 = a_size * b_mod_fee;
if (f1 == f2) {
return a.GetTime() >= b.GetTime();
}
return f1 < f2;
}
// Return the fee/size we're using for sorting this entry.
void GetModFeeAndSize(const CTxMemPoolEntry &a, double &mod_fee,
double &size) const {
// Compare feerate with descendants to feerate of the transaction, and
// return the fee/size for the max.
double f1 = a.GetSizeWithDescendants() * (a.GetModifiedFee() / SATOSHI);
double f2 = a.GetTxSize() * (a.GetModFeesWithDescendants() / SATOSHI);
if (f2 > f1) {
mod_fee = a.GetModFeesWithDescendants() / SATOSHI;
size = a.GetSizeWithDescendants();
} else {
mod_fee = a.GetModifiedFee() / SATOSHI;
size = a.GetTxSize();
}
}
};
/** \class CompareTxMemPoolEntryByScore
*
* Sort by feerate of entry (fee/size) in descending order
* This is only used for transaction relay, so we use GetFee()
* instead of GetModifiedFee() to avoid leaking prioritization
* information via the sort order.
*/
class CompareTxMemPoolEntryByScore {
public:
bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const {
double f1 = b.GetTxSize() * (a.GetFee() / SATOSHI);
double f2 = a.GetTxSize() * (b.GetFee() / SATOSHI);
if (f1 == f2) {
return b.GetTx().GetId() < a.GetTx().GetId();
}
return f1 > f2;
}
};
class CompareTxMemPoolEntryByEntryTime {
public:
bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const {
return a.GetTime() < b.GetTime();
}
};
/** \class CompareTxMemPoolEntryByAncestorScore
*
* Sort an entry by min(score/size of entry's tx, score/size with all
* ancestors).
*/
class CompareTxMemPoolEntryByAncestorFee {
public:
template <typename T> bool operator()(const T &a, const T &b) const {
double a_mod_fee, a_size, b_mod_fee, b_size;
GetModFeeAndSize(a, a_mod_fee, a_size);
GetModFeeAndSize(b, b_mod_fee, b_size);
// Avoid division by rewriting (a/b > c/d) as (a*d > c*b).
double f1 = a_mod_fee * b_size;
double f2 = a_size * b_mod_fee;
if (f1 == f2) {
return a.GetTx().GetId() < b.GetTx().GetId();
}
return f1 > f2;
}
// Return the fee/size we're using for sorting this entry.
template <typename T>
void GetModFeeAndSize(const T &a, double &mod_fee, double &size) const {
// Compare feerate with ancestors to feerate of the transaction, and
// return the fee/size for the min.
double f1 = a.GetSizeWithAncestors() * (a.GetModifiedFee() / SATOSHI);
double f2 = a.GetTxSize() * (a.GetModFeesWithAncestors() / SATOSHI);
if (f1 > f2) {
mod_fee = a.GetModFeesWithAncestors() / SATOSHI;
size = a.GetSizeWithAncestors();
} else {
mod_fee = a.GetModifiedFee() / SATOSHI;
size = a.GetTxSize();
}
}
};
// Multi_index tag names
struct descendant_score {};
struct entry_time {};
struct ancestor_score {};
/**
* Information about a mempool transaction.
*/
struct TxMempoolInfo {
/** The transaction itself */
CTransactionRef tx;
/** Time the transaction entered the mempool. */
int64_t nTime;
/** Feerate of the transaction. */
CFeeRate feeRate;
/** The fee delta. */
Amount nFeeDelta;
};
/**
* Reason why a transaction was removed from the mempool, this is passed to the
* notification signal.
*/
enum class MemPoolRemovalReason {
- //! Manually removed or unknown reason
+ //!< Manually removed or unknown reason
UNKNOWN = 0,
- //! Expired from mempool
+ //!< Expired from mempool
EXPIRY,
- //! Removed in size limiting
+ //!< Removed in size limiting
SIZELIMIT,
- //! Removed for reorganization
+ //!< Removed for reorganization
REORG,
- //! Removed for block
+ //!< Removed for block
BLOCK,
- //! Removed for conflict with in-block transaction
+ //!< Removed for conflict with in-block transaction
CONFLICT,
- //! Removed for replacement
+ //!< Removed for replacement
REPLACED
};
class SaltedTxidHasher {
private:
/** Salt */
const uint64_t k0, k1;
public:
SaltedTxidHasher();
size_t operator()(const uint256 &txid) const {
return SipHashUint256(k0, k1, txid);
}
};
typedef std::pair<double, Amount> TXModifier;
/**
* CTxMemPool stores valid-according-to-the-current-best-chain transactions that
* may be included in the next block.
*
* Transactions are added when they are seen on the network (or created by the
* local node), but not all transactions seen are added to the pool. For
* example, the following new transactions will not be added to the mempool:
* - a transaction which doesn't meet the minimum fee requirements.
* - a new transaction that double-spends an input of a transaction already in
* the pool where the new transaction does not meet the Replace-By-Fee
* requirements as defined in BIP 125.
* - a non-standard transaction.
*
* CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:
*
* mapTx is a boost::multi_index that sorts the mempool on 4 criteria:
* - transaction hash
* - descendant feerate [we use max(feerate of tx, feerate of tx with all
* descendants)]
* - time in mempool
* - ancestor feerate [we use min(feerate of tx, feerate of tx with all
* unconfirmed ancestors)]
*
* Note: the term "descendant" refers to in-mempool transactions that depend on
* this one, while "ancestor" refers to in-mempool transactions that a given
* transaction depends on.
*
* In order for the feerate sort to remain correct, we must update transactions
* in the mempool when new descendants arrive. To facilitate this, we track the
* set of in-mempool direct parents and direct children in mapLinks. Within each
* CTxMemPoolEntry, we track the size and fees of all descendants.
*
* Usually when a new transaction is added to the mempool, it has no in-mempool
* children (because any such children would be an orphan). So in
* addUnchecked(), we:
* - update a new entry's setMemPoolParents to include all in-mempool parents
* - update the new entry's direct parents to include the new tx as a child
* - update all ancestors of the transaction to include the new tx's size/fee
*
* When a transaction is removed from the mempool, we must:
* - update all in-mempool parents to not track the tx in setMemPoolChildren
* - update all ancestors to not include the tx's size/fees in descendant state
* - update all in-mempool children to not include it as a parent
*
* These happen in UpdateForRemoveFromMempool(). (Note that when removing a
* transaction along with its descendants, we must calculate that set of
* transactions to be removed before doing the removal, or else the mempool can
* be in an inconsistent state where it's impossible to walk the ancestors of a
* transaction.)
*
* In the event of a reorg, the assumption that a newly added tx has no
* in-mempool children is false. In particular, the mempool is in an
* inconsistent state while new transactions are being added, because there may
* be descendant transactions of a tx coming from a disconnected block that are
* unreachable from just looking at transactions in the mempool (the linking
* transactions may also be in the disconnected block, waiting to be added).
* Because of this, there's not much benefit in trying to search for in-mempool
* children in addUnchecked(). Instead, in the special case of transactions
* being added from a disconnected block, we require the caller to clean up the
* state, to account for in-mempool, out-of-block descendants for all the
* in-block transactions by calling UpdateTransactionsFromBlock(). Note that
* until this is called, the mempool state is not consistent, and in particular
* mapLinks may not be correct (and therefore functions like
* CalculateMemPoolAncestors() and CalculateDescendants() that rely on them to
* walk the mempool are not generally safe to use).
*
* Computational limits:
*
* Updating all in-mempool ancestors of a newly added transaction can be slow,
* if no bound exists on how many in-mempool ancestors there may be.
* CalculateMemPoolAncestors() takes configurable limits that are designed to
* prevent these calculations from being too CPU intensive.
*/
class CTxMemPool {
private:
//!< Value n means that n times in 2^32 we check.
uint32_t nCheckFrequency GUARDED_BY(cs);
//!< Used by getblocktemplate to trigger CreateNewBlock() invocation
unsigned int nTransactionsUpdated;
//!< sum of all mempool tx's virtual sizes.
uint64_t totalTxSize;
//!< sum of dynamic memory usage of all the map elements (NOT the maps
//! themselves)
uint64_t cachedInnerUsage;
mutable int64_t lastRollingFeeUpdate;
mutable bool blockSinceLastRollingFeeBump;
//!< minimum fee to get into the pool, decreases exponentially
mutable double rollingMinimumFeeRate;
void trackPackageRemoved(const CFeeRate &rate) EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
// public only for testing
static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12;
typedef boost::multi_index_container<
CTxMemPoolEntry, boost::multi_index::indexed_by<
// sorted by txid
boost::multi_index::hashed_unique<
mempoolentry_txid, SaltedTxidHasher>,
// sorted by fee rate
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<descendant_score>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByDescendantScore>,
// sorted by entry time
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<entry_time>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByEntryTime>,
// sorted by fee rate with ancestors
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<ancestor_score>,
boost::multi_index::identity<CTxMemPoolEntry>,
CompareTxMemPoolEntryByAncestorFee>>>
indexed_transaction_set;
mutable CCriticalSection cs;
indexed_transaction_set mapTx GUARDED_BY(cs);
typedef indexed_transaction_set::nth_index<0>::type::iterator txiter;
//!< All tx hashes/entries in mapTx, in random order
std::vector<std::pair<uint256, txiter>> vTxHashes;
struct CompareIteratorByHash {
bool operator()(const txiter &a, const txiter &b) const {
return a->GetTx().GetId() < b->GetTx().GetId();
}
};
typedef std::set<txiter, CompareIteratorByHash> setEntries;
const setEntries &GetMemPoolParents(txiter entry) const
EXCLUSIVE_LOCKS_REQUIRED(cs);
const setEntries &GetMemPoolChildren(txiter entry) const
EXCLUSIVE_LOCKS_REQUIRED(cs);
uint64_t CalculateDescendantMaximum(txiter entry) const
EXCLUSIVE_LOCKS_REQUIRED(cs);
private:
typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;
struct TxLinks {
setEntries parents;
setEntries children;
};
typedef std::map<txiter, TxLinks, CompareIteratorByHash> txlinksMap;
txlinksMap mapLinks;
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 EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
indirectmap<COutPoint, const CTransaction *> mapNextTx GUARDED_BY(cs);
std::map<uint256, TXModifier> mapDeltas;
/**
* Create a new CTxMemPool.
*/
CTxMemPool();
~CTxMemPool();
/**
* If sanity-checking is turned on, check makes sure the pool is consistent
* (does not contain two transactions that spend the same inputs, all inputs
* are in the mapNextTx array). If sanity-checking is turned off, check does
* nothing.
*/
void check(const CCoinsViewCache *pcoins) const;
void setSanityCheck(double dFrequency = 1.0) {
LOCK(cs);
nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0);
}
// addUnchecked must updated state for all ancestors of a given transaction,
// to track size/count of descendant transactions. First version of
// addUnchecked can be used to have it call CalculateMemPoolAncestors(), and
// then invoke the second version.
// Note that addUnchecked is ONLY called from ATMP outside of tests
// and any other callers may break wallet's in-mempool tracking (due to
// lack of CValidationInterface::TransactionAddedToMempool callbacks).
bool addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry);
bool addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry,
setEntries &setAncestors);
void removeRecursive(
const CTransaction &tx,
MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
void removeForReorg(const Config &config, const CCoinsViewCache *pcoins,
unsigned int nMemPoolHeight, int flags)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void removeConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeForBlock(const std::vector<CTransactionRef> &vtx,
unsigned int nBlockHeight);
void clear();
// lock free
void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs);
bool CompareDepthAndScore(const uint256 &hasha, const uint256 &hashb);
void queryHashes(std::vector<uint256> &vtxid);
bool isSpent(const COutPoint &outpoint) const;
unsigned int GetTransactionsUpdated() const;
void AddTransactionsUpdated(unsigned int n);
/**
* Check that none of this transactions inputs are in the mempool, and thus
* the tx is not dependent on other mempool transactions to be included in a
* block.
*/
bool HasNoInputsOf(const CTransaction &tx) const;
/** Affect CreateNewBlock prioritisation of transactions */
void PrioritiseTransaction(const uint256 &hash, double dPriorityDelta,
const Amount nFeeDelta);
void ApplyDeltas(const uint256 hash, double &dPriorityDelta,
Amount &nFeeDelta) const;
void ClearPrioritisation(const uint256 hash);
public:
/**
* Remove a set of transactions from the mempool. If a transaction is in
* this set, then all in-mempool descendants must also be in the set, unless
* this transaction is being removed for being in a block. Set
* updateDescendants to true when removing a tx that was in a block, so that
* any in-mempool descendants have their ancestor state updated.
*/
void
RemoveStaged(setEntries &stage, bool updateDescendants,
MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN)
EXCLUSIVE_LOCKS_REQUIRED(cs);
/**
* When adding transactions from a disconnected block back to the mempool,
* new mempool entries may have children in the mempool (which is generally
* not the case when otherwise adding transactions).
* UpdateTransactionsFromBlock() will find child transactions and update the
* descendant state for each transaction in txidsToUpdate (excluding any
* child transactions present in txidsToUpdate, which are already accounted
* for).
* Note: txidsToUpdate should be the set of transactions from the
* disconnected block that have been accepted back into the mempool.
*/
void UpdateTransactionsFromBlock(const std::vector<TxId> &txidsToUpdate);
/**
* Try to calculate all in-mempool ancestors of entry.
* (these are all calculated including the tx itself)
* limitAncestorCount = max number of ancestors
* limitAncestorSize = max size of ancestors
* limitDescendantCount = max number of descendants any ancestor can have
* limitDescendantSize = max size of descendants any ancestor can have
* errString = populated with error reason if any limits are hit
* fSearchForParents = whether to search a tx's vin for in-mempool parents,
* or look up parents from mapLinks. Must be true for entries not in the
* mempool
*/
bool CalculateMemPoolAncestors(
const CTxMemPoolEntry &entry, setEntries &setAncestors,
uint64_t limitAncestorCount, uint64_t limitAncestorSize,
uint64_t limitDescendantCount, uint64_t limitDescendantSize,
std::string &errString, bool fSearchForParents = true) const;
/**
* Populate setDescendants with all in-mempool descendants of hash.
* Assumes that setDescendants includes all in-mempool descendants of
* anything already in it.
*/
void CalculateDescendants(txiter it, setEntries &setDescendants) const
EXCLUSIVE_LOCKS_REQUIRED(cs);
/**
* The minimum fee to get into the mempool, which may itself not be enough
* for larger-sized transactions. The incrementalRelayFee policy variable is
* used to bound the time it takes the fee rate to go back down all the way
* to 0. When the feerate would otherwise be half of this, it is set to 0
* instead.
*/
CFeeRate GetMinFee(size_t sizelimit) const;
/**
* Remove transactions from the mempool until its dynamic size is <=
* sizelimit. pvNoSpendsRemaining, if set, will be populated with the list
* of outpoints which are not in mempool which no longer have any spends in
* this mempool.
*/
void TrimToSize(size_t sizelimit,
std::vector<COutPoint> *pvNoSpendsRemaining = nullptr);
/**
* Expire all transaction (and their dependencies) in the mempool older than
* time. Return the number of removed transactions.
*/
int Expire(int64_t time);
/**
* Reduce the size of the mempool by expiring and then trimming the mempool.
*/
void LimitSize(size_t limit, unsigned long age);
/**
* Calculate the ancestor and descendant count for the given transaction.
* The counts include the transaction itself.
*/
void GetTransactionAncestry(const uint256 &txid, size_t &ancestors,
size_t &descendants) const;
unsigned long size() {
LOCK(cs);
return mapTx.size();
}
uint64_t GetTotalTxSize() const {
LOCK(cs);
return totalTxSize;
}
bool exists(uint256 hash) const {
LOCK(cs);
return mapTx.count(hash) != 0;
}
CTransactionRef get(const uint256 &hash) const;
TxMempoolInfo info(const uint256 &hash) const;
std::vector<TxMempoolInfo> infoAll() const;
CFeeRate estimateFee() const;
size_t DynamicMemoryUsage() const;
boost::signals2::signal<void(CTransactionRef)> NotifyEntryAdded;
boost::signals2::signal<void(CTransactionRef, MemPoolRemovalReason)>
NotifyEntryRemoved;
private:
/**
* UpdateForDescendants is used by UpdateTransactionsFromBlock to update the
* descendants for a single transaction that has been added to the mempool
* but may have child transactions in the mempool, eg during a chain reorg.
* setExclude is the set of descendant transactions in the mempool that must
* not be accounted for (because any descendants in setExclude were added to
* the mempool after the transaction being updated and hence their state is
* already reflected in the parent state).
*
* cachedDescendants will be updated with the descendants of the transaction
* being updated, so that future invocations don't need to walk the same
* transaction again, if encountered in another transaction chain.
*/
void UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants,
const std::set<TxId> &setExclude)
EXCLUSIVE_LOCKS_REQUIRED(cs);
/**
* Update ancestors of hash to add/remove it as a descendant transaction.
*/
void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors)
EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Set ancestor state for an entry */
void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors)
EXCLUSIVE_LOCKS_REQUIRED(cs);
/**
* For each transaction being removed, update ancestors and any direct
* children. If updateDescendants is true, then also update in-mempool
* descendants' ancestor state.
*/
void UpdateForRemoveFromMempool(const setEntries &entriesToRemove,
bool updateDescendants)
EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Sever link between specified transaction and direct children. */
void UpdateChildrenForRemoval(txiter entry) EXCLUSIVE_LOCKS_REQUIRED(cs);
/**
* Before calling removeUnchecked for a given transaction,
* UpdateForRemoveFromMempool must be called on the entire (dependent) set
* of transactions being removed at the same time. We use each
* CTxMemPoolEntry's setMemPoolParents in order to walk ancestors of a given
* transaction that is removed, so we can't remove intermediate transactions
* in a chain before we've updated all the state for the removal.
*/
void
removeUnchecked(txiter entry,
MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN)
EXCLUSIVE_LOCKS_REQUIRED(cs);
};
/**
* CCoinsView that brings transactions from a mempool into view.
* It does not check for spendings by memory pool transactions.
* Instead, it provides access to all Coins which are either unspent in the
* base CCoinsView, or are outputs from any mempool transaction!
* This allows transaction replacement to work as expected, as you want to
* have all inputs "available" to check signatures, and any cycles in the
* dependency graph are checked directly in AcceptToMemoryPool.
* It also allows you to sign a double-spend directly in
* signrawtransactionwithkey and signrawtransactionwithwallet, as long as the
* conflicting transaction is not yet confirmed.
*/
class CCoinsViewMemPool : public CCoinsViewBacked {
protected:
const CTxMemPool &mempool;
public:
CCoinsViewMemPool(CCoinsView *baseIn, const CTxMemPool &mempoolIn);
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
};
// We want to sort transactions by coin age priority
typedef std::pair<double, CTxMemPool::txiter> TxCoinAgePriority;
struct TxCoinAgePriorityCompare {
bool operator()(const TxCoinAgePriority &a, const TxCoinAgePriority &b) {
if (a.first == b.first) {
// Reverse order to make sort less than
return CompareTxMemPoolEntryByScore()(*(b.second), *(a.second));
}
return a.first < b.first;
}
};
/**
* DisconnectedBlockTransactions
*
* During the reorg, it's desirable to re-add previously confirmed transactions
* to the mempool, so that anything not re-confirmed in the new chain is
* available to be mined. However, it's more efficient to wait until the reorg
* is complete and process all still-unconfirmed transactions at that time,
* since we expect most confirmed transactions to (typically) still be
* confirmed in the new chain, and re-accepting to the memory pool is expensive
* (and therefore better to not do in the middle of reorg-processing).
* Instead, store the disconnected transactions (in order!) as we go, remove any
* that are included in blocks in the new chain, and then process the remaining
* still-unconfirmed transactions at the end.
*
* It also enables efficient reprocessing of current mempool entries, useful
* when (de)activating forks that result in in-mempool transactions becoming
* invalid
*/
// multi_index tag names
struct txid_index {};
struct insertion_order {};
class DisconnectedBlockTransactions {
private:
typedef boost::multi_index_container<
CTransactionRef, boost::multi_index::indexed_by<
// sorted by txid
boost::multi_index::hashed_unique<
boost::multi_index::tag<txid_index>,
mempoolentry_txid, SaltedTxidHasher>,
// sorted by order in the blockchain
boost::multi_index::sequenced<
boost::multi_index::tag<insertion_order>>>>
indexed_disconnected_transactions;
indexed_disconnected_transactions queuedTx;
uint64_t cachedInnerUsage = 0;
void addTransaction(const CTransactionRef &tx) {
queuedTx.insert(tx);
cachedInnerUsage += RecursiveDynamicUsage(tx);
}
public:
// It's almost certainly a logic bug if we don't clear out queuedTx before
// destruction, as we add to it while disconnecting blocks, and then we
// need to re-process remaining transactions to ensure mempool consistency.
// For now, assert() that we've emptied out this object on destruction.
// This assert() can always be removed if the reorg-processing code were
// to be refactored such that this assumption is no longer true (for
// instance if there was some other way we cleaned up the mempool after a
// reorg, besides draining this object).
~DisconnectedBlockTransactions() { assert(queuedTx.empty()); }
// Estimate the overhead of queuedTx to be 6 pointers + an allocation, as
// no exact formula for boost::multi_index_contained is implemented.
size_t DynamicMemoryUsage() const {
return memusage::MallocUsage(sizeof(CTransactionRef) +
6 * sizeof(void *)) *
queuedTx.size() +
cachedInnerUsage;
}
const indexed_disconnected_transactions &GetQueuedTx() const {
return queuedTx;
}
// Import mempool entries in topological order into queuedTx and clear the
// mempool. Caller should call updateMempoolForReorg to reprocess these
// transactions
void importMempool(CTxMemPool &pool);
// Add entries for a block while reconstructing the topological ordering so
// they can be added back to the mempool simply.
void addForBlock(const std::vector<CTransactionRef> &vtx);
// Remove entries based on txid_index, and update memory usage.
void removeForBlock(const std::vector<CTransactionRef> &vtx) {
// Short-circuit in the common case of a block being added to the tip
if (queuedTx.empty()) {
return;
}
for (auto const &tx : vtx) {
auto it = queuedTx.find(tx->GetId());
if (it != queuedTx.end()) {
cachedInnerUsage -= RecursiveDynamicUsage(*it);
queuedTx.erase(it);
}
}
}
// Remove an entry by insertion_order index, and update memory usage.
void removeEntry(indexed_disconnected_transactions::index<
insertion_order>::type::iterator entry) {
cachedInnerUsage -= RecursiveDynamicUsage(*entry);
queuedTx.get<insertion_order>().erase(entry);
}
bool isEmpty() const { return queuedTx.empty(); }
void clear() {
cachedInnerUsage = 0;
queuedTx.clear();
}
/**
* Make mempool consistent after a reorg, by re-adding or recursively
* erasing disconnected block transactions from the mempool, and also
* removing any other transactions from the mempool that are no longer valid
* given the new tip/height.
*
* Note: we assume that disconnectpool only contains transactions that are
* NOT confirmed in the current chain nor already in the mempool (otherwise,
* in-mempool descendants of such transactions would be removed).
*
* Passing fAddToMempool=false will skip trying to add the transactions
* back, and instead just erase from the mempool as needed.
*/
void updateMempoolForReorg(const Config &config, bool fAddToMempool);
};
#endif // BITCOIN_TXMEMPOOL_H

File Metadata

Mime Type
text/x-diff
Expires
Sun, Mar 2, 08:50 (1 d, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187130
Default Alt Text
(69 KB)

Event Timeline