2016-04-16 01:13:15 -03:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2020-12-31 05:48:25 -03:00
// Copyright (c) 2009-2020 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>
2019-12-29 18:04:02 -03:00
# include <cstdint>
2017-11-09 21:57:53 -03:00
# include <hash.h>
2020-09-12 11:59:09 -03:00
# include <logging/timer.h>
2021-01-14 05:33:04 -03:00
# include <netbase.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>
# include <util/settings.h>
2018-10-22 19:51:11 -03:00
# include <util/system.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 {
2020-11-26 18:59:44 -03:00
CHashWriter hasher ( stream . GetType ( ) , stream . GetVersion ( ) ) ;
2018-03-20 21:37:32 -03:00
stream < < Params ( ) . MessageStart ( ) < < data ;
hasher < < Params ( ) . MessageStart ( ) < < data ;
2017-04-21 08:50:55 -03:00
stream < < hasher . GetHash ( ) ;
} 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
2019-12-29 18:04:02 -03:00
uint16_t randv = 0 ;
2016-04-16 01:13:15 -03:00
GetRandBytes ( ( unsigned char * ) & randv , sizeof ( randv ) ) ;
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
2021-05-04 07:00:25 -04:00
fs : : path pathTmp = gArgs . GetDataDirNet ( ) / 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 ) ;
2016-04-16 01:13:15 -03:00
return error ( " %s: Failed to open file %s " , __func__ , pathTmp . string ( ) ) ;
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 ) ;
2018-04-20 06:21:08 -03:00
return error ( " %s: Failed to flush file %s " , __func__ , pathTmp . string ( ) ) ;
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 )
: m_banlist_dat ( ban_list_path . string ( ) + " .dat " ) ,
m_banlist_json ( ban_list_path . string ( ) + " .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 ;
if ( util : : WriteSettings ( m_banlist_json , { { JSON_KEY , BanMapToJson ( banSet ) } } , errors ) ) {
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 ) ) {
LogPrintf ( " banlist.dat ignored because it can only be read by " PACKAGE_NAME " version 22.x. Remove %s to silence this warning. \n " , m_banlist_dat ) ;
}
// 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
}
std : : map < std : : string , util : : SettingsValue > settings ;
std : : vector < std : : string > errors ;
if ( ! util : : ReadSettings ( m_banlist_json , settings , errors ) ) {
for ( const auto & err : errors ) {
LogPrintf ( " Cannot load banlist %s: %s \n " , m_banlist_json . string ( ) , err ) ;
}
return false ;
}
try {
BanMapFromJson ( settings [ JSON_KEY ] , banSet ) ;
} catch ( const std : : runtime_error & e ) {
LogPrintf ( " Cannot parse banlist %s: %s \n " , m_banlist_json . string ( ) , e . what ( ) ) ;
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
2021-09-10 21:16:37 -03:00
std : : optional < bilingual_str > LoadAddrman ( const std : : vector < bool > & asmap , const ArgsManager & args , std : : unique_ptr < AddrMan > & addrman )
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 ) ;
2021-09-10 21:16:37 -03:00
addrman = std : : make_unique < AddrMan > ( asmap , /* deterministic */ false , /* consistency_check_ratio */ check_addrman ) ;
2021-08-21 07:49:16 -04:00
int64_t nStart = GetTimeMillis ( ) ;
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 ) ;
2021-08-21 07:49:16 -04:00
LogPrintf ( " Loaded %i addresses from peers.dat %dms \n " , addrman - > size ( ) , GetTimeMillis ( ) - nStart ) ;
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-09-10 21:16:37 -03:00
addrman = std : : make_unique < AddrMan > ( asmap , /* deterministic */ false , /* consistency_check_ratio */ check_addrman ) ;
2021-08-21 10:17:52 -04:00
LogPrintf ( " Creating peers.dat because the file was not found (%s) \n " , path_addr ) ;
2021-08-21 07:49:16 -04:00
DumpPeerAddresses ( args , * addrman ) ;
2021-08-21 10:17:52 -04:00
} catch ( const std : : exception & e ) {
addrman = nullptr ;
return 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 , path_addr ) ;
2021-08-21 07:49:16 -04:00
}
return std : : nullopt ;
}
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 ) ;
2020-09-12 12:01:19 -03:00
LogPrintf ( " Loaded %i addresses from %s \n " , anchors . size ( ) , 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 ;
}