2016-04-16 01:13:15 -03:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2022-12-24 20:49:50 -03:00
// Copyright (c) 2009-2022 The Bitcoin Core developers
2016-04-16 01:13:15 -03:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-11-09 21:57:53 -03:00
# include <addrdb.h>
2016-04-16 01:13:15 -03:00
2017-11-09 21:57:53 -03:00
# include <addrman.h>
# include <chainparams.h>
# include <clientversion.h>
2023-03-23 08:23:29 -03:00
# include <common/args.h>
2023-05-24 09:55:53 -04:00
# include <common/settings.h>
2019-12-29 18:04:02 -03:00
# include <cstdint>
2017-11-09 21:57:53 -03:00
# include <hash.h>
2023-03-06 18:01:13 -03:00
# include <logging.h>
2020-09-12 11:59:09 -03:00
# include <logging/timer.h>
2021-01-14 05:33:04 -03:00
# include <netbase.h>
2021-08-31 13:40:18 -04:00
# include <netgroup.h>
2017-11-09 21:57:53 -03:00
# include <random.h>
# include <streams.h>
# include <tinyformat.h>
2021-01-14 05:33:04 -03:00
# include <univalue.h>
2023-03-15 07:18:06 -03:00
# include <util/fs.h>
2023-03-06 19:41:46 -03:00
# include <util/fs_helpers.h>
2021-08-21 07:49:16 -04:00
# include <util/translation.h>
2016-04-16 01:13:15 -03:00
2017-04-21 08:50:55 -03:00
namespace {
2021-08-21 10:17:52 -04:00
class DbNotFoundError : public std : : exception
{
using std : : exception : : exception ;
} ;
2017-04-21 08:50:55 -03:00
template < typename Stream , typename Data >
bool SerializeDB ( Stream & stream , const Data & data )
2016-04-16 01:13:15 -03:00
{
2017-04-21 08:50:55 -03:00
// Write and commit header, data
try {
2023-01-13 16:12:25 -03:00
HashedSourceWriter hashwriter { stream } ;
hashwriter < < Params ( ) . MessageStart ( ) < < data ;
stream < < hashwriter . GetHash ( ) ;
2017-04-21 08:50:55 -03:00
} catch ( const std : : exception & e ) {
return error ( " %s: Serialize or I/O error - %s " , __func__ , e . what ( ) ) ;
}
return true ;
2016-04-16 01:13:15 -03:00
}
2017-04-21 08:50:55 -03:00
template < typename Data >
2020-11-26 18:59:44 -03:00
bool SerializeFileDB ( const std : : string & prefix , const fs : : path & path , const Data & data , int version )
2016-04-16 01:13:15 -03:00
{
// Generate random temporary filename
2022-01-31 09:32:59 -03:00
const uint16_t randv { GetRand < uint16_t > ( ) } ;
2017-04-21 08:50:55 -03:00
std : : string tmpfn = strprintf ( " %s.%04x " , prefix , randv ) ;
2016-04-16 01:13:15 -03:00
// open temp output file, and associate with CAutoFile
2022-03-03 16:40:18 -03:00
fs : : path pathTmp = gArgs . GetDataDirNet ( ) / fs : : u8path ( tmpfn ) ;
2017-03-01 13:28:39 -03:00
FILE * file = fsbridge : : fopen ( pathTmp , " wb " ) ;
2020-11-26 18:59:44 -03:00
CAutoFile fileout ( file , SER_DISK , version ) ;
2019-06-14 02:30:43 -04:00
if ( fileout . IsNull ( ) ) {
fileout . fclose ( ) ;
remove ( pathTmp ) ;
2021-09-10 01:17:20 -03:00
return error ( " %s: Failed to open file %s " , __func__ , fs : : PathToString ( pathTmp ) ) ;
2019-06-14 02:30:43 -04:00
}
2016-04-16 01:13:15 -03:00
2017-04-21 08:50:55 -03:00
// Serialize
2019-06-14 02:30:43 -04:00
if ( ! SerializeDB ( fileout , data ) ) {
fileout . fclose ( ) ;
remove ( pathTmp ) ;
return false ;
}
if ( ! FileCommit ( fileout . Get ( ) ) ) {
fileout . fclose ( ) ;
remove ( pathTmp ) ;
2021-09-10 01:17:20 -03:00
return error ( " %s: Failed to flush file %s " , __func__ , fs : : PathToString ( pathTmp ) ) ;
2019-06-14 02:30:43 -04:00
}
2016-04-16 01:13:15 -03:00
fileout . fclose ( ) ;
2017-04-21 08:50:55 -03:00
// replace existing file, if any, with new file
2019-06-14 02:30:43 -04:00
if ( ! RenameOver ( pathTmp , path ) ) {
remove ( pathTmp ) ;
2016-04-16 01:13:15 -03:00
return error ( " %s: Rename-into-place failed " , __func__ ) ;
2019-06-14 02:30:43 -04:00
}
2016-04-16 01:13:15 -03:00
return true ;
}
2017-04-21 08:50:55 -03:00
template < typename Stream , typename Data >
2021-08-21 10:17:52 -04:00
void DeserializeDB ( Stream & stream , Data & data , bool fCheckSum = true )
2016-04-16 01:13:15 -03:00
{
2021-08-21 10:17:52 -04:00
CHashVerifier < Stream > verifier ( & stream ) ;
// de-serialize file header (network specific magic number) and ..
unsigned char pchMsgTmp [ 4 ] ;
verifier > > pchMsgTmp ;
// ... verify the network matches ours
if ( memcmp ( pchMsgTmp , Params ( ) . MessageStart ( ) , sizeof ( pchMsgTmp ) ) ) {
throw std : : runtime_error { " Invalid network magic number " } ;
}
// de-serialize data
verifier > > data ;
// verify checksum
if ( fCheckSum ) {
uint256 hashTmp ;
stream > > hashTmp ;
if ( hashTmp ! = verifier . GetHash ( ) ) {
throw std : : runtime_error { " Checksum mismatch, data corrupted " } ;
2017-04-21 08:50:55 -03:00
}
2016-04-16 01:13:15 -03:00
}
}
2017-04-21 08:50:55 -03:00
template < typename Data >
2021-08-21 10:17:52 -04:00
void DeserializeFileDB ( const fs : : path & path , Data & data , int version )
2016-04-16 01:13:15 -03:00
{
2017-04-21 08:50:55 -03:00
// open input file, and associate with CAutoFile
2021-02-18 09:34:18 -03:00
FILE * file = fsbridge : : fopen ( path , " rb " ) ;
2020-11-26 18:59:44 -03:00
CAutoFile filein ( file , SER_DISK , version ) ;
2021-02-18 09:34:18 -03:00
if ( filein . IsNull ( ) ) {
2021-08-21 10:17:52 -04:00
throw DbNotFoundError { } ;
2021-02-18 09:34:18 -03:00
}
2021-08-21 10:17:52 -04:00
DeserializeDB ( filein , data ) ;
2016-04-16 01:13:15 -03:00
}
2021-02-18 09:34:18 -03:00
} // namespace
2016-04-16 01:13:15 -03:00
2021-01-14 05:33:04 -03:00
CBanDB : : CBanDB ( fs : : path ban_list_path )
2021-09-10 01:17:20 -03:00
: m_banlist_dat ( ban_list_path + " .dat " ) ,
m_banlist_json ( ban_list_path + " .json " )
2017-04-21 08:50:55 -03:00
{
}
2016-04-16 01:13:15 -03:00
2017-04-21 08:50:55 -03:00
bool CBanDB : : Write ( const banmap_t & banSet )
{
2021-01-14 05:33:04 -03:00
std : : vector < std : : string > errors ;
2023-05-24 10:18:59 -04:00
if ( common : : WriteSettings ( m_banlist_json , { { JSON_KEY , BanMapToJson ( banSet ) } } , errors ) ) {
2021-01-14 05:33:04 -03:00
return true ;
}
for ( const auto & err : errors ) {
error ( " %s " , err ) ;
}
return false ;
2017-04-21 08:50:55 -03:00
}
2016-04-16 01:13:15 -03:00
2021-07-28 14:00:23 -04:00
bool CBanDB : : Read ( banmap_t & banSet )
2017-04-21 08:50:55 -03:00
{
2021-07-28 14:00:23 -04:00
if ( fs : : exists ( m_banlist_dat ) ) {
2021-09-10 01:17:20 -03:00
LogPrintf ( " banlist.dat ignored because it can only be read by " PACKAGE_NAME " version 22.x. Remove %s to silence this warning. \n " , fs : : quoted ( fs : : PathToString ( m_banlist_dat ) ) ) ;
2021-07-28 14:00:23 -04:00
}
// If the JSON banlist does not exist, then recreate it
2021-01-14 05:33:04 -03:00
if ( ! fs : : exists ( m_banlist_json ) ) {
2021-07-28 14:00:23 -04:00
return false ;
2021-01-14 05:33:04 -03:00
}
2023-05-24 10:18:59 -04:00
std : : map < std : : string , common : : SettingsValue > settings ;
2021-01-14 05:33:04 -03:00
std : : vector < std : : string > errors ;
2023-05-24 10:18:59 -04:00
if ( ! common : : ReadSettings ( m_banlist_json , settings , errors ) ) {
2021-01-14 05:33:04 -03:00
for ( const auto & err : errors ) {
2021-09-10 01:17:20 -03:00
LogPrintf ( " Cannot load banlist %s: %s \n " , fs : : PathToString ( m_banlist_json ) , err ) ;
2021-01-14 05:33:04 -03:00
}
return false ;
}
try {
BanMapFromJson ( settings [ JSON_KEY ] , banSet ) ;
} catch ( const std : : runtime_error & e ) {
2021-09-10 01:17:20 -03:00
LogPrintf ( " Cannot parse banlist %s: %s \n " , fs : : PathToString ( m_banlist_json ) , e . what ( ) ) ;
2021-01-14 05:33:04 -03:00
return false ;
}
return true ;
2017-04-21 08:50:55 -03:00
}
2016-04-16 01:13:15 -03:00
2021-09-10 21:16:37 -03:00
bool DumpPeerAddresses ( const ArgsManager & args , const AddrMan & addr )
2017-04-21 08:50:55 -03:00
{
2021-08-21 05:22:21 -04:00
const auto pathAddr = args . GetDataDirNet ( ) / " peers.dat " ;
2020-11-26 18:59:44 -03:00
return SerializeFileDB ( " peers " , pathAddr , addr , CLIENT_VERSION ) ;
2016-04-16 01:13:15 -03:00
}
2021-09-10 21:16:37 -03:00
void ReadFromStream ( AddrMan & addr , CDataStream & ssPeers )
2016-04-16 01:13:15 -03:00
{
2021-08-21 10:17:52 -04:00
DeserializeDB ( ssPeers , addr , false ) ;
2016-04-16 01:13:15 -03:00
}
2020-09-12 11:59:09 -03:00
2022-09-01 15:35:23 -04:00
util : : Result < std : : unique_ptr < AddrMan > > LoadAddrman ( const NetGroupManager & netgroupman , const ArgsManager & args )
2021-08-21 07:49:16 -04:00
{
2019-08-22 21:40:41 -04:00
auto check_addrman = std : : clamp < int32_t > ( args . GetIntArg ( " -checkaddrman " , DEFAULT_ADDRMAN_CONSISTENCY_CHECKS ) , 0 , 1000000 ) ;
2022-09-01 15:35:23 -04:00
auto addrman { std : : make_unique < AddrMan > ( netgroupman , /*deterministic=*/ false , /*consistency_check_ratio=*/ check_addrman ) } ;
2021-08-21 07:49:16 -04:00
2022-06-28 11:50:53 -04:00
const auto start { SteadyClock : : now ( ) } ;
2021-08-21 09:20:00 -04:00
const auto path_addr { args . GetDataDirNet ( ) / " peers.dat " } ;
2021-08-21 10:17:52 -04:00
try {
DeserializeFileDB ( path_addr , * addrman , CLIENT_VERSION ) ;
2023-01-13 19:23:38 -03:00
LogPrintf ( " Loaded %i addresses from peers.dat %dms \n " , addrman - > Size ( ) , Ticks < std : : chrono : : milliseconds > ( SteadyClock : : now ( ) - start ) ) ;
2021-08-21 10:17:52 -04:00
} catch ( const DbNotFoundError & ) {
2021-08-21 07:49:16 -04:00
// Addrman can be in an inconsistent state after failure, reset it
2021-08-31 13:40:18 -04:00
addrman = std : : make_unique < AddrMan > ( netgroupman , /*deterministic=*/ false , /*consistency_check_ratio=*/ check_addrman ) ;
2021-09-10 01:17:20 -03:00
LogPrintf ( " Creating peers.dat because the file was not found (%s) \n " , fs : : quoted ( fs : : PathToString ( path_addr ) ) ) ;
2021-08-21 07:49:16 -04:00
DumpPeerAddresses ( args , * addrman ) ;
2022-01-29 09:58:59 -03:00
} catch ( const InvalidAddrManVersionError & ) {
if ( ! RenameOver ( path_addr , ( fs : : path ) path_addr + " .bak " ) ) {
2022-09-01 15:35:23 -04:00
return util : : Error { strprintf ( _ ( " Failed to rename invalid peers.dat file. Please move or delete it and try again. " ) ) } ;
2022-01-29 09:58:59 -03:00
}
// Addrman can be in an inconsistent state after failure, reset it
2021-08-31 13:40:18 -04:00
addrman = std : : make_unique < AddrMan > ( netgroupman , /*deterministic=*/ false , /*consistency_check_ratio=*/ check_addrman ) ;
2022-01-29 09:58:59 -03:00
LogPrintf ( " Creating new peers.dat because the file version was not compatible (%s). Original backed up to peers.dat.bak \n " , fs : : quoted ( fs : : PathToString ( path_addr ) ) ) ;
DumpPeerAddresses ( args , * addrman ) ;
2021-08-21 10:17:52 -04:00
} catch ( const std : : exception & e ) {
2022-09-01 15:35:23 -04:00
return util : : Error { strprintf ( _ ( " Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start. " ) ,
e . what ( ) , PACKAGE_BUGREPORT , fs : : quoted ( fs : : PathToString ( path_addr ) ) ) } ;
2021-08-21 07:49:16 -04:00
}
2023-05-29 07:15:47 -04:00
return { std : : move ( addrman ) } ; // std::move should be unneccessary but is temporarily needed to work around clang bug
// (https://github.com/bitcoin/bitcoin/pull/25977#issuecomment-1561270092)
2021-08-21 07:49:16 -04:00
}
2020-09-12 11:59:09 -03:00
void DumpAnchors ( const fs : : path & anchors_db_path , const std : : vector < CAddress > & anchors )
{
LOG_TIME_SECONDS ( strprintf ( " Flush %d outbound block-relay-only peer addresses to anchors.dat " , anchors . size ( ) ) ) ;
2020-11-26 18:59:44 -03:00
SerializeFileDB ( " anchors " , anchors_db_path , anchors , CLIENT_VERSION | ADDRV2_FORMAT ) ;
2020-09-12 11:59:09 -03:00
}
2020-09-12 12:01:19 -03:00
std : : vector < CAddress > ReadAnchors ( const fs : : path & anchors_db_path )
{
std : : vector < CAddress > anchors ;
2021-08-21 10:17:52 -04:00
try {
DeserializeFileDB ( anchors_db_path , anchors , CLIENT_VERSION | ADDRV2_FORMAT ) ;
2021-09-10 01:17:20 -03:00
LogPrintf ( " Loaded %i addresses from %s \n " , anchors . size ( ) , fs : : quoted ( fs : : PathToString ( anchors_db_path . filename ( ) ) ) ) ;
2021-08-21 10:17:52 -04:00
} catch ( const std : : exception & ) {
2020-09-12 12:01:19 -03:00
anchors . clear ( ) ;
}
fs : : remove ( anchors_db_path ) ;
return anchors ;
}