banman: save the banlist in a JSON format on disk

Save the banlist in `banlist.json` instead of `banlist.dat`.

This makes it possible to store Tor v3 entries in the banlist on disk
(and any other addresses that cannot be serialized in addrv1 format).

Only read `banlist.dat` if it exists and `banlist.json` does not
exist (first start after an upgrade).

Supersedes https://github.com/bitcoin/bitcoin/pull/20904
Resolves https://github.com/bitcoin/bitcoin/issues/19748
This commit is contained in:
Vasil Dimov
2021-01-14 09:33:04 +01:00
parent 6a67366fdc
commit d197977ae2
9 changed files with 170 additions and 39 deletions

View File

@@ -9,6 +9,7 @@
#include <fs.h>
#include <net_types.h> // For banmap_t
#include <serialize.h>
#include <univalue.h>
#include <string>
#include <vector>
@@ -36,6 +37,13 @@ public:
nCreateTime = nCreateTimeIn;
}
/**
* Create a ban entry from JSON.
* @param[in] json A JSON representation of a ban entry, as created by `ToJson()`.
* @throw std::runtime_error if the JSON does not have the expected fields.
*/
explicit CBanEntry(const UniValue& json);
SERIALIZE_METHODS(CBanEntry, obj)
{
uint8_t ban_reason = 2; //! For backward compatibility
@@ -48,6 +56,12 @@ public:
nCreateTime = 0;
nBanUntil = 0;
}
/**
* Generate a JSON representation of this ban entry.
* @return JSON suitable for passing to the `CBanEntry(const UniValue&)` constructor.
*/
UniValue ToJson() const;
};
/** Access to the (IP) address database (peers.dat) */
@@ -62,15 +76,30 @@ public:
static bool Read(CAddrMan& addr, CDataStream& ssPeers);
};
/** Access to the banlist database (banlist.dat) */
/** Access to the banlist databases (banlist.json and banlist.dat) */
class CBanDB
{
private:
const fs::path m_ban_list_path;
/**
* JSON key under which the data is stored in the json database.
*/
static constexpr const char* JSON_KEY = "banned_nets";
const fs::path m_banlist_dat;
const fs::path m_banlist_json;
public:
explicit CBanDB(fs::path ban_list_path);
bool Write(const banmap_t& banSet);
bool Read(banmap_t& banSet);
/**
* Read the banlist from disk.
* @param[out] banSet The loaded list. Set if `true` is returned, otherwise it is left
* in an undefined state.
* @param[out] dirty Indicates whether the loaded list needs flushing to disk. Set if
* `true` is returned, otherwise it is left in an undefined state.
* @return true on success
*/
bool Read(banmap_t& banSet, bool& dirty);
};
/**