2019-07-01 12:42:45 -06:00
2018-08-06 15:40:20 -04:00
# include <claimtrie.h>
# include <coins.h>
# include <hash.h>
2019-05-07 16:32:22 -06:00
# include <logging.h>
2019-07-02 18:49:02 +03:00
# include <util.h>
2018-08-06 15:40:20 -04:00
# include <algorithm>
2019-07-01 12:42:45 -06:00
# include <memory>
2018-08-06 15:40:20 -04:00
2019-07-19 18:36:53 +03:00
extern const uint256 one = uint256S ( " 0000000000000000000000000000000000000000000000000000000000000001 " ) ;
2018-08-06 15:40:20 -04:00
std : : vector < unsigned char > heightToVch ( int n )
{
2019-07-01 12:42:45 -06:00
std : : vector < unsigned char > vchHeight ( 8 , 0 ) ;
2018-08-06 15:40:20 -04:00
vchHeight [ 4 ] = n > > 24 ;
vchHeight [ 5 ] = n > > 16 ;
vchHeight [ 6 ] = n > > 8 ;
vchHeight [ 7 ] = n ;
return vchHeight ;
}
2019-07-01 12:42:45 -06:00
uint256 getValueHash ( const COutPoint & outPoint , int nHeightOfLastTakeover )
2018-08-06 15:40:20 -04:00
{
CHash256 hasher ;
2019-05-07 16:32:22 -06:00
auto hash = Hash ( outPoint . hash . begin ( ) , outPoint . hash . end ( ) ) ;
hasher . Write ( hash . begin ( ) , hash . size ( ) ) ;
auto snOut = std : : to_string ( outPoint . n ) ;
hash = Hash ( snOut . begin ( ) , snOut . end ( ) ) ;
hasher . Write ( hash . begin ( ) , hash . size ( ) ) ;
2018-08-06 15:40:20 -04:00
2019-05-07 16:32:22 -06:00
auto vchHash = heightToVch ( nHeightOfLastTakeover ) ;
hash = Hash ( vchHash . begin ( ) , vchHash . end ( ) ) ;
hasher . Write ( hash . begin ( ) , hash . size ( ) ) ;
uint256 result ;
hasher . Finalize ( result . begin ( ) ) ;
return result ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < typename T >
2019-07-15 08:48:24 +03:00
bool equals ( const T & lhs , const T & rhs )
2019-07-02 18:49:02 +03:00
{
2019-07-15 08:48:24 +03:00
return lhs = = rhs ;
2019-07-02 18:49:02 +03:00
}
template < typename T >
2019-07-15 08:48:24 +03:00
bool equals ( const T & value , const COutPoint & outPoint )
2019-07-02 18:49:02 +03:00
{
2019-07-15 08:48:24 +03:00
return value . outPoint = = outPoint ;
2019-07-02 18:49:02 +03:00
}
template < typename K , typename V >
2019-07-15 08:48:24 +03:00
bool equals ( const std : : pair < K , V > & pair , const CNameOutPointType & point )
2019-07-02 18:49:02 +03:00
{
2019-07-15 08:48:24 +03:00
return pair . first = = point . name & & pair . second . outPoint = = point . outPoint ;
2019-07-02 18:49:02 +03:00
}
2019-07-15 08:48:24 +03:00
template < typename T , typename C >
auto findOutPoint ( T & cont , const C & point ) - > decltype ( cont . begin ( ) )
2019-07-02 18:49:02 +03:00
{
using type = typename T : : value_type ;
2019-08-28 19:13:50 +03:00
static_assert ( std : : is_same < typename std : : decay < T > : : type , std : : vector < type > > : : value , " T should be a vector type " ) ;
2019-07-15 08:48:24 +03:00
return std : : find_if ( cont . begin ( ) , cont . end ( ) , [ & point ] ( const type & val ) {
return equals ( val , point ) ;
2019-07-02 18:49:02 +03:00
} ) ;
}
2019-07-15 08:48:24 +03:00
template < typename T , typename C >
bool eraseOutPoint ( std : : vector < T > & cont , const C & point , T * value = nullptr )
2019-07-02 18:49:02 +03:00
{
2019-07-15 08:48:24 +03:00
auto it = findOutPoint ( cont , point ) ;
2019-07-02 18:49:02 +03:00
if ( it = = cont . end ( ) )
return false ;
if ( value )
std : : swap ( * it , * value ) ;
cont . erase ( it ) ;
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieData : : insertClaim ( const CClaimValue & claim )
2018-08-06 15:40:20 -04:00
{
claims . push_back ( claim ) ;
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieData : : removeClaim ( const COutPoint & outPoint , CClaimValue & claim )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
if ( eraseOutPoint ( claims , outPoint , & claim ) )
return true ;
2019-07-29 09:47:33 -06:00
if ( LogAcceptCategory ( BCLog : : CLAIMS ) ) {
LogPrintf ( " CClaimTrieData::%s() : asked to remove a claim that doesn't exist \n " , __func__ ) ;
LogPrintf ( " CClaimTrieData::%s() : claims that do exist: \n " , __func__ ) ;
for ( auto & iClaim : claims )
LogPrintf ( " \t %s \n " , iClaim . outPoint . ToString ( ) ) ;
}
2019-07-01 12:42:45 -06:00
return false ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieData : : getBestClaim ( CClaimValue & claim ) const
2018-08-06 15:40:20 -04:00
{
if ( claims . empty ( ) )
return false ;
claim = claims . front ( ) ;
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieData : : haveClaim ( const COutPoint & outPoint ) const
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
return findOutPoint ( claims , outPoint ) ! = claims . end ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
void CClaimTrieData : : reorderClaims ( const supportEntryType & supports )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
for ( auto & claim : claims ) {
claim . nEffectiveAmount = claim . nAmount ;
for ( const auto & support : supports )
if ( support . supportedClaimId = = claim . claimId )
claim . nEffectiveAmount + = support . nAmount ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
std : : sort ( claims . rbegin ( ) , claims . rend ( ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-30 15:19:09 -06:00
CClaimTrie : : CClaimTrie ( bool fMemory , bool fWipe , int proportionalDelayFactor , std : : size_t cacheMB )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
nProportionalDelayFactor = proportionalDelayFactor ;
2019-08-30 15:19:09 -06:00
db . reset ( new CDBWrapper ( GetDataDir ( ) / " claimtrie " , cacheMB * 1024ULL * 1024ULL , fMemory , fWipe , false ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrie : : SyncToDisk ( )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
return db & & db - > Sync ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-28 19:13:50 +03:00
template < typename T >
using rm_ref = typename std : : remove_reference < T > : : type ;
template < typename Key , typename Map >
auto getRow ( const CDBWrapper & db , uint8_t dbkey , const Key & key , Map & queue ) - > COptional < rm_ref < decltype ( queue . at ( key ) ) > >
{
auto it = queue . find ( key ) ;
if ( it ! = queue . end ( ) )
return { & ( it - > second ) } ;
typename Map : : mapped_type row ;
if ( db . Read ( std : : make_pair ( dbkey , key ) , row ) )
return { std : : move ( row ) } ;
return { } ;
}
template < typename Key , typename Value >
Value * getQueue ( const CDBWrapper & db , uint8_t dbkey , const Key & key , std : : map < Key , Value > & queue , bool create )
2018-08-06 15:40:20 -04:00
{
2019-08-28 19:13:50 +03:00
auto row = getRow ( db , dbkey , key , queue ) ;
if ( row . unique ( ) | | ( ! row & & create ) ) {
auto ret = queue . emplace ( key , row ? std : : move ( * row ) : Value { } ) ;
2019-07-01 12:42:45 -06:00
assert ( ret . second ) ;
2019-08-28 19:13:50 +03:00
return & ( ret . first - > second ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-28 19:13:50 +03:00
return row ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < typename T >
inline constexpr bool supportedType ( )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
static_assert ( std : : is_same < T , CClaimValue > : : value | | std : : is_same < T , CSupportValue > : : value , " T is unsupported type " ) ;
return true ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < >
2019-08-28 19:13:50 +03:00
std : : vector < queueEntryType < CClaimValue > > * CClaimTrieCacheBase : : getQueueCacheRow ( int nHeight , bool createIfNotExists )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return getQueue ( * ( base - > db ) , CLAIM_QUEUE_ROW , nHeight , claimQueueCache , createIfNotExists ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < >
2019-08-28 19:13:50 +03:00
std : : vector < queueEntryType < CSupportValue > > * CClaimTrieCacheBase : : getQueueCacheRow ( int nHeight , bool createIfNotExists )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
return getQueue ( * ( base - > db ) , SUPPORT_QUEUE_ROW , nHeight , supportQueueCache , createIfNotExists ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < typename T >
2019-08-28 19:13:50 +03:00
std : : vector < queueEntryType < T > > * CClaimTrieCacheBase : : getQueueCacheRow ( int , bool )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
supportedType < T > ( ) ;
return nullptr ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < >
2019-08-28 19:13:50 +03:00
COptional < const std : : vector < queueEntryType < CClaimValue > > > CClaimTrieCacheBase : : getQueueCacheRow ( int nHeight ) const
{
return getRow ( * ( base - > db ) , CLAIM_QUEUE_ROW , nHeight , claimQueueCache ) ;
}
template < >
COptional < const std : : vector < queueEntryType < CSupportValue > > > CClaimTrieCacheBase : : getQueueCacheRow ( int nHeight ) const
{
return getRow ( * ( base - > db ) , SUPPORT_QUEUE_ROW , nHeight , supportQueueCache ) ;
}
template < typename T >
COptional < const std : : vector < queueEntryType < T > > > CClaimTrieCacheBase : : getQueueCacheRow ( int ) const
{
supportedType < T > ( ) ;
return { } ;
}
template < >
queueNameRowType * CClaimTrieCacheBase : : getQueueCacheNameRow < CClaimValue > ( const std : : string & name , bool createIfNotExists )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
return getQueue ( * ( base - > db ) , CLAIM_QUEUE_NAME_ROW , name , claimQueueNameCache , createIfNotExists ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < >
2019-08-28 19:13:50 +03:00
queueNameRowType * CClaimTrieCacheBase : : getQueueCacheNameRow < CSupportValue > ( const std : : string & name , bool createIfNotExists )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return getQueue ( * ( base - > db ) , SUPPORT_QUEUE_NAME_ROW , name , supportQueueNameCache , createIfNotExists ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < typename T >
2019-08-28 19:13:50 +03:00
queueNameRowType * CClaimTrieCacheBase : : getQueueCacheNameRow ( const std : : string & , bool )
2019-07-02 18:49:02 +03:00
{
supportedType < T > ( ) ;
return nullptr ;
}
template < >
2019-08-28 19:13:50 +03:00
COptional < const queueNameRowType > CClaimTrieCacheBase : : getQueueCacheNameRow < CClaimValue > ( const std : : string & name ) const
{
return getRow ( * ( base - > db ) , CLAIM_QUEUE_NAME_ROW , name , claimQueueNameCache ) ;
}
template < >
COptional < const queueNameRowType > CClaimTrieCacheBase : : getQueueCacheNameRow < CSupportValue > ( const std : : string & name ) const
{
return getRow ( * ( base - > db ) , SUPPORT_QUEUE_NAME_ROW , name , supportQueueNameCache ) ;
}
template < typename T >
COptional < const queueNameRowType > CClaimTrieCacheBase : : getQueueCacheNameRow ( const std : : string & ) const
{
supportedType < T > ( ) ;
return { } ;
}
template < >
expirationQueueRowType * CClaimTrieCacheBase : : getExpirationQueueCacheRow < CClaimValue > ( int nHeight , bool createIfNotExists )
2019-07-02 18:49:02 +03:00
{
2019-08-01 18:35:58 -06:00
return getQueue ( * ( base - > db ) , CLAIM_EXP_QUEUE_ROW , nHeight , expirationQueueCache , createIfNotExists ) ;
2019-07-02 18:49:02 +03:00
}
template < >
2019-08-28 19:13:50 +03:00
expirationQueueRowType * CClaimTrieCacheBase : : getExpirationQueueCacheRow < CSupportValue > ( int nHeight , bool createIfNotExists )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return getQueue ( * ( base - > db ) , SUPPORT_EXP_QUEUE_ROW , nHeight , supportExpirationQueueCache , createIfNotExists ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < typename T >
2019-08-28 19:13:50 +03:00
expirationQueueRowType * CClaimTrieCacheBase : : getExpirationQueueCacheRow ( int , bool )
2019-07-02 18:49:02 +03:00
{
supportedType < T > ( ) ;
return nullptr ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : haveClaim ( const std : : string & name , const COutPoint & outPoint ) const
2018-08-06 15:40:20 -04:00
{
2019-08-01 18:35:58 -06:00
auto it = nodesToAddOrUpdate . find ( name ) ;
if ( it & & it - > haveClaim ( outPoint ) )
return true ;
if ( it | | nodesToDelete . count ( name ) )
return false ;
2019-08-24 18:43:56 -06:00
CClaimTrieData data ;
return base - > find ( name , data ) & & data . haveClaim ( outPoint ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : haveSupport ( const std : : string & name , const COutPoint & outPoint ) const
{
const auto supports = getSupportsForName ( name ) ;
return findOutPoint ( supports , outPoint ) ! = supports . end ( ) ;
}
2019-07-01 12:42:45 -06:00
supportEntryType CClaimTrieCacheBase : : getSupportsForName ( const std : : string & name ) const
2018-08-06 15:40:20 -04:00
{
2019-07-22 15:53:17 -06:00
auto sit = supportCache . find ( name ) ;
if ( sit ! = supportCache . end ( ) )
2019-07-01 12:42:45 -06:00
return sit - > second ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
supportEntryType supports ;
if ( base - > db - > Read ( std : : make_pair ( SUPPORT , name ) , supports ) ) // don't trust the try/catch in here
return supports ;
return { } ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < typename T >
2019-08-28 19:13:50 +03:00
bool CClaimTrieCacheBase : : haveInQueue ( const std : : string & name , const COutPoint & outPoint , int & nValidAtHeight ) const
2019-07-01 12:42:45 -06:00
{
2019-07-02 18:49:02 +03:00
supportedType < T > ( ) ;
if ( auto nameRow = getQueueCacheNameRow < T > ( name ) ) {
2019-08-28 19:13:50 +03:00
auto itNameRow = findOutPoint ( * nameRow , outPoint ) ;
if ( itNameRow ! = nameRow - > end ( ) ) {
2019-07-02 18:49:02 +03:00
nValidAtHeight = itNameRow - > nHeight ;
if ( auto row = getQueueCacheRow < T > ( nValidAtHeight ) ) {
2019-08-28 19:13:50 +03:00
auto iRow = findOutPoint ( * row , CNameOutPointType { name , outPoint } ) ;
if ( iRow ! = row - > end ( ) ) {
2019-07-02 18:49:02 +03:00
if ( iRow - > second . nValidAtHeight ! = nValidAtHeight )
LogPrintf ( " %s: An inconsistency was found in the support queue. Please report this to the developers: \n Different nValidAtHeight between named queue and height queue \n : name: %s, txid: %s, nOut: %d, nValidAtHeight in named queue: %d, nValidAtHeight in height queue: %d current height: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nValidAtHeight , iRow - > second . nValidAtHeight , nNextHeight ) ;
2019-07-01 12:42:45 -06:00
return true ;
2018-08-06 15:40:20 -04:00
}
}
}
2019-07-02 18:49:02 +03:00
LogPrintf ( " %s: An inconsistency was found in the claim queue. Please report this to the developers: \n Found in named queue but not in height queue: name: %s, txid: %s, nOut: %d, nValidAtHeight: %d, current height: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nValidAtHeight , nNextHeight ) ;
2018-08-06 15:40:20 -04:00
}
return false ;
}
2019-08-28 19:13:50 +03:00
bool CClaimTrieCacheBase : : haveClaimInQueue ( const std : : string & name , const COutPoint & outPoint , int & nValidAtHeight ) const
2019-07-02 18:49:02 +03:00
{
return haveInQueue < CClaimValue > ( name , outPoint , nValidAtHeight ) ;
}
2019-08-28 19:13:50 +03:00
bool CClaimTrieCacheBase : : haveSupportInQueue ( const std : : string & name , const COutPoint & outPoint , int & nValidAtHeight ) const
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
return haveInQueue < CSupportValue > ( name , outPoint , nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-24 18:43:56 -06:00
void CClaimTrie : : recurseNodes ( const std : : string & name , const CClaimTrieDataNode & current , std : : function < recurseNodesCB > function ) const {
CClaimTrieData data ;
2019-08-28 19:13:50 +03:00
find ( name , data ) ;
2019-08-24 18:43:56 -06:00
data . hash = current . hash ;
data . flags | = current . children . empty ( ) ? 0 : CClaimTrieDataFlags : : POTENTIAL_CHILDREN ;
function ( name , data , current . children ) ;
2019-08-01 18:35:58 -06:00
for ( auto & child : current . children ) {
CClaimTrieDataNode node ;
2019-08-28 19:13:50 +03:00
auto childName = name + child ;
if ( find ( childName , node ) )
recurseNodes ( childName , node , function ) ;
2019-08-01 18:35:58 -06:00
}
}
std : : size_t CClaimTrie : : getTotalNamesInTrie ( ) const
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
std : : size_t count = 0 ;
2019-08-01 18:35:58 -06:00
CClaimTrieDataNode node ;
2019-08-28 19:13:50 +03:00
if ( find ( { } , node ) )
recurseNodes ( { } , node , [ & count ] ( const std : : string & name , const CClaimTrieData & data , const std : : vector < std : : string > & children ) {
2019-08-24 18:43:56 -06:00
count + = ! data . empty ( ) ;
2019-08-01 18:35:58 -06:00
} ) ;
2019-07-01 12:42:45 -06:00
return count ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
std : : size_t CClaimTrie : : getTotalClaimsInTrie ( ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
std : : size_t count = 0 ;
2019-08-01 18:35:58 -06:00
CClaimTrieDataNode node ;
2019-08-28 19:13:50 +03:00
if ( find ( { } , node ) )
recurseNodes ( { } , node , [ & count ]
2019-08-24 18:43:56 -06:00
( const std : : string & name , const CClaimTrieData & data , const std : : vector < std : : string > & children ) {
count + = data . claims . size ( ) ;
2019-08-01 18:35:58 -06:00
} ) ;
2019-07-01 12:42:45 -06:00
return count ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
CAmount CClaimTrie : : getTotalValueOfClaimsInTrie ( bool fControllingOnly ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
CAmount value_in_subtrie = 0 ;
2019-08-01 18:35:58 -06:00
CClaimTrieDataNode node ;
2019-08-28 19:13:50 +03:00
if ( find ( { } , node ) )
recurseNodes ( { } , node , [ & value_in_subtrie , fControllingOnly ]
2019-08-24 18:43:56 -06:00
( const std : : string & name , const CClaimTrieData & data , const std : : vector < std : : string > & children ) {
for ( const auto & claim : data . claims ) {
2019-08-01 18:35:58 -06:00
value_in_subtrie + = claim . nAmount ;
if ( fControllingOnly )
break ;
}
} ) ;
2019-07-01 12:42:45 -06:00
return value_in_subtrie ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : getInfoForName ( const std : : string & name , CClaimValue & claim ) const
2018-08-06 15:40:20 -04:00
{
2019-08-01 18:35:58 -06:00
auto it = nodesToAddOrUpdate . find ( name ) ;
if ( it & & it - > getBestClaim ( claim ) )
return true ;
if ( it | | nodesToDelete . count ( name ) )
return false ;
2019-08-24 18:43:56 -06:00
CClaimTrieData claims ;
return base - > find ( name , claims ) & & claims . getBestClaim ( claim ) ;
2018-08-06 15:40:20 -04:00
}
2019-09-02 16:39:01 +03:00
template < typename T >
void CClaimTrieCacheBase : : insertRowsFromQueue ( std : : vector < T > & result , const std : : string & name ) const
{
supportedType < T > ( ) ;
if ( auto nameRows = getQueueCacheNameRow < T > ( name ) )
for ( auto & nameRow : * nameRows )
if ( auto rows = getQueueCacheRow < T > ( nameRow . nHeight ) )
for ( auto & row : * rows )
if ( row . first = = name )
result . push_back ( row . second ) ;
}
2019-08-08 16:39:57 +03:00
CClaimSupportToName CClaimTrieCacheBase : : getClaimsForName ( const std : : string & name ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
claimEntryType claims ;
int nLastTakeoverHeight = 0 ;
auto supports = getSupportsForName ( name ) ;
2019-09-02 16:39:01 +03:00
insertRowsFromQueue ( supports , name ) ;
2019-07-01 12:42:45 -06:00
2019-08-01 18:35:58 -06:00
if ( auto it = nodesToAddOrUpdate . find ( name ) ) {
2019-07-01 12:42:45 -06:00
claims = it - > claims ;
nLastTakeoverHeight = it - > nHeightOfLastTakeover ;
2019-09-02 16:39:01 +03:00
} else if ( ! nodesToDelete . count ( name ) ) {
CClaimTrieData data ;
if ( base - > find ( name , data ) ) {
claims = data . claims ;
nLastTakeoverHeight = data . nHeightOfLastTakeover ;
}
2018-08-06 15:40:20 -04:00
}
2019-09-02 16:39:01 +03:00
insertRowsFromQueue ( claims , name ) ;
2019-08-08 16:39:57 +03:00
auto find = [ & supports ] ( decltype ( supports ) : : iterator & it , const CClaimValue & claim ) {
it = std : : find_if ( it , supports . end ( ) , [ & claim ] ( const CSupportValue & support ) {
return claim . claimId = = support . supportedClaimId ;
} ) ;
return it ! = supports . end ( ) ;
} ;
2019-09-02 16:39:01 +03:00
2019-08-08 16:39:57 +03:00
// match support to claim
std : : vector < CClaimNsupports > claimsNsupports ;
for ( const auto & claim : claims ) {
CAmount nAmount = claim . nValidAtHeight < nNextHeight ? claim . nAmount : 0 ;
auto ic = claimsNsupports . emplace ( claimsNsupports . end ( ) , claim , nAmount ) ;
for ( auto it = supports . begin ( ) ; find ( it , claim ) ; it = supports . erase ( it ) ) {
if ( it - > nValidAtHeight < nNextHeight )
ic - > effectiveAmount + = it - > nAmount ;
ic - > supports . emplace_back ( std : : move ( * it ) ) ;
2019-07-01 12:42:45 -06:00
}
2018-08-06 15:40:20 -04:00
}
2019-08-08 16:39:57 +03:00
return { name , nLastTakeoverHeight , std : : move ( claimsNsupports ) , std : : move ( supports ) } ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
void completeHash ( uint256 & partialHash , const std : : string & key , std : : size_t to )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
CHash256 hasher ;
for ( auto i = key . size ( ) ; i > to + 1 ; - - i , hasher . Reset ( ) )
hasher
. Write ( ( uint8_t * ) & key [ i - 1 ] , 1 )
. Write ( partialHash . begin ( ) , partialHash . size ( ) )
. Finalize ( partialHash . begin ( ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
bool CClaimTrie : : checkConsistency ( const uint256 & rootHash ) const
2019-07-02 18:49:02 +03:00
{
2019-08-01 18:35:58 -06:00
CClaimTrieDataNode node ;
2019-08-28 19:13:50 +03:00
if ( ! find ( { } , node ) | | node . hash ! = rootHash ) {
2019-08-01 18:35:58 -06:00
if ( rootHash = = one )
return true ;
2019-07-02 18:49:02 +03:00
2019-08-01 18:35:58 -06:00
return error ( " Mismatched root claim trie hashes. This may happen when there is not a clean process shutdown. Please run with -reindex. " ) ;
}
bool success = true ;
2019-08-28 19:13:50 +03:00
recurseNodes ( { } , node , [ & success , this ] ( const std : : string & name , const CClaimTrieData & data , const std : : vector < std : : string > & children ) {
2019-08-02 17:27:28 -06:00
if ( ! success ) return ;
2019-08-01 18:35:58 -06:00
std : : vector < uint8_t > vchToHash ;
const auto pos = name . size ( ) ;
2019-08-24 18:43:56 -06:00
for ( auto & child : children ) {
auto key = name + child ;
CClaimTrieDataNode node ;
success & = find ( key , node ) ;
auto hash = node . hash ;
2019-08-01 18:35:58 -06:00
completeHash ( hash , key , pos ) ;
vchToHash . push_back ( key [ pos ] ) ;
vchToHash . insert ( vchToHash . end ( ) , hash . begin ( ) , hash . end ( ) ) ;
2019-07-02 18:49:02 +03:00
}
2019-08-01 18:35:58 -06:00
CClaimValue claim ;
2019-08-24 18:43:56 -06:00
if ( data . getBestClaim ( claim ) ) {
uint256 valueHash = getValueHash ( claim . outPoint , data . nHeightOfLastTakeover ) ;
2019-08-01 18:35:58 -06:00
vchToHash . insert ( vchToHash . end ( ) , valueHash . begin ( ) , valueHash . end ( ) ) ;
} else {
2019-08-24 18:43:56 -06:00
success & = ! children . empty ( ) ; // we disallow leaf nodes without claims
2019-07-02 18:49:02 +03:00
}
2019-08-24 18:43:56 -06:00
success & = data . hash = = Hash ( vchToHash . begin ( ) , vchToHash . end ( ) ) ;
2019-08-01 18:35:58 -06:00
} ) ;
return success ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
std : : vector < std : : pair < std : : string , CClaimTrieDataNode > > CClaimTrie : : nodes ( const std : : string & key ) const {
std : : vector < std : : pair < std : : string , CClaimTrieDataNode > > ret ;
CClaimTrieDataNode node ;
2018-08-06 15:40:20 -04:00
2019-08-28 19:13:50 +03:00
if ( ! find ( { } , node ) )
2019-08-01 18:35:58 -06:00
return ret ;
2019-08-28 19:13:50 +03:00
ret . emplace_back ( std : : string { } , node ) ;
2019-08-01 18:35:58 -06:00
std : : string partialKey = key ;
while ( ! node . children . empty ( ) ) {
2019-08-02 17:27:28 -06:00
// auto it = node.children.lower_bound(partialKey); // for using a std::map
2019-08-24 18:43:56 -06:00
auto it = std : : lower_bound ( node . children . begin ( ) , node . children . end ( ) , partialKey ) ;
if ( it ! = node . children . end ( ) & & * it = = partialKey ) {
2019-08-01 18:35:58 -06:00
// we're completely done
2019-08-24 18:43:56 -06:00
if ( find ( key , node ) )
2019-08-01 18:35:58 -06:00
ret . emplace_back ( key , node ) ;
break ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
if ( it ! = node . children . begin ( ) ) - - it ;
2019-08-24 18:43:56 -06:00
const auto count = match ( partialKey , * it ) ;
2019-08-01 18:35:58 -06:00
2019-08-24 18:43:56 -06:00
if ( count ! = it - > size ( ) ) break ;
2019-08-01 18:35:58 -06:00
if ( count = = partialKey . size ( ) ) break ;
partialKey = partialKey . substr ( count ) ;
2019-08-24 18:43:56 -06:00
auto frontKey = key . substr ( 0 , key . size ( ) - partialKey . size ( ) ) ;
if ( find ( frontKey , node ) )
ret . emplace_back ( frontKey , node ) ;
2019-08-01 18:35:58 -06:00
else break ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
return ret ;
}
bool CClaimTrie : : contains ( const std : : string & key ) const {
2019-08-24 18:43:56 -06:00
return db - > Exists ( std : : make_pair ( TRIE_NODE_CHILDREN , key ) ) ;
2019-08-01 18:35:58 -06:00
}
bool CClaimTrie : : empty ( ) const {
2019-08-28 19:13:50 +03:00
return ! contains ( { } ) ;
2019-08-01 18:35:58 -06:00
}
2019-08-24 18:43:56 -06:00
bool CClaimTrie : : find ( const std : : string & key , CClaimTrieDataNode & node ) const {
return db - > Read ( std : : make_pair ( TRIE_NODE_CHILDREN , key ) , node ) ;
2019-08-01 18:35:58 -06:00
}
2019-08-24 18:43:56 -06:00
bool CClaimTrie : : find ( const std : : string & key , CClaimTrieData & data ) const {
return db - > Read ( std : : make_pair ( TRIE_NODE_CLAIMS , key ) , data ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
template < typename K , typename T >
void BatchWrite ( CDBBatch & batch , uint8_t dbkey , const K & key , const std : : vector < T > & value )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
if ( value . empty ( ) ) {
batch . Erase ( std : : make_pair ( dbkey , key ) ) ;
} else {
batch . Write ( std : : make_pair ( dbkey , key ) , value ) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
template < typename Container >
void BatchWriteQueue ( CDBBatch & batch , uint8_t dbkey , const Container & queue )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
for ( auto & itQueue : queue )
BatchWrite ( batch , dbkey , itQueue . first , itQueue . second ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : flush ( )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
CDBBatch batch ( * ( base - > db ) ) ;
2018-08-06 15:40:20 -04:00
2019-07-22 15:53:17 -06:00
for ( const auto & claim : claimsToDeleteFromByIdIndex ) {
auto it = std : : find_if ( claimsToAddToByIdIndex . begin ( ) , claimsToAddToByIdIndex . end ( ) ,
2019-07-01 12:42:45 -06:00
[ & claim ] ( const CClaimIndexElement & e ) {
return e . claim . claimId = = claim . claimId ;
}
) ;
2019-07-22 15:53:17 -06:00
if ( it = = claimsToAddToByIdIndex . end ( ) )
2019-07-01 12:42:45 -06:00
batch . Erase ( std : : make_pair ( CLAIM_BY_ID , claim . claimId ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-22 15:53:17 -06:00
for ( const auto & e : claimsToAddToByIdIndex )
2019-07-01 12:42:45 -06:00
batch . Write ( std : : make_pair ( CLAIM_BY_ID , e . claim . claimId ) , e ) ;
2018-08-06 15:40:20 -04:00
2019-07-19 18:36:53 +03:00
getMerkleHash ( ) ;
2018-08-06 15:40:20 -04:00
2019-07-22 15:53:17 -06:00
for ( auto it = nodesToAddOrUpdate . begin ( ) ; it ! = nodesToAddOrUpdate . end ( ) ; + + it ) {
2019-08-28 19:13:50 +03:00
bool removed = forDeleteFromBase . erase ( it . key ( ) ) ;
2019-08-24 18:43:56 -06:00
if ( it - > flags & CClaimTrieDataFlags : : HASH_DIRTY ) {
CClaimTrieDataNode node ;
node . hash = it - > hash ;
for ( auto & child : it . children ( ) ) // ordering here is important
node . children . push_back ( child . key ( ) . substr ( it . key ( ) . size ( ) ) ) ;
2019-08-01 18:35:58 -06:00
2019-08-24 18:43:56 -06:00
batch . Write ( std : : make_pair ( TRIE_NODE_CHILDREN , it . key ( ) ) , node ) ;
2019-08-01 18:35:58 -06:00
2019-08-24 18:43:56 -06:00
if ( removed | | ( it - > flags & CClaimTrieDataFlags : : CLAIMS_DIRTY ) )
batch . Write ( std : : make_pair ( TRIE_NODE_CLAIMS , it . key ( ) ) , it . data ( ) ) ;
}
2019-08-01 18:35:58 -06:00
}
2019-08-28 19:13:50 +03:00
for ( auto & name : forDeleteFromBase ) {
2019-08-24 18:43:56 -06:00
batch . Erase ( std : : make_pair ( TRIE_NODE_CHILDREN , name ) ) ;
batch . Erase ( std : : make_pair ( TRIE_NODE_CLAIMS , name ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-22 15:53:17 -06:00
BatchWriteQueue ( batch , SUPPORT , supportCache ) ;
2019-08-01 18:35:58 -06:00
2019-07-01 12:42:45 -06:00
BatchWriteQueue ( batch , CLAIM_QUEUE_ROW , claimQueueCache ) ;
BatchWriteQueue ( batch , CLAIM_QUEUE_NAME_ROW , claimQueueNameCache ) ;
2019-08-01 18:35:58 -06:00
BatchWriteQueue ( batch , CLAIM_EXP_QUEUE_ROW , expirationQueueCache ) ;
2019-07-01 12:42:45 -06:00
BatchWriteQueue ( batch , SUPPORT_QUEUE_ROW , supportQueueCache ) ;
BatchWriteQueue ( batch , SUPPORT_QUEUE_NAME_ROW , supportQueueNameCache ) ;
BatchWriteQueue ( batch , SUPPORT_EXP_QUEUE_ROW , supportExpirationQueueCache ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
base - > nNextHeight = nNextHeight ;
2019-08-01 18:35:58 -06:00
if ( ! nodesToAddOrUpdate . empty ( ) & & ( LogAcceptCategory ( BCLog : : CLAIMS ) | | LogAcceptCategory ( BCLog : : BENCH ) ) ) {
LogPrintf ( " TrieCache size: %zu nodes on block %d, batch writes %zu bytes. \n " ,
nodesToAddOrUpdate . height ( ) , nNextHeight , batch . SizeEstimate ( ) ) ;
}
2019-07-01 12:42:45 -06:00
auto ret = base - > db - > WriteBatch ( batch ) ;
2019-08-24 18:43:56 -06:00
2019-07-01 12:42:45 -06:00
clear ( ) ;
return ret ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
bool CClaimTrieCacheBase : : validateTrieConsistency ( const CBlockIndex * tip )
2018-08-06 15:40:20 -04:00
{
2019-08-01 18:35:58 -06:00
if ( ! tip | | tip - > nHeight < 1 )
return true ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
LogPrintf ( " Checking claim trie consistency... " ) ;
2019-08-01 18:35:58 -06:00
if ( base - > checkConsistency ( tip - > hashClaimTrie ) ) {
2019-07-01 12:42:45 -06:00
LogPrintf ( " consistent \n " ) ;
return true ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
LogPrintf ( " inconsistent! \n " ) ;
return false ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
bool CClaimTrieCacheBase : : ReadFromDisk ( const CBlockIndex * tip )
{
base - > nNextHeight = nNextHeight = tip ? tip - > nHeight + 1 : 0 ;
clear ( ) ;
2019-08-24 18:43:56 -06:00
if ( tip & & base - > db - > Exists ( std : : make_pair ( TRIE_NODE , std : : string ( ) ) ) ) {
2019-09-16 14:54:05 -06:00
LogPrintf ( " The claim trie database contains deprecated data and will need to be rebuilt \n " ) ;
2019-08-01 18:35:58 -06:00
return false ;
}
return validateTrieConsistency ( tip ) ;
}
2019-07-29 10:25:41 -06:00
CClaimTrieCacheBase : : CClaimTrieCacheBase ( CClaimTrie * base ) : base ( base )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
assert ( base ) ;
nNextHeight = base - > nNextHeight ;
2018-08-06 15:40:20 -04:00
}
2019-07-09 18:02:54 +03:00
int CClaimTrieCacheBase : : expirationTime ( ) const
2018-08-06 15:40:20 -04:00
{
2019-07-09 18:02:54 +03:00
return Params ( ) . GetConsensus ( ) . nOriginalClaimExpirationTime ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
uint256 CClaimTrieCacheBase : : recursiveComputeMerkleHash ( CClaimPrefixTrie : : iterator & it )
2018-08-06 15:40:20 -04:00
{
2019-08-24 18:43:56 -06:00
if ( ! it - > hash . IsNull ( ) )
return it - > hash ;
std : : vector < uint8_t > vchToHash ;
const auto pos = it . key ( ) . size ( ) ;
for ( auto & child : it . children ( ) ) {
auto hash = recursiveComputeMerkleHash ( child ) ;
auto & key = child . key ( ) ;
completeHash ( hash , key , pos ) ;
vchToHash . push_back ( key [ pos ] ) ;
vchToHash . insert ( vchToHash . end ( ) , hash . begin ( ) , hash . end ( ) ) ;
}
CClaimValue claim ;
if ( it - > getBestClaim ( claim ) ) {
uint256 valueHash = getValueHash ( claim . outPoint , it - > nHeightOfLastTakeover ) ;
vchToHash . insert ( vchToHash . end ( ) , valueHash . begin ( ) , valueHash . end ( ) ) ;
}
2019-08-28 19:13:50 +03:00
return it - > hash = Hash ( vchToHash . begin ( ) , vchToHash . end ( ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
uint256 CClaimTrieCacheBase : : getMerkleHash ( )
2018-08-06 15:40:20 -04:00
{
2019-08-28 19:13:50 +03:00
if ( auto it = nodesToAddOrUpdate . begin ( ) )
2019-08-01 18:35:58 -06:00
return recursiveComputeMerkleHash ( it ) ;
if ( nodesToDelete . empty ( ) & & nodesAlreadyCached . empty ( ) ) {
CClaimTrieDataNode node ;
2019-08-28 19:13:50 +03:00
if ( base - > find ( { } , node ) )
2019-08-24 18:43:56 -06:00
return node . hash ; // it may be valuable to have base cache its current root hash
2019-08-01 18:35:58 -06:00
}
return one ; // we have no data or we deleted everything
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
CClaimPrefixTrie : : const_iterator CClaimTrieCacheBase : : begin ( ) const
2018-08-06 15:40:20 -04:00
{
2019-08-01 18:35:58 -06:00
return nodesToAddOrUpdate . begin ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
CClaimPrefixTrie : : const_iterator CClaimTrieCacheBase : : end ( ) const
2019-07-01 12:42:45 -06:00
{
2019-08-01 18:35:58 -06:00
return nodesToAddOrUpdate . end ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : empty ( ) const
2018-08-06 15:40:20 -04:00
{
2019-08-01 18:35:58 -06:00
return nodesToAddOrUpdate . empty ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
CClaimPrefixTrie : : iterator CClaimTrieCacheBase : : cacheData ( const std : : string & name , bool create )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
// we need all parent nodes and their one level deep children
// to calculate merkle hash
auto nodes = base - > nodes ( name ) ;
for ( auto & node : nodes ) {
2019-08-02 17:27:28 -06:00
if ( nodesAlreadyCached . insert ( node . first ) . second ) {
2019-08-01 18:35:58 -06:00
// do not insert nodes that are already present
2019-08-24 18:43:56 -06:00
CClaimTrieData data ;
2019-08-28 19:13:50 +03:00
base - > find ( node . first , data ) ;
2019-08-24 18:43:56 -06:00
data . hash = node . second . hash ;
data . flags = node . second . children . empty ( ) ? 0 : CClaimTrieDataFlags : : POTENTIAL_CHILDREN ;
nodesToAddOrUpdate . insert ( node . first , data ) ;
2019-08-01 18:35:58 -06:00
}
for ( auto & child : node . second . children ) {
2019-08-24 18:43:56 -06:00
auto childKey = node . first + child ;
2019-08-02 17:27:28 -06:00
if ( nodesAlreadyCached . insert ( childKey ) . second ) {
2019-08-24 18:43:56 -06:00
CClaimTrieData childData ;
if ( ! base - > find ( childKey , childData ) )
childData = { } ;
2019-08-01 18:35:58 -06:00
CClaimTrieDataNode childNode ;
2019-08-28 19:13:50 +03:00
if ( base - > find ( childKey , childNode ) ) {
2019-08-24 18:43:56 -06:00
childData . hash = childNode . hash ;
childData . flags = childNode . children . empty ( ) ? 0 : CClaimTrieDataFlags : : POTENTIAL_CHILDREN ;
2019-08-01 18:35:58 -06:00
}
2019-08-24 18:43:56 -06:00
nodesToAddOrUpdate . insert ( childKey , childData ) ;
2019-08-01 18:35:58 -06:00
}
}
2018-08-06 15:40:20 -04:00
}
2019-07-22 15:53:17 -06:00
auto it = nodesToAddOrUpdate . find ( name ) ;
2019-07-01 12:42:45 -06:00
if ( ! it & & create ) {
2019-07-22 15:53:17 -06:00
it = nodesToAddOrUpdate . insert ( name , CClaimTrieData { } ) ;
2019-08-24 18:43:56 -06:00
// if (it.hasChildren()) any children should be in the trie (not base alone)
// it->flags |= CClaimTrieDataFlags::POTENTIAL_CHILDREN;
2019-07-01 12:42:45 -06:00
confirmTakeoverWorkaroundNeeded ( name ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
// make sure takeover height is updated
if ( it & & it - > nHeightOfLastTakeover < = 0 ) {
uint160 unused ;
getLastTakeoverForName ( name , unused , it - > nHeightOfLastTakeover ) ;
}
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
return it ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : getLastTakeoverForName ( const std : : string & name , uint160 & claimId , int & takeoverHeight ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
// takeoverCache always contains the most recent takeover occurring before the current block
auto cit = takeoverCache . find ( name ) ;
if ( cit ! = takeoverCache . end ( ) ) {
std : : tie ( claimId , takeoverHeight ) = cit - > second ;
return true ;
2018-08-06 15:40:20 -04:00
}
2019-08-24 18:43:56 -06:00
CClaimTrieData data ;
2019-08-01 18:35:58 -06:00
if ( base - > find ( name , data ) ) {
2019-08-24 18:43:56 -06:00
takeoverHeight = data . nHeightOfLastTakeover ;
2019-07-01 12:42:45 -06:00
CClaimValue claim ;
2019-08-24 18:43:56 -06:00
if ( data . getBestClaim ( claim ) ) {
2019-07-01 12:42:45 -06:00
claimId = claim . claimId ;
return true ;
}
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
return false ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
void CClaimTrieCacheBase : : markAsDirty ( const std : : string & name , bool fCheckTakeover )
2018-08-06 15:40:20 -04:00
{
2019-08-01 18:35:58 -06:00
for ( auto & node : nodesToAddOrUpdate . nodes ( name ) ) {
2019-08-24 18:43:56 -06:00
node - > flags | = CClaimTrieDataFlags : : HASH_DIRTY ;
2019-07-01 12:42:45 -06:00
node - > hash . SetNull ( ) ;
2019-08-24 18:43:56 -06:00
if ( node . key ( ) = = name )
node - > flags | = CClaimTrieDataFlags : : CLAIMS_DIRTY ;
2019-08-01 18:35:58 -06:00
}
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
if ( fCheckTakeover )
namesToCheckForTakeover . insert ( name ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : insertClaimIntoTrie ( const std : : string & name , const CClaimValue & claim , bool fCheckTakeover )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto it = cacheData ( name ) ;
it - > insertClaim ( claim ) ;
auto supports = getSupportsForName ( name ) ;
it - > reorderClaims ( supports ) ;
markAsDirty ( name , fCheckTakeover ) ;
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : removeClaimFromTrie ( const std : : string & name , const COutPoint & outPoint , CClaimValue & claim , bool fCheckTakeover )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto it = cacheData ( name , false ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
if ( ! it | | ! it - > removeClaim ( outPoint , claim ) ) {
2019-08-01 18:35:58 -06:00
LogPrint ( BCLog : : CLAIMS , " %s: Removing a claim was unsuccessful. name = %s, txhash = %s, nOut = %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n ) ;
2018-08-06 15:40:20 -04:00
return false ;
}
2019-07-01 12:42:45 -06:00
if ( ! it - > claims . empty ( ) ) {
auto supports = getSupportsForName ( name ) ;
it - > reorderClaims ( supports ) ;
} else {
// in case we pull a child into our spot; we will then need their kids for hash
2019-08-28 19:13:50 +03:00
bool hasChild = it . hasChildren ( ) ;
for ( auto & child : it . children ( ) )
2019-07-01 12:42:45 -06:00
cacheData ( child . key ( ) , false ) ;
2019-08-28 19:13:50 +03:00
for ( auto & node : nodesToAddOrUpdate . nodes ( name ) )
forDeleteFromBase . emplace ( node . key ( ) ) ;
2018-08-06 15:40:20 -04:00
2019-07-22 15:53:17 -06:00
nodesToAddOrUpdate . erase ( name ) ;
2019-07-01 12:42:45 -06:00
nodesToDelete . insert ( name ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
// NOTE: old code had a bug in it where nodes with no claims but with children would get left in the cache.
// This would cause the getNumBlocksOfContinuousOwnership to return zero (causing incorrect takeover height calc).
if ( hasChild & & nNextHeight < Params ( ) . GetConsensus ( ) . nMaxTakeoverWorkaroundHeight ) {
removalWorkaround . insert ( name ) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
markAsDirty ( name , fCheckTakeover ) ;
return true ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < typename T >
T CClaimTrieCacheBase : : add ( const std : : string & name , const COutPoint & outPoint , const uint160 & claimId , CAmount nAmount , int nHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
supportedType < T > ( ) ;
2019-07-01 12:42:45 -06:00
assert ( nHeight = = nNextHeight ) ;
2019-07-02 18:49:02 +03:00
auto delay = getDelayForName ( name , claimId ) ;
T value ( outPoint , claimId , nAmount , nHeight , nHeight + delay ) ;
addToQueue ( name , value ) ;
return value ;
}
bool CClaimTrieCacheBase : : addClaim ( const std : : string & name , const COutPoint & outPoint , const uint160 & claimId , CAmount nAmount , int nHeight )
{
auto claim = add < CClaimValue > ( name , outPoint , claimId , nAmount , nHeight ) ;
2019-07-22 15:53:17 -06:00
claimsToAddToByIdIndex . emplace_back ( name , claim ) ;
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " %s: name: %s, txhash: %s, nOut: %d, claimId: %s, nAmount: %d, nHeight: %d, nValidHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , claimId . GetHex ( ) , nAmount , nHeight , claim . nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : addSupport ( const std : : string & name , const COutPoint & outPoint , CAmount nAmount , const uint160 & supportedClaimId , int nHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " %s: name: %s, txhash: %s, nOut: %d, nAmount: %d, supportedClaimId: %s, nHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nAmount , supportedClaimId . GetHex ( ) , nHeight , nNextHeight ) ;
2019-07-02 18:49:02 +03:00
add < CSupportValue > ( name , outPoint , supportedClaimId , nAmount , nHeight ) ;
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-02 18:49:02 +03:00
template < typename T >
bool CClaimTrieCacheBase : : addToQueue ( const std : : string & name , const T & value )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
supportedType < T > ( ) ;
const auto newName = adjustNameForValidHeight ( name , value . nValidAtHeight ) ;
auto itQueueCache = getQueueCacheRow < T > ( value . nValidAtHeight , true ) ;
2019-08-28 19:13:50 +03:00
itQueueCache - > emplace_back ( newName , value ) ;
2019-07-02 18:49:02 +03:00
auto itQueueName = getQueueCacheNameRow < T > ( newName , true ) ;
2019-08-28 19:13:50 +03:00
itQueueName - > emplace_back ( value . outPoint , value . nValidAtHeight ) ;
2019-07-02 18:49:02 +03:00
auto itQueueExpiration = getExpirationQueueCacheRow < T > ( value . nHeight + expirationTime ( ) , true ) ;
2019-08-28 19:13:50 +03:00
itQueueExpiration - > emplace_back ( newName , value . outPoint ) ;
2019-07-01 12:42:45 -06:00
return true ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < >
bool CClaimTrieCacheBase : : addToCache ( const std : : string & name , const CClaimValue & value , bool fCheckTakeover )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
return insertClaimIntoTrie ( name , value , fCheckTakeover ) ;
}
template < >
bool CClaimTrieCacheBase : : addToCache ( const std : : string & name , const CSupportValue & value , bool fCheckTakeover )
{
return insertSupportIntoMap ( name , value , fCheckTakeover ) ;
}
template < typename T >
bool CClaimTrieCacheBase : : addToCache ( const std : : string & , const T & , bool )
{
supportedType < T > ( ) ;
return false ;
}
template < typename T >
bool CClaimTrieCacheBase : : undoSpend ( const std : : string & name , const T & value , int nValidAtHeight )
{
supportedType < T > ( ) ;
if ( nValidAtHeight < nNextHeight ) {
auto itQueueExpiration = getExpirationQueueCacheRow < T > ( value . nHeight + expirationTime ( ) , true ) ;
2019-08-28 19:13:50 +03:00
itQueueExpiration - > emplace_back ( adjustNameForValidHeight ( name , nValidAtHeight ) , value . outPoint ) ;
2019-07-02 18:49:02 +03:00
return addToCache ( name , value , false ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
return addToQueue ( name , value ) ;
}
bool CClaimTrieCacheBase : : undoSpendClaim ( const std : : string & name , const COutPoint & outPoint , const uint160 & claimId , CAmount nAmount , int nHeight , int nValidAtHeight )
{
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " %s: name: %s, txhash: %s, nOut: %d, claimId: %s, nAmount: %d, nHeight: %d, nValidAtHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , claimId . GetHex ( ) , nAmount , nHeight , nValidAtHeight , nNextHeight ) ;
2019-07-02 18:49:02 +03:00
CClaimValue claim ( outPoint , claimId , nAmount , nHeight , nValidAtHeight ) ;
2019-07-22 15:53:17 -06:00
claimsToAddToByIdIndex . emplace_back ( name , claim ) ;
2019-07-02 18:49:02 +03:00
return undoSpend ( name , claim , nValidAtHeight ) ;
}
2018-08-06 15:40:20 -04:00
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : undoSpendSupport ( const std : : string & name , const COutPoint & outPoint , const uint160 & supportedClaimId , CAmount nAmount , int nHeight , int nValidAtHeight )
{
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " %s: name: %s, txhash: %s, nOut: %d, nAmount: %d, supportedClaimId: %s, nHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nAmount , supportedClaimId . GetHex ( ) , nHeight , nNextHeight ) ;
2019-07-02 18:49:02 +03:00
CSupportValue support ( outPoint , supportedClaimId , nAmount , nHeight , nValidAtHeight ) ;
return undoSpend ( name , support , nValidAtHeight ) ;
}
template < typename T >
bool CClaimTrieCacheBase : : removeFromQueue ( const std : : string & name , const COutPoint & outPoint , T & value )
{
supportedType < T > ( ) ;
2019-08-28 19:13:50 +03:00
if ( auto itQueueNameRow = getQueueCacheNameRow < T > ( name , false ) ) {
auto itQueueName = findOutPoint ( * itQueueNameRow , outPoint ) ;
if ( itQueueName ! = itQueueNameRow - > end ( ) ) {
if ( auto itQueueRow = getQueueCacheRow < T > ( itQueueName - > nHeight , false ) ) {
auto itQueue = findOutPoint ( * itQueueRow , CNameOutPointType { name , outPoint } ) ;
if ( itQueue ! = itQueueRow - > end ( ) ) {
2019-07-02 18:49:02 +03:00
std : : swap ( value , itQueue - > second ) ;
2019-08-28 19:13:50 +03:00
itQueueNameRow - > erase ( itQueueName ) ;
itQueueRow - > erase ( itQueue ) ;
2019-07-02 18:49:02 +03:00
return true ;
2019-07-01 12:42:45 -06:00
}
}
2019-07-02 18:49:02 +03:00
LogPrintf ( " %s: An inconsistency was found in the claim queue. Please report this to the developers: \n Found in named queue but not in height queue: name: %s, txid: %s, nOut: %d, nValidAtHeight: %d, current height: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , itQueueName - > nHeight , nNextHeight ) ;
2018-08-06 15:40:20 -04:00
}
}
return false ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : undoAddClaim ( const std : : string & name , const COutPoint & outPoint , int nHeight )
2018-08-06 15:40:20 -04:00
{
int throwaway ;
return removeClaim ( name , outPoint , nHeight , throwaway , false ) ;
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : undoAddSupport ( const std : : string & name , const COutPoint & outPoint , int nHeight )
{
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " %s: name: %s, txhash: %s, nOut: %d, nHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nHeight , nNextHeight ) ;
2019-07-02 18:49:02 +03:00
int throwaway ;
return removeSupport ( name , outPoint , nHeight , throwaway , false ) ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : spendClaim ( const std : : string & name , const COutPoint & outPoint , int nHeight , int & nValidAtHeight )
2018-08-06 15:40:20 -04:00
{
return removeClaim ( name , outPoint , nHeight , nValidAtHeight , true ) ;
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : spendSupport ( const std : : string & name , const COutPoint & outPoint , int nHeight , int & nValidAtHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " %s: name: %s, txhash: %s, nOut: %d, nHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nHeight , nNextHeight ) ;
2019-07-02 18:49:02 +03:00
return removeSupport ( name , outPoint , nHeight , nValidAtHeight , true ) ;
}
2019-07-01 12:42:45 -06:00
2019-07-02 18:49:02 +03:00
template < >
bool CClaimTrieCacheBase : : removeFromCache ( const std : : string & name , const COutPoint & outPoint , CClaimValue & value , bool fCheckTakeover )
{
return removeClaimFromTrie ( name , outPoint , value , fCheckTakeover ) ;
}
template < >
bool CClaimTrieCacheBase : : removeFromCache ( const std : : string & name , const COutPoint & outPoint , CSupportValue & value , bool fCheckTakeover )
{
return removeSupportFromMap ( name , outPoint , value , fCheckTakeover ) ;
}
template < typename T >
bool CClaimTrieCacheBase : : removeFromCache ( const std : : string & name , const COutPoint & outPoint , T & value , bool fCheckTakeover )
{
supportedType < T > ( ) ;
return false ;
}
template < typename T >
bool CClaimTrieCacheBase : : remove ( T & value , const std : : string & name , const COutPoint & outPoint , int nHeight , int & nValidAtHeight , bool fCheckTakeover )
{
supportedType < T > ( ) ;
2018-08-06 15:40:20 -04:00
nValidAtHeight = nHeight + getDelayForName ( name ) ;
std : : string adjusted = adjustNameForValidHeight ( name , nValidAtHeight ) ;
2019-07-02 18:49:02 +03:00
if ( removeFromQueue ( adjusted , outPoint , value ) | | removeFromCache ( name , outPoint , value , fCheckTakeover ) ) {
int expirationHeight = value . nHeight + expirationTime ( ) ;
2019-08-28 19:13:50 +03:00
if ( auto itQueueRow = getExpirationQueueCacheRow < T > ( expirationHeight , false ) )
eraseOutPoint ( * itQueueRow , CNameOutPointType { adjusted , outPoint } ) ;
2019-07-02 18:49:02 +03:00
nValidAtHeight = value . nValidAtHeight ;
2019-07-01 12:42:45 -06:00
return true ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
return false ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : removeClaim ( const std : : string & name , const COutPoint & outPoint , int nHeight , int & nValidAtHeight , bool fCheckTakeover )
2018-08-06 15:40:20 -04:00
{
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " %s: name: %s, txhash: %s, nOut: %s, nNextHeight: %s \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nNextHeight ) ;
2019-07-02 18:49:02 +03:00
CClaimValue claim ;
if ( remove ( claim , name , outPoint , nHeight , nValidAtHeight , fCheckTakeover ) ) {
2019-07-22 15:53:17 -06:00
claimsToDeleteFromByIdIndex . insert ( claim ) ;
2019-07-02 18:49:02 +03:00
return true ;
}
return false ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : removeSupport ( const std : : string & name , const COutPoint & outPoint , int nHeight , int & nValidAtHeight , bool fCheckTakeover )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
CSupportValue support ;
return remove ( support , name , outPoint , nHeight , nValidAtHeight , fCheckTakeover ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : insertSupportIntoMap ( const std : : string & name , const CSupportValue & support , bool fCheckTakeover )
2018-08-06 15:40:20 -04:00
{
2019-07-22 15:53:17 -06:00
auto sit = supportCache . find ( name ) ;
if ( sit = = supportCache . end ( ) )
sit = supportCache . emplace ( name , getSupportsForName ( name ) ) . first ;
2018-08-06 15:40:20 -04:00
2019-07-02 18:49:02 +03:00
sit - > second . push_back ( support ) ;
2019-07-01 12:42:45 -06:00
addTakeoverWorkaroundPotential ( name ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
if ( auto it = cacheData ( name , false ) ) {
markAsDirty ( name , fCheckTakeover ) ;
it - > reorderClaims ( sit - > second ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : removeSupportFromMap ( const std : : string & name , const COutPoint & outPoint , CSupportValue & support , bool fCheckTakeover )
2018-08-06 15:40:20 -04:00
{
2019-07-22 15:53:17 -06:00
auto sit = supportCache . find ( name ) ;
if ( sit = = supportCache . end ( ) )
sit = supportCache . emplace ( name , getSupportsForName ( name ) ) . first ;
2018-08-06 15:40:20 -04:00
2019-07-02 18:49:02 +03:00
if ( eraseOutPoint ( sit - > second , outPoint , & support ) ) {
addTakeoverWorkaroundPotential ( name ) ;
2018-08-06 15:40:20 -04:00
2019-07-02 18:49:02 +03:00
if ( auto dit = cacheData ( name , false ) ) {
markAsDirty ( name , fCheckTakeover ) ;
dit - > reorderClaims ( sit - > second ) ;
2019-07-01 12:42:45 -06:00
}
return true ;
2018-08-06 15:40:20 -04:00
}
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " CClaimTrieCacheBase::%s() : asked to remove a support that doesn't exist \n " , __func__ ) ;
2019-07-01 12:42:45 -06:00
return false ;
2018-08-06 15:40:20 -04:00
}
2019-08-01 18:35:58 -06:00
void CClaimTrieCacheBase : : dumpToLog ( CClaimPrefixTrie : : const_iterator it , bool diffFromBase ) const
2018-08-06 15:40:20 -04:00
{
2019-08-01 18:35:58 -06:00
if ( ! it ) return ;
2019-07-01 12:42:45 -06:00
if ( diffFromBase ) {
2019-08-01 18:35:58 -06:00
CClaimTrieDataNode node ;
2019-08-24 18:43:56 -06:00
if ( base - > find ( it . key ( ) , node ) & & node . hash = = it - > hash )
2019-07-01 12:42:45 -06:00
return ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
std : : string indent ( it . depth ( ) , ' ' ) ;
auto children = it . children ( ) ;
2019-07-22 15:53:17 -06:00
auto empty = children . empty ( ) & & it - > claims . empty ( ) ;
2019-07-01 12:42:45 -06:00
LogPrintf ( " %s%s, %s, %zu = %s,%s take: %d, kids: %zu \n " , indent , it . key ( ) , HexStr ( it . key ( ) . begin ( ) , it . key ( ) . end ( ) ) ,
2019-07-02 18:49:02 +03:00
empty ? " empty, " : " " , it . depth ( ) , it - > hash . ToString ( ) , it - > nHeightOfLastTakeover , children . size ( ) ) ;
2019-07-01 12:42:45 -06:00
for ( auto & claim : it - > claims )
LogPrintf ( " %s claim: %s, %ld, %ld, %d, %d \n " , indent , claim . claimId . ToString ( ) , claim . nAmount , claim . nEffectiveAmount , claim . nHeight , claim . nValidAtHeight ) ;
auto supports = getSupportsForName ( it . key ( ) ) ;
for ( auto & support : supports )
LogPrintf ( " %s suprt: %s, %ld, %d, %d \n " , indent , support . supportedClaimId . ToString ( ) , support . nAmount , support . nHeight , support . nValidAtHeight ) ;
for ( auto & child : it . children ( ) )
dumpToLog ( child , diffFromBase ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : shouldUseTakeoverWorkaround ( const std : : string & key ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto it = takeoverWorkaround . find ( key ) ;
return it ! = takeoverWorkaround . end ( ) & & it - > second ;
}
2019-07-02 18:49:02 +03:00
void CClaimTrieCacheBase : : addTakeoverWorkaroundPotential ( const std : : string & key )
{
2019-07-01 12:42:45 -06:00
// the old code would add to the cache using a shortcut in the add/removeSupport methods
// this logic mimics the effects of that.
// (and the shortcut would later lead to a miscalculation of the takeover height)
if ( nNextHeight > Params ( ) . GetConsensus ( ) . nMinTakeoverWorkaroundHeight
& & nNextHeight < Params ( ) . GetConsensus ( ) . nMaxTakeoverWorkaroundHeight
2019-07-22 15:53:17 -06:00
& & ! nodesToAddOrUpdate . contains ( key ) & & base - > contains ( key ) )
2019-07-01 12:42:45 -06:00
takeoverWorkaround . emplace ( key , false ) ;
}
2019-07-02 18:49:02 +03:00
void CClaimTrieCacheBase : : confirmTakeoverWorkaroundNeeded ( const std : : string & key )
{
2019-07-01 12:42:45 -06:00
// This is a super ugly hack to work around bug in old code.
// The bug: un/support a name then update it. This will cause its takeover height to be reset to current.
// This is because the old code with add to the cache without setting block originals when dealing in supports.
// Disable this takeoverWorkaround stuff on a future hard fork.
if ( nNextHeight > Params ( ) . GetConsensus ( ) . nMinTakeoverWorkaroundHeight
& & nNextHeight < Params ( ) . GetConsensus ( ) . nMaxTakeoverWorkaroundHeight ) {
auto it = takeoverWorkaround . find ( key ) ;
if ( it ! = takeoverWorkaround . end ( ) )
( * it ) . second = true ;
}
}
2019-07-02 18:49:02 +03:00
template < typename T >
inline void addTo ( std : : set < T > * set , const T & value )
{
set - > insert ( value ) ;
}
2019-07-01 12:42:45 -06:00
2019-07-02 18:49:02 +03:00
template < >
inline void addTo ( std : : set < CSupportValue > * , const CSupportValue & )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
}
template < typename T >
void CClaimTrieCacheBase : : undoIncrement ( insertUndoType & insertUndo , std : : vector < queueEntryType < T > > & expireUndo , std : : set < T > * deleted )
{
supportedType < T > ( ) ;
2019-08-28 19:13:50 +03:00
if ( auto itQueueRow = getQueueCacheRow < T > ( nNextHeight , false ) ) {
for ( const auto & itEntry : * itQueueRow ) {
if ( auto itQueueNameRow = getQueueCacheNameRow < T > ( itEntry . first , false ) ) {
auto & points = * itQueueNameRow ;
2019-07-02 18:49:02 +03:00
auto itQueueName = std : : find_if ( points . begin ( ) , points . end ( ) , [ & itEntry , this ] ( const COutPointHeightType & point ) {
return point . outPoint = = itEntry . second . outPoint & & point . nHeight = = nNextHeight ;
} ) ;
if ( itQueueName ! = points . end ( ) ) {
points . erase ( itQueueName ) ;
} else {
LogPrintf ( " %s: An inconsistency was found in the queue. Please report this to the developers: \n Found in height queue but not in named queue: name: %s, txid: %s, nOut: %d, nValidAtHeight: %d, current height: %d \n " , __func__ , itEntry . first , itEntry . second . outPoint . hash . GetHex ( ) , itEntry . second . outPoint . n , itEntry . second . nValidAtHeight , nNextHeight ) ;
LogPrintf ( " Elements found for that name: \n " ) ;
2019-08-28 19:13:50 +03:00
for ( const auto & itQueueNameInner : points )
2019-07-22 15:53:17 -06:00
LogPrintf ( " \t txid: %s, nOut: %d, nValidAtHeight: %d \n " , itQueueNameInner . outPoint . hash . GetHex ( ) , itQueueNameInner . outPoint . n , itQueueNameInner . nHeight ) ;
2019-07-02 18:49:02 +03:00
assert ( false ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
} else {
2019-07-02 18:49:02 +03:00
LogPrintf ( " Nothing found for %s \n " , itEntry . first ) ;
assert ( false ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
addToCache ( itEntry . first , itEntry . second , true ) ;
2019-07-01 12:42:45 -06:00
insertUndo . emplace_back ( itEntry . first , itEntry . second . outPoint , itEntry . second . nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-28 19:13:50 +03:00
itQueueRow - > clear ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
2019-08-28 19:13:50 +03:00
if ( auto itExpirationRow = getExpirationQueueCacheRow < T > ( nNextHeight , false ) ) {
for ( const auto & itEntry : * itExpirationRow ) {
2019-07-02 18:49:02 +03:00
T value ;
assert ( removeFromCache ( itEntry . name , itEntry . outPoint , value , true ) ) ;
expireUndo . emplace_back ( itEntry . name , value ) ;
addTo ( deleted , value ) ;
2018-08-06 15:40:20 -04:00
}
2019-08-28 19:13:50 +03:00
itExpirationRow - > clear ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
}
2019-07-01 12:42:45 -06:00
2019-07-02 18:49:02 +03:00
template < typename T >
void CClaimTrieCacheBase : : undoIncrement ( const std : : string & name , insertUndoType & insertUndo , std : : vector < queueEntryType < T > > & expireUndo )
{
supportedType < T > ( ) ;
2019-08-28 19:13:50 +03:00
if ( auto itQueueNameRow = getQueueCacheNameRow < T > ( name , false ) ) {
for ( const auto & itQueueName : * itQueueNameRow ) {
2018-08-06 15:40:20 -04:00
bool found = false ;
2019-07-02 18:49:02 +03:00
// Pull those claims out of the height-based queue
2019-08-28 19:13:50 +03:00
if ( auto itQueueRow = getQueueCacheRow < T > ( itQueueName . nHeight , false ) ) {
auto & points = * itQueueRow ;
2019-07-02 18:49:02 +03:00
auto itQueue = std : : find_if ( points . begin ( ) , points . end ( ) , [ & name , & itQueueName ] ( const queueEntryType < T > & point ) {
return name = = point . first & & point . second . outPoint = = itQueueName . outPoint & & point . second . nValidAtHeight = = itQueueName . nHeight ;
} ) ;
if ( itQueue ! = points . end ( ) ) {
// Insert them into the queue undo with their previous nValidAtHeight
insertUndo . emplace_back ( itQueue - > first , itQueue - > second . outPoint , itQueue - > second . nValidAtHeight ) ;
// Insert them into the name trie with the new nValidAtHeight
itQueue - > second . nValidAtHeight = nNextHeight ;
addToCache ( itQueue - > first , itQueue - > second , false ) ;
// Delete them from the height-based queue
points . erase ( itQueue ) ;
found = true ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-02 18:49:02 +03:00
if ( ! found )
LogPrintf ( " %s(): An inconsistency was found in the queue. Please report this to the developers: \n Found in name queue but not in height based queue: \n name: %s, txid: %s, nOut: %d, nValidAtHeight in name based queue: %d, current height: %d \n " , __func__ , name , itQueueName . outPoint . hash . GetHex ( ) , itQueueName . outPoint . n , itQueueName . nHeight , nNextHeight ) ;
2019-07-01 12:42:45 -06:00
assert ( found ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
// remove all claims from the queue for that name
2019-08-28 19:13:50 +03:00
itQueueNameRow - > clear ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
}
bool CClaimTrieCacheBase : : incrementBlock ( insertUndoType & insertUndo , claimQueueRowType & expireUndo , insertUndoType & insertSupportUndo , supportQueueRowType & expireSupportUndo , std : : vector < std : : pair < std : : string , int > > & takeoverHeightUndo )
{
2019-07-22 15:53:17 -06:00
undoIncrement ( insertUndo , expireUndo , & claimsToDeleteFromByIdIndex ) ;
2019-07-02 18:49:02 +03:00
undoIncrement ( insertSupportUndo , expireSupportUndo ) ;
2019-07-01 12:42:45 -06:00
2018-08-06 15:40:20 -04:00
// check each potentially taken over name to see if a takeover occurred.
// if it did, then check the claim and support insertion queues for
// the names that have been taken over, immediately insert all claim and
// supports for those names, and stick them in the insertUndo or
// insertSupportUndo vectors, with the nValidAtHeight they had prior to
// this block.
// Run through all names that have been taken over
2019-07-01 12:42:45 -06:00
for ( const auto & itNamesToCheck : namesToCheckForTakeover ) {
// Check if a takeover has occurred (only going to hit each name once)
2019-07-22 15:53:17 -06:00
auto itCachedNode = nodesToAddOrUpdate . find ( itNamesToCheck ) ;
2018-08-06 15:40:20 -04:00
// many possibilities
// if this node is new, don't put it into the undo -- there will be nothing to restore, after all
// if all of this node's claims were deleted, it should be put into the undo -- there could be
// claims in the queue for that name and the takeover height should be the current height
// if the node is not in the cache, or getbestclaim fails, that means all of its claims were
// deleted
2019-07-01 12:42:45 -06:00
// if getLastTakeoverForName returns false, that means it's new and shouldn't go into the undo
2018-08-06 15:40:20 -04:00
// if both exist, and the current best claim is not the same as or the parent to the new best
// claim, then ownership has changed and the current height of last takeover should go into
// the queue
2019-07-01 12:42:45 -06:00
uint160 ownersClaimId ;
2019-07-02 18:49:02 +03:00
CClaimValue claimInCache ;
2019-07-01 12:42:45 -06:00
int ownersTakeoverHeight = 0 ;
bool haveClaimInTrie = getLastTakeoverForName ( itNamesToCheck , ownersClaimId , ownersTakeoverHeight ) ;
2019-07-02 18:49:02 +03:00
bool haveClaimInCache = itCachedNode & & itCachedNode - > getBestClaim ( claimInCache ) ;
2019-07-01 12:42:45 -06:00
bool takeoverHappened = ! haveClaimInCache | | ! haveClaimInTrie | | claimInCache . claimId ! = ownersClaimId ;
if ( takeoverHappened ) {
2018-08-06 15:40:20 -04:00
// Get all pending claims for that name and activate them all in the case that our winner is defunct.
2019-07-02 18:49:02 +03:00
undoIncrement ( itNamesToCheck , insertUndo , expireUndo ) ;
undoIncrement ( itNamesToCheck , insertSupportUndo , expireSupportUndo ) ;
2019-07-01 12:42:45 -06:00
}
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
// not sure if this should happen above or below the above code:
auto shouldUse = shouldUseTakeoverWorkaround ( itNamesToCheck ) ;
if ( ! takeoverHappened & & shouldUse )
2019-07-29 09:47:33 -06:00
LogPrint ( BCLog : : CLAIMS , " TakeoverHeight workaround affects block: %d, name: %s, th: %d \n " , nNextHeight , itNamesToCheck , ownersTakeoverHeight ) ;
2019-07-01 12:42:45 -06:00
takeoverHappened | = shouldUse ;
if ( haveClaimInTrie & & takeoverHappened )
takeoverHeightUndo . emplace_back ( itNamesToCheck , ownersTakeoverHeight ) ;
// some possible conditions:
// 1. we added a new claim
// 2. we updated a claim
// 3. we had a claim fall out of the queue early and take over (or not)
// 4. we removed a claim
// 5. we got new supports and so a new claim took over (or not)
// 6. we removed supports and so a new claim took over (or not)
// claim removal is handled by "else" below
// if there was a takeover, we set it to current height
// if there was no takeover, we set it to old height if we have one
// else set it to new height
2019-07-22 15:53:17 -06:00
if ( ( itCachedNode = nodesToAddOrUpdate . find ( itNamesToCheck ) ) ) {
2019-07-01 12:42:45 -06:00
if ( takeoverHappened ) {
itCachedNode - > nHeightOfLastTakeover = nNextHeight ;
CClaimValue winner ;
if ( itCachedNode - > getBestClaim ( winner ) )
takeoverCache [ itNamesToCheck ] = std : : make_pair ( winner . claimId , nNextHeight ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
assert ( itCachedNode - > hash . IsNull ( ) ) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
2018-08-06 15:40:20 -04:00
namesToCheckForTakeover . clear ( ) ;
2019-07-01 12:42:45 -06:00
takeoverWorkaround . clear ( ) ;
nNextHeight + + ;
return true ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
template < typename T >
inline void addToIndex ( std : : vector < CClaimIndexElement > * , const std : : string & , const T & )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
}
2018-08-06 15:40:20 -04:00
2019-07-02 18:49:02 +03:00
template < >
inline void addToIndex ( std : : vector < CClaimIndexElement > * index , const std : : string & name , const CClaimValue & value )
{
index - > emplace_back ( name , value ) ;
}
2018-08-06 15:40:20 -04:00
2019-07-02 18:49:02 +03:00
template < typename T >
void CClaimTrieCacheBase : : undoDecrement ( insertUndoType & insertUndo , std : : vector < queueEntryType < T > > & expireUndo , std : : vector < CClaimIndexElement > * index , std : : set < T > * deleted )
{
supportedType < T > ( ) ;
2019-07-01 12:42:45 -06:00
if ( ! expireUndo . empty ( ) ) {
for ( auto itExpireUndo = expireUndo . crbegin ( ) ; itExpireUndo ! = expireUndo . crend ( ) ; + + itExpireUndo ) {
2019-07-02 18:49:02 +03:00
addToCache ( itExpireUndo - > first , itExpireUndo - > second , false ) ;
addToIndex ( index , itExpireUndo - > first , itExpireUndo - > second ) ;
2019-08-28 19:13:50 +03:00
if ( nNextHeight = = itExpireUndo - > second . nHeight + expirationTime ( ) ) {
auto itExpireRow = getExpirationQueueCacheRow < T > ( nNextHeight , true ) ;
itExpireRow - > emplace_back ( itExpireUndo - > first , itExpireUndo - > second . outPoint ) ;
}
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
for ( auto itInsertUndo = insertUndo . crbegin ( ) ; itInsertUndo ! = insertUndo . crend ( ) ; + + itInsertUndo ) {
2019-07-02 18:49:02 +03:00
T value ;
assert ( removeFromCache ( itInsertUndo - > name , itInsertUndo - > outPoint , value , false ) ) ;
2019-07-01 12:42:45 -06:00
if ( itInsertUndo - > nHeight > = 0 ) { // aka it became valid at height rather than being rename/normalization
2019-07-02 18:49:02 +03:00
// value.nValidHeight may have been changed if this was inserted before activation height
2019-07-01 12:42:45 -06:00
// due to a triggered takeover, change it back to original nValidAtHeight
2019-07-02 18:49:02 +03:00
value . nValidAtHeight = itInsertUndo - > nHeight ;
auto itQueueRow = getQueueCacheRow < T > ( itInsertUndo - > nHeight , true ) ;
auto itQueueNameRow = getQueueCacheNameRow < T > ( itInsertUndo - > name , true ) ;
2019-08-28 19:13:50 +03:00
itQueueRow - > emplace_back ( itInsertUndo - > name , value ) ;
itQueueNameRow - > emplace_back ( itInsertUndo - > outPoint , value . nValidAtHeight ) ;
2019-07-01 12:42:45 -06:00
} else {
2019-07-02 18:49:02 +03:00
addTo ( deleted , value ) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-02 18:49:02 +03:00
}
bool CClaimTrieCacheBase : : decrementBlock ( insertUndoType & insertUndo , claimQueueRowType & expireUndo , insertUndoType & insertSupportUndo , supportQueueRowType & expireSupportUndo )
{
nNextHeight - - ;
undoDecrement ( insertSupportUndo , expireSupportUndo ) ;
2019-07-22 15:53:17 -06:00
undoDecrement ( insertUndo , expireUndo , & claimsToAddToByIdIndex , & claimsToDeleteFromByIdIndex ) ;
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : finalizeDecrement ( std : : vector < std : : pair < std : : string , int > > & takeoverHeightUndo )
{
2019-07-01 12:42:45 -06:00
for ( auto itTakeoverHeightUndo = takeoverHeightUndo . crbegin ( ) ; itTakeoverHeightUndo ! = takeoverHeightUndo . crend ( ) ; + + itTakeoverHeightUndo ) {
auto it = cacheData ( itTakeoverHeightUndo - > first , false ) ;
if ( it & & itTakeoverHeightUndo - > second ) {
it - > nHeightOfLastTakeover = itTakeoverHeightUndo - > second ;
CClaimValue winner ;
if ( it - > getBestClaim ( winner ) ) {
assert ( itTakeoverHeightUndo - > second < = nNextHeight ) ;
takeoverCache [ itTakeoverHeightUndo - > first ] = std : : make_pair ( winner . claimId , itTakeoverHeightUndo - > second ) ;
}
}
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-02 18:49:02 +03:00
template < typename T >
void CClaimTrieCacheBase : : reactivate ( const expirationQueueRowType & row , int height , bool increment )
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
supportedType < T > ( ) ;
2019-07-22 15:53:17 -06:00
for ( auto & e : row ) {
2019-07-02 18:49:02 +03:00
// remove and insert with new expiration time
2019-08-28 19:13:50 +03:00
if ( auto itQueueRow = getExpirationQueueCacheRow < T > ( height , false ) )
eraseOutPoint ( * itQueueRow , CNameOutPointType { e . name , e . outPoint } ) ;
2019-07-02 18:49:02 +03:00
int extend_expiration = Params ( ) . GetConsensus ( ) . nExtendedClaimExpirationTime - Params ( ) . GetConsensus ( ) . nOriginalClaimExpirationTime ;
int new_expiration_height = increment ? height + extend_expiration : height - extend_expiration ;
auto itQueueExpiration = getExpirationQueueCacheRow < T > ( new_expiration_height , true ) ;
2019-08-28 19:13:50 +03:00
itQueueExpiration - > emplace_back ( e . name , e . outPoint ) ;
2019-07-02 18:49:02 +03:00
}
}
2019-07-15 08:48:24 +03:00
void CClaimTrieCacheBase : : reactivateClaim ( const expirationQueueRowType & row , int height , bool increment )
{
reactivate < CClaimValue > ( row , height , increment ) ;
}
void CClaimTrieCacheBase : : reactivateSupport ( const expirationQueueRowType & row , int height , bool increment )
{
reactivate < CSupportValue > ( row , height , increment ) ;
}
2019-07-02 18:49:02 +03:00
int CClaimTrieCacheBase : : getNumBlocksOfContinuousOwnership ( const std : : string & name ) const
{
auto hit = removalWorkaround . find ( name ) ;
2019-07-01 12:42:45 -06:00
if ( hit ! = removalWorkaround . end ( ) ) {
2019-07-02 18:49:02 +03:00
auto that = const_cast < CClaimTrieCacheBase * > ( this ) ;
that - > removalWorkaround . erase ( hit ) ;
2018-08-06 15:40:20 -04:00
return 0 ;
}
2019-08-28 19:13:50 +03:00
if ( auto it = nodesToAddOrUpdate . find ( name ) )
return it - > empty ( ) ? 0 : nNextHeight - it - > nHeightOfLastTakeover ;
2019-08-24 18:43:56 -06:00
CClaimTrieData data ;
if ( base - > find ( name , data ) & & ! data . empty ( ) )
return nNextHeight - data . nHeightOfLastTakeover ;
2019-08-01 18:35:58 -06:00
return 0 ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
int CClaimTrieCacheBase : : getDelayForName ( const std : : string & name ) const
2018-08-06 15:40:20 -04:00
{
int nBlocksOfContinuousOwnership = getNumBlocksOfContinuousOwnership ( name ) ;
return std : : min ( nBlocksOfContinuousOwnership / base - > nProportionalDelayFactor , 4032 ) ;
}
2019-07-02 18:49:02 +03:00
int CClaimTrieCacheBase : : getDelayForName ( const std : : string & name , const uint160 & claimId ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
uint160 winningClaimId ;
int winningTakeoverHeight ;
if ( getLastTakeoverForName ( name , winningClaimId , winningTakeoverHeight ) & & winningClaimId = = claimId ) {
assert ( winningTakeoverHeight < = nNextHeight ) ;
return 0 ;
}
2019-07-02 18:49:02 +03:00
return getDelayForName ( name ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
std : : string CClaimTrieCacheBase : : adjustNameForValidHeight ( const std : : string & name , int validHeight ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return name ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : clear ( )
2018-08-06 15:40:20 -04:00
{
2019-08-28 19:13:50 +03:00
forDeleteFromBase . clear ( ) ;
2019-07-22 15:53:17 -06:00
nodesToAddOrUpdate . clear ( ) ;
claimsToAddToByIdIndex . clear ( ) ;
supportCache . clear ( ) ;
2019-07-01 12:42:45 -06:00
nodesToDelete . clear ( ) ;
2019-07-22 15:53:17 -06:00
claimsToDeleteFromByIdIndex . clear ( ) ;
2019-07-01 12:42:45 -06:00
takeoverCache . clear ( ) ;
2018-08-06 15:40:20 -04:00
claimQueueCache . clear ( ) ;
2019-07-01 12:42:45 -06:00
supportQueueCache . clear ( ) ;
2019-07-22 15:53:17 -06:00
nodesAlreadyCached . clear ( ) ;
2019-07-01 12:42:45 -06:00
takeoverWorkaround . clear ( ) ;
removalWorkaround . clear ( ) ;
2018-08-06 15:40:20 -04:00
claimQueueNameCache . clear ( ) ;
expirationQueueCache . clear ( ) ;
supportQueueNameCache . clear ( ) ;
namesToCheckForTakeover . clear ( ) ;
2019-07-01 12:42:45 -06:00
supportExpirationQueueCache . clear ( ) ;
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : getProofForName ( const std : : string & name , CClaimTrieProof & proof )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
// cache the parent nodes
cacheData ( name , false ) ;
getMerkleHash ( ) ;
2019-07-19 18:36:53 +03:00
proof = CClaimTrieProof ( ) ;
for ( auto & it : static_cast < const CClaimPrefixTrie & > ( nodesToAddOrUpdate ) . nodes ( name ) ) {
2018-08-06 15:40:20 -04:00
CClaimValue claim ;
2019-07-01 12:42:45 -06:00
const auto & key = it . key ( ) ;
bool fNodeHasValue = it - > getBestClaim ( claim ) ;
2018-08-06 15:40:20 -04:00
uint256 valueHash ;
2019-07-02 18:49:02 +03:00
if ( fNodeHasValue )
2019-07-01 12:42:45 -06:00
valueHash = getValueHash ( claim . outPoint , it - > nHeightOfLastTakeover ) ;
2019-07-02 18:49:02 +03:00
2019-07-01 12:42:45 -06:00
const auto pos = key . size ( ) ;
std : : vector < std : : pair < unsigned char , uint256 > > children ;
2019-07-19 18:36:53 +03:00
for ( auto & child : it . children ( ) ) {
auto & childKey = child . key ( ) ;
2019-07-01 12:42:45 -06:00
if ( name . find ( childKey ) = = 0 ) {
for ( auto i = pos ; i + 1 < childKey . size ( ) ; + + i ) {
children . emplace_back ( childKey [ i ] , uint256 { } ) ;
2019-07-19 18:36:53 +03:00
proof . nodes . emplace_back ( children , fNodeHasValue , valueHash ) ;
2019-07-22 15:53:17 -06:00
children . clear ( ) ; // move promises to leave it in a valid state only
2019-07-01 12:42:45 -06:00
valueHash . SetNull ( ) ;
fNodeHasValue = false ;
}
children . emplace_back ( childKey . back ( ) , uint256 { } ) ;
continue ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
auto hash = child - > hash ;
completeHash ( hash , childKey , pos ) ;
children . emplace_back ( childKey [ pos ] , hash ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
if ( key = = name ) {
2019-07-19 18:36:53 +03:00
proof . hasValue = fNodeHasValue ;
if ( proof . hasValue ) {
proof . outPoint = claim . outPoint ;
proof . nHeightOfLastTakeover = it - > nHeightOfLastTakeover ;
2018-08-06 15:40:20 -04:00
}
valueHash . SetNull ( ) ;
}
2019-07-19 18:36:53 +03:00
proof . nodes . emplace_back ( std : : move ( children ) , fNodeHasValue , valueHash ) ;
2018-08-06 15:40:20 -04:00
}
return true ;
}
2019-08-24 18:43:56 -06:00
void CClaimTrieCacheBase : : recurseNodes ( const std : : string & name ,
std : : function < void ( const std : : string & , const CClaimTrieData & ) > function ) const {
std : : function < CClaimTrie : : recurseNodesCB > baseFunction = [ this , & function ]
( const std : : string & name , const CClaimTrieData & data , const std : : vector < std : : string > & ) {
if ( nodesToDelete . find ( name ) = = nodesToDelete . end ( ) )
function ( name , data ) ;
} ;
if ( empty ( ) ) {
CClaimTrieDataNode node ;
if ( base - > find ( name , node ) )
base - > recurseNodes ( name , node , baseFunction ) ;
}
else {
for ( auto it = begin ( ) ; it ! = end ( ) ; + + it ) {
function ( it . key ( ) , it . data ( ) ) ;
if ( ( it - > flags & CClaimTrieDataFlags : : POTENTIAL_CHILDREN ) & & ! it . hasChildren ( ) ) {
CClaimTrieDataNode node ;
if ( base - > find ( it . key ( ) , node ) )
for ( auto & partialKey : node . children ) {
auto childKey = it . key ( ) + partialKey ;
CClaimTrieDataNode childNode ;
if ( base - > find ( childKey , childNode ) )
base - > recurseNodes ( childKey , childNode , baseFunction ) ;
}
}
}
}
}