aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/amount.cpp20
-rw-r--r--src/amount.h11
-rw-r--r--src/chainparams.cpp4
-rw-r--r--src/main.cpp86
-rw-r--r--src/main.h18
-rw-r--r--src/netbase.cpp10
-rw-r--r--src/netbase.h3
-rw-r--r--src/policy/fees.h4
-rw-r--r--src/policy/policy.cpp4
-rw-r--r--src/rpc/blockchain.cpp30
-rw-r--r--src/rpc/client.cpp4
-rw-r--r--src/script/interpreter.cpp12
-rw-r--r--src/script/standard.h2
-rw-r--r--src/test/amount_tests.cpp29
-rw-r--r--src/txmempool.h40
-rw-r--r--src/utiltime.cpp2
-rw-r--r--src/wallet/wallet.h8
18 files changed, 183 insertions, 106 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 1e54512cbd..d91e959cff 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -479,7 +479,7 @@ endif
%.pb.cc %.pb.h: %.proto
@test -f $(PROTOC)
- $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(<D) $<)
+ $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(<D) $<
if ENABLE_TESTS
include Makefile.test.include
diff --git a/src/amount.cpp b/src/amount.cpp
index 68806ff062..7b8618de33 100644
--- a/src/amount.cpp
+++ b/src/amount.cpp
@@ -9,20 +9,30 @@
const std::string CURRENCY_UNIT = "BTC";
-CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize)
+CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)
{
+ assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
+ int64_t nSize = int64_t(nBytes_);
+
if (nSize > 0)
- nSatoshisPerK = nFeePaid*1000/nSize;
+ nSatoshisPerK = nFeePaid * 1000 / nSize;
else
nSatoshisPerK = 0;
}
-CAmount CFeeRate::GetFee(size_t nSize) const
+CAmount CFeeRate::GetFee(size_t nBytes_) const
{
+ assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
+ int64_t nSize = int64_t(nBytes_);
+
CAmount nFee = nSatoshisPerK * nSize / 1000;
- if (nFee == 0 && nSize != 0 && nSatoshisPerK > 0)
- nFee = CAmount(1);
+ if (nFee == 0 && nSize != 0) {
+ if (nSatoshisPerK > 0)
+ nFee = CAmount(1);
+ if (nSatoshisPerK < 0)
+ nFee = CAmount(-1);
+ }
return nFee;
}
diff --git a/src/amount.h b/src/amount.h
index 9aba6525c7..5e52f37f23 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <string>
+/** Amount in satoshis (Can be negative) */
typedef int64_t CAmount;
static const CAmount COIN = 100000000;
@@ -30,22 +31,24 @@ extern const std::string CURRENCY_UNIT;
static const CAmount MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
-/** Type-safe wrapper class for fee rates
- * (how much to pay based on transaction size)
+/**
+ * Fee rate in satoshis per kilobyte: CAmount / kB
*/
class CFeeRate
{
private:
CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
public:
+ /** Fee rate of 0 satoshis per kB */
CFeeRate() : nSatoshisPerK(0) { }
explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
- CFeeRate(const CAmount& nFeePaid, size_t nSize);
+ /** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
+ CFeeRate(const CAmount& nFeePaid, size_t nBytes);
CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
/**
* Return the fee in satoshis for the given size in bytes.
*/
- CAmount GetFee(size_t size) const;
+ CAmount GetFee(size_t nBytes) const;
/**
* Return the fee in satoshis for a size of 1000 bytes
*/
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 965d131695..5c7d190125 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -266,8 +266,8 @@ public:
assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
- vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds.
- vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds.
+ vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
+ vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds.
fMiningRequiresPeers = false;
fDefaultConsistencyChecks = true;
diff --git a/src/main.cpp b/src/main.cpp
index 2c0b3bfee7..9b164c7999 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -194,16 +194,11 @@ namespace {
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
uint256 hash;
- CBlockIndex *pindex; //! Optional.
- int64_t nTime; //! Time of "getdata" request in microseconds.
- bool fValidatedHeaders; //! Whether this block has validated headers at the time of request.
- int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer)
+ CBlockIndex* pindex; //!< Optional.
+ bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request.
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
- /** Number of blocks in flight with validated headers. */
- int nQueuedValidatedHeaders = 0;
-
/** Number of preferable block download peers. */
int nPreferredDownload = 0;
@@ -212,6 +207,9 @@ namespace {
/** Dirty block file entries. */
set<int> setDirtyFileInfo;
+
+ /** Number of peers from which we're downloading blocks. */
+ int nPeersWithValidatedDownloads = 0;
} // anon namespace
//////////////////////////////////////////////////////////////////////////////
@@ -259,6 +257,8 @@ struct CNodeState {
//! Since when we're stalling block download progress (in microseconds), or 0.
int64_t nStallingSince;
list<QueuedBlock> vBlocksInFlight;
+ //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
+ int64_t nDownloadingSince;
int nBlocksInFlight;
int nBlocksInFlightValidHeaders;
//! Whether we consider this a preferred download peer.
@@ -276,6 +276,7 @@ struct CNodeState {
pindexBestHeaderSent = NULL;
fSyncStarted = false;
nStallingSince = 0;
+ nDownloadingSince = 0;
nBlocksInFlight = 0;
nBlocksInFlightValidHeaders = 0;
fPreferredDownload = false;
@@ -310,12 +311,6 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
nPreferredDownload += state->fPreferredDownload;
}
-// Returns time at which to timeout block request (nTime in microseconds)
-int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams)
-{
- return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore);
-}
-
void InitializeNode(NodeId nodeid, const CNode *pnode) {
LOCK(cs_main);
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
@@ -335,13 +330,21 @@ void FinalizeNode(NodeId nodeid) {
}
BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) {
- nQueuedValidatedHeaders -= entry.fValidatedHeaders;
mapBlocksInFlight.erase(entry.hash);
}
EraseOrphansFor(nodeid);
nPreferredDownload -= state->fPreferredDownload;
+ nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
+ assert(nPeersWithValidatedDownloads >= 0);
mapNodeState.erase(nodeid);
+
+ if (mapNodeState.empty()) {
+ // Do a consistency check after the last peer is removed.
+ assert(mapBlocksInFlight.empty());
+ assert(nPreferredDownload == 0);
+ assert(nPeersWithValidatedDownloads == 0);
+ }
}
// Requires cs_main.
@@ -350,8 +353,15 @@ bool MarkBlockAsReceived(const uint256& hash) {
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first);
- nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders;
state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
+ if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) {
+ // Last validated block on the queue was received.
+ nPeersWithValidatedDownloads--;
+ }
+ if (state->vBlocksInFlight.begin() == itInFlight->second.second) {
+ // First block on the queue was received, update the start download time for the next one
+ state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros());
+ }
state->vBlocksInFlight.erase(itInFlight->second.second);
state->nBlocksInFlight--;
state->nStallingSince = 0;
@@ -369,12 +379,17 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa
// Make sure it's not listed somewhere already.
MarkBlockAsReceived(hash);
- int64_t nNow = GetTimeMicros();
- QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)};
- nQueuedValidatedHeaders += newentry.fValidatedHeaders;
+ QueuedBlock newentry = {hash, pindex, pindex != NULL};
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
state->nBlocksInFlight++;
state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders;
+ if (state->nBlocksInFlight == 1) {
+ // We're starting a block download (batch) from this peer.
+ state->nDownloadingSince = GetTimeMicros();
+ }
+ if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL) {
+ nPeersWithValidatedDownloads++;
+ }
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
}
@@ -1010,6 +1025,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (fRequireStandard && !IsStandardTx(tx, reason))
return state.DoS(0, false, REJECT_NONSTANDARD, reason);
+ // Don't relay version 2 transactions until CSV is active, and we can be
+ // sure that such transactions will be mined (unless we're on
+ // -testnet/-regtest).
+ const CChainParams& chainparams = Params();
+ if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) {
+ return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx");
+ }
+
// 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.
@@ -2877,6 +2900,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
CBlockIndex *pindexMostWork = NULL;
do {
boost::this_thread::interruption_point();
+ if (ShutdownRequested())
+ break;
CBlockIndex *pindexNewTip = NULL;
const CBlockIndex *pindexFork;
@@ -3894,7 +3919,6 @@ void UnloadBlockIndex()
nBlockSequenceId = 1;
mapBlockSource.clear();
mapBlocksInFlight.clear();
- nQueuedValidatedHeaders = 0;
nPreferredDownload = 0;
setDirtyBlockIndex.clear();
setDirtyFileInfo.clear();
@@ -4475,9 +4499,8 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
}
-bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
+bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams)
{
- const CChainParams& chainparams = Params();
RandAddSeedPerfmon();
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
@@ -5487,7 +5510,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false;
try
{
- fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime);
+ fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams);
boost::this_thread::interruption_point();
}
catch (const std::ios_base::failure& e)
@@ -5811,24 +5834,15 @@ bool SendMessages(CNode* pto)
LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id);
pto->fDisconnect = true;
}
- // In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval
- // (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to
- // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
+ // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval
+ // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout.
+ // We compensate for other peers to prevent killing off peers due to our own downstream link
// being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
// to unreasonably increase our timeout.
- // We also compare the block download timeout originally calculated against the time at which we'd disconnect
- // if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're
- // only looking at this peer's oldest request). This way a large queue in the past doesn't result in a
- // permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing
- // more quickly than once every 5 minutes, then we'll shorten the download window for this block).
if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) {
QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
- int64_t nTimeoutIfRequestedNow = GetBlockTimeout(nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders, consensusParams);
- if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) {
- LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow);
- queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow;
- }
- if (queuedBlock.nTimeDisconnect < nNow) {
+ int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0);
+ if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) {
LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id);
pto->fDisconnect = true;
}
diff --git a/src/main.h b/src/main.h
index 0bfcfab213..0962f44e94 100644
--- a/src/main.h
+++ b/src/main.h
@@ -106,6 +106,10 @@ static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5;
static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
/** Maximum feefilter broadcast delay after significant change. */
static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
+/** Block download timeout base, expressed in millionths of the block interval (i.e. 10 min) */
+static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
+/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */
+static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000;
static const unsigned int DEFAULT_LIMITFREERELAY = 15;
static const bool DEFAULT_RELAYPRIORITY = true;
@@ -469,13 +473,13 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
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
+ 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;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 7f79dd02c6..281c6bcb7f 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -170,7 +170,8 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
if (aiTrav->ai_family == AF_INET6)
{
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
- vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr));
+ struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
+ vIP.push_back(CNetAddr(s6->sin6_addr, s6->sin6_scope_id));
}
aiTrav = aiTrav->ai_next;
@@ -629,6 +630,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
void CNetAddr::Init()
{
memset(ip, 0, sizeof(ip));
+ scopeId = 0;
}
void CNetAddr::SetIP(const CNetAddr& ipIn)
@@ -678,9 +680,10 @@ CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr);
}
-CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr)
+CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope)
{
SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr);
+ scopeId = scope;
}
CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup)
@@ -1099,7 +1102,7 @@ CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), po
assert(addr.sin_family == AF_INET);
}
-CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port))
+CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port))
{
assert(addr.sin6_family == AF_INET6);
}
@@ -1192,6 +1195,7 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
memset(paddrin6, 0, *addrlen);
if (!GetIn6Addr(&paddrin6->sin6_addr))
return false;
+ paddrin6->sin6_scope_id = scopeId;
paddrin6->sin6_family = AF_INET6;
paddrin6->sin6_port = htons(port);
return true;
diff --git a/src/netbase.h b/src/netbase.h
index 1db66ac27f..db736154fa 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -44,6 +44,7 @@ class CNetAddr
{
protected:
unsigned char ip[16]; // in network byte order
+ uint32_t scopeId; // for scoped/link-local ipv6 addresses
public:
CNetAddr();
@@ -89,7 +90,7 @@ class CNetAddr
std::vector<unsigned char> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
- CNetAddr(const struct in6_addr& pipv6Addr);
+ CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
friend bool operator==(const CNetAddr& a, const CNetAddr& b);
diff --git a/src/policy/fees.h b/src/policy/fees.h
index cdd984de7d..463f62f710 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -265,8 +265,8 @@ public:
void Read(CAutoFile& filein);
private:
- CFeeRate minTrackedFee; //! Passed to constructor to avoid dependency on main
- double minTrackedPriority; //! Set to AllowFreeThreshold
+ CFeeRate minTrackedFee; //!< Passed to constructor to avoid dependency on main
+ double minTrackedPriority; //!< Set to AllowFreeThreshold
unsigned int nBestSeenHeight;
struct TxStatsInfo
{
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index e3ed7be000..d1a15451dc 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -73,12 +73,12 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
- // keys. (remember the 520 byte limit on redeemScript size) That works
+ // keys (remember the 520 byte limit on redeemScript size). That works
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
// bytes of scriptSig, which we round off to 1650 bytes for some minor
// future-proofing. That's also enough to spend a 20-of-20
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
- // considered standard)
+ // considered standard.
if (txin.scriptSig.size() > 1650) {
reason = "scriptsig-size";
return false;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index f1c9d9f7ab..7a01a10b7d 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -70,6 +70,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", blockindex->nVersion));
+ result.push_back(Pair("versionHex", strprintf("%08x", blockindex->nVersion)));
result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex()));
result.push_back(Pair("time", (int64_t)blockindex->nTime));
result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
@@ -98,6 +99,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
+ result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion)));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
UniValue txs(UniValue::VARR);
BOOST_FOREACH(const CTransaction&tx, block.vtx)
@@ -316,6 +318,7 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
" \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
" \"height\" : n, (numeric) The block height or index\n"
" \"version\" : n, (numeric) The block version\n"
+ " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n"
" \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
" \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
@@ -375,6 +378,7 @@ UniValue getblock(const UniValue& params, bool fHelp)
" \"size\" : n, (numeric) The block size\n"
" \"height\" : n, (numeric) The block height or index\n"
" \"version\" : n, (numeric) The block version\n"
+ " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n"
" \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
" \"tx\" : [ (array of string) The transaction ids\n"
" \"transactionid\" (string) The transaction id\n"
@@ -604,17 +608,23 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex*
return rv;
}
-static UniValue BIP9SoftForkDesc(const std::string& name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
+static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
{
UniValue rv(UniValue::VOBJ);
- rv.push_back(Pair("id", name));
- switch (VersionBitsTipState(consensusParams, id)) {
+ const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id);
+ switch (thresholdState) {
case THRESHOLD_DEFINED: rv.push_back(Pair("status", "defined")); break;
case THRESHOLD_STARTED: rv.push_back(Pair("status", "started")); break;
case THRESHOLD_LOCKED_IN: rv.push_back(Pair("status", "locked_in")); break;
case THRESHOLD_ACTIVE: rv.push_back(Pair("status", "active")); break;
case THRESHOLD_FAILED: rv.push_back(Pair("status", "failed")); break;
}
+ if (THRESHOLD_STARTED == thresholdState)
+ {
+ rv.push_back(Pair("bit", consensusParams.vDeployments[id].bit));
+ }
+ rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime));
+ rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout));
return rv;
}
@@ -649,12 +659,14 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
" }, ...\n"
" ],\n"
- " \"bip9_softforks\": [ (array) status of BIP9 softforks in progress\n"
- " {\n"
- " \"id\": \"xxxx\", (string) name of the softfork\n"
+ " \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
+ " \"xxxx\" : { (string) name of the softfork\n"
" \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"lockedin\", \"active\", \"failed\"\n"
+ " \"bit\": xx, (numeric) the bit, 0-28, in the block version field used to signal this soft fork\n"
+ " \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
+ " \"timeout\": xx (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
" }\n"
- " ]\n"
+ " }\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
@@ -677,11 +689,11 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
const Consensus::Params& consensusParams = Params().GetConsensus();
CBlockIndex* tip = chainActive.Tip();
UniValue softforks(UniValue::VARR);
- UniValue bip9_softforks(UniValue::VARR);
+ UniValue bip9_softforks(UniValue::VOBJ);
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
- bip9_softforks.push_back(BIP9SoftForkDesc("csv", consensusParams, Consensus::DEPLOYMENT_CSV));
+ bip9_softforks.push_back(Pair("csv", BIP9SoftForkDesc(consensusParams, Consensus::DEPLOYMENT_CSV)));
obj.push_back(Pair("softforks", softforks));
obj.push_back(Pair("bip9_softforks", bip9_softforks));
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index b040d2bc80..c89af6bfa7 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -18,8 +18,8 @@ using namespace std;
class CRPCConvertParam
{
public:
- std::string methodName; //! method whose params want conversion
- int paramIdx; //! 0-based idx of param to convert
+ std::string methodName; //!< method whose params want conversion
+ int paramIdx; //!< 0-based idx of param to convert
};
static const CRPCConvertParam vRPCConvertParams[] =
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 149a4f0156..9c47f7c6c9 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1015,12 +1015,12 @@ namespace {
*/
class CTransactionSignatureSerializer {
private:
- const CTransaction &txTo; //! reference to the spending transaction (the one being serialized)
- const CScript &scriptCode; //! output script being consumed
- const unsigned int nIn; //! input index of txTo being signed
- const bool fAnyoneCanPay; //! whether the hashtype has the SIGHASH_ANYONECANPAY flag set
- const bool fHashSingle; //! whether the hashtype is SIGHASH_SINGLE
- const bool fHashNone; //! whether the hashtype is SIGHASH_NONE
+ const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized)
+ const CScript& scriptCode; //!< output script being consumed
+ const unsigned int nIn; //!< input index of txTo being signed
+ const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set
+ const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE
+ const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE
public:
CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
diff --git a/src/script/standard.h b/src/script/standard.h
index 64bf010ec1..f348da8e19 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -27,7 +27,7 @@ public:
CScriptID(const uint160& in) : uint160(in) {}
};
-static const unsigned int MAX_OP_RETURN_RELAY = 83; //! bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
+static const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
extern bool fAcceptDatacarrier;
extern unsigned nMaxDatacarrierBytes;
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index 59dab20633..fd6f88b366 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -27,6 +27,15 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1e3);
BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9e3);
+ feeRate = CFeeRate(-1000);
+ // Must always just return -1 * arg
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1), -1);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(121), -121);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(999), -999);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), -1e3);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), -9e3);
+
feeRate = CFeeRate(123);
// Truncates the result, if not integer
BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
@@ -37,6 +46,26 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK_EQUAL(feeRate.GetFee(999), 122);
BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 123);
BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 1107);
+
+ feeRate = CFeeRate(-123);
+ // Truncates the result, if not integer
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(8), -1); // Special case: returns -1 instead of 0
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9), -1);
+
+ // Check full constructor
+ // default value
+ BOOST_CHECK(CFeeRate(CAmount(-1), 1000) == CFeeRate(-1));
+ BOOST_CHECK(CFeeRate(CAmount(0), 1000) == CFeeRate(0));
+ BOOST_CHECK(CFeeRate(CAmount(1), 1000) == CFeeRate(1));
+ // lost precision (can only resolve satoshis per kB)
+ BOOST_CHECK(CFeeRate(CAmount(1), 1001) == CFeeRate(0));
+ BOOST_CHECK(CFeeRate(CAmount(2), 1001) == CFeeRate(1));
+ // some more integer checks
+ BOOST_CHECK(CFeeRate(CAmount(26), 789) == CFeeRate(32));
+ BOOST_CHECK(CFeeRate(CAmount(27), 789) == CFeeRate(34));
+ // Maximum size in bytes, should not crash
+ CFeeRate(MAX_MONEY, std::numeric_limits<size_t>::max() >> 1).GetFeePerK();
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txmempool.h b/src/txmempool.h
index 9dbb37dad0..de4ba0b371 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -74,28 +74,28 @@ class CTxMemPoolEntry
{
private:
CTransaction tx;
- CAmount nFee; //! Cached to avoid expensive parent-transaction lookups
- size_t nTxSize; //! ... and avoid recomputing tx size
- size_t nModSize; //! ... and modified size for priority
- size_t nUsageSize; //! ... and total memory usage
- int64_t nTime; //! Local time when entering the mempool
- double entryPriority; //! Priority when entering the mempool
- unsigned int entryHeight; //! Chain height when entering the mempool
- bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool
- CAmount inChainInputValue; //! Sum of all txin values that are already in blockchain
- bool spendsCoinbase; //! keep track of transactions that spend a coinbase
- unsigned int sigOpCount; //! Legacy sig ops plus P2SH sig op count
- int64_t feeDelta; //! Used for determining the priority of the transaction for mining in a block
- LockPoints lockPoints; //! Track the height and time at which tx was final
+ CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
+ size_t nTxSize; //!< ... and avoid recomputing tx size
+ size_t nModSize; //!< ... and modified size for priority
+ size_t nUsageSize; //!< ... and total memory usage
+ int64_t nTime; //!< Local time when entering the mempool
+ double entryPriority; //!< Priority when entering the mempool
+ unsigned int entryHeight; //!< Chain height when entering the mempool
+ bool hadNoDependencies; //!< Not dependent on any other txs when it entered the mempool
+ CAmount inChainInputValue; //!< Sum of all txin values that are already in blockchain
+ bool spendsCoinbase; //!< keep track of transactions that spend a coinbase
+ unsigned int sigOpCount; //!< Legacy sig ops plus P2SH sig op count
+ int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block
+ LockPoints lockPoints; //!< Track the height and time at which tx was final
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
// descendants as well. if nCountWithDescendants is 0, treat this entry as
// dirty, and nSizeWithDescendants and nModFeesWithDescendants will not be
// correct.
- uint64_t nCountWithDescendants; //! number of descendant transactions
- uint64_t nSizeWithDescendants; //! ... and size
- CAmount nModFeesWithDescendants; //! ... and total fees (all including us)
+ uint64_t nCountWithDescendants; //!< number of descendant transactions
+ uint64_t nSizeWithDescendants; //!< ... and size
+ CAmount nModFeesWithDescendants; //!< ... and total fees (all including us)
// Analogous statistics for ancestor transactions
uint64_t nCountWithAncestors;
@@ -399,18 +399,18 @@ public:
class CTxMemPool
{
private:
- uint32_t nCheckFrequency; //! Value n means that n times in 2^32 we check.
+ uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check.
unsigned int nTransactionsUpdated;
CBlockPolicyEstimator* minerPolicyEstimator;
- uint64_t totalTxSize; //! sum of all mempool tx' byte sizes
- uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves)
+ uint64_t totalTxSize; //!< sum of all mempool tx' byte sizes
+ uint64_t cachedInnerUsage; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves)
CFeeRate minReasonableRelayFee;
mutable int64_t lastRollingFeeUpdate;
mutable bool blockSinceLastRollingFeeBump;
- mutable double rollingMinimumFeeRate; //! minimum fee to get into the pool, decreases exponentially
+ mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially
void trackPackageRemoved(const CFeeRate& rate);
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index 91b40d9991..da590f8889 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -14,7 +14,7 @@
using namespace std;
-static int64_t nMockTime = 0; //! For unit testing
+static int64_t nMockTime = 0; //!< For unit testing
int64_t GetTime()
{
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 867f33a7b5..96d5d4e1e0 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -228,11 +228,11 @@ public:
mapValue_t mapValue;
std::vector<std::pair<std::string, std::string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime;
- unsigned int nTimeReceived; //! time received by this node
+ unsigned int nTimeReceived; //!< time received by this node
unsigned int nTimeSmart;
char fFromMe;
std::string strFromAccount;
- int64_t nOrderPos; //! position in ordered transaction list
+ int64_t nOrderPos; //!< position in ordered transaction list
// memory only
mutable bool fDebitCached;
@@ -324,7 +324,7 @@ public:
}
READWRITE(*(CMerkleTx*)this);
- std::vector<CMerkleTx> vUnused; //! Used to be vtxPrev
+ std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
READWRITE(vUnused);
READWRITE(mapValue);
READWRITE(vOrderForm);
@@ -465,7 +465,7 @@ public:
std::string strOtherAccount;
std::string strComment;
mapValue_t mapValue;
- int64_t nOrderPos; //! position in ordered transaction list
+ int64_t nOrderPos; //!< position in ordered transaction list
uint64_t nEntryNo;
CAccountingEntry()