aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arith_uint256.cpp2
-rw-r--r--src/arith_uint256.h2
-rw-r--r--src/base58.cpp10
-rw-r--r--src/bench/base58.cpp2
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/compat/byteswap.h2
-rw-r--r--src/compat/endian.h2
-rw-r--r--src/main.cpp165
-rw-r--r--src/memusage.h2
-rw-r--r--src/net.cpp173
-rw-r--r--src/net.h255
-rw-r--r--src/policy/fees.cpp170
-rw-r--r--src/policy/fees.h117
-rw-r--r--src/policy/policy.cpp2
-rw-r--r--src/policy/policy.h2
-rw-r--r--src/policy/rbf.cpp2
-rw-r--r--src/policy/rbf.h2
-rw-r--r--src/primitives/transaction.cpp5
-rw-r--r--src/primitives/transaction.h2
-rw-r--r--src/qt/clientmodel.cpp3
-rw-r--r--src/qt/paymentrequestplus.h2
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/rpc/mining.cpp4
-rw-r--r--src/script/bitcoinconsensus.cpp9
-rw-r--r--src/script/bitcoinconsensus.h4
-rw-r--r--src/serialize.h49
-rw-r--r--src/streams.h7
-rw-r--r--src/support/lockedpool.cpp127
-rw-r--r--src/support/lockedpool.h24
-rw-r--r--src/test/DoS_tests.cpp12
-rw-r--r--src/test/allocator_tests.cpp14
-rw-r--r--src/test/bctest.py177
-rwxr-xr-xsrc/test/bitcoin-util-test.py9
-rw-r--r--src/test/policyestimator_tests.cpp60
-rw-r--r--src/test/script_tests.cpp13
-rw-r--r--src/test/serialize_tests.cpp71
-rw-r--r--src/test/univalue_tests.cpp2
-rw-r--r--src/txmempool.cpp5
-rw-r--r--src/wallet/rpcdump.cpp4
39 files changed, 671 insertions, 846 deletions
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index 2e61363576..a58ad01b5a 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin developers
+// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index ba3d620158..5cc52f6e72 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/base58.cpp b/src/base58.cpp
index d1d60a6f1d..f7768b5a64 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -25,12 +25,14 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
psz++;
// Skip and count leading '1's.
int zeroes = 0;
+ int length = 0;
while (*psz == '1') {
zeroes++;
psz++;
}
// Allocate enough space in big-endian base256 representation.
- std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
+ int size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up.
+ std::vector<unsigned char> b256(size);
// Process the characters.
while (*psz && !isspace(*psz)) {
// Decode base58 character
@@ -39,12 +41,14 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
return false;
// Apply "b256 = b256 * 58 + ch".
int carry = ch - pszBase58;
- for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
+ int i = 0;
+ for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
carry += 58 * (*it);
*it = carry % 256;
carry /= 256;
}
assert(carry == 0);
+ length = i;
psz++;
}
// Skip trailing spaces.
@@ -53,7 +57,7 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
if (*psz != 0)
return false;
// Skip leading zeroes in b256.
- std::vector<unsigned char>::iterator it = b256.begin();
+ std::vector<unsigned char>::iterator it = b256.begin() + (size - length);
while (it != b256.end() && *it == 0)
it++;
// Copy result into output vector.
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 1279c3e7df..a791b5b7fa 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 the Bitcoin Core developers
+// Copyright (c) 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.
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 2d66448d80..8a2f380e67 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -240,7 +240,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
event_base_free(base);
if (response.status == 0)
- throw CConnectionFailed(strprintf("couldn't connect to server (%d %s)", response.error, http_errorstring(response.error)));
+ throw CConnectionFailed(strprintf("couldn't connect to server\n(make sure server is running and you are connecting to the correct RPC port: %d %s)", response.error, http_errorstring(response.error)));
else if (response.status == HTTP_UNAUTHORIZED)
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
index 899220bdc5..07ca535728 100644
--- a/src/compat/byteswap.h
+++ b/src/compat/byteswap.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Bitcoin developers
+// Copyright (c) 2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 6bfae42c77..f7c1f9318a 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015 The Bitcoin developers
+// Copyright (c) 2014-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/main.cpp b/src/main.cpp
index b65b9874e9..7e5b9528b9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -18,6 +18,7 @@
#include "init.h"
#include "merkleblock.h"
#include "net.h"
+#include "netbase.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "pow.h"
@@ -259,7 +260,7 @@ struct CBlockReject {
*/
struct CNodeState {
//! The peer's address
- CService address;
+ const CService address;
//! Whether we have a fully established connection.
bool fCurrentlyConnected;
//! Accumulated misbehaviour score for this peer.
@@ -267,7 +268,7 @@ struct CNodeState {
//! Whether this peer should be disconnected and banned (unless whitelisted).
bool fShouldBan;
//! String name of this peer (debugging/logging purposes).
- std::string name;
+ const std::string name;
//! List of asynchronously-determined block rejections to notify this peer about.
std::vector<CBlockReject> rejects;
//! The best known block we know this peer has announced.
@@ -311,7 +312,7 @@ struct CNodeState {
*/
bool fSupportsDesiredCmpctVersion;
- CNodeState() {
+ CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) {
fCurrentlyConnected = false;
nMisbehavior = 0;
fShouldBan = false;
@@ -356,11 +357,36 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
nPreferredDownload += state->fPreferredDownload;
}
-void InitializeNode(NodeId nodeid, const CNode *pnode) {
- LOCK(cs_main);
- CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
- state.name = pnode->addrName;
- state.address = pnode->addr;
+void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)
+{
+ ServiceFlags nLocalNodeServices = pnode->GetLocalServices();
+ uint64_t nonce = pnode->GetLocalNonce();
+ int nNodeStartingHeight = pnode->GetMyStartingHeight();
+ NodeId nodeid = pnode->GetId();
+ CAddress addr = pnode->addr;
+
+ CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices));
+ CAddress addrMe = CAddress(CService(), nLocalNodeServices);
+
+ connman.PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
+ nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes);
+
+ if (fLogIPs)
+ LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
+ else
+ LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid);
+}
+
+void InitializeNode(CNode *pnode, CConnman& connman) {
+ CAddress addr = pnode->addr;
+ std::string addrName = pnode->addrName;
+ NodeId nodeid = pnode->GetId();
+ {
+ LOCK(cs_main);
+ mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName)));
+ }
+ if(!pnode->fInbound)
+ PushNodeVersion(pnode, connman, GetTime());
}
void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
@@ -503,15 +529,15 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
- bool found = connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
- pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ bool found = connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
+ connman.PushMessage(pnodeStop, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
return true;
});
if(found)
lNodesAnnouncingHeaderAndIDs.pop_front();
}
fAnnounceUsingCMPCTBLOCK = true;
- pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ connman.PushMessage(pfrom, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
}
}
@@ -4902,9 +4928,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
if (!ReadBlockFromDisk(block, (*mi).second, consensusParams))
assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
- pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
+ connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
else if (inv.type == MSG_WITNESS_BLOCK)
- pfrom->PushMessage(NetMsgType::BLOCK, block);
+ connman.PushMessage(pfrom, NetMsgType::BLOCK, block);
else if (inv.type == MSG_FILTERED_BLOCK)
{
bool sendMerkleBlock = false;
@@ -4917,7 +4943,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
}
if (sendMerkleBlock) {
- pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock);
+ connman.PushMessage(pfrom, NetMsgType::MERKLEBLOCK, merkleBlock);
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
// Note that there is currently no way for a node to request any single transactions we didn't send here -
@@ -4926,7 +4952,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
- pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, block.vtx[pair.first]);
+ connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, block.vtx[pair.first]);
}
// else
// no response
@@ -4940,9 +4966,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;
if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness);
- pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
+ connman.PushMessageWithFlag(pfrom, fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
} else
- pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
+ connman.PushMessageWithFlag(pfrom, fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
}
// Trigger the peer node to send a getblocks request for the next batch of inventory
@@ -4953,7 +4979,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// wait for other stuff first.
vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
- pfrom->PushMessage(NetMsgType::INV, vInv);
+ connman.PushMessage(pfrom, NetMsgType::INV, vInv);
pfrom->hashContinue.SetNull();
}
}
@@ -4964,14 +4990,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
bool push = false;
auto mi = mapRelay.find(inv.hash);
if (mi != mapRelay.end()) {
- pfrom->PushMessageWithFlag(inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, NetMsgType::TX, *mi->second);
+ connman.PushMessageWithFlag(pfrom, inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, 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 (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) {
- pfrom->PushMessageWithFlag(inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, NetMsgType::TX, *txinfo.tx);
+ connman.PushMessageWithFlag(pfrom, inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, NetMsgType::TX, *txinfo.tx);
push = true;
}
}
@@ -4998,7 +5024,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// do that because they want to know about (and store and rebroadcast and
// risk analyze) the dependencies of transactions relevant to them, without
// having to download the entire memory pool.
- pfrom->PushMessage(NetMsgType::NOTFOUND, vNotFound);
+ connman.PushMessage(pfrom, NetMsgType::NOTFOUND, vNotFound);
}
}
@@ -5024,8 +5050,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!(pfrom->GetLocalServices() & NODE_BLOOM) &&
(strCommand == NetMsgType::FILTERLOAD ||
- strCommand == NetMsgType::FILTERADD ||
- strCommand == NetMsgType::FILTERCLEAR))
+ strCommand == NetMsgType::FILTERADD))
{
if (pfrom->nVersion >= NO_BLOOM_VERSION) {
LOCK(cs_main);
@@ -5049,7 +5074,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
+ connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 1);
return false;
@@ -5069,7 +5094,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pfrom->nServicesExpected & ~pfrom->nServices)
{
LogPrint("net", "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->id, pfrom->nServices, pfrom->nServicesExpected);
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
+ connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
strprintf("Expected to offer services %08x", pfrom->nServicesExpected));
pfrom->fDisconnect = true;
return false;
@@ -5079,7 +5104,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
// disconnect from peers older than this proto version
LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
+ connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION));
pfrom->fDisconnect = true;
return false;
@@ -5120,7 +5145,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Be shy and don't send version until we hear
if (pfrom->fInbound)
- pfrom->PushVersion();
+ PushNodeVersion(pfrom, connman, GetAdjustedTime());
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
@@ -5137,8 +5162,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// Change version
- pfrom->PushMessage(NetMsgType::VERACK);
- pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
+ connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::VERACK);
+ pfrom->SetSendVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
if (!pfrom->fInbound)
{
@@ -5161,7 +5186,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Get recent addresses
if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000)
{
- pfrom->PushMessage(NetMsgType::GETADDR);
+ connman.PushMessage(pfrom, NetMsgType::GETADDR);
pfrom->fGetAddr = true;
}
connman.MarkAddressGood(pfrom->addr);
@@ -5208,7 +5233,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
- pfrom->PushMessage(NetMsgType::SENDHEADERS);
+ connman.PushMessage(pfrom, NetMsgType::SENDHEADERS);
}
if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) {
// Tell our peer we are willing to provide version 1 or 2 cmpctblocks
@@ -5219,9 +5244,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 2;
if (pfrom->GetLocalServices() & NODE_WITNESS)
- pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ connman.PushMessage(pfrom, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
nCMPCTBLOCKVersion = 1;
- pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ connman.PushMessage(pfrom, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
}
}
@@ -5349,7 +5374,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// time the block arrives, the header chain leading up to it is already validated. Not
// doing this will result in the received block being rejected as an orphan in case it is
// not a direct successor.
- pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash);
+ connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash);
CNodeState *nodestate = State(pfrom->GetId());
if (CanDirectFetch(chainparams.GetConsensus()) &&
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
@@ -5385,7 +5410,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
if (!vToFetch.empty())
- pfrom->PushMessage(NetMsgType::GETDATA, vToFetch);
+ connman.PushMessage(pfrom, NetMsgType::GETDATA, vToFetch);
}
@@ -5485,7 +5510,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
resp.txn[i] = block.vtx[req.indexes[i]];
}
- pfrom->PushMessageWithFlag(State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp);
+ connman.PushMessageWithFlag(pfrom, State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp);
}
@@ -5534,7 +5559,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip.
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
- pfrom->PushMessage(NetMsgType::HEADERS, vHeaders);
+ connman.PushMessage(pfrom, NetMsgType::HEADERS, vHeaders);
}
@@ -5697,7 +5722,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->id,
FormatStateMessage(state));
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
+ connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0) {
Misbehaving(pfrom->GetId(), nDoS);
@@ -5716,7 +5741,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!IsInitialBlockDownload())
- pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
+ connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
return true;
}
@@ -5749,7 +5774,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// so we just grab the block via normal getdata
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- pfrom->PushMessage(NetMsgType::GETDATA, vInv);
+ connman.PushMessage(pfrom, NetMsgType::GETDATA, vInv);
}
return true;
}
@@ -5793,7 +5818,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Duplicate txindexes, the block is now in-flight, so just request it
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- pfrom->PushMessage(NetMsgType::GETDATA, vInv);
+ connman.PushMessage(pfrom, NetMsgType::GETDATA, vInv);
return true;
}
@@ -5817,7 +5842,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman);
} else {
req.blockhash = pindex->GetBlockHash();
- pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req);
+ connman.PushMessage(pfrom, NetMsgType::GETBLOCKTXN, req);
}
}
} else {
@@ -5826,7 +5851,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// mempool will probably be useless - request the block normally
std::vector<CInv> vInv(1);
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- pfrom->PushMessage(NetMsgType::GETDATA, vInv);
+ connman.PushMessage(pfrom, NetMsgType::GETDATA, vInv);
return true;
} else {
// If this was an announce-cmpctblock, we want the same treatment as a header message
@@ -5868,7 +5893,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Might have collided, fall back to getdata now :(
std::vector<CInv> invs;
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash));
- pfrom->PushMessage(NetMsgType::GETDATA, invs);
+ connman.PushMessage(pfrom, NetMsgType::GETDATA, invs);
} else {
// Block is either okay, or possibly we received
// READ_STATUS_CHECKBLOCK_FAILED.
@@ -5902,7 +5927,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
+ connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash());
}
}
@@ -5946,7 +5971,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// nUnconnectingHeaders gets reset back to 0.
if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++;
- pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
+ connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
LogPrint("net", "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(),
@@ -5993,7 +6018,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
- pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256());
+ connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256());
}
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
@@ -6046,7 +6071,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// In any case, we want to download using a compact block, not a regular one
vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
}
- pfrom->PushMessage(NetMsgType::GETDATA, vGetData);
+ connman.PushMessage(pfrom, NetMsgType::GETDATA, vGetData);
}
}
}
@@ -6078,7 +6103,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
+ connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash());
if (nDoS > 0) {
LOCK(cs_main);
@@ -6155,7 +6180,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// it, if the remote node sends a ping once per second and this node takes 5
// seconds to respond to each, the 5th ping the remote sends would appear to
// return very quickly.
- pfrom->PushMessage(NetMsgType::PONG, nonce);
+ connman.PushMessage(pfrom, NetMsgType::PONG, nonce);
}
}
@@ -6267,8 +6292,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == NetMsgType::FILTERCLEAR)
{
LOCK(pfrom->cs_filter);
- delete pfrom->pfilter;
- pfrom->pfilter = new CBloomFilter();
+ if (pfrom->GetLocalServices() & NODE_BLOOM) {
+ delete pfrom->pfilter;
+ pfrom->pfilter = new CBloomFilter();
+ }
pfrom->fRelayTxes = true;
}
@@ -6390,7 +6417,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman)
// Checksum
CDataStream& vRecv = msg.vRecv;
- uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
+ const uint256& hash = msg.GetMessageHash();
if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0)
{
LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
@@ -6409,7 +6436,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman)
}
catch (const std::ios_base::failure& e)
{
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message"));
+ connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message"));
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from under-length message on vRecv
@@ -6498,11 +6525,11 @@ bool SendMessages(CNode* pto, CConnman& connman)
pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
- pto->PushMessage(NetMsgType::PING, nonce);
+ connman.PushMessage(pto, NetMsgType::PING, nonce);
} else {
// Peer is too old to support ping command with nonce, pong will never arrive.
pto->nPingNonceSent = 0;
- pto->PushMessage(NetMsgType::PING);
+ connman.PushMessage(pto, NetMsgType::PING);
}
}
@@ -6533,14 +6560,14 @@ bool SendMessages(CNode* pto, CConnman& connman)
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
- pto->PushMessage(NetMsgType::ADDR, vAddr);
+ connman.PushMessage(pto, NetMsgType::ADDR, vAddr);
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
- pto->PushMessage(NetMsgType::ADDR, vAddr);
+ connman.PushMessage(pto, NetMsgType::ADDR, vAddr);
// we only send the big addr message once
if (pto->vAddrToSend.capacity() > 40)
pto->vAddrToSend.shrink_to_fit();
@@ -6563,7 +6590,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
}
BOOST_FOREACH(const CBlockReject& reject, state.rejects)
- pto->PushMessage(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock);
+ connman.PushMessage(pto, NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock);
state.rejects.clear();
// Start block sync
@@ -6586,7 +6613,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight);
- pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256());
+ connman.PushMessage(pto, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256());
}
}
@@ -6675,7 +6702,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
CBlock block;
assert(ReadBlockFromDisk(block, pBestIndex, consensusParams));
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
- pto->PushMessageWithFlag(state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
+ connman.PushMessageWithFlag(pto, state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
state.pindexBestHeaderSent = pBestIndex;
} else if (state.fPreferHeaders) {
if (vHeaders.size() > 1) {
@@ -6687,7 +6714,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
LogPrint("net", "%s: sending header %s to peer=%d\n", __func__,
vHeaders.front().GetHash().ToString(), pto->id);
}
- pto->PushMessage(NetMsgType::HEADERS, vHeaders);
+ connman.PushMessage(pto, NetMsgType::HEADERS, vHeaders);
state.pindexBestHeaderSent = pBestIndex;
} else
fRevertToInv = true;
@@ -6733,7 +6760,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
BOOST_FOREACH(const uint256& hash, pto->vInventoryBlockToSend) {
vInv.push_back(CInv(MSG_BLOCK, hash));
if (vInv.size() == MAX_INV_SZ) {
- pto->PushMessage(NetMsgType::INV, vInv);
+ connman.PushMessage(pto, NetMsgType::INV, vInv);
vInv.clear();
}
}
@@ -6779,7 +6806,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
pto->filterInventoryKnown.insert(hash);
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
- pto->PushMessage(NetMsgType::INV, vInv);
+ connman.PushMessage(pto, NetMsgType::INV, vInv);
vInv.clear();
}
}
@@ -6845,7 +6872,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
}
}
if (vInv.size() == MAX_INV_SZ) {
- pto->PushMessage(NetMsgType::INV, vInv);
+ connman.PushMessage(pto, NetMsgType::INV, vInv);
vInv.clear();
}
pto->filterInventoryKnown.insert(hash);
@@ -6853,7 +6880,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
}
}
if (!vInv.empty())
- pto->PushMessage(NetMsgType::INV, vInv);
+ connman.PushMessage(pto, NetMsgType::INV, vInv);
// Detect whether we're stalling
nNow = GetTimeMicros();
@@ -6914,7 +6941,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
- pto->PushMessage(NetMsgType::GETDATA, vGetData);
+ connman.PushMessage(pto, NetMsgType::GETDATA, vGetData);
vGetData.clear();
}
} else {
@@ -6924,7 +6951,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
- pto->PushMessage(NetMsgType::GETDATA, vGetData);
+ connman.PushMessage(pto, NetMsgType::GETDATA, vGetData);
//
// Message: feefilter
@@ -6937,7 +6964,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
if (timeNow > pto->nextSendTimeFeeFilter) {
CAmount filterToSend = filterRounder.round(currentFilter);
if (filterToSend != pto->lastSentFeeFilter) {
- pto->PushMessage(NetMsgType::FEEFILTER, filterToSend);
+ connman.PushMessage(pto, NetMsgType::FEEFILTER, filterToSend);
pto->lastSentFeeFilter = filterToSend;
}
pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
diff --git a/src/memusage.h b/src/memusage.h
index 3810bfad07..2e3c5a9b92 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin developers
+// Copyright (c) 2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/net.cpp b/src/net.cpp
index 18d25cbcd1..e47a8bb168 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -393,18 +393,15 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false);
-
- GetNodeSignals().InitializeNode(pnode->GetId(), pnode);
+ pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
+ pnode->nTimeConnected = GetTime();
pnode->AddRef();
-
+ GetNodeSignals().InitializeNode(pnode, *this);
{
LOCK(cs_vNodes);
vNodes.push_back(pnode);
}
- pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
- pnode->nTimeConnected = GetTime();
-
return pnode;
} else if (!proxyConnectionFailed) {
// If connecting to the node failed, and failure is not caused by a problem connecting to
@@ -450,23 +447,6 @@ void CNode::CloseSocketDisconnect()
vRecvMsg.clear();
}
-void CNode::PushVersion()
-{
- int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
- CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices));
- CAddress addrMe = CAddress(CService(), nLocalServices);
- if (fLogIPs)
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id);
- else
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), id);
- PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe,
- nLocalHostNonce, strSubVersion, nMyStartingHeight, ::fRelayTxes);
-}
-
-
-
-
-
void CConnman::ClearBanned()
{
{
@@ -762,12 +742,21 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes)
vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
}
+ hasher.Write((const unsigned char*)pch, nCopy);
memcpy(&vRecv[nDataPos], pch, nCopy);
nDataPos += nCopy;
return nCopy;
}
+const uint256& CNetMessage::GetMessageHash() const
+{
+ assert(complete());
+ if (data_hash.IsNull())
+ hasher.Finalize(data_hash.begin());
+ return data_hash;
+}
+
@@ -829,7 +818,7 @@ struct NodeEvictionCandidate
int64_t nMinPingUsecTime;
int64_t nLastBlockTime;
int64_t nLastTXTime;
- bool fNetworkNode;
+ bool fRelevantServices;
bool fRelayTxes;
bool fBloomFilter;
CAddress addr;
@@ -854,7 +843,7 @@ static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvict
{
// There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.
if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime;
- if (a.fNetworkNode != b.fNetworkNode) return b.fNetworkNode;
+ if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;
return a.nTimeConnected > b.nTimeConnected;
}
@@ -889,7 +878,8 @@ bool CConnman::AttemptToEvictConnection()
if (node->fDisconnect)
continue;
NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime,
- node->nLastBlockTime, node->nLastTXTime, node->fNetworkNode,
+ node->nLastBlockTime, node->nLastTXTime,
+ (node->nServices & nRelevantServices) == nRelevantServices,
node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup};
vEvictionCandidates.push_back(candidate);
}
@@ -1032,9 +1022,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, "", true);
- GetNodeSignals().InitializeNode(pnode->GetId(), pnode);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
+ GetNodeSignals().InitializeNode(pnode, *this);
LogPrint("net", "connection from %s accepted\n", addr.ToString());
@@ -1059,7 +1049,7 @@ void CConnman::ThreadSocketHandler()
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
if (pnode->fDisconnect ||
- (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty()))
+ (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0))
{
// remove from vNodes
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
@@ -1163,10 +1153,6 @@ void CConnman::ThreadSocketHandler()
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend) {
- if (pnode->nOptimisticBytesWritten) {
- RecordBytesSent(pnode->nOptimisticBytesWritten);
- pnode->nOptimisticBytesWritten = 0;
- }
if (!pnode->vSendMsg.empty()) {
FD_SET(pnode->hSocket, &fdsetSend);
continue;
@@ -2130,7 +2116,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
pnodeLocalHost = new CNode(id, nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0, nonce);
- GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost);
+ GetNodeSignals().InitializeNode(pnodeLocalHost, *this);
}
//
@@ -2482,46 +2468,10 @@ int CConnman::GetBestHeight() const
return nBestHeight.load(std::memory_order_acquire);
}
-void CNode::Fuzz(int nChance)
-{
- if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake
- if (GetRand(nChance) != 0) return; // Fuzz 1 of every nChance messages
-
- switch (GetRand(3))
- {
- case 0:
- // xor a random byte with a random value:
- if (!ssSend.empty()) {
- CDataStream::size_type pos = GetRand(ssSend.size());
- ssSend[pos] ^= (unsigned char)(GetRand(256));
- }
- break;
- case 1:
- // delete a random byte:
- if (!ssSend.empty()) {
- CDataStream::size_type pos = GetRand(ssSend.size());
- ssSend.erase(ssSend.begin()+pos);
- }
- break;
- case 2:
- // insert a random byte at a random position
- {
- CDataStream::size_type pos = GetRand(ssSend.size());
- char ch = (char)GetRand(256);
- ssSend.insert(ssSend.begin()+pos, ch);
- }
- break;
- }
- // Chance of more than one change half the time:
- // (more changes exponentially less likely):
- Fuzz(2);
-}
-
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }
CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string& addrNameIn, bool fInboundIn) :
- ssSend(SER_NETWORK, INIT_PROTO_VERSION),
addr(addrIn),
fInbound(fInboundIn),
id(idIn),
@@ -2530,7 +2480,8 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
filterInventoryKnown(50000, 0.000001),
nLocalHostNonce(nLocalHostNonceIn),
nLocalServices(nLocalServicesIn),
- nMyStartingHeight(nMyStartingHeightIn)
+ nMyStartingHeight(nMyStartingHeightIn),
+ nSendVersion(0)
{
nServices = NODE_NONE;
nServicesExpected = NODE_NONE;
@@ -2577,7 +2528,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
minFeeFilter = 0;
lastSentFeeFilter = 0;
nextSendTimeFeeFilter = 0;
- nOptimisticBytesWritten = 0;
BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
mapRecvBytesPerMsgCmd[msg] = 0;
@@ -2587,10 +2537,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
LogPrint("net", "Added connection to %s peer=%d\n", addrName, id);
else
LogPrint("net", "Added connection peer=%d\n", id);
-
- // Be shy and don't send version until we hear
- if (hSocket != INVALID_SOCKET && !fInbound)
- PushVersion();
}
CNode::~CNode()
@@ -2635,65 +2581,50 @@ void CNode::AskFor(const CInv& inv)
mapAskFor.insert(std::make_pair(nRequestTime, inv));
}
-void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend)
+CDataStream CConnman::BeginMessage(CNode* pnode, int nVersion, int flags, const std::string& sCommand)
{
- ENTER_CRITICAL_SECTION(cs_vSend);
- assert(ssSend.size() == 0);
- ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0);
- LogPrint("net", "sending: %s ", SanitizeString(pszCommand));
+ return {SER_NETWORK, (nVersion ? nVersion : pnode->GetSendVersion()) | flags, CMessageHeader(Params().MessageStart(), sCommand.c_str(), 0) };
}
-void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
+void CConnman::EndMessage(CDataStream& strm)
{
- ssSend.clear();
-
- LEAVE_CRITICAL_SECTION(cs_vSend);
+ // Set the size
+ assert(strm.size () >= CMessageHeader::HEADER_SIZE);
+ unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE;
+ WriteLE32((uint8_t*)&strm[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
+ // Set the checksum
+ uint256 hash = Hash(strm.begin() + CMessageHeader::HEADER_SIZE, strm.end());
+ memcpy((char*)&strm[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE);
- LogPrint("net", "(aborted)\n");
}
-void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend)
+void CConnman::PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand)
{
- // The -*messagestest options are intentionally not documented in the help message,
- // since they are only used during development to debug the networking code and are
- // not intended for end-users.
- if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0)
- {
- LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n");
- AbortMessage();
- return;
- }
- if (mapArgs.count("-fuzzmessagestest"))
- Fuzz(GetArg("-fuzzmessagestest", 10));
-
- if (ssSend.size() == 0)
- {
- LEAVE_CRITICAL_SECTION(cs_vSend);
+ if(strm.empty())
return;
- }
- // Set the size
- unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
- WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
-
- //log total amount of bytes per command
- mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE;
- // Set the checksum
- uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
- assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + CMessageHeader::CHECKSUM_SIZE);
- memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE);
-
- LogPrint("net", "(%d bytes) peer=%d\n", nSize, id);
+ unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE;
+ LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(sCommand.c_str()), nSize, pnode->id);
- std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData());
- ssSend.GetAndClear(*it);
- nSendSize += (*it).size();
+ size_t nBytesSent = 0;
+ {
+ LOCK(pnode->cs_vSend);
+ if(pnode->hSocket == INVALID_SOCKET) {
+ return;
+ }
+ bool optimisticSend(pnode->vSendMsg.empty());
+ pnode->vSendMsg.emplace_back(strm.begin(), strm.end());
- // If write queue empty, attempt "optimistic write"
- if (it == vSendMsg.begin())
- nOptimisticBytesWritten += SocketSendData(this);
+ //log total amount of bytes per command
+ pnode->mapSendBytesPerMsgCmd[sCommand] += strm.size();
+ pnode->nSendSize += strm.size();
- LEAVE_CRITICAL_SECTION(cs_vSend);
+ // If write queue empty, attempt "optimistic write"
+ if (optimisticSend == true)
+ nBytesSent = SocketSendData(pnode);
+ }
+ if (nBytesSent)
+ RecordBytesSent(nBytesSent);
}
bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
diff --git a/src/net.h b/src/net.h
index bfce516237..e712953be3 100644
--- a/src/net.h
+++ b/src/net.h
@@ -136,6 +136,33 @@ public:
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
+ template <typename... Args>
+ void PushMessageWithVersionAndFlag(CNode* pnode, int nVersion, int flag, const std::string& sCommand, Args&&... args)
+ {
+ auto msg(BeginMessage(pnode, nVersion, flag, sCommand));
+ ::SerializeMany(msg, msg.nType, msg.nVersion, std::forward<Args>(args)...);
+ EndMessage(msg);
+ PushMessage(pnode, msg, sCommand);
+ }
+
+ template <typename... Args>
+ void PushMessageWithFlag(CNode* pnode, int flag, const std::string& sCommand, Args&&... args)
+ {
+ PushMessageWithVersionAndFlag(pnode, 0, flag, sCommand, std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ void PushMessageWithVersion(CNode* pnode, int nVersion, const std::string& sCommand, Args&&... args)
+ {
+ PushMessageWithVersionAndFlag(pnode, nVersion, 0, sCommand, std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ void PushMessage(CNode* pnode, const std::string& sCommand, Args&&... args)
+ {
+ PushMessageWithVersionAndFlag(pnode, 0, 0, sCommand, std::forward<Args>(args)...);
+ }
+
template<typename Callable>
bool ForEachNodeContinueIf(Callable&& func)
{
@@ -345,6 +372,10 @@ private:
unsigned int GetReceiveFloodSize() const;
+ CDataStream BeginMessage(CNode* node, int nVersion, int flags, const std::string& sCommand);
+ void PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand);
+ void EndMessage(CDataStream& strm);
+
// Network stats
void RecordBytesRecv(uint64_t bytes);
void RecordBytesSent(uint64_t bytes);
@@ -428,7 +459,7 @@ struct CNodeSignals
{
boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> ProcessMessages;
boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> SendMessages;
- boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
+ boost::signals2::signal<void (CNode*, CConnman&)> InitializeNode;
boost::signals2::signal<void (NodeId, bool&)> FinalizeNode;
};
@@ -512,6 +543,9 @@ public:
class CNetMessage {
+private:
+ mutable CHash256 hasher;
+ mutable uint256 data_hash;
public:
bool in_data; // parsing header (false) or data (true)
@@ -539,6 +573,8 @@ public:
return (hdr.nMessageSize == nDataPos);
}
+ const uint256& GetMessageHash() const;
+
void SetVersion(int nVersionIn)
{
hdrbuf.SetVersion(nVersionIn);
@@ -553,15 +589,14 @@ public:
/** Information about a peer */
class CNode
{
+ friend class CConnman;
public:
// socket
ServiceFlags nServices;
ServiceFlags nServicesExpected;
SOCKET hSocket;
- CDataStream ssSend;
size_t nSendSize; // total size of all vSendMsg entries
size_t nSendOffset; // offset inside the first vSendMsg already sent
- uint64_t nOptimisticBytesWritten;
uint64_t nSendBytes;
std::deque<CSerializeData> vSendMsg;
CCriticalSection cs_vSend;
@@ -611,9 +646,6 @@ protected:
mapMsgCmdSize mapSendBytesPerMsgCmd;
mapMsgCmdSize mapRecvBytesPerMsgCmd;
- // Basic fuzz-testing
- void Fuzz(int nChance); // modifies ssSend
-
public:
uint256 hashContinue;
int nStartingHeight;
@@ -681,6 +713,7 @@ private:
// Services offered to this peer
const ServiceFlags nLocalServices;
const int nMyStartingHeight;
+ int nSendVersion;
public:
NodeId GetId() const {
@@ -691,6 +724,10 @@ public:
return nLocalHostNonce;
}
+ int GetMyStartingHeight() const {
+ return nMyStartingHeight;
+ }
+
int GetRefCount()
{
assert(nRefCount >= 0);
@@ -716,6 +753,25 @@ public:
BOOST_FOREACH(CNetMessage &msg, vRecvMsg)
msg.SetVersion(nVersionIn);
}
+ void SetSendVersion(int nVersionIn)
+ {
+ // Send version may only be changed in the version message, and
+ // only one version message is allowed per session. We can therefore
+ // treat this value as const and even atomic as long as it's only used
+ // once the handshake is complete. Any attempt to set this twice is an
+ // error.
+ assert(nSendVersion == 0);
+ nSendVersion = nVersionIn;
+ }
+
+ int GetSendVersion() const
+ {
+ // The send version should always be explicitly set to
+ // INIT_PROTO_VERSION rather than using this value until the handshake
+ // is complete. See PushMessageWithVersion().
+ assert(nSendVersion != 0);
+ return nSendVersion;
+ }
CNode* AddRef()
{
@@ -778,193 +834,6 @@ public:
void AskFor(const CInv& inv);
- // TODO: Document the postcondition of this function. Is cs_vSend locked?
- void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend);
-
- // TODO: Document the precondition of this function. Is cs_vSend locked?
- void AbortMessage() UNLOCK_FUNCTION(cs_vSend);
-
- // TODO: Document the precondition of this function. Is cs_vSend locked?
- void EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend);
-
- void PushVersion();
-
-
- void PushMessage(const char* pszCommand)
- {
- try
- {
- BeginMessage(pszCommand);
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1>
- void PushMessage(const char* pszCommand, const T1& a1)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- /** Send a message containing a1, serialized with flag flag. */
- template<typename T1>
- void PushMessageWithFlag(int flag, const char* pszCommand, const T1& a1)
- {
- try
- {
- BeginMessage(pszCommand);
- WithOrVersion(&ssSend, flag) << a1;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5 << a6;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
void CloseSocketDisconnect();
void copyStats(CNodeStats &stats);
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index c07cd2eff8..7113390cdf 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,10 +14,9 @@
#include "util.h"
void TxConfirmStats::Initialize(std::vector<double>& defaultBuckets,
- unsigned int maxConfirms, double _decay, std::string _dataTypeString)
+ unsigned int maxConfirms, double _decay)
{
decay = _decay;
- dataTypeString = _dataTypeString;
for (unsigned int i = 0; i < defaultBuckets.size(); i++) {
buckets.push_back(defaultBuckets[i]);
bucketMap[defaultBuckets[i]] = i;
@@ -87,10 +86,10 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
int maxbucketindex = buckets.size() - 1;
- // requireGreater means we are looking for the lowest fee/priority such that all higher
- // values pass, so we start at maxbucketindex (highest fee) and look at successively
+ // requireGreater means we are looking for the lowest feerate such that all higher
+ // values pass, so we start at maxbucketindex (highest feerate) and look at successively
// smaller buckets until we reach failure. Otherwise, we are looking for the highest
- // fee/priority such that all lower values fail, and we go in the opposite direction.
+ // feerate such that all lower values fail, and we go in the opposite direction.
unsigned int startbucket = requireGreater ? maxbucketindex : 0;
int step = requireGreater ? -1 : 1;
@@ -107,7 +106,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
bool foundAnswer = false;
unsigned int bins = unconfTxs.size();
- // Start counting from highest(default) or lowest fee/pri transactions
+ // Start counting from highest(default) or lowest feerate transactions
for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
curFarBucket = bucket;
nConf += confAvg[confTarget - 1][bucket];
@@ -145,8 +144,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
double median = -1;
double txSum = 0;
- // Calculate the "average" fee of the best bucket range that met success conditions
- // Find the bucket with the median transaction and then report the average fee from that bucket
+ // Calculate the "average" feerate of the best bucket range that met success conditions
+ // Find the bucket with the median transaction and then report the average feerate from that bucket
// This is a compromise between finding the median which we can't since we don't save all tx's
// and reporting the average which is less accurate
unsigned int minBucket = bestNearBucket < bestFarBucket ? bestNearBucket : bestFarBucket;
@@ -166,8 +165,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
}
}
- LogPrint("estimatefee", "%3d: For conf success %s %4.2f need %s %s: %12.5g from buckets %8g - %8g Cur Bucket stats %6.2f%% %8.1f/(%.1f+%d mempool)\n",
- confTarget, requireGreater ? ">" : "<", successBreakPoint, dataTypeString,
+ LogPrint("estimatefee", "%3d: For conf success %s %4.2f need feerate %s: %12.5g from buckets %8g - %8g Cur Bucket stats %6.2f%% %8.1f/(%.1f+%d mempool)\n",
+ confTarget, requireGreater ? ">" : "<", successBreakPoint,
requireGreater ? ">" : "<", median, buckets[minBucket], buckets[maxBucket],
100 * nConf / (totalNum + extraNum), nConf, totalNum, extraNum);
@@ -200,10 +199,10 @@ void TxConfirmStats::Read(CAutoFile& filein)
filein >> fileBuckets;
numBuckets = fileBuckets.size();
if (numBuckets <= 1 || numBuckets > 1000)
- throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 fee/pri buckets");
+ throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
filein >> fileAvg;
if (fileAvg.size() != numBuckets)
- throw std::runtime_error("Corrupt estimates file. Mismatch in fee/pri average bucket count");
+ throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
filein >> fileTxCtAvg;
if (fileTxCtAvg.size() != numBuckets)
throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
@@ -213,9 +212,9 @@ void TxConfirmStats::Read(CAutoFile& filein)
throw std::runtime_error("Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
for (unsigned int i = 0; i < maxConfirms; i++) {
if (fileConfAvg[i].size() != numBuckets)
- throw std::runtime_error("Corrupt estimates file. Mismatch in fee/pri conf average bucket count");
+ throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
}
- // Now that we've processed the entire fee estimate data file and not
+ // Now that we've processed the entire feerate estimate data file and not
// thrown any errors, we can copy it to our data structures
decay = fileDecay;
buckets = fileBuckets;
@@ -242,8 +241,8 @@ void TxConfirmStats::Read(CAutoFile& filein)
for (unsigned int i = 0; i < buckets.size(); i++)
bucketMap[buckets[i]] = i;
- LogPrint("estimatefee", "Reading estimates: %u %s buckets counting confirms up to %u blocks\n",
- numBuckets, dataTypeString, maxConfirms);
+ LogPrint("estimatefee", "Reading estimates: %u buckets counting confirms up to %u blocks\n",
+ numBuckets, maxConfirms);
}
unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
@@ -251,7 +250,6 @@ unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
unsigned int bucketindex = bucketMap.lower_bound(val)->second;
unsigned int blockIndex = nBlockHeight % unconfTxs.size();
unconfTxs[blockIndex][bucketindex]++;
- LogPrint("estimatefee", "adding to %s", dataTypeString);
return bucketindex;
}
@@ -291,12 +289,10 @@ void CBlockPolicyEstimator::removeTx(uint256 hash)
hash.ToString().c_str());
return;
}
- TxConfirmStats *stats = pos->second.stats;
unsigned int entryHeight = pos->second.blockHeight;
unsigned int bucketIndex = pos->second.bucketIndex;
- if (stats != NULL)
- stats->removeTx(entryHeight, nBestSeenHeight, bucketIndex);
+ feeStats.removeTx(entryHeight, nBestSeenHeight, bucketIndex);
mapMemPoolTxs.erase(hash);
}
@@ -309,45 +305,14 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
vfeelist.push_back(bucketBoundary);
}
vfeelist.push_back(INF_FEERATE);
- feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "FeeRate");
-
- minTrackedPriority = AllowFreeThreshold() < MIN_PRIORITY ? MIN_PRIORITY : AllowFreeThreshold();
- std::vector<double> vprilist;
- for (double bucketBoundary = minTrackedPriority; bucketBoundary <= MAX_PRIORITY; bucketBoundary *= PRI_SPACING) {
- vprilist.push_back(bucketBoundary);
- }
- vprilist.push_back(INF_PRIORITY);
- priStats.Initialize(vprilist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "Priority");
-
- feeUnlikely = CFeeRate(0);
- feeLikely = CFeeRate(INF_FEERATE);
- priUnlikely = 0;
- priLikely = INF_PRIORITY;
-}
-
-bool CBlockPolicyEstimator::isFeeDataPoint(const CFeeRate &fee, double pri)
-{
- if ((pri < minTrackedPriority && fee >= minTrackedFee) ||
- (pri < priUnlikely && fee > feeLikely)) {
- return true;
- }
- return false;
-}
-
-bool CBlockPolicyEstimator::isPriDataPoint(const CFeeRate &fee, double pri)
-{
- if ((fee < minTrackedFee && pri >= minTrackedPriority) ||
- (fee < feeUnlikely && pri > priLikely)) {
- return true;
- }
- return false;
+ feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
}
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate)
{
unsigned int txHeight = entry.GetHeight();
uint256 hash = entry.GetTx().GetHash();
- if (mapMemPoolTxs[hash].stats != NULL) {
+ if (mapMemPoolTxs.count(hash)) {
LogPrint("estimatefee", "Blockpolicy error mempool tx %s already being tracked\n",
hash.ToString().c_str());
return;
@@ -371,30 +336,11 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
return;
}
- // Fees are stored and reported as BTC-per-kb:
+ // Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
- // Want the priority of the tx at confirmation. However we don't know
- // what that will be and its too hard to continue updating it
- // so use starting priority as a proxy
- double curPri = entry.GetPriority(txHeight);
mapMemPoolTxs[hash].blockHeight = txHeight;
-
- LogPrint("estimatefee", "Blockpolicy mempool tx %s ", hash.ToString().substr(0,10));
- // Record this as a priority estimate
- if (entry.GetFee() == 0 || isPriDataPoint(feeRate, curPri)) {
- mapMemPoolTxs[hash].stats = &priStats;
- mapMemPoolTxs[hash].bucketIndex = priStats.NewTx(txHeight, curPri);
- }
- // Record this as a fee estimate
- else if (isFeeDataPoint(feeRate, curPri)) {
- mapMemPoolTxs[hash].stats = &feeStats;
- mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
- }
- else {
- LogPrint("estimatefee", "not adding");
- }
- LogPrint("estimatefee", "\n");
+ mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
}
void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry)
@@ -417,21 +363,10 @@ void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
return;
}
- // Fees are stored and reported as BTC-per-kb:
+ // Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
- // Want the priority of the tx at confirmation. The priority when it
- // entered the mempool could easily be very small and change quickly
- double curPri = entry.GetPriority(nBlockHeight);
-
- // Record this as a priority estimate
- if (entry.GetFee() == 0 || isPriDataPoint(feeRate, curPri)) {
- priStats.Record(blocksToConfirm, curPri);
- }
- // Record this as a fee estimate
- else if (isFeeDataPoint(feeRate, curPri)) {
- feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK());
- }
+ feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK());
}
void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
@@ -452,41 +387,15 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
if (!fCurrentEstimate)
return;
- // Update the dynamic cutoffs
- // a fee/priority is "likely" the reason your tx was included in a block if >85% of such tx's
- // were confirmed in 2 blocks and is "unlikely" if <50% were confirmed in 10 blocks
- LogPrint("estimatefee", "Blockpolicy recalculating dynamic cutoffs:\n");
- priLikely = priStats.EstimateMedianVal(2, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBlockHeight);
- if (priLikely == -1)
- priLikely = INF_PRIORITY;
-
- double feeLikelyEst = feeStats.EstimateMedianVal(2, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBlockHeight);
- if (feeLikelyEst == -1)
- feeLikely = CFeeRate(INF_FEERATE);
- else
- feeLikely = CFeeRate(feeLikelyEst);
-
- priUnlikely = priStats.EstimateMedianVal(10, SUFFICIENT_PRITXS, UNLIKELY_PCT, false, nBlockHeight);
- if (priUnlikely == -1)
- priUnlikely = 0;
-
- double feeUnlikelyEst = feeStats.EstimateMedianVal(10, SUFFICIENT_FEETXS, UNLIKELY_PCT, false, nBlockHeight);
- if (feeUnlikelyEst == -1)
- feeUnlikely = CFeeRate(0);
- else
- feeUnlikely = CFeeRate(feeUnlikelyEst);
-
- // Clear the current block states
+ // Clear the current block state
feeStats.ClearCurrent(nBlockHeight);
- priStats.ClearCurrent(nBlockHeight);
// Repopulate the current block states
for (unsigned int i = 0; i < entries.size(); i++)
processBlockTx(nBlockHeight, entries[i]);
- // Update all exponential averages with the current block states
+ // Update all exponential averages with the current block state
feeStats.UpdateMovingAverages();
- priStats.UpdateMovingAverages();
LogPrint("estimatefee", "Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n",
entries.size(), mapMemPoolTxs.size());
@@ -522,7 +431,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
if (answerFoundAtTarget)
*answerFoundAtTarget = confTarget - 1;
- // If mempool is limiting txs , return at least the min fee from the mempool
+ // If mempool is limiting txs , return at least the min feerate from the mempool
CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
if (minPoolFee > 0 && minPoolFee > median)
return CFeeRate(minPoolFee);
@@ -535,51 +444,38 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
double CBlockPolicyEstimator::estimatePriority(int confTarget)
{
- // Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > priStats.GetMaxConfirms())
- return -1;
-
- return priStats.EstimateMedianVal(confTarget, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
+ return -1;
}
double CBlockPolicyEstimator::estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
{
if (answerFoundAtTarget)
*answerFoundAtTarget = confTarget;
- // Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > priStats.GetMaxConfirms())
- return -1;
// If mempool is limiting txs, no priority txs are allowed
CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
if (minPoolFee > 0)
return INF_PRIORITY;
- double median = -1;
- while (median < 0 && (unsigned int)confTarget <= priStats.GetMaxConfirms()) {
- median = priStats.EstimateMedianVal(confTarget++, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
- }
-
- if (answerFoundAtTarget)
- *answerFoundAtTarget = confTarget - 1;
-
- return median;
+ return -1;
}
void CBlockPolicyEstimator::Write(CAutoFile& fileout)
{
fileout << nBestSeenHeight;
feeStats.Write(fileout);
- priStats.Write(fileout);
}
-void CBlockPolicyEstimator::Read(CAutoFile& filein)
+void CBlockPolicyEstimator::Read(CAutoFile& filein, int nFileVersion)
{
int nFileBestSeenHeight;
filein >> nFileBestSeenHeight;
feeStats.Read(filein);
- priStats.Read(filein);
nBestSeenHeight = nFileBestSeenHeight;
+ if (nFileVersion < 139900) {
+ TxConfirmStats priStats;
+ priStats.Read(filein);
+ }
}
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 2c1ac3b934..c7d2febfa5 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// Copyright (c) 2009-2015 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_POLICYESTIMATOR_H
@@ -19,60 +19,50 @@ class CTxMemPoolEntry;
class CTxMemPool;
/** \class CBlockPolicyEstimator
- * The BlockPolicyEstimator is used for estimating the fee or priority needed
+ * The BlockPolicyEstimator is used for estimating the feerate needed
* for a transaction to be included in a block within a certain number of
* blocks.
*
* At a high level the algorithm works by grouping transactions into buckets
- * based on having similar priorities or fees and then tracking how long it
+ * based on having similar feerates and then tracking how long it
* takes transactions in the various buckets to be mined. It operates under
- * the assumption that in general transactions of higher fee/priority will be
- * included in blocks before transactions of lower fee/priority. So for
- * example if you wanted to know what fee you should put on a transaction to
+ * the assumption that in general transactions of higher feerate will be
+ * included in blocks before transactions of lower feerate. So for
+ * example if you wanted to know what feerate you should put on a transaction to
* be included in a block within the next 5 blocks, you would start by looking
- * at the bucket with the highest fee transactions and verifying that a
+ * at the bucket with the highest feerate transactions and verifying that a
* sufficiently high percentage of them were confirmed within 5 blocks and
- * then you would look at the next highest fee bucket, and so on, stopping at
- * the last bucket to pass the test. The average fee of transactions in this
- * bucket will give you an indication of the lowest fee you can put on a
+ * then you would look at the next highest feerate bucket, and so on, stopping at
+ * the last bucket to pass the test. The average feerate of transactions in this
+ * bucket will give you an indication of the lowest feerate you can put on a
* transaction and still have a sufficiently high chance of being confirmed
* within your desired 5 blocks.
*
- * When a transaction enters the mempool or is included within a block we
- * decide whether it can be used as a data point for fee estimation, priority
- * estimation or neither. If the value of exactly one of those properties was
- * below the required minimum it can be used to estimate the other. In
- * addition, if a priori our estimation code would indicate that the
- * transaction would be much more quickly included in a block because of one
- * of the properties compared to the other, we can also decide to use it as
- * an estimate for that property.
- *
- * Here is a brief description of the implementation for fee estimation.
- * When a transaction that counts for fee estimation enters the mempool, we
+ * Here is a brief description of the implementation:
+ * When a transaction enters the mempool, we
* track the height of the block chain at entry. Whenever a block comes in,
- * we count the number of transactions in each bucket and the total amount of fee
+ * we count the number of transactions in each bucket and the total amount of feerate
* paid in each bucket. Then we calculate how many blocks Y it took each
* transaction to be mined and we track an array of counters in each bucket
* for how long it to took transactions to get confirmed from 1 to a max of 25
* and we increment all the counters from Y up to 25. This is because for any
* number Z>=Y the transaction was successfully mined within Z blocks. We
* want to save a history of this information, so at any time we have a
- * counter of the total number of transactions that happened in a given fee
+ * counter of the total number of transactions that happened in a given feerate
* bucket and the total number that were confirmed in each number 1-25 blocks
* or less for any bucket. We save this history by keeping an exponentially
* decaying moving average of each one of these stats. Furthermore we also
* keep track of the number unmined (in mempool) transactions in each bucket
* and for how many blocks they have been outstanding and use that to increase
- * the number of transactions we've seen in that fee bucket when calculating
+ * the number of transactions we've seen in that feerate bucket when calculating
* an estimate for any number of confirmations below the number of blocks
* they've been outstanding.
*/
/**
- * We will instantiate two instances of this class, one to track transactions
- * that were included in a block due to fee, and one for tx's included due to
- * priority. We will lump transactions into a bucket according to their approximate
- * fee or priority and then track how long it took for those txs to be included in a block
+ * We will instantiate an instance of this class to track transactions that were
+ * included in a block. We will lump transactions into a bucket according to their
+ * approximate feerate and then track how long it took for those txs to be included in a block
*
* The tracking of unconfirmed (mempool) transactions is completely independent of the
* historical tracking of transactions that have been confirmed in a block.
@@ -80,7 +70,7 @@ class CTxMemPool;
class TxConfirmStats
{
private:
- //Define the buckets we will group transactions into (both fee buckets and priority buckets)
+ //Define the buckets we will group transactions into
std::vector<double> buckets; // The upper-bound of the range for the bucket (inclusive)
std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
@@ -97,16 +87,15 @@ private:
// and calculate the totals for the current block to update the moving averages
std::vector<std::vector<int> > curBlockConf; // curBlockConf[Y][X]
- // Sum the total priority/fee of all tx's in each bucket
+ // Sum the total feerate of all tx's in each bucket
// Track the historical moving average of this total over blocks
std::vector<double> avg;
// and calculate the total for the current block to update the moving average
std::vector<double> curBlockVal;
// Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
- // Combine the total value with the tx counts to calculate the avg fee/priority per bucket
+ // Combine the total value with the tx counts to calculate the avg feerate per bucket
- std::string dataTypeString;
double decay;
// Mempool counts of outstanding transactions
@@ -123,9 +112,8 @@ public:
* @param defaultBuckets contains the upper limits for the bucket boundaries
* @param maxConfirms max number of confirms to track
* @param decay how much to decay the historical moving average per block
- * @param dataTypeString for logging purposes
*/
- void Initialize(std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay, std::string dataTypeString);
+ void Initialize(std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay);
/** Clear the state of the curBlock variables to start counting for the new block */
void ClearCurrent(unsigned int nBlockHeight);
@@ -133,7 +121,7 @@ public:
/**
* Record a new transaction data point in the current block stats
* @param blocksToConfirm the number of blocks it took this transaction to confirm
- * @param val either the fee or the priority when entered of the transaction
+ * @param val the feerate of the transaction
* @warning blocksToConfirm is 1-based and has to be >= 1
*/
void Record(int blocksToConfirm, double val);
@@ -150,14 +138,14 @@ public:
void UpdateMovingAverages();
/**
- * Calculate a fee or priority estimate. Find the lowest value bucket (or range of buckets
+ * Calculate a feerate estimate. Find the lowest value bucket (or range of buckets
* to make sure we have enough data points) whose transactions still have sufficient likelihood
* of being confirmed within the target number of confirmations
* @param confTarget target number of confirmations
* @param sufficientTxVal required average number of transactions per block in a bucket range
* @param minSuccess the success probability we require
- * @param requireGreater return the lowest fee/pri such that all higher values pass minSuccess OR
- * return the highest fee/pri such that all lower values fail minSuccess
+ * @param requireGreater return the lowest feerate such that all higher values pass minSuccess OR
+ * return the highest feerate such that all lower values fail minSuccess
* @param nBlockHeight the current block height
*/
double EstimateMedianVal(int confTarget, double sufficientTxVal,
@@ -184,35 +172,27 @@ static const unsigned int MAX_BLOCK_CONFIRMS = 25;
/** Decay of .998 is a half-life of 346 blocks or about 2.4 days */
static const double DEFAULT_DECAY = .998;
-/** Require greater than 95% of X fee transactions to be confirmed within Y blocks for X to be big enough */
+/** Require greater than 95% of X feerate transactions to be confirmed within Y blocks for X to be big enough */
static const double MIN_SUCCESS_PCT = .95;
static const double UNLIKELY_PCT = .5;
-/** Require an avg of 1 tx in the combined fee bucket per block to have stat significance */
+/** Require an avg of 1 tx in the combined feerate bucket per block to have stat significance */
static const double SUFFICIENT_FEETXS = 1;
-/** Require only an avg of 1 tx every 5 blocks in the combined pri bucket (way less pri txs) */
-static const double SUFFICIENT_PRITXS = .2;
-
-// Minimum and Maximum values for tracking fees and priorities
+// Minimum and Maximum values for tracking feerates
static const double MIN_FEERATE = 10;
static const double MAX_FEERATE = 1e7;
static const double INF_FEERATE = MAX_MONEY;
-static const double MIN_PRIORITY = 10;
-static const double MAX_PRIORITY = 1e16;
static const double INF_PRIORITY = 1e9 * MAX_MONEY;
-// We have to lump transactions into buckets based on fee or priority, but we want to be able
-// to give accurate estimates over a large range of potential fees and priorities
+// We have to lump transactions into buckets based on feerate, but we want to be able
+// to give accurate estimates over a large range of potential feerates
// Therefore it makes sense to exponentially space the buckets
/** Spacing of FeeRate buckets */
static const double FEE_SPACING = 1.1;
-/** Spacing of Priority buckets */
-static const double PRI_SPACING = 2;
-
/**
- * We want to be able to estimate fees or priorities that are needed on tx's to be included in
+ * We want to be able to estimate feerates that are needed on tx's to be included in
* a certain number of blocks. Every time a block is added to the best chain, this class records
* stats on the transactions included in that block
*/
@@ -235,27 +215,26 @@ public:
/** Remove a transaction from the mempool tracking stats*/
void removeTx(uint256 hash);
- /** Is this transaction likely included in a block because of its fee?*/
- bool isFeeDataPoint(const CFeeRate &fee, double pri);
-
- /** Is this transaction likely included in a block because of its priority?*/
- bool isPriDataPoint(const CFeeRate &fee, double pri);
-
- /** Return a fee estimate */
+ /** Return a feerate estimate */
CFeeRate estimateFee(int confTarget);
- /** Estimate fee rate needed to get be included in a block within
+ /** Estimate feerate needed to get be included in a block within
* confTarget blocks. If no answer can be given at confTarget, return an
* estimate at the lowest target where one can be given.
*/
CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
- /** Return a priority estimate */
+ /** Return a priority estimate.
+ * DEPRECATED
+ * Returns -1
+ */
double estimatePriority(int confTarget);
/** Estimate priority needed to get be included in a block within
- * confTarget blocks. If no answer can be given at confTarget, return an
- * estimate at the lowest target where one can be given.
+ * confTarget blocks.
+ * DEPRECATED
+ * Returns -1 unless mempool is currently limited then returns INF_PRIORITY
+ * answerFoundAtTarget is set to confTarget
*/
double estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
@@ -263,29 +242,23 @@ public:
void Write(CAutoFile& fileout);
/** Read estimation data from a file */
- void Read(CAutoFile& filein);
+ void Read(CAutoFile& filein, int nFileVersion);
private:
CFeeRate minTrackedFee; //!< Passed to constructor to avoid dependency on main
- double minTrackedPriority; //!< Set to AllowFreeThreshold
unsigned int nBestSeenHeight;
struct TxStatsInfo
{
- TxConfirmStats *stats;
unsigned int blockHeight;
unsigned int bucketIndex;
- TxStatsInfo() : stats(NULL), blockHeight(0), bucketIndex(0) {}
+ TxStatsInfo() : blockHeight(0), bucketIndex(0) {}
};
// map of txids to information about that transaction
std::map<uint256, TxStatsInfo> mapMemPoolTxs;
/** Classes to track historical data on transaction confirmations */
- TxConfirmStats feeStats, priStats;
-
- /** Breakpoints to help determine whether a transaction was confirmed by priority or Fee */
- CFeeRate feeLikely, feeUnlikely;
- double priLikely, priUnlikely;
+ TxConfirmStats feeStats;
};
class FeeFilterRounder
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index ae42b2bd74..a3eee474ab 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2016 The Bitcoin developers
+// 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.
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 814e6c0b6f..764ee27806 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2016 The Bitcoin developers
+// 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.
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 133cff611d..d9b47e71bb 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 The Bitcoin developers
+// Copyright (c) 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.
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index 5a711dba07..139aec5760 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 The Bitcoin developers
+// Copyright (c) 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.
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 4afbe99fd3..7acdac17f2 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -49,11 +49,6 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
scriptPubKey = scriptPubKeyIn;
}
-uint256 CTxOut::GetHash() const
-{
- return SerializeHash(*this);
-}
-
std::string CTxOut::ToString() const
{
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 16c2e5c454..1afeb87039 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -160,8 +160,6 @@ public:
return (nValue == -1);
}
- uint256 GetHash() const;
-
CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
{
// "Dust" is defined in terms of CTransaction::minRelayTxFee,
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 87704c641d..f9caca6878 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -6,6 +6,7 @@
#include "bantablemodel.h"
#include "guiconstants.h"
+#include "guiutil.h"
#include "peertablemodel.h"
#include "chainparams.h"
@@ -208,7 +209,7 @@ QString ClientModel::formatClientStartupTime() const
QString ClientModel::dataDir() const
{
- return QString::fromStdString(GetDataDir().string());
+ return GUIUtil::boostPathToQString(GetDataDir());
}
void ClientModel::updateBanlist()
diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h
index a73fe5f29d..a8bfcd2ac4 100644
--- a/src/qt/paymentrequestplus.h
+++ b/src/qt/paymentrequestplus.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin developers
+// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 9f23e77a13..478f5ccf12 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -80,7 +80,7 @@ static QString ipcServerName()
// Append a simple hash of the datadir
// Note that GetDataDir(true) returns a different path
// for -testnet versus main net
- QString ddir(QString::fromStdString(GetDataDir(true).string()));
+ QString ddir(GUIUtil::boostPathToQString(GetDataDir(true)));
name.append(QString::number(qHash(ddir)));
return name;
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 564102ff95..3e91a79a64 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -810,7 +810,7 @@ UniValue estimatepriority(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatepriority nblocks\n"
- "\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
+ "\nDEPRECATED. Estimates the approximate priority a zero-fee transaction needs to begin\n"
"confirmation within nblocks blocks.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
@@ -873,7 +873,7 @@ UniValue estimatesmartpriority(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatesmartpriority nblocks\n"
- "\nWARNING: This interface is unstable and may disappear or change!\n"
+ "\nDEPRECATED. WARNING: This interface is unstable and may disappear or change!\n"
"\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
"confirmation within nblocks blocks if possible and return the number of blocks\n"
"for which the estimate is valid.\n"
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index b629f4278b..1d0ca0c5ac 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -69,10 +69,19 @@ struct ECCryptoClosure
ECCryptoClosure instance_of_eccryptoclosure;
}
+/** Check that all specified flags are part of the libconsensus interface. */
+static bool verify_flags(unsigned int flags)
+{
+ return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0;
+}
+
static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
{
+ if (!verify_flags(flags)) {
+ return bitcoinconsensus_ERR_INVALID_FLAGS;
+ }
try {
TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen);
CTransaction tx;
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 1d2d5c23e4..1bef4fe9e9 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -42,6 +42,7 @@ typedef enum bitcoinconsensus_error_t
bitcoinconsensus_ERR_TX_SIZE_MISMATCH,
bitcoinconsensus_ERR_TX_DESERIALIZE,
bitcoinconsensus_ERR_AMOUNT_REQUIRED,
+ bitcoinconsensus_ERR_INVALID_FLAGS,
} bitcoinconsensus_error;
/** Script verification flags */
@@ -54,6 +55,9 @@ enum
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), // enable CHECKSEQUENCEVERIFY (BIP112)
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS = (1U << 11), // enable WITNESS (BIP141)
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL = bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG |
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY |
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS
};
/// Returns 1 if the input nIn of the serialized transaction pointed to by
diff --git a/src/serialize.h b/src/serialize.h
index 1f51da82ff..82870c45b3 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -160,6 +160,7 @@ enum
};
#define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action))
+#define READWRITEMANY(...) (::SerReadWriteMany(s, nType, nVersion, ser_action, __VA_ARGS__))
/**
* Implement three methods for serializable objects. These are actually wrappers over
@@ -960,4 +961,52 @@ public:
}
};
+template<typename Stream>
+void SerializeMany(Stream& s, int nType, int nVersion)
+{
+}
+
+template<typename Stream, typename Arg>
+void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg)
+{
+ ::Serialize(s, std::forward<Arg>(arg), nType, nVersion);
+}
+
+template<typename Stream, typename Arg, typename... Args>
+void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg, Args&&... args)
+{
+ ::Serialize(s, std::forward<Arg>(arg), nType, nVersion);
+ ::SerializeMany(s, nType, nVersion, std::forward<Args>(args)...);
+}
+
+template<typename Stream>
+inline void UnserializeMany(Stream& s, int nType, int nVersion)
+{
+}
+
+template<typename Stream, typename Arg>
+inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg)
+{
+ ::Unserialize(s, arg, nType, nVersion);
+}
+
+template<typename Stream, typename Arg, typename... Args>
+inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg, Args&... args)
+{
+ ::Unserialize(s, arg, nType, nVersion);
+ ::UnserializeMany(s, nType, nVersion, args...);
+}
+
+template<typename Stream, typename... Args>
+inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionSerialize ser_action, Args&&... args)
+{
+ ::SerializeMany(s, nType, nVersion, std::forward<Args>(args)...);
+}
+
+template<typename Stream, typename... Args>
+inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionUnserialize ser_action, Args&... args)
+{
+ ::UnserializeMany(s, nType, nVersion, args...);
+}
+
#endif // BITCOIN_SERIALIZE_H
diff --git a/src/streams.h b/src/streams.h
index 7132364eb1..fa001c112a 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -112,6 +112,13 @@ public:
Init(nTypeIn, nVersionIn);
}
+ template <typename... Args>
+ CDataStream(int nTypeIn, int nVersionIn, Args&&... args)
+ {
+ Init(nTypeIn, nVersionIn);
+ ::SerializeMany(*this, nType, nVersion, std::forward<Args>(args)...);
+ }
+
void Init(int nTypeIn, int nVersionIn)
{
nReadPos = 0;
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index 813869a131..01273c9791 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -26,6 +26,8 @@
#include <unistd.h> // for sysconf
#endif
+#include <algorithm>
+
LockedPoolManager* LockedPoolManager::_instance = NULL;
std::once_flag LockedPoolManager::init_flag;
@@ -45,7 +47,7 @@ Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
{
// Start with one free chunk that covers the entire arena
- chunks.emplace(base, Chunk(size_in, false));
+ chunks_free.emplace(base, size_in);
}
Arena::~Arena()
@@ -57,24 +59,30 @@ void* Arena::alloc(size_t size)
// Round to next multiple of alignment
size = align_up(size, alignment);
- // Don't handle zero-sized chunks, or those bigger than MAX_SIZE
- if (size == 0 || size >= Chunk::MAX_SIZE) {
+ // Don't handle zero-sized chunks
+ if (size == 0)
return nullptr;
- }
- for (auto& chunk: chunks) {
- if (!chunk.second.isInUse() && size <= chunk.second.getSize()) {
- char* _base = chunk.first;
- size_t leftover = chunk.second.getSize() - size;
- if (leftover > 0) { // Split chunk
- chunks.emplace(_base + size, Chunk(leftover, false));
- chunk.second.setSize(size);
- }
- chunk.second.setInUse(true);
- return reinterpret_cast<void*>(_base);
- }
+ // Pick a large enough free-chunk
+ auto it = std::find_if(chunks_free.begin(), chunks_free.end(),
+ [=](const std::map<char*, size_t>::value_type& chunk){ return chunk.second >= size; });
+ if (it == chunks_free.end())
+ return nullptr;
+
+ // Create the used-chunk, taking its space from the end of the free-chunk
+ auto alloced = chunks_used.emplace(it->first + it->second - size, size).first;
+ if (!(it->second -= size))
+ chunks_free.erase(it);
+ return reinterpret_cast<void*>(alloced->first);
+}
+
+/* extend the Iterator if other begins at its end */
+template <class Iterator, class Pair> bool extend(Iterator it, const Pair& other) {
+ if (it->first + it->second == other.first) {
+ it->second += other.second;
+ return true;
}
- return nullptr;
+ return false;
}
void Arena::free(void *ptr)
@@ -83,65 +91,49 @@ void Arena::free(void *ptr)
if (ptr == nullptr) {
return;
}
- auto i = chunks.find(static_cast<char*>(ptr));
- if (i == chunks.end() || !i->second.isInUse()) {
- throw std::runtime_error("Arena: invalid or double free");
- }
- i->second.setInUse(false);
-
- if (i != chunks.begin()) { // Absorb into previous chunk if exists and free
- auto prev = i;
- --prev;
- if (!prev->second.isInUse()) {
- // Absorb current chunk size into previous chunk.
- prev->second.setSize(prev->second.getSize() + i->second.getSize());
- // Erase current chunk. Erasing does not invalidate current
- // iterators for a map, except for that pointing to the object
- // itself, which will be overwritten in the next statement.
- chunks.erase(i);
- // From here on, the previous chunk is our current chunk.
- i = prev;
- }
- }
- auto next = i;
- ++next;
- if (next != chunks.end()) { // Absorb next chunk if exists and free
- if (!next->second.isInUse()) {
- // Absurb next chunk size into current chunk
- i->second.setSize(i->second.getSize() + next->second.getSize());
- // Erase next chunk.
- chunks.erase(next);
- }
+ // Remove chunk from used map
+ auto i = chunks_used.find(static_cast<char*>(ptr));
+ if (i == chunks_used.end()) {
+ throw std::runtime_error("Arena: invalid or double free");
}
+ auto freed = *i;
+ chunks_used.erase(i);
+
+ // Add space to free map, coalescing contiguous chunks
+ auto next = chunks_free.upper_bound(freed.first);
+ auto prev = (next == chunks_free.begin()) ? chunks_free.end() : std::prev(next);
+ if (prev == chunks_free.end() || !extend(prev, freed))
+ prev = chunks_free.emplace_hint(next, freed);
+ if (next != chunks_free.end() && extend(prev, *next))
+ chunks_free.erase(next);
}
Arena::Stats Arena::stats() const
{
- Arena::Stats r;
- r.used = r.free = r.total = r.chunks_used = r.chunks_free = 0;
- for (const auto& chunk: chunks) {
- if (chunk.second.isInUse()) {
- r.used += chunk.second.getSize();
- r.chunks_used += 1;
- } else {
- r.free += chunk.second.getSize();
- r.chunks_free += 1;
- }
- r.total += chunk.second.getSize();
- }
+ Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
+ for (const auto& chunk: chunks_used)
+ r.used += chunk.second;
+ for (const auto& chunk: chunks_free)
+ r.free += chunk.second;
+ r.total = r.used + r.free;
return r;
}
#ifdef ARENA_DEBUG
+void printchunk(char* base, size_t sz, bool used) {
+ std::cout <<
+ "0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
+ " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
+ " 0x" << used << std::endl;
+}
void Arena::walk() const
{
- for (const auto& chunk: chunks) {
- std::cout <<
- "0x" << std::hex << std::setw(16) << std::setfill('0') << chunk.first <<
- " 0x" << std::hex << std::setw(16) << std::setfill('0') << chunk.second.getSize() <<
- " 0x" << chunk.second.isInUse() << std::endl;
- }
+ for (const auto& chunk: chunks_used)
+ printchunk(chunk.first, chunk.second, true);
+ std::cout << std::endl;
+ for (const auto& chunk: chunks_free)
+ printchunk(chunk.first, chunk.second, false);
std::cout << std::endl;
}
#endif
@@ -276,6 +268,11 @@ LockedPool::~LockedPool()
void* LockedPool::alloc(size_t size)
{
std::lock_guard<std::mutex> lock(mutex);
+
+ // Don't handle impossible sizes
+ if (size == 0 || size > ARENA_SIZE)
+ return nullptr;
+
// Try allocating from each current arena
for (auto &arena: arenas) {
void *addr = arena.alloc(size);
@@ -307,9 +304,7 @@ void LockedPool::free(void *ptr)
LockedPool::Stats LockedPool::stats() const
{
std::lock_guard<std::mutex> lock(mutex);
- LockedPool::Stats r;
- r.used = r.free = r.total = r.chunks_used = r.chunks_free = 0;
- r.locked = cumulative_bytes_locked;
+ LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
for (const auto &arena: arenas) {
Arena::Stats i = arena.stats();
r.used += i.used;
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
index 526c17a73f..3403415436 100644
--- a/src/support/lockedpool.h
+++ b/src/support/lockedpool.h
@@ -50,27 +50,6 @@ public:
Arena(void *base, size_t size, size_t alignment);
virtual ~Arena();
- /** A chunk of memory.
- */
- struct Chunk
- {
- /** Most significant bit of size_t. This is used to mark
- * in-usedness of chunk.
- */
- const static size_t SIZE_MSB = 1LLU << ((sizeof(size_t)*8)-1);
- /** Maximum size of a chunk */
- const static size_t MAX_SIZE = SIZE_MSB - 1;
-
- Chunk(size_t size_in, bool used_in):
- size(size_in | (used_in ? SIZE_MSB : 0)) {}
-
- bool isInUse() const { return size & SIZE_MSB; }
- void setInUse(bool used_in) { size = (size & ~SIZE_MSB) | (used_in ? SIZE_MSB : 0); }
- size_t getSize() const { return size & ~SIZE_MSB; }
- void setSize(size_t size_in) { size = (size & SIZE_MSB) | size_in; }
- private:
- size_t size;
- };
/** Memory statistics. */
struct Stats
{
@@ -112,7 +91,8 @@ private:
/** Map of chunk address to chunk information. This class makes use of the
* sorted order to merge previous and next chunks during deallocation.
*/
- std::map<char*, Chunk> chunks;
+ std::map<char*, size_t> chunks_free;
+ std::map<char*, size_t> chunks_used;
/** Base address of arena */
char* base;
/** End address of arena */
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 4aa7166815..6eed636080 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -49,7 +49,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
connman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true);
- GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1);
+ dummyNode1.SetSendVersion(PROTOCOL_VERSION);
+ GetNodeSignals().InitializeNode(&dummyNode1, *connman);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
SendMessages(&dummyNode1, *connman);
@@ -58,7 +59,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true);
- GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2);
+ dummyNode2.SetSendVersion(PROTOCOL_VERSION);
+ GetNodeSignals().InitializeNode(&dummyNode2, *connman);
dummyNode2.nVersion = 1;
Misbehaving(dummyNode2.GetId(), 50);
SendMessages(&dummyNode2, *connman);
@@ -75,7 +77,8 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
mapArgs["-banscore"] = "111"; // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true);
- GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1);
+ dummyNode1.SetSendVersion(PROTOCOL_VERSION);
+ GetNodeSignals().InitializeNode(&dummyNode1, *connman);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100);
SendMessages(&dummyNode1, *connman);
@@ -97,7 +100,8 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
CAddress addr(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true);
- GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode);
+ dummyNode.SetSendVersion(PROTOCOL_VERSION);
+ GetNodeSignals().InitializeNode(&dummyNode, *connman);
dummyNode.nVersion = 1;
Misbehaving(dummyNode.GetId(), 100);
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index f0e848655f..77e9df5d82 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -39,7 +39,6 @@ BOOST_AUTO_TEST_CASE(arena_tests)
}
void *a0 = b.alloc(128);
- BOOST_CHECK(a0 == synth_base); // first allocation must start at beginning
void *a1 = b.alloc(256);
void *a2 = b.alloc(512);
BOOST_CHECK(b.stats().used == 896);
@@ -63,8 +62,10 @@ BOOST_AUTO_TEST_CASE(arena_tests)
BOOST_CHECK(b.stats().used == 128);
b.free(a3);
BOOST_CHECK(b.stats().used == 0);
+ BOOST_CHECK_EQUAL(b.stats().chunks_used, 0);
BOOST_CHECK(b.stats().total == synth_size);
BOOST_CHECK(b.stats().free == synth_size);
+ BOOST_CHECK_EQUAL(b.stats().chunks_free, 1);
std::vector<void*> addr;
BOOST_CHECK(b.alloc(0) == nullptr); // allocating 0 always returns nullptr
@@ -74,7 +75,6 @@ BOOST_AUTO_TEST_CASE(arena_tests)
// Sweeping allocate all memory
for (int x=0; x<1024; ++x)
addr.push_back(b.alloc(1024));
- BOOST_CHECK(addr[0] == synth_base); // first allocation must start at beginning
BOOST_CHECK(b.stats().free == 0);
BOOST_CHECK(b.alloc(1024) == nullptr); // memory is full, this must return nullptr
BOOST_CHECK(b.alloc(0) == nullptr);
@@ -166,6 +166,16 @@ BOOST_AUTO_TEST_CASE(lockedpool_tests_mock)
BOOST_CHECK(pool.stats().total == 0);
BOOST_CHECK(pool.stats().locked == 0);
+ // Ensure unreasonable requests are refused without allocating anything
+ void *invalid_toosmall = pool.alloc(0);
+ BOOST_CHECK(invalid_toosmall == nullptr);
+ BOOST_CHECK(pool.stats().used == 0);
+ BOOST_CHECK(pool.stats().free == 0);
+ void *invalid_toobig = pool.alloc(LockedPool::ARENA_SIZE+1);
+ BOOST_CHECK(invalid_toobig == nullptr);
+ BOOST_CHECK(pool.stats().used == 0);
+ BOOST_CHECK(pool.stats().free == 0);
+
void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2);
BOOST_CHECK(a0);
BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
diff --git a/src/test/bctest.py b/src/test/bctest.py
index 00d96eff19..adc5d0e418 100644
--- a/src/test/bctest.py
+++ b/src/test/bctest.py
@@ -1,4 +1,5 @@
-# Copyright 2014 BitPay, Inc.
+# Copyright 2014 BitPay Inc.
+# Copyright 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.
from __future__ import division,print_function,unicode_literals
@@ -11,94 +12,110 @@ import difflib
import logging
def parse_output(a, fmt):
- if fmt == 'json': # json: compare parsed data
- return json.loads(a)
- elif fmt == 'hex': # hex: parse and compare binary data
- return binascii.a2b_hex(a.strip())
- else:
- raise NotImplementedError("Don't know how to compare %s" % fmt)
+ """Parse the output according to specified format.
+
+ Raise an error if the output can't be parsed."""
+ if fmt == 'json': # json: compare parsed data
+ return json.loads(a)
+ elif fmt == 'hex': # hex: parse and compare binary data
+ return binascii.a2b_hex(a.strip())
+ else:
+ raise NotImplementedError("Don't know how to compare %s" % fmt)
def bctest(testDir, testObj, exeext):
+ """Runs a single test, comparing output and RC to expected output and RC.
- execprog = testObj['exec'] + exeext
- execargs = testObj['args']
- execrun = [execprog] + execargs
- stdinCfg = None
- inputData = None
- if "input" in testObj:
- filename = testDir + "/" + testObj['input']
- inputData = open(filename).read()
- stdinCfg = subprocess.PIPE
+ Raises an error if input can't be read, executable fails, or output/RC
+ are not as expected. Error is caught by bctester() and reported.
+ """
+ # Get the exec names and arguments
+ execprog = testObj['exec'] + exeext
+ execargs = testObj['args']
+ execrun = [execprog] + execargs
- outputFn = None
- outputData = None
- if "output_cmp" in testObj:
- outputFn = testObj['output_cmp']
- outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
- try:
- outputData = open(testDir + "/" + outputFn).read()
- except:
- logging.error("Output file " + outputFn + " can not be opened")
- raise
- if not outputData:
- logging.error("Output data missing for " + outputFn)
- raise Exception
+ # Read the input data (if there is any)
+ stdinCfg = None
+ inputData = None
+ if "input" in testObj:
+ filename = testDir + "/" + testObj['input']
+ inputData = open(filename).read()
+ stdinCfg = subprocess.PIPE
- proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True)
- try:
- outs = proc.communicate(input=inputData)
- except OSError:
- logging.error("OSError, Failed to execute " + execprog)
- raise
+ # Read the expected output data (if there is any)
+ outputFn = None
+ outputData = None
+ if "output_cmp" in testObj:
+ outputFn = testObj['output_cmp']
+ outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
+ try:
+ outputData = open(testDir + "/" + outputFn).read()
+ except:
+ logging.error("Output file " + outputFn + " can not be opened")
+ raise
+ if not outputData:
+ logging.error("Output data missing for " + outputFn)
+ raise Exception
- if outputData:
- try:
- a_parsed = parse_output(outs[0], outputType)
- except Exception as e:
- logging.error('Error parsing command output as %s: %s' % (outputType,e))
- raise
- try:
- b_parsed = parse_output(outputData, outputType)
- except Exception as e:
- logging.error('Error parsing expected output %s as %s: %s' % (outputFn,outputType,e))
- raise
- if a_parsed != b_parsed:
- logging.error("Output data mismatch for " + outputFn + " (format " + outputType + ")")
- raise Exception
- if outs[0] != outputData:
- error_message = "Output formatting mismatch for " + outputFn + ":\n"
- error_message += "".join(difflib.context_diff(outputData.splitlines(True),
- outs[0].splitlines(True),
- fromfile=outputFn,
- tofile="returned"))
- logging.error(error_message)
- raise Exception
+ # Run the test
+ proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True)
+ try:
+ outs = proc.communicate(input=inputData)
+ except OSError:
+ logging.error("OSError, Failed to execute " + execprog)
+ raise
- wantRC = 0
- if "return_code" in testObj:
- wantRC = testObj['return_code']
- if proc.returncode != wantRC:
- logging.error("Return code mismatch for " + outputFn)
- raise Exception
+ if outputData:
+ # Parse command output and expected output
+ try:
+ a_parsed = parse_output(outs[0], outputType)
+ except Exception as e:
+ logging.error('Error parsing command output as %s: %s' % (outputType,e))
+ raise
+ try:
+ b_parsed = parse_output(outputData, outputType)
+ except Exception as e:
+ logging.error('Error parsing expected output %s as %s: %s' % (outputFn,outputType,e))
+ raise
+ # Compare data
+ if a_parsed != b_parsed:
+ logging.error("Output data mismatch for " + outputFn + " (format " + outputType + ")")
+ raise Exception
+ # Compare formatting
+ if outs[0] != outputData:
+ error_message = "Output formatting mismatch for " + outputFn + ":\n"
+ error_message += "".join(difflib.context_diff(outputData.splitlines(True),
+ outs[0].splitlines(True),
+ fromfile=outputFn,
+ tofile="returned"))
+ logging.error(error_message)
+ raise Exception
-def bctester(testDir, input_basename, buildenv):
- input_filename = testDir + "/" + input_basename
- raw_data = open(input_filename).read()
- input_data = json.loads(raw_data)
+ # Compare the return code to the expected return code
+ wantRC = 0
+ if "return_code" in testObj:
+ wantRC = testObj['return_code']
+ if proc.returncode != wantRC:
+ logging.error("Return code mismatch for " + outputFn)
+ raise Exception
- failed_testcases = []
+def bctester(testDir, input_basename, buildenv):
+ """ Loads and parses the input file, runs all tests and reports results"""
+ input_filename = testDir + "/" + input_basename
+ raw_data = open(input_filename).read()
+ input_data = json.loads(raw_data)
- for testObj in input_data:
- try:
- bctest(testDir, testObj, buildenv.exeext)
- logging.info("PASSED: " + testObj["description"])
- except:
- logging.info("FAILED: " + testObj["description"])
- failed_testcases.append(testObj["description"])
+ failed_testcases = []
- if failed_testcases:
- logging.error("FAILED TESTCASES: [" + ", ".join(failed_testcases) + "]")
- sys.exit(1)
- else:
- sys.exit(0)
+ for testObj in input_data:
+ try:
+ bctest(testDir, testObj, buildenv.exeext)
+ logging.info("PASSED: " + testObj["description"])
+ except:
+ logging.info("FAILED: " + testObj["description"])
+ failed_testcases.append(testObj["description"])
+ if failed_testcases:
+ logging.error("FAILED TESTCASES: [" + ", ".join(failed_testcases) + "]")
+ sys.exit(1)
+ else:
+ sys.exit(0)
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
index 9afe91aca0..4301b93b7c 100755
--- a/src/test/bitcoin-util-test.py
+++ b/src/test/bitcoin-util-test.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
-# Copyright 2014 BitPay, Inc.
+# Copyright 2014 BitPay Inc.
+# Copyright 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.
from __future__ import division,print_function,unicode_literals
@@ -16,11 +17,13 @@ Runs automatically during `make check`.
Can also be run manually from the src directory by specifiying the source directory:
-test/bitcoin-util-test.py --src=[srcdir]
+test/bitcoin-util-test.py --srcdir='srcdir' [--verbose]
"""
-
if __name__ == '__main__':
+ # Try to get the source directory from the environment variables. This will
+ # be set for `make check` automated runs. If environment variable is not set,
+ # then get the source directory from command line args.
try:
srcdir = os.environ["srcdir"]
verbose = False
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index f57c24270c..38aaaba267 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -19,26 +19,18 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
CTxMemPool mpool(CFeeRate(1000));
TestMemPoolEntryHelper entry;
CAmount basefee(2000);
- double basepri = 1e6;
CAmount deltaFee(100);
- double deltaPri=5e5;
- std::vector<CAmount> feeV[2];
- std::vector<double> priV[2];
+ std::vector<CAmount> feeV;
- // Populate vectors of increasing fees or priorities
+ // Populate vectors of increasing fees
for (int j = 0; j < 10; j++) {
- //V[0] is for fee transactions
- feeV[0].push_back(basefee * (j+1));
- priV[0].push_back(0);
- //V[1] is for priority transactions
- feeV[1].push_back(CAmount(0));
- priV[1].push_back(basepri * pow(10, j+1));
+ feeV.push_back(basefee * (j+1));
}
// Store the hashes of transactions that have been
- // added to the mempool by their associate fee/pri
+ // added to the mempool by their associate fee
// txHashes[j] is populated with transactions either of
- // fee = basefee * (j+1) OR pri = 10^6 * 10^(j+1)
+ // fee = basefee * (j+1)
std::vector<uint256> txHashes[10];
// Create a transaction template
@@ -60,19 +52,19 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// At a decay .998 and 4 fee transactions per block
// This makes the tx count about 1.33 per bucket, above the 1 threshold
while (blocknum < 200) {
- for (int j = 0; j < 10; j++) { // For each fee/pri multiple
- for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ for (int j = 0; j < 10; j++) { // For each fee
+ for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
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));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
txHashes[j].push_back(hash);
}
}
- //Create blocks where higher fee/pri txs are included more often
+ //Create blocks where higher fee txs are included more often
for (int h = 0; h <= blocknum%10; h++) {
- // 10/10 blocks add highest fee/pri transactions
+ // 10/10 blocks add highest fee transactions
// 9/10 blocks add 2nd highest and so on until ...
- // 1/10 blocks add lowest fee/pri transactions
+ // 1/10 blocks add lowest fee transactions
while (txHashes[9-h].size()) {
std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[9-h].back());
if (ptx)
@@ -100,7 +92,6 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
}
std::vector<CAmount> origFeeEst;
- std::vector<double> origPriEst;
// Highest feerate is 10*baseRate and gets in all blocks,
// second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
// third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
@@ -109,16 +100,12 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// so estimateFee(2) should return 9*baseRate etc...
for (int i = 1; i < 10;i++) {
origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
- origPriEst.push_back(mpool.estimatePriority(i));
if (i > 1) { // Fee estimates should be monotonically decreasing
BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
- BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]);
}
int mult = 11-i;
BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee);
BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee);
- BOOST_CHECK(origPriEst[i-1] < pow(10,mult) * basepri + deltaPri);
- BOOST_CHECK(origPriEst[i-1] > pow(10,mult) * basepri - deltaPri);
}
// Mine 50 more blocks with no transactions happening, estimates shouldn't change
@@ -129,19 +116,17 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int i = 1; i < 10;i++) {
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
- BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] + deltaPri);
- BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
}
// Mine 15 more blocks with lots of transactions happening and not getting mined
// Estimates should go up
while (blocknum < 265) {
- for (int j = 0; j < 10; j++) { // For each fee/pri multiple
- for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ for (int j = 0; j < 10; j++) { // For each fee multiple
+ for (int k = 0; k < 4; k++) { // add 4 fee txs
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));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
txHashes[j].push_back(hash);
}
}
@@ -152,8 +137,6 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int i = 1; i < 10;i++) {
BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
- BOOST_CHECK(mpool.estimatePriority(i) == -1 || mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
- BOOST_CHECK(mpool.estimateSmartPriority(i, &answerFound) > origPriEst[answerFound-1] - deltaPri);
}
// Mine all those transactions
@@ -170,20 +153,20 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
block.clear();
for (int i = 1; i < 10;i++) {
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
- BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
}
// Mine 200 more blocks where everything is mined every block
// Estimates should be below original estimates
while (blocknum < 465) {
- for (int j = 0; j < 10; j++) { // For each fee/pri multiple
- for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ for (int j = 0; j < 10; j++) { // For each fee multiple
+ for (int k = 0; k < 4; k++) { // add 4 fee txs
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));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
std::shared_ptr<const CTransaction> ptx = mpool.get(hash);
if (ptx)
block.push_back(*ptx);
+
}
}
mpool.removeForBlock(block, ++blocknum);
@@ -191,15 +174,14 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
}
for (int i = 1; i < 10; i++) {
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
- BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri);
}
// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
// and that estimateSmartPriority returns essentially an infinite value
- mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[0][5]).Time(GetTime()).Priority(priV[1][5]).Height(blocknum).FromTx(tx, &mpool));
- // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[0][5]
+ mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
+ // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
mpool.TrimToSize(1);
- BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[0][5]);
+ BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
for (int i = 1; i < 10; i++) {
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK());
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 561adb8ea2..3169afb13a 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -173,11 +173,14 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << tx2;
- if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message);
- } else {
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message);
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect,message);
+ int libconsensus_flags = flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL;
+ if (libconsensus_flags == flags) {
+ if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
+ BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
+ } else {
+ BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
+ BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect,message);
+ }
}
#endif
}
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index bec2c7459d..4c0fdc77f7 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -10,11 +10,54 @@
#include <stdint.h>
#include <boost/test/unit_test.hpp>
-
using namespace std;
BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup)
+class CSerializeMethodsTestSingle
+{
+protected:
+ int intval;
+ bool boolval;
+ std::string stringval;
+ const char* charstrval;
+ CTransaction txval;
+public:
+ CSerializeMethodsTestSingle() = default;
+ CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), charstrval(charstrvalin), txval(txvalin){}
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(intval);
+ READWRITE(boolval);
+ READWRITE(stringval);
+ READWRITE(FLATDATA(charstrval));
+ READWRITE(txval);
+ }
+
+ bool operator==(const CSerializeMethodsTestSingle& rhs)
+ {
+ return intval == rhs.intval && \
+ boolval == rhs.boolval && \
+ stringval == rhs.stringval && \
+ strcmp(charstrval, rhs.charstrval) == 0 && \
+ txval == rhs.txval;
+ }
+};
+
+class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle
+{
+public:
+ using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle;
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval);
+ }
+};
+
BOOST_AUTO_TEST_CASE(sizes)
{
BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0));
@@ -297,4 +340,30 @@ BOOST_AUTO_TEST_CASE(insert_delete)
BOOST_CHECK_EQUAL(ss.size(), 0);
}
+BOOST_AUTO_TEST_CASE(class_methods)
+{
+ int intval(100);
+ bool boolval(true);
+ std::string stringval("testing");
+ const char* charstrval("testing charstr");
+ CMutableTransaction txval;
+ CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval);
+ CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval);
+ CSerializeMethodsTestSingle methodtest3;
+ CSerializeMethodsTestMany methodtest4;
+ CDataStream ss(SER_DISK, PROTOCOL_VERSION);
+ BOOST_CHECK(methodtest1 == methodtest2);
+ ss << methodtest1;
+ ss >> methodtest4;
+ ss << methodtest2;
+ ss >> methodtest3;
+ BOOST_CHECK(methodtest1 == methodtest2);
+ BOOST_CHECK(methodtest2 == methodtest3);
+ BOOST_CHECK(methodtest3 == methodtest4);
+
+ CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, FLATDATA(charstrval), txval);
+ ss2 >> methodtest3;
+ BOOST_CHECK(methodtest3 == methodtest4);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index 45d480c816..7f794fcbe9 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright 2014 BitPay, Inc.
+// Copyright (c) 2014 BitPay Inc.
// Copyright (c) 2014-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 313d33507f..45135a5f73 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -895,7 +895,7 @@ CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
{
try {
LOCK(cs);
- fileout << 109900; // version required to read: 0.10.99 or later
+ fileout << 139900; // version required to read: 0.13.99 or later
fileout << CLIENT_VERSION; // version that wrote the file
minerPolicyEstimator->Write(fileout);
}
@@ -914,9 +914,8 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
filein >> nVersionRequired >> nVersionThatWrote;
if (nVersionRequired > CLIENT_VERSION)
return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired);
-
LOCK(cs);
- minerPolicyEstimator->Read(filein);
+ minerPolicyEstimator->Read(filein, nVersionThatWrote);
}
catch (const std::exception&) {
LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n");
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index b638810e9d..c5feb47899 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -798,8 +798,8 @@ UniValue processImport(const UniValue& data) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
}
- std::vector<unsigned char> data(ParseHex(strPubKey));
- CPubKey pubKey(data.begin(), data.end());
+ std::vector<unsigned char> vData(ParseHex(strPubKey));
+ CPubKey pubKey(vData.begin(), vData.end());
if (!pubKey.IsFullyValid()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");