mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-11 22:43:06 +02:00
rpc: Add exportasmap RPC
This commit is contained in:
@@ -9,12 +9,17 @@
|
||||
#include <banman.h>
|
||||
#include <chainparams.h>
|
||||
#include <clientversion.h>
|
||||
#include <common/args.h>
|
||||
#include <core_io.h>
|
||||
#include <hash.h>
|
||||
#include <net_permissions.h>
|
||||
#include <net_processing.h>
|
||||
#include <net_types.h>
|
||||
#include <netbase.h>
|
||||
#include <node/context.h>
|
||||
#ifdef ENABLE_EMBEDDED_ASMAP
|
||||
#include <node/data/ip_asn.dat.h>
|
||||
#endif
|
||||
#include <node/protocol_version.h>
|
||||
#include <node/warnings.h>
|
||||
#include <policy/settings.h>
|
||||
@@ -25,6 +30,7 @@
|
||||
#include <rpc/util.h>
|
||||
#include <sync.h>
|
||||
#include <univalue.h>
|
||||
#include <util/asmap.h>
|
||||
#include <util/chaintype.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
@@ -1116,6 +1122,59 @@ static RPCMethod getaddrmaninfo()
|
||||
};
|
||||
}
|
||||
|
||||
static RPCMethod exportasmap()
|
||||
{
|
||||
return RPCMethod{
|
||||
"exportasmap",
|
||||
"Export the embedded ASMap data to a file. Any existing file at the path will be overwritten.\n",
|
||||
{
|
||||
{"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
{RPCResult::Type::STR, "path", "the absolute path that the ASMap data was written to"},
|
||||
{RPCResult::Type::NUM, "bytes_written", "the number of bytes written to the file"},
|
||||
{RPCResult::Type::STR_HEX, "file_hash", "the SHA256 hash of the exported ASMap data"},
|
||||
}
|
||||
},
|
||||
RPCExamples{
|
||||
HelpExampleCli("exportasmap", "\"asmap.dat\"") + HelpExampleRpc("exportasmap", "\"asmap.dat\"")},
|
||||
[&](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
|
||||
#ifndef ENABLE_EMBEDDED_ASMAP
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "No embedded ASMap data available");
|
||||
#else
|
||||
if (node::data::ip_asn.empty() || !CheckStandardAsmap(node::data::ip_asn)) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Embedded ASMap data appears to be corrupted");
|
||||
}
|
||||
|
||||
const ArgsManager& args{EnsureAnyArgsman(request.context)};
|
||||
const fs::path export_path{fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(self.Arg<std::string_view>("path")))};
|
||||
|
||||
AutoFile file{fsbridge::fopen(export_path, "wb")};
|
||||
if (file.IsNull()) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to open asmap file: %s", fs::PathToString(export_path)));
|
||||
}
|
||||
|
||||
file << node::data::ip_asn;
|
||||
|
||||
if (file.fclose() != 0) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to close asmap file: %s", fs::PathToString(export_path)));
|
||||
}
|
||||
|
||||
HashWriter hasher;
|
||||
hasher.write(node::data::ip_asn);
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("path", export_path.utf8string());
|
||||
result.pushKV("bytes_written", (uint64_t)node::data::ip_asn.size());
|
||||
result.pushKV("file_hash", HexStr(hasher.GetSHA256()));
|
||||
return result;
|
||||
#endif
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
UniValue AddrmanEntryToJSON(const AddrInfo& info, const CConnman& connman)
|
||||
{
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
@@ -1210,6 +1269,7 @@ void RegisterNetRPCCommands(CRPCTable& t)
|
||||
{"network", &setnetworkactive},
|
||||
{"network", &getnodeaddresses},
|
||||
{"network", &getaddrmaninfo},
|
||||
{"network", &exportasmap},
|
||||
{"hidden", &addconnection},
|
||||
{"hidden", &addpeeraddress},
|
||||
{"hidden", &sendmsgtopeer},
|
||||
|
||||
@@ -78,15 +78,16 @@ const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{
|
||||
"dumptxoutset", // avoid writing to disk
|
||||
"enumeratesigners",
|
||||
"echoipc", // avoid assertion failure (Assertion `"EnsureAnyNodeContext(request.context).init" && check' failed.)
|
||||
"exportasmap", // avoid writing to disk
|
||||
"generatetoaddress", // avoid prohibitively slow execution (when `num_blocks` is large)
|
||||
"generatetodescriptor", // avoid prohibitively slow execution (when `nblocks` is large)
|
||||
"gettxoutproof", // avoid prohibitively slow execution
|
||||
"importmempool", // avoid reading from disk
|
||||
"loadtxoutset", // avoid reading from disk
|
||||
"loadwallet", // avoid reading from disk
|
||||
"savemempool", // disabled as a precautionary measure: may take a file path argument in the future
|
||||
"setban", // avoid DNS lookups
|
||||
"stop", // avoid shutdown state
|
||||
"importmempool", // avoid reading from disk
|
||||
"loadtxoutset", // avoid reading from disk
|
||||
"loadwallet", // avoid reading from disk
|
||||
"savemempool", // disabled as a precautionary measure: may take a file path argument in the future
|
||||
"setban", // avoid DNS lookups
|
||||
"stop", // avoid shutdown state
|
||||
};
|
||||
|
||||
// RPC commands which are safe for fuzzing.
|
||||
|
||||
@@ -11,11 +11,15 @@ with missing and unparseable files.
|
||||
The tests are order-independent.
|
||||
|
||||
"""
|
||||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_raises_rpc_error,
|
||||
)
|
||||
|
||||
ASMAP = 'src/test/data/asmap.raw' # path to unit test skeleton asmap
|
||||
VERSION = 'bafc9da308f45179443bd1d22325400ac9104f741522d003e3fac86700f68895'
|
||||
@@ -124,6 +128,29 @@ class AsmapTest(BitcoinTestFramework):
|
||||
asns.append(asn)
|
||||
assert_equal(len(asns), 3)
|
||||
|
||||
def test_export_embedded_asmap(self):
|
||||
self.log.info('Test exportasmap RPC')
|
||||
export_path = os.path.join(self.datadir, "asmap.dat")
|
||||
|
||||
if not self.is_embedded_asmap_compiled():
|
||||
assert_raises_rpc_error(-1, "No embedded ASMap data available", self.node.exportasmap, export_path)
|
||||
return
|
||||
|
||||
# Relative paths are resolved against the datadir.
|
||||
result = self.node.exportasmap("asmap.dat")
|
||||
assert_equal(result["path"], export_path)
|
||||
|
||||
with open(export_path, 'rb') as f:
|
||||
data = f.read()
|
||||
assert_equal(result["bytes_written"], len(data))
|
||||
|
||||
# Added in https://github.com/bitcoin/bitcoin/pull/34696
|
||||
expected_hash = "478d61986c59365cf86cd244485bbbe76a9ca0c630864717286dd19949879074"
|
||||
assert_equal(hashlib.sha256(data).hexdigest(), expected_hash)
|
||||
assert_equal(result["file_hash"], expected_hash)
|
||||
|
||||
os.remove(export_path)
|
||||
|
||||
def run_test(self):
|
||||
self.node = self.nodes[0]
|
||||
self.datadir = self.node.chain_path
|
||||
@@ -139,6 +166,7 @@ class AsmapTest(BitcoinTestFramework):
|
||||
self.test_asmap_with_missing_file()
|
||||
self.test_empty_asmap()
|
||||
self.test_asmap_health_check()
|
||||
self.test_export_embedded_asmap()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user