IBC#031: Bitcoin Core Initialization, Step 12: Ports Binding
Default ports and "-bind" input argument
Hello everyone and welcome to this new episode of Inside Bitcoin Code.
A special welcome to the new people that recently subscribed to this newsletter, I hope that you will enjoy what I write. A small suggestion for you: if you know nothing about coding, start reading the posts from Learn2Code to get some basic knowledge before diving in the real deal.
A huge thanks to each of the 194 subscribers of this newsletter and to those who decided to contribute with some sats to this project. It means the world to me!
We concluded the previous episode with discussing about the different connection options. Today, we continue our deep dive into step 12 of the initialization of Bitcoin Core, discussing about ports binding. [Code Link]
Let’s start!
Retrieve Default Ports
Port binding is a process that allows to tell the operative system on which IP address and port a certain process will be listening.
In the case of our node, the first step is to retrieve the default port number provided by the user through the -port input argument. The result is saved in the default_bind_port variable.
The static_cast<uint16_t>() function makes sure that the retrieved input has the correct type, uint16_t.
// Port to bind to if `-bind=addr` is provided without a `:port` suffix.
const uint16_t default_bind_port =
static_cast<uint16_t>(args.GetIntArg(”-port”, Params().GetDefaultPort()));The program also derives an onion port to bind to.
const uint16_t default_bind_port_onion = default_bind_port + 1;Finally, the code goes on to define a Lamba function, BadPortWarning() that returns a warning string in case a “bad” port — like a reserved one — is chosen.
const auto BadPortWarning = [](const char* prefix, uint16_t port) {
return strprintf(_(
”%s request to listen on port %u. This port is considered \”bad\” and “
“thus it is unlikely that any peer will connect to it. See “
“doc/p2p-bad-ports.md for details and a full list.”),
prefix,
port
);
};A document with a full list of “bad” ports is available here.
Consider supporting this newsletter by using one of my affiliate links. These are not sponsorships, just products I use everyday. Thank you!
Check Input Argument: -bind
Then, the program iterates with a range-based for loop over all the -bind input arguments provided by the user.
for (const std::string& bind_arg : args.GetArgs(”-bind”)) {
.
.
.
}Inside the loop, an std::optional variable is declared. This type of container stores a value that may or may not be present.
std::optional<CService> bind_addr;Then, the rfind method is used on the bind_arg string, in order to find the last occurrence of the = sign.
const size_t index = bind_arg.rfind(’=’);According to the result of this function, two different scenarios can happen.
if (index == std::string::npos) {
.
.
.
} else {
.
.
.
}1) ‘=’ Sign Not Found
The first case happens if the index variable acquires value std::string::npos, which means that = sign was not found. Our input looks like this:
192.168.1.5In this scenario, the Lookup() function is used to see if the address can be retrieved from the input argument. The function returns empty() if not.
bind_addr = Lookup(bind_arg, default_bind_port, /*fAllowLookup=*/false);If Lookup() returns a value, this value is added to the vBinds vector in the connOptions object.
Then, the value is also checked to see if the chosen port belongs to the “bad” ports list, using the IsBadPort() function. If so, it returns a warning through the BadPortWarning() Lambda.
Finally, the continue keyword allows the code to jump to the following iteration.
if (bind_addr.has_value()) {
connOptions.vBinds.push_back(bind_addr.value());
if (IsBadPort(bind_addr.value().GetPort())) {
InitWarning(BadPortWarning(”-bind”, bind_addr.value().GetPort()));
}
continue;
}2) ‘=’ Sign Found
On the other hand, if the argument contains an = sign it means that our input looks like this:
127.0.0.1=onionFirst of all, the code takes the sub-string from the = sign up to end and stores it in network_type.
const std::string network_type = bind_arg.substr(index + 1);Then, the string is checked to be equal to “onion”. If so, a sub-string containing the IP address — from 0 to index position — is stored in truncated_bind_arg.
The variable is given to the Lookup() function, which works as before.
if (network_type == “onion”) {
const std::string truncated_bind_arg = bind_arg.substr(0, index);
bind_addr = Lookup(truncated_bind_arg, default_bind_port_onion, false);If bind_addr has a value, it is added to the onion_binds vector in the connOptions object and the code moves to the following iteration.
if (bind_addr.has_value()) {
connOptions.onion_binds.push_back(bind_addr.value());
continue;
}On the other hand, if has_value() returns false and InitError is launched.
return InitError(ResolveErrMsg(”bind”, bind_arg));Hey Bitcoiner!
If you here with me diving into the Bitcoin code, consider tipping some sats via Lightning to support the series. ⚡
And remember: never trust, always verify!
Let’s keep in touch:
Check out my writings on btc++ insider edition
Try my new app Sats Tracker, an expense tracker app for people living in the Bitcoin standard.


