Skip to content

Commit

Permalink
init, net: Implement usage of binary-embedded asmap data
Browse files Browse the repository at this point in the history
  • Loading branch information
fjahr committed Sep 1, 2024
1 parent 27cb982 commit c414548
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 14 deletions.
48 changes: 42 additions & 6 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
#include <rpc/util.h>
#include <scheduler.h>
#include <script/sigcache.h>
#include <span.h>
#include <sync.h>
#include <torcontrol.h>
#include <txdb.h>
Expand Down Expand Up @@ -114,6 +115,10 @@
#include <zmq/zmqrpc.h>
#endif

#ifdef ENABLE_EMBEDDED_ASMAP
#include <init/ip_asn.h>
#endif

using common::AmountErrMsg;
using common::InvalidPortErrMsg;
using common::ResolveErrMsg;
Expand Down Expand Up @@ -1243,21 +1248,52 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)

{

// Read asmap file if configured
// Read asmap file or embedded data if configured
std::vector<bool> asmap;
if (args.IsArgSet("-asmap")) {
const bool asmap_file_set{args.GetPathArg("-asmap") != ""};
fs::path asmap_path = args.GetPathArg("-asmap", DEFAULT_ASMAP_FILENAME);
if (!asmap_path.is_absolute()) {
asmap_path = args.GetDataDirNet() / asmap_path;
}
if (!fs::exists(asmap_path)) {

// If a specific path was passed with the asmap argument check if
// the file actually exists in that location
if (!fs::exists(asmap_path) && asmap_file_set) {
InitError(strprintf(_("Could not find asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
return false;
}
asmap = DecodeAsmap(asmap_path);
if (asmap.size() == 0) {
InitError(strprintf(_("Could not parse asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
return false;

if (fs::exists(asmap_path)) {
// If a file exists at the path (could be passed or the default
// location), try to read the file
asmap = DecodeAsmap(asmap_path);
if (asmap.empty()) {
// If the file could not be read, print the error depending
// on if it was passed or the default location
if (asmap_file_set) {
InitError(strprintf(_("Could not parse asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
} else {
InitError(strprintf(_("Could not parse asmap file in default location %s"), fs::quoted(fs::PathToString(asmap_path))));
}
return false;
}
} else {
#ifdef ENABLE_EMBEDDED_ASMAP
// If the file doesn't exist, try to use the embedded data
Span<const unsigned char> asmap_data(reinterpret_cast<const unsigned char*>(ip_asn), static_cast<size_t>(ip_asn_len));
asmap = DecodeAsmap(asmap_data);
if (asmap.empty()) {
InitError(strprintf(_("Could not read embedded asmap data")));
return false;
}
#else
// If there is no embedded data, fail and report the default
// file as missing since we only end up here if the no
// specific path was passed as an argument
InitError(strprintf(_("Could not find asmap file in default location %s"), fs::quoted(fs::PathToString(asmap_path))));
return false;
#endif
}
const uint256 asmap_version = (HashWriter{} << asmap).GetHash();
LogPrintf("Using asmap version %s for IP bucketing\n", asmap_version.ToString());
Expand Down
32 changes: 24 additions & 8 deletions test/functional/feature_asmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def test_asmap_with_relative_path(self):
self.start_node(0, [f'-asmap={name}'])
os.remove(filename)

def test_default_asmap(self):
def test_default_asmap_file(self):
shutil.copyfile(self.asmap_raw, self.default_asmap)
for arg in ['-asmap', '-asmap=']:
self.log.info(f'Test bitcoind {arg} (using default map file)')
Expand All @@ -82,6 +82,20 @@ def test_default_asmap(self):
self.start_node(0, [arg])
os.remove(self.default_asmap)

def test_embedded_asmap(self):
if self.is_embedded_asmap_compiled():
for arg in ['-asmap', '-asmap=1']:
self.log.info(f'Test bitcoind {arg} (using embedded map data)')
self.stop_node(0)
with self.node.assert_debug_log(["Opened asmap data", "from embedded byte array"]):
self.start_node(0, [arg])
else:
self.stop_node(0)
for arg in ['-asmap', '-asmap=1']:
self.log.info(f'Test bitcoind {arg} (compiled without embedded map data)')
msg = f"Error: Could not find asmap file in default location \"{self.default_asmap}\""
self.node.assert_start_raises_init_error(extra_args=[arg], expected_msg=msg)

def test_asmap_interaction_with_addrman_containing_entries(self):
self.log.info("Test bitcoind -asmap restart with addrman containing new and tried entries")
self.stop_node(0)
Expand All @@ -98,18 +112,19 @@ def test_asmap_interaction_with_addrman_containing_entries(self):
self.node.getnodeaddresses() # getnodeaddresses re-runs the addrman checks
os.remove(self.default_asmap)

def test_default_asmap_with_missing_file(self):
self.log.info('Test bitcoind -asmap with missing default map file')
def test_asmap_with_missing_file(self):
self.log.info('Test bitcoind -asmap= with missing map file')
self.stop_node(0)
msg = f"Error: Could not find asmap file \"{self.default_asmap}\""
self.node.assert_start_raises_init_error(extra_args=['-asmap'], expected_msg=msg)
bogus_map = os.path.join(self.datadir, "bogus.map")
msg = f"Error: Could not find asmap file \"{bogus_map}\""
self.node.assert_start_raises_init_error(extra_args=[f"-asmap={bogus_map}"], expected_msg=msg)

def test_empty_asmap(self):
self.log.info('Test bitcoind -asmap with empty map file')
self.stop_node(0)
with open(self.default_asmap, "w", encoding="utf-8") as f:
f.write("")
msg = f"Error: Could not parse asmap file \"{self.default_asmap}\""
msg = f"Error: Could not parse asmap file in default location \"{self.default_asmap}\""
self.node.assert_start_raises_init_error(extra_args=['-asmap'], expected_msg=msg)
os.remove(self.default_asmap)

Expand Down Expand Up @@ -139,9 +154,10 @@ def run_test(self):
self.test_without_asmap_arg()
self.test_asmap_with_absolute_path()
self.test_asmap_with_relative_path()
self.test_default_asmap()
self.test_default_asmap_file()
self.test_embedded_asmap()
self.test_asmap_interaction_with_addrman_containing_entries()
self.test_default_asmap_with_missing_file()
self.test_asmap_with_missing_file()
self.test_empty_asmap()
self.test_asmap_health_check()

Expand Down

0 comments on commit c414548

Please sign in to comment.