diff --git a/src/alert.cpp b/src/alert.cpp index eb1cd5e7f6ebe..9b79a3d62224c 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -121,7 +121,7 @@ bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const bool CAlert::AppliesToMe() const { - return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector())); + return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector(), 0)); } bool CAlert::RelayTo(CNode* pnode) const diff --git a/src/clientversion.cpp b/src/clientversion.cpp index aae0569bba211..9ab691668ed8e 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -7,6 +7,8 @@ #include "tinyformat.h" #include +#include +#include /** * Name of client reported in the 'version' message. Report the same name @@ -94,8 +96,18 @@ std::string FormatFullVersion() /** * Format the subversion field according to BIP 14 spec (https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki) */ -std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments) +std::string FormatSubVersion(const std::string& name, int nClientVersion, std::vector comments, uint64_t nMaxBlockSize) { + if (nMaxBlockSize) { + // Announce our excessive block acceptence. + comments.insert(comments.end(), std::string("BIP100")); + + std::stringstream ss; + double dMaxBlockSize = static_cast(nMaxBlockSize) / 1000000; + ss << "EB" << std::setprecision(static_cast(std::log10(dMaxBlockSize))+7) << dMaxBlockSize; + comments.insert(comments.end(), ss.str()); + } + std::ostringstream ss; ss << "/"; ss << name << ":" << FormatVersion(nClientVersion); diff --git a/src/clientversion.h b/src/clientversion.h index ab79da9b36b87..b3b648d2ff04f 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -50,6 +50,7 @@ #include #include +#include static const int CLIENT_VERSION = 1000000 * CLIENT_VERSION_MAJOR @@ -63,7 +64,7 @@ extern const std::string CLIENT_DATE; std::string FormatFullVersion(); -std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments); +std::string FormatSubVersion(const std::string& name, int nClientVersion, std::vector comments, uint64_t nMaxBlockSize); #endif // WINDRES_PREPROC diff --git a/src/init.cpp b/src/init.cpp index 03cae603c2aba..35552f3b6ec1c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1139,17 +1139,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterNodeSignals(GetNodeSignals()); // sanitize comments per BIP-0014, format user agent and check total size - std::vector uacomments; BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"]) { if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); - uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)); + vUAComments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)); } - strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); - if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { + uint64_t hugeBlock = static_cast((100000. / 3.) * MAX_BLOCK_SIZE); + size_t userAgentLen = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, vUAComments, hugeBlock).size(); + if (userAgentLen > MAX_SUBVERSION_LENGTH) { return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."), - strSubVersion.size(), MAX_SUBVERSION_LENGTH)); + userAgentLen, MAX_SUBVERSION_LENGTH)); } if (mapArgs.count("-onlynet")) { diff --git a/src/main.cpp b/src/main.cpp index eaa5ede611faa..e50a27e898b9e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -303,6 +303,12 @@ int GetHeight() return chainActive.Height(); } +int GetMaxBlockSize() +{ + LOCK(cs_main); + return chainActive.Tip()->nMaxBlockSize; +} + void UpdatePreferredDownload(CNode* node, CNodeState* state) { nPreferredDownload -= state->fPreferredDownload; @@ -572,6 +578,7 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals) nodeSignals.SendMessages.connect(&SendMessages); nodeSignals.InitializeNode.connect(&InitializeNode); nodeSignals.FinalizeNode.connect(&FinalizeNode); + nodeSignals.GetMaxBlockSize.connect(&GetMaxBlockSize); } void UnregisterNodeSignals(CNodeSignals& nodeSignals) @@ -582,6 +589,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) nodeSignals.SendMessages.disconnect(&SendMessages); nodeSignals.InitializeNode.disconnect(&InitializeNode); nodeSignals.FinalizeNode.disconnect(&FinalizeNode); + nodeSignals.GetMaxBlockSize.disconnect(&GetMaxBlockSize); } CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) @@ -4000,7 +4008,7 @@ bool LoadBlockIndex(bool* fRebuildRequired) return true; } -bool InitBlockIndex(const CChainParams& chainparams) +bool InitBlockIndex(const CChainParams& chainparams) { LOCK(cs_main); diff --git a/src/net.cpp b/src/net.cpp index ae69a0c730bdd..319f148f60603 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -84,7 +84,7 @@ static std::vector vhListenSocket; CAddrMan addrman; int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; bool fAddressesInitialized = false; -std::string strSubVersion; +std::vector vUAComments; vector vNodes; CCriticalSection cs_vNodes; @@ -442,6 +442,7 @@ void CNode::CloseSocketDisconnect() void CNode::PushVersion() { int nBestHeight = g_signals.GetHeight().get_value_or(0); + int nMaxBlockSize = g_signals.GetMaxBlockSize().get_value_or(0); int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0))); @@ -451,6 +452,7 @@ void CNode::PushVersion() LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id); else LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); + std::string strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, vUAComments, nMaxBlockSize); PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)); } @@ -2580,14 +2582,14 @@ bool CBanDB::Read(banmap_t& banSet) // ... verify the network matches ours if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) return error("%s: Invalid network magic number", __func__); - + // de-serialize address data into one CAddrMan object ssBanlist >> banSet; } catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } - + return true; } diff --git a/src/net.h b/src/net.h index a6801690f462f..b0c3d6339a621 100644 --- a/src/net.h +++ b/src/net.h @@ -119,6 +119,7 @@ struct CNodeSignals boost::signals2::signal SendMessages; boost::signals2::signal InitializeNode; boost::signals2::signal FinalizeNode; + boost::signals2::signal GetMaxBlockSize; }; @@ -174,8 +175,8 @@ extern CCriticalSection cs_vAddedNodes; extern NodeId nLastNodeId; extern CCriticalSection cs_nLastNodeId; -/** Subversion as sent to the P2P network in `version` messages */ -extern std::string strSubVersion; +/** Comments in subversion sent to the P2P network in `version` messages */ +extern std::vector vUAComments; struct LocalServiceInfo { int nScore; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index b4ac69639304b..74784e18372fa 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -183,7 +183,7 @@ QString ClientModel::formatFullVersion() const QString ClientModel::formatSubVersion() const { - return QString::fromStdString(strSubVersion); + return QString::fromStdString(FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, vUAComments, 0)); } QString ClientModel::formatBuildDate() const diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 779e7fbc6aa25..22c13a5e2cec6 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -466,7 +466,8 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); - obj.push_back(Pair("subversion", strSubVersion)); + obj.push_back(Pair("subversion", + FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, vUAComments, 0))); obj.push_back(Pair("protocolversion",PROTOCOL_VERSION)); obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); obj.push_back(Pair("timeoffset", GetTimeOffset())); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 517e6945cf9bc..4ecf97a6f0c5b 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -11,6 +11,7 @@ #include "utilstrencodings.h" #include "utilmoneystr.h" #include "test/test_bitcoin.h" +#include "consensus/consensus.h" #include #include @@ -419,9 +420,15 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion) std::vector comments2; comments2.push_back(std::string("comment1")); comments2.push_back(SanitizeString(std::string("Comment2; .,_?@-; !\"#$%&'()*+/<=>[]\\^`{|}~"), SAFE_CHARS_UA_COMMENT)); // Semicolon is discouraged but not forbidden by BIP-0014 - BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector()),std::string("/Test:0.9.99/")); - BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/")); - BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; Comment2; .,_?@-; )/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector(), 0),std::string("/Test:0.9.99/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments, 0),std::string("/Test:0.9.99(comment1)/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2, 0),std::string("/Test:0.9.99(comment1; Comment2; .,_?@-; )/")); + + // BIP100 + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector(), MAX_BLOCK_SIZE),std::string("/Test:0.9.99(BIP100; EB1)/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments, MAX_BLOCK_SIZE),std::string("/Test:0.9.99(comment1; BIP100; EB1)/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments, MAX_BLOCK_SIZE + (MAX_BLOCK_SIZE / 3)), + std::string("/Test:0.9.99(comment1; BIP100; EB1.333333)/")); } BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)