2020-04-29 01:23:48 +02:00
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include "wallet_chain_shortener.h"
2020-04-30 22:29:08 +02:00
# include "wallet_errors.h"
2020-04-29 01:23:48 +02:00
2020-04-30 22:29:08 +02:00
# define WALLET_EVERYBLOCK_SIZE 20
2020-04-29 01:23:48 +02:00
# define WALLET_EVERY_10_BLOCKS_SIZE 144
# define WALLET_EVERY_100_BLOCKS_SIZE 144
# define WALLET_EVERY_1000_BLOCKS_SIZE 144
2020-05-01 20:39:39 +02:00
static void exception_handler ( ) { }
2020-04-29 01:23:48 +02:00
2023-10-31 18:29:57 +01:00
2020-04-29 01:23:48 +02:00
void wallet_chain_shortener : : clear ( )
{
m_local_bc_size = 1 ;
2020-04-30 22:29:08 +02:00
m_last_20_blocks . clear ( ) ;
2020-04-29 01:23:48 +02:00
m_last_144_blocks_every_10 . clear ( ) ;
m_last_144_blocks_every_100 . clear ( ) ;
m_last_144_blocks_every_1000 . clear ( ) ;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet_chain_shortener : : get_blockchain_current_size ( ) const
{
return m_local_bc_size ;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet_chain_shortener : : get_top_block_height ( ) const
{
return m_local_bc_size - 1 ;
}
//----------------------------------------------------------------------------------------------------
2020-04-30 22:29:08 +02:00
void wallet_chain_shortener : : set_genesis ( const crypto : : hash & id )
{
m_genesis = id ;
m_local_bc_size = 1 ;
}
//----------------------------------------------------------------------------------------------------
const crypto : : hash & wallet_chain_shortener : : get_genesis ( )
{
return m_genesis ;
}
//----------------------------------------------------------------------------------------------------
2020-04-29 01:23:48 +02:00
void wallet_chain_shortener : : push_new_block_id ( const crypto : : hash & id , uint64_t height )
{
2020-05-02 22:53:52 +02:00
if ( height = = 0 )
{
m_genesis = id ;
m_local_bc_size = 1 ;
return ;
}
2020-04-30 22:29:08 +02:00
2020-04-29 01:23:48 +02:00
//primary 10
//self check
2020-05-04 17:11:25 +02:00
if ( m_local_bc_size ! = 1 )
2020-04-29 01:23:48 +02:00
{
THROW_IF_FALSE_WALLET_INT_ERR_EX ( get_blockchain_current_size ( ) = = height , " Inernal error: get_blockchain_current_height(){ " < < get_blockchain_current_size ( ) < < " } == height{ " < < height < < " } is not equal " ) ;
}
2020-05-04 17:11:25 +02:00
m_local_bc_size = height + 1 ;
2020-04-30 22:29:08 +02:00
m_last_20_blocks [ height ] = id ;
if ( m_last_20_blocks . size ( ) > WALLET_EVERYBLOCK_SIZE )
2020-04-29 01:23:48 +02:00
{
2020-04-30 22:29:08 +02:00
m_last_20_blocks . erase ( m_last_20_blocks . begin ( ) ) ;
2020-04-29 01:23:48 +02:00
}
//every 10-th
if ( height % 10 = = 0 )
{
//self check
if ( ! m_last_144_blocks_every_10 . empty ( ) )
{
THROW_IF_FALSE_WALLET_INT_ERR_EX ( ( - - m_last_144_blocks_every_10 . end ( ) ) - > first + 10 = = height , " Inernal error: (--m_last_144_blocks_every_10.end())->first + 10{ " < < ( - - m_last_144_blocks_every_10 . end ( ) ) - > first + 10 < < " } == height{ " < < height < < " } is not equal " ) ;
}
m_last_144_blocks_every_10 [ height ] = id ;
2020-04-30 22:29:08 +02:00
if ( m_last_144_blocks_every_10 . size ( ) > WALLET_EVERY_10_BLOCKS_SIZE )
{
m_last_144_blocks_every_10 . erase ( m_last_144_blocks_every_10 . begin ( ) ) ;
}
2020-04-29 01:23:48 +02:00
}
//every 100-th
if ( height % 100 = = 0 )
{
//self check
if ( ! m_last_144_blocks_every_100 . empty ( ) )
{
THROW_IF_FALSE_WALLET_INT_ERR_EX ( ( - - m_last_144_blocks_every_100 . end ( ) ) - > first + 100 = = height , " Inernal error: (--m_last_144_blocks_every_100.end())->first + 100{ " < < ( - - m_last_144_blocks_every_100 . end ( ) ) - > first + 100 < < " } == height{ " < < height < < " } is not equal " ) ;
}
m_last_144_blocks_every_100 [ height ] = id ;
2020-04-30 22:29:08 +02:00
if ( m_last_144_blocks_every_100 . size ( ) > WALLET_EVERY_100_BLOCKS_SIZE )
{
m_last_144_blocks_every_100 . erase ( m_last_144_blocks_every_100 . begin ( ) ) ;
}
2020-04-29 01:23:48 +02:00
}
//every 1000-th
//every 100-th
if ( height % 1000 = = 0 )
{
//self check
if ( ! m_last_144_blocks_every_1000 . empty ( ) )
{
THROW_IF_FALSE_WALLET_INT_ERR_EX ( ( - - m_last_144_blocks_every_1000 . end ( ) ) - > first + 1000 = = height , " Inernal error: (--m_last_144_blocks_every_1000.end())->first + 1000{ " < < ( - - m_last_144_blocks_every_1000 . end ( ) ) - > first + 1000 < < " } == height{ " < < height < < " } is not equal " ) ;
}
m_last_144_blocks_every_1000 [ height ] = id ;
2020-04-30 22:29:08 +02:00
if ( m_last_144_blocks_every_1000 . size ( ) > WALLET_EVERY_1000_BLOCKS_SIZE )
{
m_last_144_blocks_every_1000 . erase ( m_last_144_blocks_every_1000 . begin ( ) ) ;
}
2020-04-29 01:23:48 +02:00
}
2020-04-30 22:29:08 +02:00
2020-04-29 01:23:48 +02:00
}
//----------------------------------------------------------------------------------------------------
void wallet_chain_shortener : : get_short_chain_history ( std : : list < crypto : : hash > & ids ) const
{
ids . clear ( ) ;
uint64_t i = 0 ;
uint64_t sz = get_blockchain_current_size ( ) ;
if ( ! sz )
return ;
//first put last 10
2020-04-30 22:29:08 +02:00
uint64_t count = 0 ;
for ( auto it = m_last_20_blocks . rbegin ( ) ; it ! = m_last_20_blocks . rend ( ) & & count ! = 10 ; it + + )
2020-04-29 01:23:48 +02:00
{
ids . push_back ( it - > second ) ;
i = it - > first ;
2020-04-30 22:29:08 +02:00
count + + ;
2020-04-29 01:23:48 +02:00
}
2020-04-30 22:29:08 +02:00
uint64_t current_back_offset = ids . size ( ) + 1 ;
2020-04-29 01:23:48 +02:00
//self check
2020-04-30 23:21:14 +02:00
THROW_IF_FALSE_WALLET_INT_ERR_EX ( current_back_offset = = sz - i + 1 | | ! count , " Inernal error: current_back_offset{ " < < current_back_offset < < " } == sz-i{ " < < sz < < " - " < < i < < " } is not equal " ) ;
2020-04-29 01:23:48 +02:00
2020-04-30 22:29:08 +02:00
uint64_t current_offset_distance = 1 ;
2020-04-29 01:23:48 +02:00
while ( current_back_offset < sz )
{
uint64_t get_item_around = sz - current_back_offset ;
std : : pair < uint64_t , crypto : : hash > item = AUTO_VAL_INIT ( item ) ;
if ( ! lookup_item_around ( get_item_around , item ) )
break ;
//readjust item current_back_offset
current_back_offset = sz - item . first ;
ids . push_back ( item . second ) ;
current_offset_distance * = 2 ;
current_back_offset + = current_offset_distance ;
}
ids . push_back ( m_genesis ) ;
}
//----------------------------------------------------------------------------------------------------
bool wallet_chain_shortener : : lookup_item_around ( uint64_t i , std : : pair < uint64_t , crypto : : hash > & result ) const
{
//in which container we are looking for?
uint64_t devider = 0 ;
2020-04-30 22:29:08 +02:00
const std : : map < uint64_t , crypto : : hash > * pcontainer ;
if ( m_last_20_blocks . size ( ) & & i > = m_last_20_blocks . begin ( ) - > first )
{
devider = 1 ;
pcontainer = & m_last_20_blocks ;
}
else if ( m_last_144_blocks_every_10 . size ( ) & & i > = m_last_144_blocks_every_10 . begin ( ) - > first )
2020-04-29 01:23:48 +02:00
{
devider = 10 ;
pcontainer = & m_last_144_blocks_every_10 ;
}
2020-04-30 22:29:08 +02:00
else if ( m_last_144_blocks_every_100 . size ( ) & & i > = m_last_144_blocks_every_100 . begin ( ) - > first )
2020-04-29 01:23:48 +02:00
{
devider = 100 ;
pcontainer = & m_last_144_blocks_every_100 ;
}
2020-04-30 22:29:08 +02:00
else if ( m_last_144_blocks_every_1000 . size ( ) & & i > = m_last_144_blocks_every_1000 . begin ( ) - > first )
2020-04-29 01:23:48 +02:00
{
devider = 1000 ;
pcontainer = & m_last_144_blocks_every_1000 ;
}
else
return false ;
//look in every 10'th
i = i - i % devider ;
auto it = pcontainer - > find ( i ) ;
//self check
THROW_IF_FALSE_WALLET_INT_ERR_EX ( it ! = pcontainer - > end ( ) ,
" Inernal error: index " < < i < < " not found for devider " < < devider
< < " pcontainer={ " < < pcontainer - > begin ( ) - > first < < " : " < < ( - - pcontainer - > end ( ) ) - > first < < " } " ) ;
result = * it ;
return true ;
}
//----------------------------------------------------------------------------------------------------
void wallet_chain_shortener : : check_if_block_matched ( uint64_t i , const crypto : : hash & id , bool & block_found , bool & block_matched , bool & full_reset_needed ) const
{
2020-05-02 22:53:52 +02:00
if ( i = = 0 )
{
//check genesis
if ( m_local_bc_size > 0 )
{
block_found = true ;
block_matched = id = = m_genesis ;
if ( ! block_matched ) {
full_reset_needed = true ;
}
}
else
{
block_found = false ;
block_matched = false ;
full_reset_needed = true ;
}
return ;
}
2020-04-30 22:29:08 +02:00
if ( ! m_last_20_blocks . empty ( ) & & i > m_last_20_blocks . begin ( ) - > first )
2020-04-29 01:23:48 +02:00
{
2020-04-30 22:29:08 +02:00
//must be in short sequence (m_last_20_blocks)
2020-04-29 01:23:48 +02:00
//self check
2020-04-30 22:29:08 +02:00
THROW_IF_FALSE_WALLET_INT_ERR_EX ( ( - - m_last_20_blocks . end ( ) ) - > first > = i ,
" Inernal error: index " < < i < < " is not located in expected range of m_last_20_blocks={ "
< < m_last_20_blocks . begin ( ) - > first < < " : " < < ( - - m_last_20_blocks . end ( ) ) - > first < < " } " ) ;
2020-04-29 01:23:48 +02:00
2020-04-30 22:29:08 +02:00
auto it = m_last_20_blocks . find ( i ) ;
THROW_IF_FALSE_WALLET_INT_ERR_EX ( it ! = m_last_20_blocks . end ( ) ,
" Inernal error: filde to find index " < < i < < " in m_last_20_blocks={ "
< < m_last_20_blocks . begin ( ) - > first < < " : " < < ( - - m_last_20_blocks . end ( ) ) - > first < < " } " ) ;
2020-04-29 01:23:48 +02:00
block_found = true ;
if ( id = = it - > second )
block_matched = true ;
else
block_matched = false ;
}
else
{
//lazy lookup
std : : pair < uint64_t , crypto : : hash > result = AUTO_VAL_INIT ( result ) ;
bool r = lookup_item_around ( i , result ) ;
if ( ! r )
{
2020-05-02 22:53:52 +02:00
LOG_PRINT_L0 ( " Wallet is getting fully resynced due to lookup_item_around failed at " < < i ) ;
2020-04-29 01:23:48 +02:00
block_matched = block_found = false ;
full_reset_needed = true ;
return ;
}
else
{
if ( result . first = = i )
{
block_found = true ;
if ( result . second = = id )
{
block_matched = true ;
}
else
{
block_matched = false ;
}
}
else
{
block_found = false ;
block_matched = false ;
}
}
}
}
//----------------------------------------------------------------------------------------------------
2021-06-03 15:15:05 +03:00
std : : string wallet_chain_shortener : : get_internal_state_text ( ) const
{
std : : stringstream ss ;
# define PRINT_CHAIN_SHORTENER_STATE_INFO(cont_name) \
if ( cont_name . size ( ) ) \
{ \
2021-06-03 15:42:57 +03:00
ss < < # cont_name < < " .size(): [ " < < cont_name . begin ( ) - > first < < " : " < < cont_name . begin ( ) - > second < < " ] " < < ENDL ; \
2021-06-03 15:15:05 +03:00
}
PRINT_CHAIN_SHORTENER_STATE_INFO ( m_last_20_blocks ) ;
PRINT_CHAIN_SHORTENER_STATE_INFO ( m_last_144_blocks_every_10 ) ;
PRINT_CHAIN_SHORTENER_STATE_INFO ( m_last_144_blocks_every_100 ) ;
PRINT_CHAIN_SHORTENER_STATE_INFO ( m_last_144_blocks_every_1000 ) ;
ss < < " m_local_bc_size = " < < m_local_bc_size < < ENDL ;
return ss . str ( ) ;
}
//----------------------------------------------------------------------------------------------------
2020-04-29 01:23:48 +02:00
void clean_map_from_items_above ( std : : map < uint64_t , crypto : : hash > & container , uint64_t height )
{
2020-05-02 22:53:52 +02:00
while ( container . size ( ) & & ( - - container . end ( ) ) - > first > = height )
2020-04-29 01:23:48 +02:00
{
container . erase ( - - container . end ( ) ) ;
}
}
2020-04-30 22:29:08 +02:00
//----------------------------------------------------------------------------------------------------
2020-05-02 22:53:52 +02:00
void wallet_chain_shortener : : detach ( uint64_t including_height )
2020-04-29 01:23:48 +02:00
{
2020-05-02 22:53:52 +02:00
clean_map_from_items_above ( m_last_20_blocks , including_height ) ;
clean_map_from_items_above ( m_last_144_blocks_every_10 , including_height ) ;
clean_map_from_items_above ( m_last_144_blocks_every_100 , including_height ) ;
clean_map_from_items_above ( m_last_144_blocks_every_1000 , including_height ) ;
m_local_bc_size = including_height ;
2020-04-29 01:23:48 +02:00
}