diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/amount.cpp | 20 | ||||
-rw-r--r-- | src/amount.h | 11 | ||||
-rw-r--r-- | src/chainparams.cpp | 4 | ||||
-rw-r--r-- | src/main.cpp | 86 | ||||
-rw-r--r-- | src/main.h | 18 | ||||
-rw-r--r-- | src/netbase.cpp | 10 | ||||
-rw-r--r-- | src/netbase.h | 3 | ||||
-rw-r--r-- | src/policy/fees.h | 4 | ||||
-rw-r--r-- | src/policy/policy.cpp | 4 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 30 | ||||
-rw-r--r-- | src/rpc/client.cpp | 4 | ||||
-rw-r--r-- | src/script/interpreter.cpp | 12 | ||||
-rw-r--r-- | src/script/standard.h | 2 | ||||
-rw-r--r-- | src/test/amount_tests.cpp | 29 | ||||
-rw-r--r-- | src/txmempool.h | 40 | ||||
-rw-r--r-- | src/utiltime.cpp | 2 | ||||
-rw-r--r-- | src/wallet/wallet.h | 8 |
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() |