Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions doc/release-notes-dogmode-user-agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
$DOG Mode user agent
====================

P2P
---

- The user agent names $DOG Mode after Bitcoin Core's own component, for
example `/Satoshi:31.1.0/DOGMode:20260902/`, the way Bitcoin Knots names
itself. A peer, a DNS seed's crawler, `getpeerinfo` and `getnetworkinfo` can
now tell a $DOG Mode node, and which release it runs, from plain Bitcoin
Core. The Bitcoin Core component is unchanged, and `-uacomment` comments
still attach to it.
9 changes: 9 additions & 0 deletions src/clientversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ using util::Join;
*/
const std::string UA_NAME("Satoshi");

/**
* $DOG Mode's name and version, reported in the 'version' message as a second
* BIP 14 component after the Bitcoin Core one above, the way Bitcoin Knots
* reports itself: "/Satoshi:31.1.0/DOGMode:20260902/". The Bitcoin Core
* component stays first and unchanged. The version is a date (YYYYMMDD), as
* BIP 14 recommends; set it to the release date when a release is tagged.
*/
const std::string UA_DOGMODE("DOGMode:20260902");


#include <bitcoin-build-info.h>
// The <bitcoin-build-info.h>, which is generated by the build environment (cmake/script/GenerateBuildInfo.cmake),
Expand Down
1 change: 1 addition & 0 deletions src/clientversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ static const int CLIENT_VERSION =
+ 1 * CLIENT_VERSION_BUILD;

extern const std::string UA_NAME;
extern const std::string UA_DOGMODE;


std::string FormatFullVersion();
Expand Down
2 changes: 1 addition & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1679,7 +1679,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
uacomments.push_back(cmt);
}
strSubVersion = FormatSubVersion(UA_NAME, CLIENT_VERSION, uacomments);
strSubVersion = FormatSubVersion(UA_NAME, CLIENT_VERSION, uacomments) + UA_DOGMODE + "/";
if (strSubVersion.size() > 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));
Expand Down
12 changes: 6 additions & 6 deletions test/functional/feature_includeconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ def run_test(self):
f.write("uacomment=main\nincludeconf=relative.conf\n")
self.restart_node(0)

self.log.info("-includeconf works from config file. subversion should end with 'main; relative)/'")
self.log.info("-includeconf works from config file. subversion should contain 'main; relative)/'")

subversion = self.nodes[0].getnetworkinfo()["subversion"]
assert subversion.endswith("main; relative)/")
assert "main; relative)/" in subversion

self.log.info("-includeconf cannot be used as command-line arg")
self.stop_node(0)
Expand All @@ -49,13 +49,13 @@ def run_test(self):
expected_msg='Error: Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf="relative2.conf"',
)

self.log.info("-includeconf cannot be used recursively. subversion should end with 'main; relative)/'")
self.log.info("-includeconf cannot be used recursively. subversion should contain 'main; relative)/'")
with open(self.nodes[0].datadir_path / "relative.conf", "a") as f:
f.write("includeconf=relative2.conf\n")
self.start_node(0)

subversion = self.nodes[0].getnetworkinfo()["subversion"]
assert subversion.endswith("main; relative)/")
assert "main; relative)/" in subversion
self.stop_node(0, expected_stderr="warning: -includeconf cannot be used from included files; ignoring -includeconf=relative2.conf")

self.log.info("-includeconf cannot contain invalid arg")
Expand All @@ -69,7 +69,7 @@ def run_test(self):
(self.nodes[0].datadir_path / "relative.conf").unlink()
self.nodes[0].assert_start_raises_init_error(expected_msg="Error: Error reading configuration file: Failed to include configuration file relative.conf")

self.log.info("multiple -includeconf args can be used from the base config file. subversion should end with 'main; relative; relative2)/'")
self.log.info("multiple -includeconf args can be used from the base config file. subversion should contain 'main; relative; relative2)/'")
with open(self.nodes[0].datadir_path / "relative.conf", "w") as f:
# Restore initial file contents
f.write("uacomment=relative\n")
Expand All @@ -80,7 +80,7 @@ def run_test(self):
self.start_node(0)

subversion = self.nodes[0].getnetworkinfo()["subversion"]
assert subversion.endswith("main; relative; relative2)/")
assert "main; relative; relative2)/" in subversion

if __name__ == '__main__':
IncludeConfTest(__file__).main()
17 changes: 11 additions & 6 deletions test/functional/feature_uacomment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
# Copyright (c) 2017-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the -uacomment option."""
"""Test the -uacomment option, and the $DOG Mode component of the user agent."""

import re

from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
from test_framework.test_node import ErrorMatch
from test_framework.util import assert_equal
Expand All @@ -17,13 +18,17 @@ def set_test_params(self):
self.setup_clean_chain = True

def run_test(self):
self.log.info("test multiple -uacomment")
test_uacomment = self.nodes[0].getnetworkinfo()["subversion"][-12:-1]
assert_equal(test_uacomment, "(testnode0)")
self.log.info("test multiple -uacomment, on the Bitcoin Core component, followed by the $DOG Mode one")
test_uacomment = self.nodes[0].getnetworkinfo()["subversion"]
assert re.fullmatch(r"/Satoshi:\d+\.\d+\.\d+\(testnode0\)/DOGMode:[^/:()]+/", test_uacomment), test_uacomment

self.restart_node(0, ["-uacomment=foo"])
foo_uacomment = self.nodes[0].getnetworkinfo()["subversion"][-17:-1]
assert_equal(foo_uacomment, "(testnode0; foo)")
foo_uacomment = self.nodes[0].getnetworkinfo()["subversion"]
assert re.fullmatch(r"/Satoshi:\d+\.\d+\.\d+\(testnode0; foo\)/DOGMode:[^/:()]+/", foo_uacomment), foo_uacomment

self.log.info("test peers receive the same user agent")
peer = self.nodes[0].add_p2p_connection(P2PInterface())
assert_equal(peer.last_message["version"].strSubVer, foo_uacomment)

self.log.info("test -uacomment max length")
self.stop_node(0)
Expand Down