aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.leveldb.include7
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/chain.h56
-rw-r--r--src/compat.h11
-rw-r--r--src/httpserver.cpp31
-rw-r--r--src/main.cpp202
-rw-r--r--src/main.h88
-rw-r--r--src/miner.cpp2
-rw-r--r--src/net.cpp35
-rw-r--r--src/net.h24
-rw-r--r--src/pow.cpp2
-rw-r--r--src/rpc/mining.cpp2
-rw-r--r--src/rpc/misc.cpp43
-rw-r--r--src/script/script.h15
-rw-r--r--src/test/miner_tests.cpp53
-rw-r--r--src/test/script_tests.cpp117
-rw-r--r--src/tinyformat.h2
-rw-r--r--src/txdb.cpp8
-rw-r--r--src/txdb.h33
-rw-r--r--src/txmempool.cpp29
-rw-r--r--src/txmempool.h5
-rw-r--r--src/util.cpp13
-rw-r--r--src/util.h44
23 files changed, 533 insertions, 291 deletions
diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include
index 36a6bc4095..88bb0c1932 100644
--- a/src/Makefile.leveldb.include
+++ b/src/Makefile.leveldb.include
@@ -13,7 +13,7 @@ LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv
LEVELDB_CPPFLAGS_INT =
LEVELDB_CPPFLAGS_INT += -I$(srcdir)/leveldb
LEVELDB_CPPFLAGS_INT += $(LEVELDB_TARGET_FLAGS)
-LEVELDB_CPPFLAGS_INT += $(LEVELDB_ATOMIC_CPPFLAGS)
+LEVELDB_CPPFLAGS_INT += -DLEVELDB_ATOMIC_PRESENT
LEVELDB_CPPFLAGS_INT += -D__STDC_LIMIT_MACROS
if TARGET_WINDOWS
@@ -22,11 +22,8 @@ else
LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_POSIX
endif
-LEVELDB_CXXFLAGS_INT =
-LEVELDB_CXXFLAGS_INT += $(LEVELDB_ATOMIC_CXXFLAGS)
-
leveldb_libleveldb_a_CPPFLAGS = $(AM_CPPFLAGS) $(LEVELDB_CPPFLAGS_INT) $(LEVELDB_CPPFLAGS)
-leveldb_libleveldb_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(LEVELDB_CXXFLAGS_INT)
+leveldb_libleveldb_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
leveldb_libleveldb_a_SOURCES=
leveldb_libleveldb_a_SOURCES += leveldb/db/builder.cc
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 49935699fd..a04101d3ed 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -314,7 +314,7 @@ int main(int argc, char* argv[])
SetupEnvironment();
if (!SetupNetworking()) {
fprintf(stderr, "Error: Initializing networking failed\n");
- exit(1);
+ return EXIT_FAILURE;
}
try {
diff --git a/src/chain.h b/src/chain.h
index 5b9605a80b..a13dae33d1 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -14,6 +14,60 @@
#include <vector>
+class CBlockFileInfo
+{
+public:
+ unsigned int nBlocks; //!< number of blocks stored in file
+ unsigned int nSize; //!< number of used bytes of block file
+ unsigned int nUndoSize; //!< number of used bytes in the undo file
+ unsigned int nHeightFirst; //!< lowest height of block in file
+ unsigned int nHeightLast; //!< highest height of block in file
+ uint64_t nTimeFirst; //!< earliest time of block in file
+ uint64_t nTimeLast; //!< latest time of block in file
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(VARINT(nBlocks));
+ READWRITE(VARINT(nSize));
+ READWRITE(VARINT(nUndoSize));
+ READWRITE(VARINT(nHeightFirst));
+ READWRITE(VARINT(nHeightLast));
+ READWRITE(VARINT(nTimeFirst));
+ READWRITE(VARINT(nTimeLast));
+ }
+
+ void SetNull() {
+ nBlocks = 0;
+ nSize = 0;
+ nUndoSize = 0;
+ nHeightFirst = 0;
+ nHeightLast = 0;
+ nTimeFirst = 0;
+ nTimeLast = 0;
+ }
+
+ CBlockFileInfo() {
+ SetNull();
+ }
+
+ std::string ToString() const;
+
+ /** update statistics (does not update nSize) */
+ void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
+ if (nBlocks==0 || nHeightFirst > nHeightIn)
+ nHeightFirst = nHeightIn;
+ if (nBlocks==0 || nTimeFirst > nTimeIn)
+ nTimeFirst = nTimeIn;
+ nBlocks++;
+ if (nHeightIn > nHeightLast)
+ nHeightLast = nHeightIn;
+ if (nTimeIn > nTimeLast)
+ nTimeLast = nTimeIn;
+ }
+};
+
struct CDiskBlockPos
{
int nFile;
@@ -54,7 +108,7 @@ struct CDiskBlockPos
};
-enum BlockStatus {
+enum BlockStatus: uint32_t {
//! Unused.
BLOCK_VALID_UNKNOWN = 0,
diff --git a/src/compat.h b/src/compat.h
index 1225ea18ed..79a297e5e4 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -78,17 +78,6 @@ typedef u_int SOCKET;
#define MSG_NOSIGNAL 0
#endif
-#ifndef WIN32
-// PRIO_MAX is not defined on Solaris
-#ifndef PRIO_MAX
-#define PRIO_MAX 20
-#endif
-#define THREAD_PRIORITY_LOWEST PRIO_MAX
-#define THREAD_PRIORITY_BELOW_NORMAL 2
-#define THREAD_PRIORITY_NORMAL 0
-#define THREAD_PRIORITY_ABOVE_NORMAL (-2)
-#endif
-
#if HAVE_DECL_STRNLEN == 0
size_t strnlen( const char *start, size_t max_len);
#endif // HAVE_DECL_STRNLEN
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index ce1accb046..812940eaf9 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -36,7 +36,6 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
/** Maximum size of http request (request line + headers) */
static const size_t MAX_HEADERS_SIZE = 8192;
@@ -45,8 +44,8 @@ static const size_t MAX_HEADERS_SIZE = 8192;
class HTTPWorkItem : public HTTPClosure
{
public:
- HTTPWorkItem(HTTPRequest* req, const std::string &path, const HTTPRequestHandler& func):
- req(req), path(path), func(func)
+ HTTPWorkItem(std::unique_ptr<HTTPRequest> req, const std::string &path, const HTTPRequestHandler& func):
+ req(std::move(req)), path(path), func(func)
{
}
void operator()()
@@ -54,7 +53,7 @@ public:
func(req.get(), path);
}
- boost::scoped_ptr<HTTPRequest> req;
+ std::unique_ptr<HTTPRequest> req;
private:
std::string path;
@@ -71,8 +70,7 @@ private:
/** Mutex protects entire object */
CWaitableCriticalSection cs;
CConditionVariable cond;
- /* XXX in C++11 we can use std::unique_ptr here and avoid manual cleanup */
- std::deque<WorkItem*> queue;
+ std::deque<std::unique_ptr<WorkItem>> queue;
bool running;
size_t maxDepth;
int numThreads;
@@ -101,15 +99,11 @@ public:
numThreads(0)
{
}
- /*( Precondition: worker threads have all stopped
+ /** Precondition: worker threads have all stopped
* (call WaitExit)
*/
~WorkQueue()
{
- while (!queue.empty()) {
- delete queue.front();
- queue.pop_front();
- }
}
/** Enqueue a work item */
bool Enqueue(WorkItem* item)
@@ -118,7 +112,7 @@ public:
if (queue.size() >= maxDepth) {
return false;
}
- queue.push_back(item);
+ queue.emplace_back(std::unique_ptr<WorkItem>(item));
cond.notify_one();
return true;
}
@@ -127,18 +121,17 @@ public:
{
ThreadCounter count(*this);
while (running) {
- WorkItem* i = 0;
+ std::unique_ptr<WorkItem> i;
{
boost::unique_lock<boost::mutex> lock(cs);
while (running && queue.empty())
cond.wait(lock);
if (!running)
break;
- i = queue.front();
+ i = std::move(queue.front());
queue.pop_front();
}
(*i)();
- delete i;
}
}
/** Interrupt and exit loops */
@@ -252,7 +245,7 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m)
/** HTTP request callback */
static void http_request_cb(struct evhttp_request* req, void* arg)
{
- std::auto_ptr<HTTPRequest> hreq(new HTTPRequest(req));
+ std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
LogPrint("http", "Received a %s request for %s from %s\n",
RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
@@ -288,12 +281,14 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
// Dispatch to worker thread
if (i != iend) {
- std::auto_ptr<HTTPWorkItem> item(new HTTPWorkItem(hreq.release(), path, i->handler));
+ std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler));
assert(workQueue);
if (workQueue->Enqueue(item.get()))
item.release(); /* if true, queue took ownership */
- else
+ else {
+ LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
+ }
} else {
hreq->WriteReply(HTTP_NOTFOUND);
}
diff --git a/src/main.cpp b/src/main.cpp
index 11ccab253e..92a38f230f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1468,7 +1468,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
int nHeight = -1;
{
- CCoinsViewCache &view = *pcoinsTip;
+ const CCoinsViewCache& view = *pcoinsTip;
const CCoins* coins = view.AccessCoins(hash);
if (coins)
nHeight = coins->nHeight;
@@ -3705,7 +3705,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
bool static LoadBlockIndexDB()
{
const CChainParams& chainparams = Params();
- if (!pblocktree->LoadBlockIndexGuts())
+ if (!pblocktree->LoadBlockIndexGuts(InsertBlockIndex))
return false;
boost::this_thread::interruption_point();
@@ -4556,12 +4556,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
}
- if (!vRecv.empty())
+ if (!vRecv.empty()) {
vRecv >> pfrom->nStartingHeight;
- if (!vRecv.empty())
- vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
- else
- pfrom->fRelayTxes = true;
+ }
+ {
+ LOCK(pfrom->cs_filter);
+ if (!vRecv.empty())
+ vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
+ else
+ pfrom->fRelayTxes = true;
+ }
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
@@ -5234,34 +5238,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fDisconnect = true;
return true;
}
- LOCK2(cs_main, pfrom->cs_filter);
- std::vector<uint256> vtxid;
- mempool.queryHashes(vtxid);
- vector<CInv> vInv;
- BOOST_FOREACH(uint256& hash, vtxid) {
- CInv inv(MSG_TX, hash);
- if (pfrom->pfilter) {
- CTransaction tx;
- bool fInMemPool = mempool.lookup(hash, tx);
- if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
- if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue;
- }
- if (pfrom->minFeeFilter) {
- CFeeRate feeRate;
- mempool.lookupFeeRate(hash, feeRate);
- LOCK(pfrom->cs_feeFilter);
- if (feeRate.GetFeePerK() < pfrom->minFeeFilter)
- continue;
- }
- vInv.push_back(inv);
- if (vInv.size() == MAX_INV_SZ) {
- pfrom->PushMessage(NetMsgType::INV, vInv);
- vInv.clear();
- }
- }
- if (vInv.size() > 0)
- pfrom->PushMessage(NetMsgType::INV, vInv);
+ LOCK(pfrom->cs_inventory);
+ pfrom->fSendMempool = true;
}
@@ -5349,12 +5328,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CBloomFilter filter;
vRecv >> filter;
+ LOCK(pfrom->cs_filter);
+
if (!filter.IsWithinSizeConstraints())
// There is no excuse for sending a too-large filter
Misbehaving(pfrom->GetId(), 100);
else
{
- LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter->UpdateEmptyFull();
@@ -5559,6 +5539,22 @@ bool ProcessMessages(CNode* pfrom)
return fOk;
}
+class CompareInvMempoolOrder
+{
+ CTxMemPool *mp;
+public:
+ CompareInvMempoolOrder(CTxMemPool *mempool)
+ {
+ mp = mempool;
+ }
+
+ bool operator()(std::set<uint256>::iterator a, std::set<uint256>::iterator b)
+ {
+ /* As std::make_heap produces a max-heap, we want the entries with the
+ * fewest ancestors/highest fee to sort later. */
+ return mp->CompareDepthAndScore(*b, *a);
+ }
+};
bool SendMessages(CNode* pto)
{
@@ -5798,49 +5794,127 @@ bool SendMessages(CNode* pto)
// Message: inventory
//
vector<CInv> vInv;
- vector<CInv> vInvWait;
{
+ LOCK(pto->cs_inventory);
+ vInv.reserve(std::max<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX));
+
+ // Add blocks
+ 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);
+ vInv.clear();
+ }
+ }
+ pto->vInventoryBlockToSend.clear();
+
+ // Check whether periodic sends should happen
bool fSendTrickle = pto->fWhitelisted;
if (pto->nNextInvSend < nNow) {
fSendTrickle = true;
- pto->nNextInvSend = PoissonNextSend(nNow, AVG_INVENTORY_BROADCAST_INTERVAL);
+ // Use half the delay for outbound peers, as there is less privacy concern for them.
+ pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound);
+ }
+
+ // Time to send but the peer has requested we not relay transactions.
+ if (fSendTrickle) {
+ LOCK(pto->cs_filter);
+ if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();
}
- LOCK(pto->cs_inventory);
- vInv.reserve(std::min<size_t>(1000, pto->vInventoryToSend.size()));
- vInvWait.reserve(pto->vInventoryToSend.size());
- BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
- {
- if (inv.type == MSG_TX && pto->filterInventoryKnown.contains(inv.hash))
- continue;
- // trickle out tx inv to protect privacy
- if (inv.type == MSG_TX && !fSendTrickle)
+ // Respond to BIP35 mempool requests
+ if (fSendTrickle && pto->fSendMempool) {
+ std::vector<uint256> vtxid;
+ mempool.queryHashes(vtxid);
+ pto->fSendMempool = false;
+ CAmount filterrate = 0;
{
- // 1/4 of tx invs blast to all immediately
- static uint256 hashSalt;
- if (hashSalt.IsNull())
- hashSalt = GetRandHash();
- uint256 hashRand = ArithToUint256(UintToArith256(inv.hash) ^ UintToArith256(hashSalt));
- hashRand = Hash(BEGIN(hashRand), END(hashRand));
- bool fTrickleWait = ((UintToArith256(hashRand) & 3) != 0);
+ LOCK(pto->cs_feeFilter);
+ filterrate = pto->minFeeFilter;
+ }
- if (fTrickleWait)
- {
- vInvWait.push_back(inv);
- continue;
+ LOCK(pto->cs_filter);
+
+ BOOST_FOREACH(const uint256& hash, vtxid) {
+ CInv inv(MSG_TX, hash);
+ pto->setInventoryTxToSend.erase(hash);
+ if (filterrate) {
+ CFeeRate feeRate;
+ mempool.lookupFeeRate(hash, feeRate);
+ if (feeRate.GetFeePerK() < filterrate)
+ continue;
+ }
+ if (pto->pfilter) {
+ CTransaction tx;
+ bool fInMemPool = mempool.lookup(hash, tx);
+ if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
+ if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
+ }
+ pto->filterInventoryKnown.insert(hash);
+ vInv.push_back(inv);
+ if (vInv.size() == MAX_INV_SZ) {
+ pto->PushMessage(NetMsgType::INV, vInv);
+ vInv.clear();
}
}
+ }
- pto->filterInventoryKnown.insert(inv.hash);
-
- vInv.push_back(inv);
- if (vInv.size() >= 1000)
+ // Determine transactions to relay
+ if (fSendTrickle) {
+ // Produce a vector with all candidates for sending
+ vector<std::set<uint256>::iterator> vInvTx;
+ vInvTx.reserve(pto->setInventoryTxToSend.size());
+ for (std::set<uint256>::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++) {
+ vInvTx.push_back(it);
+ }
+ CAmount filterrate = 0;
{
- pto->PushMessage(NetMsgType::INV, vInv);
- vInv.clear();
+ LOCK(pto->cs_feeFilter);
+ filterrate = pto->minFeeFilter;
+ }
+ // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
+ // A heap is used so that not all items need sorting if only a few are being sent.
+ CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
+ std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+ // No reason to drain out at many times the network's capacity,
+ // especially since we have many peers and some will draw much shorter delays.
+ unsigned int nRelayedTransactions = 0;
+ LOCK(pto->cs_filter);
+ while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
+ // Fetch the top element from the heap
+ std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+ std::set<uint256>::iterator it = vInvTx.back();
+ vInvTx.pop_back();
+ uint256 hash = *it;
+ // Remove it from the to-be-sent set
+ pto->setInventoryTxToSend.erase(it);
+ // Check if not in the filter already
+ if (pto->filterInventoryKnown.contains(hash)) {
+ continue;
+ }
+ // Not in the mempool anymore? don't bother sending it.
+ CFeeRate feeRate;
+ if (!mempool.lookupFeeRate(hash, feeRate)) {
+ continue;
+ }
+ if (filterrate && feeRate.GetFeePerK() < filterrate) {
+ continue;
+ }
+ if (pto->pfilter) {
+ CTransaction tx;
+ if (!mempool.lookup(hash, tx)) continue;
+ if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
+ }
+ // Send
+ vInv.push_back(CInv(MSG_TX, hash));
+ nRelayedTransactions++;
+ if (vInv.size() == MAX_INV_SZ) {
+ pto->PushMessage(NetMsgType::INV, vInv);
+ vInv.clear();
+ }
+ pto->filterInventoryKnown.insert(hash);
}
}
- pto->vInventoryToSend = vInvWait;
}
if (!vInv.empty())
pto->PushMessage(NetMsgType::INV, vInv);
diff --git a/src/main.h b/src/main.h
index 2c9635bcf2..bdf7f5a687 100644
--- a/src/main.h
+++ b/src/main.h
@@ -99,9 +99,12 @@ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60;
/** Average delay between peer address broadcasts in seconds. */
static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
-/** Average delay between trickled inventory broadcasts in seconds.
- * Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */
-static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5;
+/** Average delay between trickled inventory transmissions in seconds.
+ * Blocks and whitelisted receivers bypass this, outbound peers get half this delay. */
+static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5;
+/** Maximum number of inventory items to send per transmission.
+ * Limits the impact of low-fee transaction floods. */
+static const unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL;
/** Average delay between feefilter broadcasts in seconds. */
static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
/** Maximum feefilter broadcast delay after significant change. */
@@ -307,30 +310,6 @@ struct CNodeStateStats {
std::vector<int> vHeightInFlight;
};
-struct CDiskTxPos : public CDiskBlockPos
-{
- unsigned int nTxOffset; // after header
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(*(CDiskBlockPos*)this);
- READWRITE(VARINT(nTxOffset));
- }
-
- CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {
- }
-
- CDiskTxPos() {
- SetNull();
- }
-
- void SetNull() {
- CDiskBlockPos::SetNull();
- nTxOffset = 0;
- }
-};
/**
@@ -470,61 +449,6 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-
-class CBlockFileInfo
-{
-public:
- unsigned int nBlocks; //!< number of blocks stored in file
- unsigned int nSize; //!< number of used bytes of block file
- unsigned int nUndoSize; //!< number of used bytes in the undo file
- unsigned int nHeightFirst; //!< lowest height of block in file
- unsigned int nHeightLast; //!< highest height of block in file
- uint64_t nTimeFirst; //!< earliest time of block in file
- uint64_t nTimeLast; //!< latest time of block in file
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(VARINT(nBlocks));
- READWRITE(VARINT(nSize));
- READWRITE(VARINT(nUndoSize));
- READWRITE(VARINT(nHeightFirst));
- READWRITE(VARINT(nHeightLast));
- READWRITE(VARINT(nTimeFirst));
- READWRITE(VARINT(nTimeLast));
- }
-
- void SetNull() {
- nBlocks = 0;
- nSize = 0;
- nUndoSize = 0;
- nHeightFirst = 0;
- nHeightLast = 0;
- nTimeFirst = 0;
- nTimeLast = 0;
- }
-
- CBlockFileInfo() {
- SetNull();
- }
-
- std::string ToString() const;
-
- /** update statistics (does not update nSize) */
- void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
- if (nBlocks==0 || nHeightFirst > nHeightIn)
- nHeightFirst = nHeightIn;
- if (nBlocks==0 || nTimeFirst > nTimeIn)
- nTimeFirst = nTimeIn;
- nBlocks++;
- if (nHeightIn > nHeightLast)
- nHeightLast = nHeightIn;
- if (nTimeIn > nTimeLast)
- nTimeLast = nTimeIn;
- }
-};
-
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
class CVerifyDB {
public:
diff --git a/src/miner.cpp b/src/miner.cpp
index ef8fd4db43..eaf29a767b 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -74,7 +74,7 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn)
{
// Create new block
- auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
+ std::unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
if(!pblocktemplate.get())
return NULL;
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
diff --git a/src/net.cpp b/src/net.cpp
index 7dec8fc1cf..5e810a0f15 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -877,6 +877,14 @@ public:
}
};
+/** Try to find a connection to evict when the node is full.
+ * Extreme care must be taken to avoid opening the node to attacker
+ * triggered network partitioning.
+ * The strategy used here is to protect a small number of peers
+ * for each of several distinct characteristics which are difficult
+ * to forge. In order to partition a node the attacker must be
+ * simultaneously better at all of them than honest peers.
+ */
static bool AttemptToEvictConnection(bool fPreferNewConnection) {
std::vector<CNodeRef> vEvictionCandidates;
{
@@ -905,7 +913,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
if (vEvictionCandidates.empty()) return false;
- // Protect the 8 nodes with the best ping times.
+ // Protect the 8 nodes with the lowest minimum ping time.
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
@@ -913,7 +921,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
if (vEvictionCandidates.empty()) return false;
// Protect the half of the remaining nodes which have been connected the longest.
- // This replicates the existing implicit behavior.
+ // This replicates the non-eviction implicit behavior, and precludes attacks that start later.
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end());
@@ -941,6 +949,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
vEvictionCandidates = mapAddrCounts[naMostConnections];
// Do not disconnect peers if there is only one unprotected connection from their network group.
+ // This step excessively favors netgroup diversity, and should be removed once more protective criteria are established.
if (vEvictionCandidates.size() <= 1)
// unless we prefer the new connection (for whitelisted peers)
if (!fPreferNewConnection)
@@ -1720,7 +1729,6 @@ void ThreadMessageHandler()
boost::mutex condition_mutex;
boost::unique_lock<boost::mutex> lock(condition_mutex);
- SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
while (true)
{
vector<CNode*> vNodesCopy;
@@ -2079,20 +2087,7 @@ void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
- if(!pnode->fRelayTxes)
- continue;
- {
- LOCK(pnode->cs_feeFilter);
- if (feerate.GetFeePerK() < pnode->minFeeFilter)
- continue;
- }
- LOCK(pnode->cs_filter);
- if (pnode->pfilter)
- {
- if (pnode->pfilter->IsRelevantAndUpdate(tx))
- pnode->PushInventory(inv);
- } else
- pnode->PushInventory(inv);
+ pnode->PushInventory(inv);
}
}
@@ -2378,6 +2373,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
hashContinue = uint256();
nStartingHeight = -1;
filterInventoryKnown.reset();
+ fSendMempool = false;
fGetAddr = false;
nNextLocalAddrSend = 0;
nNextAddrSend = 0;
@@ -2634,9 +2630,10 @@ void DumpBanlist()
CBanDB bandb;
banmap_t banmap;
+ CNode::SetBannedSetDirty(false);
CNode::GetBanned(banmap);
- if (bandb.Write(banmap))
- CNode::SetBannedSetDirty(false);
+ if (!bandb.Write(banmap))
+ CNode::SetBannedSetDirty(true);
LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
banmap.size(), GetTimeMillis() - nStart);
diff --git a/src/net.h b/src/net.h
index bf367684f6..b6ec7bf3e2 100644
--- a/src/net.h
+++ b/src/net.h
@@ -357,7 +357,7 @@ public:
// a) it allows us to not relay tx invs before receiving the peer's version message
// b) the peer may tell us in its version message that we should not relay tx invs
// unless it loads a bloom filter.
- bool fRelayTxes;
+ bool fRelayTxes; //protected by cs_filter
bool fSentAddr;
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
@@ -397,7 +397,13 @@ public:
// inventory based relay
CRollingBloomFilter filterInventoryKnown;
- std::vector<CInv> vInventoryToSend;
+ // Set of transaction ids we still have to announce.
+ // They are sorted by the mempool before relay, so the order is not important.
+ std::set<uint256> setInventoryTxToSend;
+ // List of block ids we still have announce.
+ // There is no final sorting before sending, as they are always sent immediately
+ // and in the order requested.
+ std::vector<uint256> vInventoryBlockToSend;
CCriticalSection cs_inventory;
std::set<uint256> setAskFor;
std::multimap<int64_t, CInv> mapAskFor;
@@ -405,6 +411,8 @@ public:
// Used for headers announcements - unfiltered blocks to relay
// Also protected by cs_inventory
std::vector<uint256> vBlockHashesToAnnounce;
+ // Used for BIP35 mempool sending, also protected by cs_inventory
+ bool fSendMempool;
// Ping time measurement:
// The pong reply we're expecting, or 0 if no pong expected.
@@ -517,11 +525,13 @@ public:
void PushInventory(const CInv& inv)
{
- {
- LOCK(cs_inventory);
- if (inv.type == MSG_TX && filterInventoryKnown.contains(inv.hash))
- return;
- vInventoryToSend.push_back(inv);
+ LOCK(cs_inventory);
+ if (inv.type == MSG_TX) {
+ if (!filterInventoryKnown.contains(inv.hash)) {
+ setInventoryTxToSend.insert(inv.hash);
+ }
+ } else if (inv.type == MSG_BLOCK) {
+ vInventoryBlockToSend.push_back(inv.hash);
}
}
diff --git a/src/pow.cpp b/src/pow.cpp
index 058404f357..1db3b69293 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -64,9 +64,7 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
// Retarget
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
arith_uint256 bnNew;
- arith_uint256 bnOld;
bnNew.SetCompact(pindexLast->nBits);
- bnOld = bnNew;
bnNew *= nActualTimespan;
bnNew /= params.nPowTargetTimespan;
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index b63ee22889..9a7d9d53a0 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -111,7 +111,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd)
{
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript));
+ std::unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index e8a099b445..09f5185781 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -366,6 +366,48 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
return (pubkey.GetID() == keyID);
}
+UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 2)
+ throw runtime_error(
+ "signmessagewithprivkey \"privkey\" \"message\"\n"
+ "\nSign a message with the private key of an address\n"
+ "\nArguments:\n"
+ "1. \"privkey\" (string, required) The private key to sign the message with.\n"
+ "2. \"message\" (string, required) The message to create a signature of.\n"
+ "\nResult:\n"
+ "\"signature\" (string) The signature of the message encoded in base 64\n"
+ "\nExamples:\n"
+ "\nCreate the signature\n"
+ + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
+ "\nVerify the signature\n"
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ "\nAs json rpc\n"
+ + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
+ );
+
+ string strPrivkey = params[0].get_str();
+ string strMessage = params[1].get_str();
+
+ CBitcoinSecret vchSecret;
+ bool fGood = vchSecret.SetString(strPrivkey);
+ if (!fGood)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
+ CKey key = vchSecret.GetKey();
+ if (!key.IsValid())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
+
+ CHashWriter ss(SER_GETHASH, 0);
+ ss << strMessageMagic;
+ ss << strMessage;
+
+ vector<unsigned char> vchSig;
+ if (!key.SignCompact(ss.GetHash(), vchSig))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
+
+ return EncodeBase64(&vchSig[0], vchSig.size());
+}
+
UniValue setmocktime(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@@ -404,6 +446,7 @@ static const CRPCCommand commands[] =
{ "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
{ "util", "createmultisig", &createmultisig, true },
{ "util", "verifymessage", &verifymessage, true },
+ { "util", "signmessagewithprivkey", &signmessagewithprivkey, true },
/* Not shown in help */
{ "hidden", "setmocktime", &setmocktime, true },
diff --git a/src/script/script.h b/src/script/script.h
index 2a338d6f5c..a2941ce901 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -573,17 +573,26 @@ public:
int nFound = 0;
if (b.empty())
return nFound;
- iterator pc = begin();
+ CScript result;
+ iterator pc = begin(), pc2 = begin();
opcodetype opcode;
do
{
- while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
+ result.insert(result.end(), pc2, pc);
+ while (static_cast<size_t>(end() - pc) >= b.size() && std::equal(b.begin(), b.end(), pc))
{
- pc = erase(pc, pc + b.size());
+ pc = pc + b.size();
++nFound;
}
+ pc2 = pc;
}
while (GetOp(pc, opcode));
+
+ if (nFound > 0) {
+ result.insert(result.end(), pc2, end());
+ *this = result;
+ }
+
return nFound;
}
int Find(opcodetype op) const
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index ab6485081c..469862518c 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -124,6 +124,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
delete pblocktemplate;
+ const CAmount BLOCKSUBSIDY = 50*COIN;
+ const CAmount LOWFEE = CENT;
+ const CAmount HIGHFEE = COIN;
+ const CAmount HIGHERFEE = 4*COIN;
+
// block sigops > limit: 1000 CHECKMULTISIG + 1
tx.vin.resize(1);
// NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG
@@ -131,28 +136,28 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
tx.vin[0].prevout.n = 0;
tx.vout.resize(1);
- tx.vout[0].nValue = 5000000000LL;
+ tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 1001; ++i)
{
- tx.vout[0].nValue -= 1000000;
+ tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
// If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
- mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
mempool.clear();
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vout[0].nValue = 5000000000LL;
+ tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 1001; ++i)
{
- tx.vout[0].nValue -= 1000000;
+ tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
// If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
- mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOps(20).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOps(20).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
@@ -167,13 +172,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].scriptSig << vchData << OP_DROP;
tx.vin[0].scriptSig << OP_1;
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vout[0].nValue = 5000000000LL;
+ tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 128; ++i)
{
- tx.vout[0].nValue -= 10000000;
+ tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
- mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
@@ -182,24 +187,24 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// orphan in mempool, template creation fails
hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
mempool.clear();
// child with higher priority than parent
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
- tx.vout[0].nValue = 4900000000LL;
+ tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(100000000LL).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout.hash = hash;
tx.vin.resize(2);
tx.vin[1].scriptSig = CScript() << OP_1;
tx.vin[1].prevout.hash = txFirst[0]->GetHash();
tx.vin[1].prevout.n = 0;
- tx.vout[0].nValue = 5900000000LL;
+ tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(400000000LL).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
delete pblocktemplate;
mempool.clear();
@@ -211,7 +216,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue = 0;
hash = tx.GetHash();
// give it a fee so it'll get mined
- mempool.addUnchecked(hash, entry.Fee(100000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
mempool.clear();
@@ -219,29 +224,29 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vout[0].nValue = 4900000000LL;
+ tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
script = CScript() << OP_0;
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(10000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout.hash = hash;
tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
- tx.vout[0].nValue -= 1000000;
+ tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
mempool.clear();
// double spend txn pair in mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vout[0].nValue = 4900000000LL;
+ tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
tx.vout[0].scriptPubKey = CScript() << OP_1;
hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
mempool.clear();
@@ -298,11 +303,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; // txFirst[0] is the 2nd block
prevheights[0] = baseheight + 1;
tx.vout.resize(1);
- tx.vout[0].nValue = 4900000000LL;
+ tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
tx.vout[0].scriptPubKey = CScript() << OP_1;
tx.nLockTime = 0;
hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes
BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail
BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index d42187f912..5e9711a4a7 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1051,4 +1051,121 @@ BOOST_AUTO_TEST_CASE(script_GetScriptAsm)
BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey));
}
+static CScript
+ScriptFromHex(const char* hex)
+{
+ std::vector<unsigned char> data = ParseHex(hex);
+ return CScript(data.begin(), data.end());
+}
+
+
+BOOST_AUTO_TEST_CASE(script_FindAndDelete)
+{
+ // Exercise the FindAndDelete functionality
+ CScript s;
+ CScript d;
+ CScript expect;
+
+ s = CScript() << OP_1 << OP_2;
+ d = CScript(); // delete nothing should be a no-op
+ expect = s;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK(s == expect);
+
+ s = CScript() << OP_1 << OP_2 << OP_3;
+ d = CScript() << OP_2;
+ expect = CScript() << OP_1 << OP_3;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3;
+ d = CScript() << OP_3;
+ expect = CScript() << OP_1 << OP_4;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0302ff03"); // PUSH 0x02ff03 onto stack
+ d = ScriptFromHex("0302ff03");
+ expect = CScript();
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0302ff030302ff03"); // PUSH 0x2ff03 PUSH 0x2ff03
+ d = ScriptFromHex("0302ff03");
+ expect = CScript();
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0302ff030302ff03");
+ d = ScriptFromHex("02");
+ expect = s; // FindAndDelete matches entire opcodes
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0302ff030302ff03");
+ d = ScriptFromHex("ff");
+ expect = s;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK(s == expect);
+
+ // This is an odd edge case: strip of the push-three-bytes
+ // prefix, leaving 02ff03 which is push-two-bytes:
+ s = ScriptFromHex("0302ff030302ff03");
+ d = ScriptFromHex("03");
+ expect = CScript() << ParseHex("ff03") << ParseHex("ff03");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK(s == expect);
+
+ // Byte sequence that spans multiple opcodes:
+ s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY
+ d = ScriptFromHex("feed51");
+ expect = s;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); // doesn't match 'inside' opcodes
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY
+ d = ScriptFromHex("02feed51");
+ expect = ScriptFromHex("69");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("516902feed5169");
+ d = ScriptFromHex("feed51");
+ expect = s;
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("516902feed5169");
+ d = ScriptFromHex("02feed51");
+ expect = ScriptFromHex("516969");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = CScript() << OP_0 << OP_0 << OP_1 << OP_1;
+ d = CScript() << OP_0 << OP_1;
+ expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1;
+ d = CScript() << OP_0 << OP_1;
+ expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);
+ BOOST_CHECK(s == expect);
+
+ // Another weird edge case:
+ // End with invalid push (not enough data)...
+ s = ScriptFromHex("0003feed");
+ d = ScriptFromHex("03feed"); // ... can remove the invalid push
+ expect = ScriptFromHex("00");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+
+ s = ScriptFromHex("0003feed");
+ d = ScriptFromHex("00");
+ expect = ScriptFromHex("03feed");
+ BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);
+ BOOST_CHECK(s == expect);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 73d49a1fe4..c6ec0419b3 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -113,7 +113,7 @@ namespace tfm = tinyformat;
// Define for C++11 variadic templates which make the code shorter & more
// general. If you don't define this, C++11 support is autodetected below.
-// #define TINYFORMAT_USE_VARIADIC_TEMPLATES
+#define TINYFORMAT_USE_VARIADIC_TEMPLATES
//------------------------------------------------------------------------------
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 5fbaeb608a..078c29def3 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -5,10 +5,8 @@
#include "txdb.h"
-#include "chain.h"
#include "chainparams.h"
#include "hash.h"
-#include "main.h"
#include "pow.h"
#include "uint256.h"
@@ -173,7 +171,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
return true;
}
-bool CBlockTreeDB::LoadBlockIndexGuts()
+bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
@@ -187,8 +185,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
CDiskBlockIndex diskindex;
if (pcursor->GetValue(diskindex)) {
// Construct block index object
- CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
- pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
+ CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
+ pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
pindexNew->nHeight = diskindex.nHeight;
pindexNew->nFile = diskindex.nFile;
pindexNew->nDataPos = diskindex.nDataPos;
diff --git a/src/txdb.h b/src/txdb.h
index 749802f0e5..ce3c39d7fe 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -8,15 +8,17 @@
#include "coins.h"
#include "dbwrapper.h"
+#include "chain.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
-class CBlockFileInfo;
+#include <boost/function.hpp>
+
class CBlockIndex;
-struct CDiskTxPos;
+class CCoinsViewDBCursor;
class uint256;
//! -dbcache default (MiB)
@@ -26,7 +28,30 @@ static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;
//! min. -dbcache in (MiB)
static const int64_t nMinDbCache = 4;
-class CCoinsViewDBCursor;
+struct CDiskTxPos : public CDiskBlockPos
+{
+ unsigned int nTxOffset; // after header
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(*(CDiskBlockPos*)this);
+ READWRITE(VARINT(nTxOffset));
+ }
+
+ CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {
+ }
+
+ CDiskTxPos() {
+ SetNull();
+ }
+
+ void SetNull() {
+ CDiskBlockPos::SetNull();
+ nTxOffset = 0;
+ }
+};
/** CCoinsView backed by the coin database (chainstate/) */
class CCoinsViewDB : public CCoinsView
@@ -83,7 +108,7 @@ public:
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
- bool LoadBlockIndexGuts();
+ bool LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex);
};
#endif // BITCOIN_TXDB_H
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 52c7793118..a6070f5264 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -752,6 +752,31 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(innerUsage == cachedInnerUsage);
}
+bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb)
+{
+ LOCK(cs);
+ indexed_transaction_set::const_iterator i = mapTx.find(hasha);
+ if (i == mapTx.end()) return false;
+ indexed_transaction_set::const_iterator j = mapTx.find(hashb);
+ if (j == mapTx.end()) return true;
+ uint64_t counta = i->GetCountWithAncestors();
+ uint64_t countb = j->GetCountWithAncestors();
+ if (counta == countb) {
+ return CompareTxMemPoolEntryByScore()(*i, *j);
+ }
+ return counta < countb;
+}
+
+namespace {
+class DepthAndScoreComparator
+{
+ CTxMemPool *mp;
+public:
+ DepthAndScoreComparator(CTxMemPool *mempool) : mp(mempool) {}
+ bool operator()(const uint256& a, const uint256& b) { return mp->CompareDepthAndScore(a, b); }
+};
+}
+
void CTxMemPool::queryHashes(vector<uint256>& vtxid)
{
vtxid.clear();
@@ -760,6 +785,8 @@ void CTxMemPool::queryHashes(vector<uint256>& vtxid)
vtxid.reserve(mapTx.size());
for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
vtxid.push_back(mi->GetTx().GetHash());
+
+ std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this));
}
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
@@ -885,7 +912,7 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
return true;
}
-CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
+CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
diff --git a/src/txmempool.h b/src/txmempool.h
index de4ba0b371..bca8dd9791 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -511,6 +511,7 @@ public:
std::list<CTransaction>& conflicts, bool fCurrentEstimate = true);
void clear();
void _clear(); //lock free
+ bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
void queryHashes(std::vector<uint256>& vtxid);
void pruneSpent(const uint256& hash, CCoins &coins);
unsigned int GetTransactionsUpdated() const;
@@ -672,10 +673,10 @@ private:
class CCoinsViewMemPool : public CCoinsViewBacked
{
protected:
- CTxMemPool &mempool;
+ const CTxMemPool& mempool;
public:
- CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn);
+ CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
};
diff --git a/src/util.cpp b/src/util.cpp
index 00b75fbdbe..3f0f8be544 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -790,19 +790,6 @@ bool SetupNetworking()
return true;
}
-void SetThreadPriority(int nPriority)
-{
-#ifdef WIN32
- SetThreadPriority(GetCurrentThread(), nPriority);
-#else // WIN32
-#ifdef PRIO_THREAD
- setpriority(PRIO_THREAD, 0, nPriority);
-#else // PRIO_THREAD
- setpriority(PRIO_PROCESS, 0, nPriority);
-#endif // PRIO_THREAD
-#endif // WIN32
-}
-
int GetNumCores()
{
#if BOOST_VERSION >= 105600
diff --git a/src/util.h b/src/util.h
index ac099f1184..45e81ab67f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -76,40 +76,33 @@ int LogPrintStr(const std::string &str);
#define LogPrintf(...) LogPrint(NULL, __VA_ARGS__)
-/**
- * When we switch to C++11, this can be switched to variadic templates instead
- * of this macro-based construction (see tinyformat.h).
- */
-#define MAKE_ERROR_AND_LOG_FUNC(n) \
- /** Print to debug.log if -debug=category switch is given OR category is NULL. */ \
- template<TINYFORMAT_ARGTYPES(n)> \
- static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \
- { \
- if(!LogAcceptCategory(category)) return 0; \
- return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \
- } \
- /** Log error and return false */ \
- template<TINYFORMAT_ARGTYPES(n)> \
- static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \
- { \
- LogPrintStr("ERROR: " + tfm::format(format, TINYFORMAT_PASSARGS(n)) + "\n"); \
- return false; \
- }
+template<typename T1, typename... Args>
+static inline int LogPrint(const char* category, const char* fmt, const T1& v1, const Args&... args)
+{
+ if(!LogAcceptCategory(category)) return 0; \
+ return LogPrintStr(tfm::format(fmt, v1, args...));
+}
-TINYFORMAT_FOREACH_ARGNUM(MAKE_ERROR_AND_LOG_FUNC)
+template<typename T1, typename... Args>
+bool error(const char* fmt, const T1& v1, const Args&... args)
+{
+ LogPrintStr("ERROR: " + tfm::format(fmt, v1, args...) + "\n");
+ return false;
+}
/**
* Zero-arg versions of logging and error, these are not covered by
- * TINYFORMAT_FOREACH_ARGNUM
+ * the variadic templates above (and don't take format arguments but
+ * bare strings).
*/
-static inline int LogPrint(const char* category, const char* format)
+static inline int LogPrint(const char* category, const char* s)
{
if(!LogAcceptCategory(category)) return 0;
- return LogPrintStr(format);
+ return LogPrintStr(s);
}
-static inline bool error(const char* format)
+static inline bool error(const char* s)
{
- LogPrintStr(std::string("ERROR: ") + format + "\n");
+ LogPrintStr(std::string("ERROR: ") + s + "\n");
return false;
}
@@ -215,7 +208,6 @@ std::string HelpMessageOpt(const std::string& option, const std::string& message
*/
int GetNumCores();
-void SetThreadPriority(int nPriority);
void RenameThread(const char* name);
/**