aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am20
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/compat.h1
-rw-r--r--src/consensus/consensus.h6
-rw-r--r--src/dbwrapper.cpp (renamed from src/leveldbwrapper.cpp)56
-rw-r--r--src/dbwrapper.h (renamed from src/leveldbwrapper.h)64
-rw-r--r--src/init.cpp8
-rw-r--r--src/main.cpp66
-rw-r--r--src/main.h4
-rw-r--r--src/miner.cpp8
-rw-r--r--src/net.cpp106
-rw-r--r--src/net.h27
-rw-r--r--src/netbase.cpp9
-rw-r--r--src/policy/policy.h3
-rw-r--r--src/primitives/block.h2
-rw-r--r--src/rpcblockchain.cpp4
-rw-r--r--src/rpcclient.cpp1
-rw-r--r--src/rpcnet.cpp9
-rw-r--r--src/rpcrawtransaction.cpp20
-rw-r--r--src/script/bitcoinconsensus.h7
-rw-r--r--src/script/interpreter.cpp6
-rw-r--r--src/script/script.cpp2
-rw-r--r--src/script/script.h9
-rw-r--r--src/test/alert_tests.cpp4
-rw-r--r--src/test/dbwrapper_tests.cpp (renamed from src/test/leveldbwrapper_tests.cpp)28
-rw-r--r--src/test/miner_tests.cpp7
-rw-r--r--src/txdb.cpp14
-rw-r--r--src/txdb.h8
-rw-r--r--src/txmempool.cpp12
-rw-r--r--src/txmempool.h1
-rw-r--r--src/util.cpp11
-rw-r--r--src/util.h3
-rw-r--r--src/utiltime.cpp8
-rw-r--r--src/utiltime.h1
34 files changed, 411 insertions, 126 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0a16a863eb..f35b9dc898 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -110,7 +110,7 @@ BITCOIN_CORE_H = \
init.h \
key.h \
keystore.h \
- leveldbwrapper.h \
+ dbwrapper.h \
limitedmap.h \
main.h \
memusage.h \
@@ -188,7 +188,7 @@ libbitcoin_server_a_SOURCES = \
httprpc.cpp \
httpserver.cpp \
init.cpp \
- leveldbwrapper.cpp \
+ dbwrapper.cpp \
main.cpp \
merkleblock.cpp \
miner.cpp \
@@ -412,7 +412,19 @@ libbitcoinconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BIT
endif
#
-CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno
+CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a
+CLEANFILES += *.gcda *.gcno
+CLEANFILES += compat/*.gcda compat/*.gcno
+CLEANFILES += consensus/*.gcda consensus/*.gcno
+CLEANFILES += crypto/*.gcda crypto/*.gcno
+CLEANFILES += policy/*.gcda policy/*.gcno
+CLEANFILES += primitives/*.gcda primitives/*.gcno
+CLEANFILES += script/*.gcda script/*.gcno
+CLEANFILES += support/*.gcda support/*.gcno
+CLEANFILES += univalue/*.gcda univalue/*.gcno
+CLEANFILES += wallet/*.gcda wallet/*.gcno
+CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno
+CLEANFILES += zmq/*.gcda zmq/*.gcno
DISTCLEANFILES = obj/build.h
@@ -422,7 +434,7 @@ clean-local:
-$(MAKE) -C leveldb clean
-$(MAKE) -C secp256k1 clean
-$(MAKE) -C univalue clean
- rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno
+ -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno
-rm -f config.h
.rc.o:
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 0fe8ea42ff..f23a8f41fc 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -54,7 +54,7 @@ BITCOIN_TESTS =\
test/hash_tests.cpp \
test/key_tests.cpp \
test/limitedmap_tests.cpp \
- test/leveldbwrapper_tests.cpp \
+ test/dbwrapper_tests.cpp \
test/main_tests.cpp \
test/mempool_tests.cpp \
test/miner_tests.cpp \
diff --git a/src/compat.h b/src/compat.h
index 5378c2c761..20c2a25143 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -38,6 +38,7 @@
#include <sys/types.h>
#include <net/if.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <limits.h>
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index f937844e9f..6d6ce7e099 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -13,4 +13,10 @@ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
+/** Flags for LockTime() */
+enum {
+ /* Use GetMedianTimePast() instead of nTime for end point timestamp. */
+ LOCKTIME_MEDIAN_TIME_PAST = (1 << 1),
+};
+
#endif // BITCOIN_CONSENSUS_CONSENSUS_H
diff --git a/src/leveldbwrapper.cpp b/src/dbwrapper.cpp
index 32c9345be5..b6307cf0bf 100644
--- a/src/leveldbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "leveldbwrapper.h"
+#include "dbwrapper.h"
#include "util.h"
#include "random.h"
@@ -15,18 +15,18 @@
#include <memenv.h>
#include <stdint.h>
-void HandleError(const leveldb::Status& status) throw(leveldb_error)
+void HandleError(const leveldb::Status& status) throw(dbwrapper_error)
{
if (status.ok())
return;
LogPrintf("%s\n", status.ToString());
if (status.IsCorruption())
- throw leveldb_error("Database corrupted");
+ throw dbwrapper_error("Database corrupted");
if (status.IsIOError())
- throw leveldb_error("Database I/O error");
+ throw dbwrapper_error("Database I/O error");
if (status.IsNotFound())
- throw leveldb_error("Database entry missing");
- throw leveldb_error("Unknown database error");
+ throw dbwrapper_error("Database entry missing");
+ throw dbwrapper_error("Unknown database error");
}
static leveldb::Options GetOptions(size_t nCacheSize)
@@ -45,7 +45,7 @@ static leveldb::Options GetOptions(size_t nCacheSize)
return options;
}
-CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
+CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
{
penv = NULL;
readoptions.verify_checksums = true;
@@ -76,7 +76,7 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa
bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
if (!key_exists && obfuscate && IsEmpty()) {
- // Initialize non-degenerate obfuscation if it won't upset
+ // Initialize non-degenerate obfuscation if it won't upset
// existing, non-obfuscated data.
std::vector<unsigned char> new_key = CreateObfuscateKey();
@@ -90,7 +90,7 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa
LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex());
}
-CLevelDBWrapper::~CLevelDBWrapper()
+CDBWrapper::~CDBWrapper()
{
delete pdb;
pdb = NULL;
@@ -102,7 +102,7 @@ CLevelDBWrapper::~CLevelDBWrapper()
options.env = NULL;
}
-bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb_error)
+bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) throw(dbwrapper_error)
{
leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
HandleError(status);
@@ -113,15 +113,15 @@ bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb
//
// We must use a string constructor which specifies length so that we copy
// past the null-terminator.
-const std::string CLevelDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14);
+const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14);
-const unsigned int CLevelDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
+const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
/**
- * Returns a string (consisting of 8 random bytes) suitable for use as an
- * obfuscating XOR key.
+ * Returns a string (consisting of 8 random bytes) suitable for use as an
+ * obfuscating XOR key.
*/
-std::vector<unsigned char> CLevelDBWrapper::CreateObfuscateKey() const
+std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
{
unsigned char buff[OBFUSCATE_KEY_NUM_BYTES];
GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES);
@@ -129,26 +129,24 @@ std::vector<unsigned char> CLevelDBWrapper::CreateObfuscateKey() const
}
-bool CLevelDBWrapper::IsEmpty()
+bool CDBWrapper::IsEmpty()
{
- boost::scoped_ptr<CLevelDBIterator> it(NewIterator());
+ boost::scoped_ptr<CDBIterator> it(NewIterator());
it->SeekToFirst();
return !(it->Valid());
}
-const std::vector<unsigned char>& CLevelDBWrapper::GetObfuscateKey() const
-{
- return obfuscate_key;
+const std::vector<unsigned char>& CDBWrapper::GetObfuscateKey() const
+{
+ return obfuscate_key;
}
-std::string CLevelDBWrapper::GetObfuscateKeyHex() const
-{
- return HexStr(obfuscate_key);
+std::string CDBWrapper::GetObfuscateKeyHex() const
+{
+ return HexStr(obfuscate_key);
}
-CLevelDBIterator::~CLevelDBIterator() { delete piter; }
-bool CLevelDBIterator::Valid() { return piter->Valid(); }
-void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); }
-void CLevelDBIterator::SeekToLast() { piter->SeekToLast(); }
-void CLevelDBIterator::Next() { piter->Next(); }
-void CLevelDBIterator::Prev() { piter->Prev(); }
+CDBIterator::~CDBIterator() { delete piter; }
+bool CDBIterator::Valid() { return piter->Valid(); }
+void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
+void CDBIterator::Next() { piter->Next(); }
diff --git a/src/leveldbwrapper.h b/src/dbwrapper.h
index 60101e18cc..aa28767508 100644
--- a/src/leveldbwrapper.h
+++ b/src/dbwrapper.h
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_LEVELDBWRAPPER_H
-#define BITCOIN_LEVELDBWRAPPER_H
+#ifndef BITCOIN_DBWRAPPER_H
+#define BITCOIN_DBWRAPPER_H
#include "clientversion.h"
#include "serialize.h"
@@ -17,18 +17,18 @@
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
-class leveldb_error : public std::runtime_error
+class dbwrapper_error : public std::runtime_error
{
public:
- leveldb_error(const std::string& msg) : std::runtime_error(msg) {}
+ dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
};
-void HandleError(const leveldb::Status& status) throw(leveldb_error);
+void HandleError(const leveldb::Status& status) throw(dbwrapper_error);
-/** Batch of changes queued to be written to a CLevelDBWrapper */
-class CLevelDBBatch
+/** Batch of changes queued to be written to a CDBWrapper */
+class CDBBatch
{
- friend class CLevelDBWrapper;
+ friend class CDBWrapper;
private:
leveldb::WriteBatch batch;
@@ -38,7 +38,7 @@ public:
/**
* @param[in] obfuscate_key If passed, XOR data with this key.
*/
- CLevelDBBatch(const std::vector<unsigned char> *obfuscate_key) : obfuscate_key(obfuscate_key) { };
+ CDBBatch(const std::vector<unsigned char> *obfuscate_key) : obfuscate_key(obfuscate_key) { };
template <typename K, typename V>
void Write(const K& key, const V& value)
@@ -68,8 +68,8 @@ public:
batch.Delete(slKey);
}
};
-
-class CLevelDBIterator
+
+class CDBIterator
{
private:
leveldb::Iterator *piter;
@@ -81,14 +81,13 @@ public:
* @param[in] piterIn The original leveldb iterator.
* @param[in] obfuscate_key If passed, XOR data with this key.
*/
- CLevelDBIterator(leveldb::Iterator *piterIn, const std::vector<unsigned char>* obfuscate_key) :
+ CDBIterator(leveldb::Iterator *piterIn, const std::vector<unsigned char>* obfuscate_key) :
piter(piterIn), obfuscate_key(obfuscate_key) { };
- ~CLevelDBIterator();
+ ~CDBIterator();
bool Valid();
void SeekToFirst();
- void SeekToLast();
template<typename K> void Seek(const K& key) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
@@ -99,7 +98,6 @@ public:
}
void Next();
- void Prev();
template<typename K> bool GetKey(K& key) {
leveldb::Slice slKey = piter->key();
@@ -133,8 +131,8 @@ public:
}
};
-
-class CLevelDBWrapper
+
+class CDBWrapper
{
private:
//! custom environment this database is using (may be NULL in case of default environment)
@@ -163,10 +161,10 @@ private:
//! the key under which the obfuscation key is stored
static const std::string OBFUSCATE_KEY_KEY;
-
+
//! the length of the obfuscate key in number of bytes
static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
-
+
std::vector<unsigned char> CreateObfuscateKey() const;
public:
@@ -178,11 +176,11 @@ public:
* @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
* with a zero'd byte array.
*/
- CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
- ~CLevelDBWrapper();
+ CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
+ ~CDBWrapper();
template <typename K, typename V>
- bool Read(const K& key, V& value) const throw(leveldb_error)
+ bool Read(const K& key, V& value) const throw(dbwrapper_error)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
@@ -208,15 +206,15 @@ public:
}
template <typename K, typename V>
- bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error)
+ bool Write(const K& key, const V& value, bool fSync = false) throw(dbwrapper_error)
{
- CLevelDBBatch batch(&obfuscate_key);
+ CDBBatch batch(&obfuscate_key);
batch.Write(key, value);
return WriteBatch(batch, fSync);
}
template <typename K>
- bool Exists(const K& key) const throw(leveldb_error)
+ bool Exists(const K& key) const throw(dbwrapper_error)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
@@ -235,14 +233,14 @@ public:
}
template <typename K>
- bool Erase(const K& key, bool fSync = false) throw(leveldb_error)
+ bool Erase(const K& key, bool fSync = false) throw(dbwrapper_error)
{
- CLevelDBBatch batch(&obfuscate_key);
+ CDBBatch batch(&obfuscate_key);
batch.Erase(key);
return WriteBatch(batch, fSync);
}
- bool WriteBatch(CLevelDBBatch& batch, bool fSync = false) throw(leveldb_error);
+ bool WriteBatch(CDBBatch& batch, bool fSync = false) throw(dbwrapper_error);
// not available for LevelDB; provide for compatibility with BDB
bool Flush()
@@ -250,15 +248,15 @@ public:
return true;
}
- bool Sync() throw(leveldb_error)
+ bool Sync() throw(dbwrapper_error)
{
- CLevelDBBatch batch(&obfuscate_key);
+ CDBBatch batch(&obfuscate_key);
return WriteBatch(batch, true);
}
- CLevelDBIterator *NewIterator()
+ CDBIterator *NewIterator()
{
- return new CLevelDBIterator(pdb->NewIterator(iteroptions), &obfuscate_key);
+ return new CDBIterator(pdb->NewIterator(iteroptions), &obfuscate_key);
}
/**
@@ -278,5 +276,5 @@ public:
};
-#endif // BITCOIN_LEVELDBWRAPPER_H
+#endif // BITCOIN_DBWRAPPER_H
diff --git a/src/init.cpp b/src/init.cpp
index 5c961a3ad9..920fc3069e 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -369,6 +369,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
+ strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), 0));
#ifdef ENABLE_WALLET
strUsage += HelpMessageGroup(_("Wallet options:"));
@@ -430,6 +431,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1));
if (showDebug)
{
+ strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS));
strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15));
strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1));
strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000));
@@ -727,6 +729,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Set this early so that parameter interactions go to console
fPrintToConsole = GetBoolArg("-printtoconsole", false);
fLogTimestamps = GetBoolArg("-logtimestamps", true);
+ fLogTimeMicros = GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
fLogIPs = GetBoolArg("-logips", false);
LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
@@ -1174,6 +1177,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterValidationInterface(pzmqNotificationInterface);
}
#endif
+ if (mapArgs.count("-maxuploadtarget")) {
+ CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", 0)*1024*1024);
+ }
// ********************************************************* Step 7: load block chain
@@ -1505,10 +1511,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// if pruning, unset the service bit and perform the initial blockstore prune
// after any wallet rescanning has taken place.
if (fPruneMode) {
- uiInterface.InitMessage(_("Pruning blockstore..."));
LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
nLocalServices &= ~NODE_NETWORK;
if (!fReindex) {
+ uiInterface.InitMessage(_("Pruning blockstore..."));
PruneAndFlush();
}
}
diff --git a/src/main.cpp b/src/main.cpp
index d870280e99..e038fe3663 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -650,10 +650,35 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
return true;
}
-bool CheckFinalTx(const CTransaction &tx)
+bool CheckFinalTx(const CTransaction &tx, int flags)
{
AssertLockHeld(cs_main);
- return IsFinalTx(tx, chainActive.Height() + 1, GetAdjustedTime());
+
+ // By convention a negative value for flags indicates that the
+ // current network-enforced consensus rules should be used. In
+ // a future soft-fork scenario that would mean checking which
+ // rules would be enforced for the next block and setting the
+ // appropriate flags. At the present time no soft-forks are
+ // scheduled, so no flags are set.
+ flags = std::max(flags, 0);
+
+ // CheckFinalTx() uses chainActive.Height()+1 to evaluate
+ // nLockTime because when IsFinalTx() is called within
+ // CBlock::AcceptBlock(), the height of the block *being*
+ // evaluated is what is used. Thus if we want to know if a
+ // transaction can be part of the *next* block, we need to call
+ // IsFinalTx() with one more than chainActive.Height().
+ const int nBlockHeight = chainActive.Height() + 1;
+
+ // Timestamps on the other hand don't get any special treatment,
+ // because we can't know what timestamp the next block will have,
+ // and there aren't timestamp applications where it matters.
+ // However this changes once median past time-locks are enforced:
+ const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST)
+ ? chainActive.Tip()->GetMedianTimePast()
+ : GetAdjustedTime();
+
+ return IsFinalTx(tx, nBlockHeight, nBlockTime);
}
unsigned int GetLegacySigOpCount(const CTransaction& tx)
@@ -797,7 +822,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
- if (!CheckFinalTx(tx))
+ if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
// is it already in the memory pool?
@@ -1751,11 +1776,18 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
- // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded:
+ // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks,
+ // when 75% of the network has upgraded:
if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
flags |= SCRIPT_VERIFY_DERSIG;
}
+ // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4
+ // blocks, when 75% of the network has upgraded:
+ if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
+ flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
+ }
+
CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
@@ -1892,7 +1924,7 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
std::set<int> setFilesToPrune;
bool fFlushForPrune = false;
try {
- if (fPruneMode && fCheckForPruning) {
+ if (fPruneMode && fCheckForPruning && !fReindex) {
FindFilesToPrune(setFilesToPrune);
fCheckForPruning = false;
if (!setFilesToPrune.empty()) {
@@ -2702,6 +2734,11 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return state.Invalid(error("%s : rejected nVersion=2 block", __func__),
REJECT_OBSOLETE, "bad-version");
+ // Reject block.nVersion=3 blocks when 95% (75% on testnet) of the network has upgraded:
+ if (block.nVersion < 4 && IsSuperMajority(4, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
+ return state.Invalid(error("%s : rejected nVersion=3 block", __func__),
+ REJECT_OBSOLETE, "bad-version");
+
return true;
}
@@ -2711,10 +2748,15 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
const Consensus::Params& consensusParams = Params().GetConsensus();
// Check that all transactions are finalized
- BOOST_FOREACH(const CTransaction& tx, block.vtx)
- if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) {
+ BOOST_FOREACH(const CTransaction& tx, block.vtx) {
+ int nLockTimeFlags = 0;
+ int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST)
+ ? pindexPrev->GetMedianTimePast()
+ : block.GetBlockTime();
+ if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) {
return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal");
}
+ }
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
@@ -3793,6 +3835,16 @@ void static ProcessGetData(CNode* pfrom)
}
}
}
+ // disconnect node in case we have reached the outbound limit for serving historical blocks
+ static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical
+ if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) )
+ {
+ LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
+
+ //disconnect node
+ pfrom->fDisconnect = true;
+ send = false;
+ }
// Pruned nodes may have deleted the block, so check whether
// it's available before trying to send.
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))
diff --git a/src/main.h b/src/main.h
index 202d2c772b..65732d770f 100644
--- a/src/main.h
+++ b/src/main.h
@@ -308,8 +308,10 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
* Check if transaction will be final in the next block to be created.
*
* Calls IsFinalTx() with current block height and appropriate block time.
+ *
+ * See consensus/consensus.h for flag definitions.
*/
-bool CheckFinalTx(const CTransaction &tx);
+bool CheckFinalTx(const CTransaction &tx, int flags = -1);
/**
* Closure representing one script verification
diff --git a/src/miner.cpp b/src/miner.cpp
index 42c8bb970b..053d9cdbc4 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -148,6 +148,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1;
pblock->nTime = GetAdjustedTime();
+ const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
CCoinsViewCache view(pcoinsTip);
// Priority order to process transactions
@@ -162,7 +163,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
mi != mempool.mapTx.end(); ++mi)
{
const CTransaction& tx = mi->GetTx();
- if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, pblock->nTime))
+
+ int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
+ ? nMedianTimePast
+ : pblock->GetBlockTime();
+
+ if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff))
continue;
COrphan* porphan = NULL;
diff --git a/src/net.cpp b/src/net.cpp
index 87c4f0af0a..e18e8d0e29 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -12,6 +12,7 @@
#include "addrman.h"
#include "chainparams.h"
#include "clientversion.h"
+#include "consensus/consensus.h"
#include "crypto/common.h"
#include "hash.h"
#include "primitives/transaction.h"
@@ -326,6 +327,11 @@ uint64_t CNode::nTotalBytesSent = 0;
CCriticalSection CNode::cs_totalBytesRecv;
CCriticalSection CNode::cs_totalBytesSent;
+uint64_t CNode::nMaxOutboundLimit = 0;
+uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0;
+uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day
+uint64_t CNode::nMaxOutboundCycleStartTime = 0;
+
CNode* FindNode(const CNetAddr& ip)
{
LOCK(cs_vNodes);
@@ -963,6 +969,15 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
return;
}
+ // According to the internet TCP_NODELAY is not carried into accepted sockets
+ // on all platforms. Set it again here just to be sure.
+ int set = 1;
+#ifdef WIN32
+ setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
+#else
+ setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
+#endif
+
if (CNode::IsBanned(addr) && !whitelisted)
{
LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
@@ -1790,8 +1805,11 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
+ // Disable Nagle's algorithm
+ setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&nOne, sizeof(int));
#else
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int));
+ setsockopt(hListenSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nOne, sizeof(int));
#endif
// Set to non-blocking, incoming connections will also inherit this
@@ -2071,6 +2089,94 @@ void CNode::RecordBytesSent(uint64_t bytes)
{
LOCK(cs_totalBytesSent);
nTotalBytesSent += bytes;
+
+ uint64_t now = GetTime();
+ if (nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now)
+ {
+ // timeframe expired, reset cycle
+ nMaxOutboundCycleStartTime = now;
+ nMaxOutboundTotalBytesSentInCycle = 0;
+ }
+
+ // TODO, exclude whitebind peers
+ nMaxOutboundTotalBytesSentInCycle += bytes;
+}
+
+void CNode::SetMaxOutboundTarget(uint64_t limit)
+{
+ LOCK(cs_totalBytesSent);
+ uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SIZE;
+ nMaxOutboundLimit = limit;
+
+ if (limit < recommendedMinimum)
+ LogPrintf("Max outbound target is very small (%s) and will be overshot. Recommended minimum is %s\n.", nMaxOutboundLimit, recommendedMinimum);
+}
+
+uint64_t CNode::GetMaxOutboundTarget()
+{
+ LOCK(cs_totalBytesSent);
+ return nMaxOutboundLimit;
+}
+
+uint64_t CNode::GetMaxOutboundTimeframe()
+{
+ LOCK(cs_totalBytesSent);
+ return nMaxOutboundTimeframe;
+}
+
+uint64_t CNode::GetMaxOutboundTimeLeftInCycle()
+{
+ LOCK(cs_totalBytesSent);
+ if (nMaxOutboundLimit == 0)
+ return 0;
+
+ if (nMaxOutboundCycleStartTime == 0)
+ return nMaxOutboundTimeframe;
+
+ uint64_t cycleEndTime = nMaxOutboundCycleStartTime + nMaxOutboundTimeframe;
+ uint64_t now = GetTime();
+ return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime();
+}
+
+void CNode::SetMaxOutboundTimeframe(uint64_t timeframe)
+{
+ LOCK(cs_totalBytesSent);
+ if (nMaxOutboundTimeframe != timeframe)
+ {
+ // reset measure-cycle in case of changing
+ // the timeframe
+ nMaxOutboundCycleStartTime = GetTime();
+ }
+ nMaxOutboundTimeframe = timeframe;
+}
+
+bool CNode::OutboundTargetReached(bool historicalBlockServingLimit)
+{
+ LOCK(cs_totalBytesSent);
+ if (nMaxOutboundLimit == 0)
+ return false;
+
+ if (historicalBlockServingLimit)
+ {
+ // keep a large enought buffer to at least relay each block once
+ uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle();
+ uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SIZE;
+ if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer)
+ return true;
+ }
+ else if (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit)
+ return true;
+
+ return false;
+}
+
+uint64_t CNode::GetOutboundTargetBytesLeft()
+{
+ LOCK(cs_totalBytesSent);
+ if (nMaxOutboundLimit == 0)
+ return 0;
+
+ return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle;
}
uint64_t CNode::GetTotalBytesRecv()
diff --git a/src/net.h b/src/net.h
index 6842ee5edc..f90b3385af 100644
--- a/src/net.h
+++ b/src/net.h
@@ -400,6 +400,12 @@ private:
static uint64_t nTotalBytesRecv;
static uint64_t nTotalBytesSent;
+ // outbound limit & stats
+ static uint64_t nMaxOutboundTotalBytesSentInCycle;
+ static uint64_t nMaxOutboundCycleStartTime;
+ static uint64_t nMaxOutboundLimit;
+ static uint64_t nMaxOutboundTimeframe;
+
CNode(const CNode&);
void operator=(const CNode&);
@@ -701,6 +707,27 @@ public:
static uint64_t GetTotalBytesRecv();
static uint64_t GetTotalBytesSent();
+
+ //!set the max outbound target in bytes
+ static void SetMaxOutboundTarget(uint64_t limit);
+ static uint64_t GetMaxOutboundTarget();
+
+ //!set the timeframe for the max outbound target
+ static void SetMaxOutboundTimeframe(uint64_t timeframe);
+ static uint64_t GetMaxOutboundTimeframe();
+
+ //!check if the outbound target is reached
+ // if param historicalBlockServingLimit is set true, the function will
+ // response true if the limit for serving historical blocks has been reached
+ static bool OutboundTargetReached(bool historicalBlockServingLimit);
+
+ //!response the bytes left in the current max outbound cycle
+ // in case of no limit, it will always response 0
+ static uint64_t GetOutboundTargetBytesLeft();
+
+ //!response the time in second left in the current max outbound cycle
+ // in case of no limit, it will always response 0
+ static uint64_t GetMaxOutboundTimeLeftInCycle();
};
diff --git a/src/netbase.cpp b/src/netbase.cpp
index c3d56d9184..f5316965ce 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -444,12 +444,19 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (hSocket == INVALID_SOCKET)
return false;
-#ifdef SO_NOSIGPIPE
int set = 1;
+#ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif
+ //Disable Nagle's algorithm
+#ifdef WIN32
+ setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
+#else
+ setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
+#endif
+
// Set to non-blocking
if (!SetSocketNonBlocking(hSocket, true))
return error("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 0ea0d435ad..7027f1402f 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -43,6 +43,9 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
/** For convenience, standard but not mandatory verify flags. */
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
+/** Used as the flags parameter to CheckFinalTx() in non-consensus code */
+static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_MEDIAN_TIME_PAST;
+
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
/**
* Check for standard transaction types
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 86106098f5..54731ff557 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -21,7 +21,7 @@ class CBlockHeader
{
public:
// header
- static const int32_t CURRENT_VERSION=3;
+ static const int32_t CURRENT_VERSION=4;
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 545ac12890..4786d72a3f 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -648,6 +648,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
UniValue softforks(UniValue::VARR);
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
+ softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
obj.push_back(Pair("softforks", softforks));
if (fPruneMode)
@@ -772,6 +773,9 @@ UniValue mempoolInfoToJSON()
ret.push_back(Pair("size", (int64_t) mempool.size()));
ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage()));
+ size_t maxmempool = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ ret.push_back(Pair("maxmempool", (int64_t) maxmempool));
+ ret.push_back(Pair("mempoolminfee", ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK())));
return ret;
}
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
index 4064c2fee3..343b6234d4 100644
--- a/src/rpcclient.cpp
+++ b/src/rpcclient.cpp
@@ -76,6 +76,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getrawtransaction", 1 },
{ "createrawtransaction", 0 },
{ "createrawtransaction", 1 },
+ { "createrawtransaction", 2 },
{ "signrawtransaction", 1 },
{ "signrawtransaction", 2 },
{ "sendrawtransaction", 1 },
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 7746be25f7..6b4815ebd8 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -379,6 +379,15 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
obj.push_back(Pair("timemillis", GetTimeMillis()));
+
+ UniValue outboundLimit(UniValue::VOBJ);
+ outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe()));
+ outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget()));
+ outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false)));
+ outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true)));
+ outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft()));
+ outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle()));
+ obj.push_back(Pair("uploadtarget", outboundLimit));
return obj;
}
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 4b96473504..5f3363d097 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -316,9 +316,9 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
UniValue createrawtransaction(const UniValue& params, bool fHelp)
{
- if (fHelp || params.size() != 2)
+ if (fHelp || params.size() < 2 || params.size() > 3)
throw runtime_error(
- "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...}\n"
+ "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
"Returns hex-encoded raw transaction.\n"
@@ -340,6 +340,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
" \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n"
" ...\n"
" }\n"
+ "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
"\nResult:\n"
"\"transaction\" (string) hex string of the transaction\n"
@@ -351,13 +352,22 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
+ if (params[0].isNull() || params[1].isNull())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
UniValue inputs = params[0].get_array();
UniValue sendTo = params[1].get_obj();
CMutableTransaction rawTx;
+ if (params.size() > 2 && !params[2].isNull()) {
+ int64_t nLockTime = params[2].get_int64();
+ if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
+ rawTx.nLockTime = nLockTime;
+ }
+
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
const UniValue& o = input.get_obj();
@@ -371,7 +381,9 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
if (nOutput < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
- CTxIn in(COutPoint(txid, nOutput));
+ uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max());
+ CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
+
rawTx.vin.push_back(in);
}
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 0320577797..a48ff1e18d 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -44,9 +44,10 @@ typedef enum bitcoinconsensus_error_t
/** Script verification flags */
enum
{
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
};
/// Returns 1 if the input nIn of the serialized transaction pointed to by
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index d3aec26020..6a20d497c0 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -273,7 +273,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
// Note how OP_RESERVED does not count towards the opcode limit.
- if (opcode > OP_16 && ++nOpCount > 201)
+ if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT)
return set_error(serror, SCRIPT_ERR_OP_COUNT);
if (opcode == OP_CAT ||
@@ -869,10 +869,10 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
- if (nKeysCount < 0 || nKeysCount > 20)
+ if (nKeysCount < 0 || nKeysCount > MAX_PUBKEYS_PER_MULTISIG)
return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT);
nOpCount += nKeysCount;
- if (nOpCount > 201)
+ if (nOpCount > MAX_OPS_PER_SCRIPT)
return set_error(serror, SCRIPT_ERR_OP_COUNT);
int ikey = ++i;
i += nKeysCount;
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 9a0c067a33..263c89defe 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -170,7 +170,7 @@ unsigned int CScript::GetSigOpCount(bool fAccurate) const
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
n += DecodeOP_N(lastOpcode);
else
- n += 20;
+ n += MAX_PUBKEYS_PER_MULTISIG;
}
lastOpcode = opcode;
}
diff --git a/src/script/script.h b/src/script/script.h
index cdc9a71bb2..a38d33a189 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -17,7 +17,14 @@
#include <string>
#include <vector>
-static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
+// Maximum number of bytes pushable to the stack
+static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;
+
+// Maximum number of non-push operations per script
+static const int MAX_OPS_PER_SCRIPT = 201;
+
+// Maximum number of public keys per multisig
+static const int MAX_PUBKEYS_PER_MULTISIG = 20;
// Threshold for nLockTime: below this value it is interpreted as block number,
// otherwise as UNIX timestamp.
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index dd3c51d09b..468eda1c9b 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -217,10 +217,12 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
// use them
}
+ strMiscWarning = "";
+
// Test 1: chain with blocks every nPowTargetSpacing seconds,
// as normal, no worries:
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
- BOOST_CHECK(strMiscWarning.empty());
+ BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning);
// Test 2: go 3.5 hours without a block, expect a warning:
now += 3*60*60+30*60;
diff --git a/src/test/leveldbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index 606313b004..8b6b0697ab 100644
--- a/src/test/leveldbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "leveldbwrapper.h"
+#include "dbwrapper.h"
#include "uint256.h"
#include "random.h"
#include "test/test_bitcoin.h"
@@ -25,15 +25,15 @@ bool is_null_key(const vector<unsigned char>& key) {
return isnull;
}
-BOOST_FIXTURE_TEST_SUITE(leveldbwrapper_tests, BasicTestingSetup)
+BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)
-BOOST_AUTO_TEST_CASE(leveldbwrapper)
+BOOST_AUTO_TEST_CASE(dbwrapper)
{
// Perform tests both obfuscated and non-obfuscated.
for (int i = 0; i < 2; i++) {
bool obfuscate = (bool)i;
path ph = temp_directory_path() / unique_path();
- CLevelDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
+ CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'k';
uint256 in = GetRandHash();
uint256 res;
@@ -48,13 +48,13 @@ BOOST_AUTO_TEST_CASE(leveldbwrapper)
}
// Test batch operations
-BOOST_AUTO_TEST_CASE(leveldbwrapper_batch)
+BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
// Perform tests both obfuscated and non-obfuscated.
for (int i = 0; i < 2; i++) {
bool obfuscate = (bool)i;
path ph = temp_directory_path() / unique_path();
- CLevelDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
+ CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'i';
uint256 in = GetRandHash();
@@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(leveldbwrapper_batch)
uint256 in3 = GetRandHash();
uint256 res;
- CLevelDBBatch batch(&dbw.GetObfuscateKey());
+ CDBBatch batch(&dbw.GetObfuscateKey());
batch.Write(key, in);
batch.Write(key2, in2);
@@ -85,13 +85,13 @@ BOOST_AUTO_TEST_CASE(leveldbwrapper_batch)
}
}
-BOOST_AUTO_TEST_CASE(leveldbwrapper_iterator)
+BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
// Perform tests both obfuscated and non-obfuscated.
for (int i = 0; i < 2; i++) {
bool obfuscate = (bool)i;
path ph = temp_directory_path() / unique_path();
- CLevelDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
+ CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
// The two keys are intentionally chosen for ordering
char key = 'j';
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(leveldbwrapper_iterator)
uint256 in2 = GetRandHash();
BOOST_CHECK(dbw.Write(key2, in2));
- boost::scoped_ptr<CLevelDBIterator> it(const_cast<CLevelDBWrapper*>(&dbw)->NewIterator());
+ boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
// Be sure to seek past the obfuscation key (if it exists)
it->Seek(key);
@@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- CLevelDBWrapper* dbw = new CLevelDBWrapper(ph, (1 << 10), false, false, false);
+ CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = GetRandHash();
uint256 res;
@@ -147,7 +147,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
delete dbw;
// Now, set up another wrapper that wants to obfuscate the same directory
- CLevelDBWrapper odbw(ph, (1 << 10), false, false, true);
+ CDBWrapper odbw(ph, (1 << 10), false, false, true);
// Check that the key/val we wrote with unobfuscated wrapper exists and
// is readable.
@@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- CLevelDBWrapper* dbw = new CLevelDBWrapper(ph, (1 << 10), false, false, false);
+ CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = GetRandHash();
uint256 res;
@@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
delete dbw;
// Simulate a -reindex by wiping the existing data store
- CLevelDBWrapper odbw(ph, (1 << 10), false, true, true);
+ CDBWrapper odbw(ph, (1 << 10), false, true, true);
// Check that the key/val we wrote with unobfuscated wrapper doesn't exist
uint256 res2;
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 91a3a5738e..827525783a 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -4,6 +4,7 @@
#include "chainparams.h"
#include "coins.h"
+#include "consensus/consensus.h"
#include "consensus/validation.h"
#include "main.h"
#include "miner.h"
@@ -229,7 +230,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.nLockTime = chainActive.Tip()->nHeight+1;
hash = tx.GetHash();
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
- BOOST_CHECK(!CheckFinalTx(tx));
+ BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST));
// time locked
tx2.vin.resize(1);
@@ -243,7 +244,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1;
hash = tx2.GetHash();
mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11));
- BOOST_CHECK(!CheckFinalTx(tx2));
+ BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST));
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
@@ -261,7 +262,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
//BOOST_CHECK(CheckFinalTx(tx2));
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
- BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3);
+ BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2);
delete pblocktemplate;
chainActive.Tip()->nHeight--;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index a441aea688..cd76c0155c 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -49,7 +49,7 @@ uint256 CCoinsViewDB::GetBestBlock() const {
}
bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
- CLevelDBBatch batch(&db.GetObfuscateKey());
+ CDBBatch batch(&db.GetObfuscateKey());
size_t count = 0;
size_t changed = 0;
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
@@ -71,7 +71,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
return db.WriteBatch(batch);
}
-CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
+CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
}
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
@@ -98,7 +98,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
/* It seems that there are no "const iterators" for LevelDB. Since we
only need read operations on it, use a const-cast to get around
that restriction. */
- boost::scoped_ptr<CLevelDBIterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
+ boost::scoped_ptr<CDBIterator> pcursor(const_cast<CDBWrapper*>(&db)->NewIterator());
pcursor->Seek(DB_COINS);
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
@@ -121,7 +121,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
nTotalAmount += out.nValue;
}
}
- stats.nSerializedSize += 32 + pcursor->GetKeySize();
+ stats.nSerializedSize += 32 + pcursor->GetValueSize();
ss << VARINT(0);
} else {
return error("CCoinsViewDB::GetStats() : unable to read value");
@@ -141,7 +141,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
}
bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
- CLevelDBBatch batch(&GetObfuscateKey());
+ CDBBatch batch(&GetObfuscateKey());
for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second);
}
@@ -157,7 +157,7 @@ bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
}
bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
- CLevelDBBatch batch(&GetObfuscateKey());
+ CDBBatch batch(&GetObfuscateKey());
for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
batch.Write(make_pair(DB_TXINDEX, it->first), it->second);
return WriteBatch(batch);
@@ -177,7 +177,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
bool CBlockTreeDB::LoadBlockIndexGuts()
{
- boost::scoped_ptr<CLevelDBIterator> pcursor(NewIterator());
+ boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256()));
diff --git a/src/txdb.h b/src/txdb.h
index bef5dc9fd1..586ab55d0d 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -7,7 +7,7 @@
#define BITCOIN_TXDB_H
#include "coins.h"
-#include "leveldbwrapper.h"
+#include "dbwrapper.h"
#include <map>
#include <string>
@@ -26,11 +26,11 @@ static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;
//! min. -dbcache in (MiB)
static const int64_t nMinDbCache = 4;
-/** CCoinsView backed by the LevelDB coin database (chainstate/) */
+/** CCoinsView backed by the coin database (chainstate/) */
class CCoinsViewDB : public CCoinsView
{
protected:
- CLevelDBWrapper db;
+ CDBWrapper db;
public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
@@ -42,7 +42,7 @@ public:
};
/** Access to the block database (blocks/index/) */
-class CBlockTreeDB : public CLevelDBWrapper
+class CBlockTreeDB : public CDBWrapper
{
public:
CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index bb148005cd..47e8de5361 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -309,7 +309,7 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t
CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
nTransactionsUpdated(0)
{
- clear();
+ _clear(); //lock free clear
// Sanity checks off by default for performance, because otherwise
// accepting transactions becomes O(N^2) where N is the number
@@ -512,6 +512,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
if (txConflict != tx)
{
remove(txConflict, removed, true);
+ ClearPrioritisation(txConflict.GetHash());
}
}
}
@@ -546,9 +547,8 @@ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned i
blockSinceLastRollingFeeBump = true;
}
-void CTxMemPool::clear()
+void CTxMemPool::_clear()
{
- LOCK(cs);
mapLinks.clear();
mapTx.clear();
mapNextTx.clear();
@@ -560,6 +560,12 @@ void CTxMemPool::clear()
++nTransactionsUpdated;
}
+void CTxMemPool::clear()
+{
+ LOCK(cs);
+ _clear();
+}
+
void CTxMemPool::check(const CCoinsViewCache *pcoins) const
{
if (!fSanityCheck)
diff --git a/src/txmempool.h b/src/txmempool.h
index d44995eefe..dedc7ba72c 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -375,6 +375,7 @@ public:
void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
std::list<CTransaction>& conflicts, bool fCurrentEstimate = true);
void clear();
+ void _clear(); //lock free
void queryHashes(std::vector<uint256>& vtxid);
void pruneSpent(const uint256& hash, CCoins &coins);
unsigned int GetTransactionsUpdated() const;
diff --git a/src/util.cpp b/src/util.cpp
index 8192a7c71c..e8514a2ef0 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -108,6 +108,7 @@ bool fDaemon = false;
bool fServer = false;
string strMiscWarning;
bool fLogTimestamps = false;
+bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
bool fLogIPs = false;
volatile bool fReopenDebugLog = false;
CTranslationInterface translationInterface;
@@ -263,9 +264,13 @@ static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine
if (!fLogTimestamps)
return str;
- if (*fStartedNewLine)
- strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str;
- else
+ if (*fStartedNewLine) {
+ int64_t nTimeMicros = GetLogTimeMicros();
+ strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000);
+ if (fLogTimeMicros)
+ strStamped += strprintf(".%06d", nTimeMicros%1000000);
+ strStamped += ' ' + str;
+ } else
strStamped = str;
if (!str.empty() && str[str.size()-1] == '\n')
diff --git a/src/util.h b/src/util.h
index 0b2dc01ac6..b2779fe782 100644
--- a/src/util.h
+++ b/src/util.h
@@ -28,6 +28,8 @@
#include <boost/signals2/signal.hpp>
#include <boost/thread/exceptions.hpp>
+static const bool DEFAULT_LOGTIMEMICROS = false;
+
/** Signals for translation. */
class CTranslationInterface
{
@@ -44,6 +46,7 @@ extern bool fPrintToDebugLog;
extern bool fServer;
extern std::string strMiscWarning;
extern bool fLogTimestamps;
+extern bool fLogTimeMicros;
extern bool fLogIPs;
extern volatile bool fReopenDebugLog;
extern CTranslationInterface translationInterface;
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index d316288999..3202c47f1d 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -40,6 +40,14 @@ int64_t GetTimeMicros()
boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
}
+/** Return a time useful for the debug log */
+int64_t GetLogTimeMicros()
+{
+ if (nMockTime) return nMockTime*1000000;
+
+ return GetTimeMicros();
+}
+
void MilliSleep(int64_t n)
{
diff --git a/src/utiltime.h b/src/utiltime.h
index 900992f871..241b5211e9 100644
--- a/src/utiltime.h
+++ b/src/utiltime.h
@@ -12,6 +12,7 @@
int64_t GetTime();
int64_t GetTimeMillis();
int64_t GetTimeMicros();
+int64_t GetLogTimeMicros();
void SetMockTime(int64_t nMockTimeIn);
void MilliSleep(int64_t n);