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-01 12:42:45 -06: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
# include <boost/scoped_ptr.hpp>
2019-07-01 12:42:45 -06:00
static 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-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-01 12:42:45 -06:00
for ( auto iClaim = claims . begin ( ) ; iClaim ! = claims . end ( ) ; + + iClaim ) {
if ( iClaim - > outPoint = = outPoint ) {
std : : swap ( claim , * iClaim ) ;
claims . erase ( iClaim ) ;
return true ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
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 ( ) ) ;
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-01 12:42:45 -06:00
return std : : any_of ( claims . begin ( ) , claims . end ( ) ,
[ & outPoint ] ( const CClaimValue & claim ) { return claim . outPoint = = outPoint ; } ) ;
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
}
std : : make_heap ( claims . begin ( ) , claims . end ( ) ) ;
}
2019-07-01 12:42:45 -06:00
CClaimTrie : : CClaimTrie ( bool fMemory , bool fWipe , int proportionalDelayFactor )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
nProportionalDelayFactor = proportionalDelayFactor ;
db . reset ( new CDBWrapper ( GetDataDir ( ) / " claimtrie " , 100 * 1024 * 1024 , 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-01 12:42:45 -06:00
if ( db )
return db - > Sync ( ) ;
return false ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
template < typename Key , typename Container >
typename Container : : value_type * getQueue ( CDBWrapper & db , uint8_t dbkey , const Key & key , Container & queue , bool create )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto itQueue = queue . find ( key ) ;
if ( itQueue ! = queue . end ( ) )
return & ( * itQueue ) ;
typename Container : : mapped_type row ;
if ( db . Read ( std : : make_pair ( dbkey , key ) , row ) | | create ) {
auto ret = queue . insert ( std : : make_pair ( key , row ) ) ;
assert ( ret . second ) ;
return & ( * ret . first ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
return nullptr ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
uint256 computeHash ( const std : : vector < uint8_t > & vec )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return Hash ( vec . begin ( ) , vec . end ( ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
typename claimQueueType : : value_type * 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-01 12:42:45 -06:00
typename queueNameType : : value_type * CClaimTrieCacheBase : : getQueueCacheNameRow ( 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 ) , CLAIM_QUEUE_NAME_ROW , name , claimQueueNameCache , createIfNotExists ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
typename expirationQueueType : : value_type * CClaimTrieCacheBase : : getExpirationQueueCacheRow ( int nHeight , bool createIfNotExists )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return getQueue ( * ( base - > db ) , EXP_QUEUE_ROW , nHeight , expirationQueueCache , createIfNotExists ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
typename supportQueueType : : value_type * CClaimTrieCacheBase : : getSupportQueueCacheRow ( 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_QUEUE_ROW , nHeight , supportQueueCache , createIfNotExists ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
typename queueNameType : : value_type * CClaimTrieCacheBase : : getSupportQueueCacheNameRow ( 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-01 12:42:45 -06:00
typename expirationQueueType : : value_type * CClaimTrieCacheBase : : getSupportExpirationQueueCacheRow ( 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-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-07-01 12:42:45 -06:00
auto it = find ( name ) ;
return it & & it - > haveClaim ( outPoint ) ;
2018-08-06 15:40:20 -04:00
}
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-01 12:42:45 -06:00
auto sit = cacheSupports . find ( name ) ;
if ( sit ! = cacheSupports . end ( ) )
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-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : haveSupport ( const std : : string & name , const COutPoint & outPoint ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto supports = getSupportsForName ( name ) ;
return std : : any_of ( supports . begin ( ) , supports . end ( ) ,
[ & outPoint ] ( const CSupportValue & support ) { return support . outPoint = = outPoint ; } ) ;
}
bool CClaimTrieCacheBase : : haveClaimInQueue ( const std : : string & name , const COutPoint & outPoint , int & nValidAtHeight )
{
auto nameRow = getQueueCacheNameRow ( name ) ;
if ( ! nameRow ) {
2018-08-06 15:40:20 -04:00
return false ;
}
2019-07-01 12:42:45 -06:00
for ( const auto & iNameRow : nameRow - > second ) {
if ( iNameRow . outPoint ! = outPoint )
continue ;
nValidAtHeight = iNameRow . nHeight ;
if ( auto cacheRow = getQueueCacheRow ( nValidAtHeight ) ) {
for ( const auto & iRow : cacheRow - > second ) {
if ( iRow . first = = name & & iRow . second . outPoint = = outPoint ) {
if ( iRow . second . nValidAtHeight ! = nValidAtHeight )
LogPrintf ( " %s: An inconsistency was found in the claim 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 ) ;
return true ;
2018-08-06 15:40:20 -04:00
}
}
}
2019-07-01 12:42:45 -06:00
break ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06: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-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : haveSupportInQueue ( const std : : string & name , const COutPoint & outPoint , int & nValidAtHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto nameRow = getSupportQueueCacheNameRow ( name ) ;
if ( ! nameRow ) {
2018-08-06 15:40:20 -04:00
return false ;
}
2019-07-01 12:42:45 -06:00
for ( const auto & itNameRow : nameRow - > second ) {
if ( itNameRow . outPoint ! = outPoint )
continue ;
nValidAtHeight = itNameRow . nHeight ;
if ( auto row = getSupportQueueCacheRow ( nValidAtHeight ) ) {
for ( const auto & iRow : row - > second ) {
if ( iRow . first = = name & & iRow . second . outPoint = = outPoint ) {
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 ) ;
return true ;
2018-08-06 15:40:20 -04:00
}
}
}
2019-07-01 12:42:45 -06:00
break ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06: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-07-01 12:42:45 -06:00
std : : size_t CClaimTrieCacheBase : : getTotalNamesInTrie ( ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
size_t count = 0 ;
for ( auto it = base - > cbegin ( ) ; it ! = base - > cend ( ) ; + + it ) {
if ( ! it - > claims . empty ( ) )
+ + count ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
return count ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
std : : size_t CClaimTrieCacheBase : : getTotalClaimsInTrie ( ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
std : : size_t count = 0 ;
for ( auto it = base - > cbegin ( ) ; it ! = base - > cend ( ) ; + + it ) {
count + = it - > claims . size ( ) ;
}
return count ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CAmount CClaimTrieCacheBase : : 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 ;
for ( auto it = base - > cbegin ( ) ; it ! = base - > cend ( ) ; + + it ) {
for ( const auto & claim : it - > claims ) {
value_in_subtrie + = claim . nAmount ;
if ( fControllingOnly )
break ;
}
2018-08-06 15:40:20 -04:00
}
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-07-01 12:42:45 -06:00
auto it = find ( name ) ;
return it & & it - > getBestClaim ( claim ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CClaimsForNameType 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 ) ;
if ( auto it = find ( name ) ) {
claims = it - > claims ;
nLastTakeoverHeight = it - > nHeightOfLastTakeover ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
return { std : : move ( claims ) , std : : move ( supports ) , nLastTakeoverHeight , name } ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CAmount CClaimTrieCacheBase : : getEffectiveAmountForClaim ( const std : : string & name , const uint160 & claimId , std : : vector < CSupportValue > * supports ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return getEffectiveAmountForClaim ( getClaimsForName ( name ) , claimId , supports ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CAmount CClaimTrieCacheBase : : getEffectiveAmountForClaim ( const CClaimsForNameType & claims , const uint160 & claimId , std : : vector < CSupportValue > * supports ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
CAmount effectiveAmount = 0 ;
for ( const auto & claim : claims . claims ) {
if ( claim . claimId = = claimId & & claim . nValidAtHeight < nNextHeight ) {
effectiveAmount + = claim . nAmount ;
for ( const auto & support : claims . supports ) {
if ( support . supportedClaimId = = claimId & & support . nValidAtHeight < nNextHeight ) {
effectiveAmount + = support . nAmount ;
if ( supports ) supports - > push_back ( support ) ;
}
}
break ;
}
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
return effectiveAmount ;
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-07-01 12:42:45 -06:00
bool recursiveCheckConsistency ( CClaimTrie : : const_iterator & it , int minimumHeight , std : : string & failed )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
std : : vector < uint8_t > vchToHash ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
const auto pos = it . key ( ) . size ( ) ;
auto children = it . children ( ) ;
for ( auto & child : children ) {
if ( ! recursiveCheckConsistency ( child , minimumHeight , failed ) )
2018-08-06 15:40:20 -04:00
return false ;
2019-07-01 12:42:45 -06:00
auto & key = child . key ( ) ;
auto hash = child - > hash ;
vchToHash . push_back ( key [ pos ] ) ;
completeHash ( hash , key , pos ) ;
vchToHash . insert ( vchToHash . end ( ) , hash . begin ( ) , hash . end ( ) ) ;
2018-08-06 15:40:20 -04:00
}
CClaimValue claim ;
2019-07-01 12:42:45 -06:00
if ( it - > getBestClaim ( claim ) ) {
if ( it - > nHeightOfLastTakeover < minimumHeight ) {
LogPrintf ( " \n Invalid takeover height for %s \n " , it . key ( ) ) ;
failed = it . key ( ) ;
return false ;
}
uint256 valueHash = getValueHash ( claim . outPoint , it - > nHeightOfLastTakeover ) ;
2018-08-06 15:40:20 -04:00
vchToHash . insert ( vchToHash . end ( ) , valueHash . begin ( ) , valueHash . end ( ) ) ;
2019-07-01 12:42:45 -06:00
} else if ( children . empty ( ) ) {
// we don't allow a situation of no children and no claims; no empty leaf nodes allowed
LogPrintf ( " \n Invalid empty node for %s \n " , it . key ( ) ) ;
failed = it . key ( ) ;
return false ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
auto calculatedHash = computeHash ( vchToHash ) ;
auto matched = calculatedHash = = it - > hash ;
if ( ! matched ) {
LogPrintf ( " \n Computed hash doesn't match stored hash for %s \n " , it . key ( ) ) ;
failed = it . key ( ) ;
}
return matched ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : checkConsistency ( int minimumHeight ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
if ( base - > empty ( ) )
return true ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
auto it = base - > cbegin ( ) ;
std : : string failed ;
auto consistent = recursiveCheckConsistency ( it , minimumHeight , failed ) ;
if ( ! consistent ) {
LogPrintf ( " Printing base tree from its parent: \n " , failed ) ;
auto basePath = base - > nodes ( failed ) ;
if ( basePath . size ( ) > 1 ) basePath . pop_back ( ) ;
dumpToLog ( basePath . back ( ) , false ) ;
auto cachePath = cache . nodes ( failed ) ;
if ( ! cachePath . empty ( ) ) {
LogPrintf ( " \n Printing %s's parent from cache: \n " , failed ) ;
if ( cachePath . size ( ) > 1 ) cachePath . pop_back ( ) ;
dumpToLog ( cachePath . back ( ) , false ) ;
}
if ( ! nodesToDelete . empty ( ) ) {
std : : string joined ;
for ( const auto & piece : nodesToDelete ) joined + = " , " + piece ;
LogPrintf ( " Nodes to be deleted: %s \n " , joined . substr ( 2 ) ) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
return consistent ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : getClaimById ( const uint160 & claimId , std : : string & name , CClaimValue & claim ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
CClaimIndexElement element ;
if ( ! base - > db - > Read ( std : : make_pair ( CLAIM_BY_ID , claimId ) , element ) )
return false ;
if ( element . claim . claimId = = claimId ) {
name = element . name ;
claim = element . claim ;
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-01 12:42:45 -06:00
LogPrintf ( " %s: ClaimIndex[%s] returned unmatched claimId %s when looking for %s \n " , __func__ , claimId . GetHex ( ) , element . claim . claimId . GetHex ( ) , name ) ;
return false ;
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-01 12:42:45 -06:00
for ( const auto & claim : claimsToDelete ) {
auto it = std : : find_if ( claimsToAdd . begin ( ) , claimsToAdd . end ( ) ,
[ & claim ] ( const CClaimIndexElement & e ) {
return e . claim . claimId = = claim . claimId ;
}
) ;
if ( it = = claimsToAdd . end ( ) )
batch . Erase ( std : : make_pair ( CLAIM_BY_ID , claim . claimId ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
for ( const auto & e : claimsToAdd )
batch . Write ( std : : make_pair ( CLAIM_BY_ID , e . claim . claimId ) , e ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
getMerkleHash ( ) ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
for ( const auto & nodeName : nodesToDelete ) {
if ( cache . contains ( nodeName ) )
continue ;
auto nodes = base - > nodes ( nodeName ) ;
base - > erase ( nodeName ) ;
for ( auto & node : nodes )
if ( ! node )
batch . Erase ( std : : make_pair ( TRIE_NODE , node . key ( ) ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
for ( auto it = cache . begin ( ) ; it ! = cache . end ( ) ; + + it ) {
auto old = base - > find ( it . key ( ) ) ;
if ( ! old | | old . data ( ) ! = it . data ( ) ) {
base - > copy ( it ) ;
batch . Write ( std : : make_pair ( TRIE_NODE , it . key ( ) ) , it . data ( ) ) ;
}
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
BatchWriteQueue ( batch , SUPPORT , cacheSupports ) ;
BatchWriteQueue ( batch , CLAIM_QUEUE_ROW , claimQueueCache ) ;
BatchWriteQueue ( batch , CLAIM_QUEUE_NAME_ROW , claimQueueNameCache ) ;
BatchWriteQueue ( batch , EXP_QUEUE_ROW , expirationQueueCache ) ;
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 ;
if ( ! cache . empty ( ) )
LogPrintf ( " Cache size: %zu from base size: %zu on block %d \n " , cache . height ( ) , base - > height ( ) , nNextHeight ) ;
auto ret = base - > db - > WriteBatch ( batch ) ;
clear ( ) ;
return ret ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : ReadFromDisk ( const CBlockIndex * tip )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
LogPrintf ( " Loading the claim trie from disk... \n " ) ;
2018-08-06 15:40:20 -04:00
2019-07-09 18:02:54 +03:00
base - > nNextHeight = nNextHeight = tip ? tip - > nHeight + 1 : 0 ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
clear ( ) ;
base - > clear ( ) ;
boost : : scoped_ptr < CDBIterator > pcursor ( base - > db - > NewIterator ( ) ) ;
2018-08-06 15:40:20 -04:00
2019-07-18 14:35:18 -06:00
std : : vector < std : : pair < std : : string , uint256 > > hashesOnEmptyNodes ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
for ( pcursor - > SeekToFirst ( ) ; pcursor - > Valid ( ) ; pcursor - > Next ( ) ) {
std : : pair < uint8_t , std : : string > key ;
if ( ! pcursor - > GetKey ( key ) | | key . first ! = TRIE_NODE )
continue ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
CClaimTrieData data ;
if ( pcursor - > GetValue ( data ) ) {
if ( data . empty ( ) ) {
// we have a situation where our old trie had many empty nodes
// we don't want to automatically throw those all into our prefix trie
2019-07-18 14:35:18 -06:00
hashesOnEmptyNodes . emplace_back ( key . second , data . hash ) ;
2019-07-01 12:42:45 -06:00
continue ;
}
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
// nEffectiveAmount isn't serialized but it needs to be initialized (as done in reorderClaims):
auto supports = getSupportsForName ( key . second ) ;
data . reorderClaims ( supports ) ;
base - > insert ( key . second , std : : move ( data ) ) ;
} else {
return error ( " %s() : error reading claim trie from disk " , __func__) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
CDBBatch batch ( * ( base - > db ) ) ;
for ( auto & kvp : hashesOnEmptyNodes ) {
auto hit = base - > find ( kvp . first ) ;
if ( hit ! = base - > end ( ) )
hit - > hash = kvp . second ;
else {
// the first time the prefix trie is ran there will be many unused nodes
// we need to clean those out so that we can go faster next time
batch . Erase ( std : : make_pair ( TRIE_NODE , kvp . first ) ) ;
}
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
LogPrintf ( " Checking claim trie consistency... " ) ;
if ( checkConsistency ( ) ) {
LogPrintf ( " consistent \n " ) ;
if ( tip & & tip - > hashClaimTrie ! = getMerkleHash ( ) )
return error ( " %s() : hashes don ' t match when reading claimtrie from disk " , __func__) ;
base - > db - > WriteBatch ( batch ) ;
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-07-01 12:42:45 -06:00
CClaimTrieCacheBase : : CClaimTrieCacheBase ( CClaimTrie * base , bool fRequireTakeoverHeights ) : base ( base ) , fRequireTakeoverHeights ( fRequireTakeoverHeights )
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-07-01 12:42:45 -06:00
uint256 CClaimTrieCacheBase : : recursiveComputeMerkleHash ( CClaimTrie : : iterator & it )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
if ( ! it - > hash . IsNull ( ) )
return it - > hash ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
std : : vector < uint8_t > vchToHash ;
const auto pos = it . key ( ) . size ( ) ;
for ( auto & child : it . children ( ) ) {
auto & key = child . key ( ) ;
vchToHash . push_back ( key [ pos ] ) ;
auto hash = recursiveComputeMerkleHash ( child ) ;
assert ( ! hash . IsNull ( ) ) ;
completeHash ( hash , key , pos ) ;
vchToHash . insert ( vchToHash . end ( ) , hash . begin ( ) , hash . end ( ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CClaimValue claim ;
if ( it - > getBestClaim ( claim ) ) {
uint256 valueHash = getValueHash ( claim . outPoint , it - > nHeightOfLastTakeover ) ;
vchToHash . insert ( vchToHash . end ( ) , valueHash . begin ( ) , valueHash . end ( ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
return it - > hash = computeHash ( vchToHash ) ;
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-07-01 12:42:45 -06:00
auto it = cache . begin ( ) ;
if ( cache . empty ( ) & & nodesToDelete . empty ( ) )
it = base - > begin ( ) ;
return ! it ? one : recursiveComputeMerkleHash ( it ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CClaimTrie : : const_iterator CClaimTrieCacheBase : : begin ( ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return cache . empty ( ) & & nodesToDelete . empty ( ) ? base - > cbegin ( ) : cache . begin ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CClaimTrie : : const_iterator CClaimTrieCacheBase : : end ( ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
return cache . empty ( ) & & nodesToDelete . empty ( ) ? base - > cend ( ) : cache . end ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CClaimTrie : : const_iterator CClaimTrieCacheBase : : find ( const std : : string & name ) const
{
if ( auto it = cache . find ( name ) )
return it ;
return base - > find ( name ) ;
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-07-01 12:42:45 -06:00
return base - > empty ( ) & & cache . empty ( ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
CClaimTrie : : 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
// get data from the cache. if no data, create empty one
const auto insert = [ this ] ( CClaimTrie : : iterator & it ) {
auto & key = it . key ( ) ;
// we only ever cache nodes once per cache instance
if ( ! alreadyCachedNodes . count ( key ) ) {
// do not insert nodes that are already present
alreadyCachedNodes . insert ( key ) ;
cache . insert ( key , it . data ( ) ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
} ;
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 ) {
for ( auto & child : node . children ( ) )
if ( ! alreadyCachedNodes . count ( child . key ( ) ) )
cache . copy ( child ) ;
insert ( node ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
auto it = cache . find ( name ) ;
if ( ! it & & create ) {
it = cache . insert ( name , CClaimTrieData { } ) ;
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-07-01 12:42:45 -06:00
if ( auto it = base - > find ( name ) ) {
takeoverHeight = it - > nHeightOfLastTakeover ;
CClaimValue claim ;
if ( it - > getBestClaim ( claim ) )
{
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-07-01 12:42:45 -06:00
for ( auto & node : cache . nodes ( name ) )
node - > hash . SetNull ( ) ;
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 ) ) {
LogPrintf ( " %s: Removing a claim was unsuccessful. name = %s, txhash = %s, nOut = %d " , __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
bool hasChild = false ;
for ( auto & child : it . children ( ) ) {
hasChild = true ;
cacheData ( child . key ( ) , false ) ;
}
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
cache . erase ( name ) ;
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-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : addClaim ( const std : : string & name , const COutPoint & outPoint , const uint160 & claimId , CAmount nAmount , int nHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
assert ( nHeight = = nNextHeight ) ;
2018-08-06 15:40:20 -04:00
int delayForClaim = getDelayForName ( name , claimId ) ;
CClaimValue claim ( outPoint , claimId , nAmount , nHeight , nHeight + delayForClaim ) ;
2019-07-01 12:42:45 -06:00
LogPrintf ( " %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
addClaimToQueues ( name , claim ) ;
2019-07-01 12:42:45 -06:00
CClaimIndexElement element = { name , claim } ;
2018-08-06 15:40:20 -04:00
claimsToAdd . push_back ( element ) ;
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : undoSpendClaim ( const std : : string & name , const COutPoint & outPoint , const uint160 & claimId , CAmount nAmount , int nHeight , int nValidAtHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
LogPrintf ( " %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 ) ;
2018-08-06 15:40:20 -04:00
CClaimValue claim ( outPoint , claimId , nAmount , nHeight , nValidAtHeight ) ;
2019-07-01 12:42:45 -06:00
if ( nValidAtHeight < nNextHeight ) {
CNameOutPointType entry ( adjustNameForValidHeight ( name , nValidAtHeight ) , claim . outPoint ) ;
2019-07-09 18:02:54 +03:00
addToExpirationQueue ( claim . nHeight + expirationTime ( ) , entry ) ;
2018-08-06 15:40:20 -04:00
CClaimIndexElement element = { name , claim } ;
claimsToAdd . push_back ( element ) ;
return insertClaimIntoTrie ( name , claim , false ) ;
}
addClaimToQueues ( name , claim ) ;
2019-07-01 12:42:45 -06:00
CClaimIndexElement element = { name , claim } ;
2018-08-06 15:40:20 -04:00
claimsToAdd . push_back ( element ) ;
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : addClaimToQueues ( const std : : string & name , const CClaimValue & claim )
2018-08-06 15:40:20 -04:00
{
claimQueueEntryType entry ( name , claim ) ;
2019-07-01 12:42:45 -06:00
auto itQueueRow = getQueueCacheRow ( claim . nValidAtHeight , true ) ;
auto itQueueNameRow = getQueueCacheNameRow ( name , true ) ;
2018-08-06 15:40:20 -04:00
itQueueRow - > second . push_back ( entry ) ;
2019-07-01 12:42:45 -06:00
itQueueNameRow - > second . emplace_back ( claim . outPoint , claim . nValidAtHeight ) ;
CNameOutPointType expireEntry ( name , claim . outPoint ) ;
2019-07-09 18:02:54 +03:00
addToExpirationQueue ( claim . nHeight + expirationTime ( ) , expireEntry ) ;
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
bool CClaimTrieCacheBase : : removeClaimFromQueue ( const std : : string & name , const COutPoint & outPoint , CClaimValue & claim )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto itQueueNameRow = getQueueCacheNameRow ( name ) ;
if ( ! itQueueNameRow ) {
2018-08-06 15:40:20 -04:00
return false ;
}
2019-07-01 12:42:45 -06:00
auto itQueueName = itQueueNameRow - > second . cbegin ( ) ;
for ( ; itQueueName ! = itQueueNameRow - > second . cend ( ) ; + + itQueueName ) {
if ( itQueueName - > outPoint = = outPoint ) {
if ( auto itQueueRow = getQueueCacheRow ( itQueueName - > nHeight ) ) {
auto itQueue = itQueueRow - > second . begin ( ) ;
for ( ; itQueue ! = itQueueRow - > second . end ( ) ; + + itQueue ) {
if ( outPoint = = itQueue - > second . outPoint & & name = = itQueue - > first ) {
std : : swap ( claim , itQueue - > second ) ;
itQueueNameRow - > second . erase ( itQueueName ) ;
itQueueRow - > second . erase ( itQueue ) ;
return true ;
}
}
}
break ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
if ( itQueueName ! = itQueueNameRow - > second . cend ( ) )
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-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-01 12:42:45 -06: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-01 12:42:45 -06:00
LogPrintf ( " %s: name: %s, txhash: %s, nOut: %u, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nNextHeight ) ;
2018-08-06 15:40:20 -04:00
CClaimValue claim ;
nValidAtHeight = nHeight + getDelayForName ( name ) ;
std : : string adjusted = adjustNameForValidHeight ( name , nValidAtHeight ) ;
2019-07-01 12:42:45 -06:00
if ( removeClaimFromQueue ( adjusted , outPoint , claim ) | | removeClaimFromTrie ( name , outPoint , claim , fCheckTakeover ) ) {
2019-07-09 18:02:54 +03:00
int expirationHeight = claim . nHeight + expirationTime ( ) ;
2018-08-06 15:40:20 -04:00
removeFromExpirationQueue ( adjusted , outPoint , expirationHeight ) ;
claimsToDelete . insert ( claim ) ;
nValidAtHeight = claim . 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-01 12:42:45 -06:00
void CClaimTrieCacheBase : : addToExpirationQueue ( int nExpirationHeight , CNameOutPointType & entry )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto itQueueRow = getExpirationQueueCacheRow ( nExpirationHeight , true ) ;
2018-08-06 15:40:20 -04:00
itQueueRow - > second . push_back ( entry ) ;
}
2019-07-01 12:42:45 -06:00
void CClaimTrieCacheBase : : removeFromExpirationQueue ( const std : : string & name , const COutPoint & outPoint , int expirationHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
if ( auto itQueueRow = getExpirationQueueCacheRow ( expirationHeight ) ) {
auto itQueue = itQueueRow - > second . cbegin ( ) ;
for ( ; itQueue ! = itQueueRow - > second . cend ( ) ; + + itQueue ) {
if ( name = = itQueue - > name & & outPoint = = itQueue - > outPoint ) {
itQueueRow - > second . erase ( itQueue ) ;
2018-08-06 15:40:20 -04:00
break ;
2019-07-01 12:42:45 -06:00
}
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-01 12:42:45 -06:00
auto sit = cacheSupports . find ( name ) ;
if ( sit = = cacheSupports . end ( ) ) {
sit = cacheSupports . emplace ( name , getSupportsForName ( name ) ) . first ;
}
sit - > second . push_back ( support ) ;
2018-08-06 15:40:20 -04:00
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-01 12:42:45 -06:00
auto sit = cacheSupports . find ( name ) ;
if ( sit = = cacheSupports . end ( ) ) {
sit = cacheSupports . emplace ( name , getSupportsForName ( name ) ) . first ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
for ( auto it = sit - > second . begin ( ) ; it ! = sit - > second . end ( ) ; + + it ) {
if ( it - > outPoint = = outPoint ) {
support = * it ;
sit - > second . erase ( it ) ;
2018-08-06 15:40:20 -04:00
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 dit = cacheData ( name , false ) ) {
markAsDirty ( name , fCheckTakeover ) ;
dit - > reorderClaims ( sit - > second ) ;
}
return true ;
}
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
LogPrintf ( " CClaimTrieCacheBase::%s() : asked to remove a support that doesn't exist for %s#%s \n " ,
__func__ , name , outPoint . ToString ( ) ) ;
2018-08-06 15:40:20 -04:00
return false ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : addSupportToQueues ( const std : : string & name , const CSupportValue & support )
2018-08-06 15:40:20 -04:00
{
LogPrintf ( " %s: nValidAtHeight: %d \n " , __func__ , support . nValidAtHeight ) ;
supportQueueEntryType entry ( name , support ) ;
2019-07-01 12:42:45 -06:00
auto itQueueRow = getSupportQueueCacheRow ( support . nValidAtHeight , true ) ;
auto itQueueNameRow = getSupportQueueCacheNameRow ( name , true ) ;
2018-08-06 15:40:20 -04:00
itQueueRow - > second . push_back ( entry ) ;
2019-07-01 12:42:45 -06:00
itQueueNameRow - > second . emplace_back ( support . outPoint , support . nValidAtHeight ) ;
CNameOutPointType expireEntry ( name , support . outPoint ) ;
2019-07-09 18:02:54 +03:00
addSupportToExpirationQueue ( support . nHeight + expirationTime ( ) , expireEntry ) ;
2018-08-06 15:40:20 -04:00
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : removeSupportFromQueue ( const std : : string & name , const COutPoint & outPoint , CSupportValue & support )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto itQueueNameRow = getSupportQueueCacheNameRow ( name ) ;
if ( ! itQueueNameRow ) {
2018-08-06 15:40:20 -04:00
return false ;
}
2019-07-01 12:42:45 -06:00
auto itQueueName = itQueueNameRow - > second . cbegin ( ) ;
for ( ; itQueueName ! = itQueueNameRow - > second . cend ( ) ; + + itQueueName ) {
if ( itQueueName - > outPoint = = outPoint ) {
if ( auto itQueueRow = getSupportQueueCacheRow ( itQueueName - > nHeight ) ) {
auto itQueue = itQueueRow - > second . begin ( ) ;
for ( ; itQueue ! = itQueueRow - > second . end ( ) ; + + itQueue ) {
if ( outPoint = = itQueue - > second . outPoint & & name = = itQueue - > first ) {
std : : swap ( support , itQueue - > second ) ;
itQueueNameRow - > second . erase ( itQueueName ) ;
itQueueRow - > second . erase ( itQueue ) ;
return true ;
}
}
}
break ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
if ( itQueueName ! = itQueueNameRow - > second . cend ( ) )
LogPrintf ( " %s: An inconsistency was found in the claim queue. Please report this to the developers: \n Found in named support queue but not in height support 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 : : 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-01 12:42:45 -06:00
assert ( nHeight = = nNextHeight ) ;
2018-08-06 15:40:20 -04:00
int delayForSupport = getDelayForName ( name , supportedClaimId ) ;
CSupportValue support ( outPoint , supportedClaimId , nAmount , nHeight , nHeight + delayForSupport ) ;
2019-07-01 12:42:45 -06:00
LogPrintf ( " %s: name: %s, txhash: %s, nOut: %d, nAmount: %d, supportedClaimId: %s, nHeight: %d, nValidHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nAmount , supportedClaimId . GetHex ( ) , nHeight , support . nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
return addSupportToQueues ( name , support ) ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : undoSpendSupport ( const std : : string & name , const COutPoint & outPoint , const uint160 & supportedClaimId , CAmount nAmount , int nHeight , int nValidAtHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
LogPrintf ( " %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 ) ;
2018-08-06 15:40:20 -04:00
CSupportValue support ( outPoint , supportedClaimId , nAmount , nHeight , nValidAtHeight ) ;
2019-07-01 12:42:45 -06:00
if ( nValidAtHeight < nNextHeight ) {
CNameOutPointType entry ( adjustNameForValidHeight ( name , nValidAtHeight ) , support . outPoint ) ;
2019-07-09 18:02:54 +03:00
addSupportToExpirationQueue ( support . nHeight + expirationTime ( ) , entry ) ;
2018-08-06 15:40:20 -04:00
return insertSupportIntoMap ( name , support , false ) ;
2019-07-01 12:42:45 -06:00
} else {
return addSupportToQueues ( name , support ) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06: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
{
CSupportValue support ;
nValidAtHeight = nHeight + getDelayForName ( name ) ;
std : : string adjusted = adjustNameForValidHeight ( name , nValidAtHeight ) ;
2019-07-01 12:42:45 -06:00
if ( removeSupportFromQueue ( adjusted , outPoint , support ) | | removeSupportFromMap ( name , outPoint , support , fCheckTakeover ) ) {
2019-07-09 18:02:54 +03:00
int expirationHeight = support . nHeight + expirationTime ( ) ;
2018-08-06 15:40:20 -04:00
removeSupportFromExpirationQueue ( adjusted , outPoint , expirationHeight ) ;
2019-07-01 12:42:45 -06:00
nValidAtHeight = support . nValidAtHeight ;
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 : : addSupportToExpirationQueue ( int nExpirationHeight , CNameOutPointType & entry )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
auto itQueueRow = getSupportExpirationQueueCacheRow ( nExpirationHeight , true ) ;
2018-08-06 15:40:20 -04:00
itQueueRow - > second . push_back ( entry ) ;
}
2019-07-01 12:42:45 -06:00
void CClaimTrieCacheBase : : removeSupportFromExpirationQueue ( const std : : string & name , const COutPoint & outPoint , int expirationHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
if ( auto itQueueRow = getSupportExpirationQueueCacheRow ( expirationHeight ) ) {
auto itQueue = itQueueRow - > second . cbegin ( ) ;
for ( ; itQueue ! = itQueueRow - > second . end ( ) ; + + itQueue ) {
if ( name = = itQueue - > name & & outPoint = = itQueue - > outPoint ) {
itQueueRow - > second . erase ( itQueue ) ;
2018-08-06 15:40:20 -04:00
break ;
2019-07-01 12:42:45 -06:00
}
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:40:18 -06:00
if ( itQueue ! = itQueueRow - > second . end ( ) )
itQueueRow - > second . erase ( itQueue ) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
void CClaimTrieCacheBase : : dumpToLog ( CClaimTrie : : const_iterator it , bool diffFromBase ) const {
if ( diffFromBase ) {
auto hit = base - > find ( it . key ( ) ) ;
if ( hit & & hit - > hash = = it - > hash )
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 ( ) ;
auto empty = children . size ( ) = = 0 & & it - > claims . size ( ) = = 0 ;
LogPrintf ( " %s%s, %s, %zu = %s,%s take: %d, kids: %zu \n " , indent , it . key ( ) , HexStr ( it . key ( ) . begin ( ) , it . key ( ) . end ( ) ) ,
empty ? " empty, " : " " , it . depth ( ) , it - > hash . ToString ( ) , it - > nHeightOfLastTakeover , children . size ( ) ) ;
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-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : undoAddSupport ( const std : : string & name , const COutPoint & outPoint , int nHeight )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
LogPrintf ( " %s: name: %s, txhash: %s, nOut: %d, nHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nHeight , nNextHeight ) ;
2018-08-06 15:40:20 -04:00
int throwaway ;
return removeSupport ( name , outPoint , nHeight , throwaway , false ) ;
}
2019-07-01 12:42:45 -06: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-01 12:42:45 -06:00
LogPrintf ( " %s: name: %s, txhash: %s, nOut: %d, nHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nHeight , nNextHeight ) ;
2018-08-06 15:40:20 -04:00
return removeSupport ( name , outPoint , nHeight , nValidAtHeight , true ) ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : shouldUseTakeoverWorkaround ( const std : : string & key ) const {
auto it = takeoverWorkaround . find ( key ) ;
return it ! = takeoverWorkaround . end ( ) & & it - > second ;
}
void CClaimTrieCacheBase : : addTakeoverWorkaroundPotential ( const std : : string & key ) {
// 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
& & ! cache . contains ( key ) & & base - > contains ( key ) )
takeoverWorkaround . emplace ( key , false ) ;
}
void CClaimTrieCacheBase : : confirmTakeoverWorkaroundNeeded ( const std : : string & key ) {
// 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 ;
}
}
bool CClaimTrieCacheBase : : incrementBlock ( insertUndoType & insertUndo , claimQueueRowType & expireUndo , insertUndoType & insertSupportUndo , supportQueueRowType & expireSupportUndo , std : : vector < std : : pair < std : : string , int > > & takeoverHeightUndo )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
if ( auto itQueueRow = getQueueCacheRow ( nNextHeight ) ) {
for ( const auto & itEntry : itQueueRow - > second ) {
2018-08-06 15:40:20 -04:00
bool found = false ;
2019-07-01 12:42:45 -06:00
if ( auto itQueueNameRow = getQueueCacheNameRow ( itEntry . first ) ) {
auto itQueueName = itQueueNameRow - > second . cbegin ( ) ;
for ( ; itQueueName ! = itQueueNameRow - > second . cend ( ) ; + + itQueueName ) {
if ( itQueueName - > outPoint = = itEntry . second . outPoint & & itQueueName - > nHeight = = nNextHeight ) {
2018-08-06 15:40:20 -04:00
itQueueNameRow - > second . erase ( itQueueName ) ;
2019-07-01 12:42:45 -06:00
found = true ;
2018-08-06 15:40:20 -04:00
break ;
}
}
2019-07-01 12:42:45 -06:00
if ( ! found ) {
LogPrintf ( " %s: An inconsistency was found in the claim 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 ) ;
2018-08-06 15:40:20 -04:00
LogPrintf ( " Claims found for that name: \n " ) ;
2019-07-01 12:42:45 -06:00
for ( const auto & itQueueName : itQueueNameRow - > second )
LogPrintf ( " \t txid: %s, nOut: %d, nValidAtHeight: %d \n " , itQueueName . outPoint . hash . GetHex ( ) , itQueueName . outPoint . n , itQueueName . nHeight ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
} else {
LogPrintf ( " No claims found for that name \n " ) ;
2018-08-06 15:40:20 -04:00
}
assert ( found ) ;
2019-07-01 12:42:45 -06:00
insertClaimIntoTrie ( itEntry . first , itEntry . second , true ) ;
insertUndo . emplace_back ( itEntry . first , itEntry . second . outPoint , itEntry . second . nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
}
itQueueRow - > second . clear ( ) ;
}
2019-07-01 12:42:45 -06:00
if ( auto itExpirationRow = getExpirationQueueCacheRow ( nNextHeight ) ) {
for ( const auto & itEntry : itExpirationRow - > second ) {
2018-08-06 15:40:20 -04:00
CClaimValue claim ;
2019-07-01 12:42:45 -06:00
assert ( removeClaimFromTrie ( itEntry . name , itEntry . outPoint , claim , true ) ) ;
2018-08-06 15:40:20 -04:00
claimsToDelete . insert ( claim ) ;
2019-07-01 12:42:45 -06:00
expireUndo . emplace_back ( itEntry . name , claim ) ;
LogPrintf ( " Expiring claim %s: %s, nHeight: %d, nValidAtHeight: %d \n " , claim . claimId . GetHex ( ) , itEntry . name , claim . nHeight , claim . nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
}
itExpirationRow - > second . clear ( ) ;
}
2019-07-01 12:42:45 -06:00
if ( auto itSupportRow = getSupportQueueCacheRow ( nNextHeight ) ) {
for ( const auto & itSupport : itSupportRow - > second ) {
2018-08-06 15:40:20 -04:00
bool found = false ;
2019-07-01 12:42:45 -06:00
if ( auto itSupportNameRow = getSupportQueueCacheNameRow ( itSupport . first ) ) {
auto itSupportName = itSupportNameRow - > second . cbegin ( ) ;
for ( ; itSupportName ! = itSupportNameRow - > second . cend ( ) ; + + itSupportName ) {
if ( itSupportName - > outPoint = = itSupport . second . outPoint & & itSupportName - > nHeight = = itSupport . second . nValidAtHeight ) {
2018-08-06 15:40:20 -04:00
itSupportNameRow - > second . erase ( itSupportName ) ;
2019-07-01 12:42:45 -06:00
found = true ;
2018-08-06 15:40:20 -04:00
break ;
}
}
2019-07-01 12:42:45 -06:00
if ( ! found ) {
LogPrintf ( " %s: An inconsistency was found in the support queue. Please report this to the developers: \n Found in height queue but not in named queue: %s, txid: %s, nOut: %d, nValidAtHeight: %d, current height: %d \n " , __func__ , itSupport . first , itSupport . second . outPoint . hash . GetHex ( ) , itSupport . second . outPoint . n , itSupport . second . nValidAtHeight , nNextHeight ) ;
2018-08-06 15:40:20 -04:00
LogPrintf ( " Supports found for that name: \n " ) ;
2019-07-01 12:42:45 -06:00
for ( const auto & itSupportName : itSupportNameRow - > second )
LogPrintf ( " \t txid: %s, nOut: %d, nValidAtHeight: %d \n " , itSupportName . outPoint . hash . GetHex ( ) , itSupportName . outPoint . n , itSupportName . nHeight ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
} else {
LogPrintf ( " No support found for that name \n " ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
assert ( found ) ;
insertSupportIntoMap ( itSupport . first , itSupport . second , true ) ;
insertSupportUndo . emplace_back ( itSupport . first , itSupport . second . outPoint , itSupport . second . nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
}
itSupportRow - > second . clear ( ) ;
}
2019-07-01 12:42:45 -06:00
if ( auto itSupportExpirationRow = getSupportExpirationQueueCacheRow ( nNextHeight ) ) {
for ( const auto & itEntry : itSupportExpirationRow - > second ) {
2018-08-06 15:40:20 -04:00
CSupportValue support ;
2019-07-01 12:42:45 -06:00
assert ( removeSupportFromMap ( itEntry . name , itEntry . outPoint , support , true ) ) ;
expireSupportUndo . emplace_back ( itEntry . name , support ) ;
LogPrintf ( " Expiring support %s: %s, nHeight: %d, nValidAtHeight: %d \n " , support . supportedClaimId . GetHex ( ) , itEntry . name , support . nHeight , support . nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
}
itSupportExpirationRow - > second . clear ( ) ;
}
// 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)
auto itCachedNode = cache . 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
CClaimValue claimInCache ;
2019-07-01 12:42:45 -06:00
bool haveClaimInCache = itCachedNode & & itCachedNode - > getBestClaim ( claimInCache ) ;
uint160 ownersClaimId ;
int ownersTakeoverHeight = 0 ;
bool haveClaimInTrie = getLastTakeoverForName ( itNamesToCheck , ownersClaimId , ownersTakeoverHeight ) ;
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-01 12:42:45 -06:00
if ( auto itQueueNameRow = getQueueCacheNameRow ( itNamesToCheck ) ) {
for ( const auto & itQueueName : itQueueNameRow - > second ) {
2018-08-06 15:40:20 -04:00
bool found = false ;
2019-07-01 12:42:45 -06:00
// Pull those claims out of the height-based queue
if ( auto itQueueRow = getQueueCacheRow ( itQueueName . nHeight ) ) {
auto itQueue = itQueueRow - > second . begin ( ) ;
for ( ; itQueue ! = itQueueRow - > second . end ( ) ; + + itQueue ) {
if ( itNamesToCheck = = itQueue - > first & & itQueue - > second . outPoint = = itQueueName . outPoint & & itQueue - > second . nValidAtHeight = = itQueueName . nHeight ) {
// 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 ;
insertClaimIntoTrie ( itQueue - > first , itQueue - > second , false ) ;
// Delete them from the height-based queue
itQueueRow - > second . erase ( itQueue ) ;
2018-08-06 15:40:20 -04:00
found = true ;
break ;
}
}
}
2019-07-01 12:42:45 -06:00
if ( ! found )
LogPrintf ( " %s(): An inconsistency was found in the claim queue. Please report this to the developers: \n Claim 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__ , itNamesToCheck , itQueueName . outPoint . hash . GetHex ( ) , itQueueName . outPoint . n , itQueueName . nHeight , nNextHeight ) ;
assert ( found ) ;
2018-08-06 15:40:20 -04:00
}
// remove all claims from the queue for that name
itQueueNameRow - > second . clear ( ) ;
}
2019-07-01 12:42:45 -06:00
2018-08-06 15:40:20 -04:00
// Then, get all supports in the queue for that name
2019-07-01 12:42:45 -06:00
if ( auto itSupportQueueNameRow = getSupportQueueCacheNameRow ( itNamesToCheck ) ) {
for ( const auto & itSupportQueueName : itSupportQueueNameRow - > second ) {
2018-08-06 15:40:20 -04:00
// Pull those supports out of the height-based queue
2019-07-01 12:42:45 -06:00
if ( auto itSupportQueueRow = getSupportQueueCacheRow ( itSupportQueueName . nHeight ) ) {
auto itSupportQueue = itSupportQueueRow - > second . begin ( ) ;
for ( ; itSupportQueue ! = itSupportQueueRow - > second . end ( ) ; + + itSupportQueue ) {
if ( itNamesToCheck = = itSupportQueue - > first & & itSupportQueue - > second . outPoint = = itSupportQueueName . outPoint & & itSupportQueue - > second . nValidAtHeight = = itSupportQueueName . nHeight ) {
// Insert them into the support queue undo with the previous nValidAtHeight
insertSupportUndo . emplace_back ( itSupportQueue - > first , itSupportQueue - > second . outPoint , itSupportQueue - > second . nValidAtHeight ) ;
// Insert them into the support map with the new nValidAtHeight
itSupportQueue - > second . nValidAtHeight = nNextHeight ;
insertSupportIntoMap ( itSupportQueue - > first , itSupportQueue - > second , false ) ;
// Delete them from the height-based queue
itSupportQueueRow - > second . erase ( itSupportQueue ) ;
2018-08-06 15:40:20 -04:00
break ;
2019-07-01 12:42:45 -06:00
} else {
// here be problems TODO: show error, assert false
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
} else {
2018-08-06 15:40:20 -04:00
// here be problems
}
}
// remove all supports from the queue for that name
itSupportQueueNameRow - > second . clear ( ) ;
}
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 )
LogPrintf ( " TakeoverHeight workaround affects block: %d, name: %s, th: %d \n " , nNextHeight , itNamesToCheck , ownersTakeoverHeight ) ;
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
if ( ( itCachedNode = cache . find ( itNamesToCheck ) ) ) {
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-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : decrementBlock ( insertUndoType & insertUndo , claimQueueRowType & expireUndo , insertUndoType & insertSupportUndo , supportQueueRowType & expireSupportUndo )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
nNextHeight - - ;
2018-08-06 15:40:20 -04:00
2019-07-01 12:42:45 -06:00
if ( ! expireSupportUndo . empty ( ) ) {
for ( auto itSupportExpireUndo = expireSupportUndo . crbegin ( ) ; itSupportExpireUndo ! = expireSupportUndo . crend ( ) ; + + itSupportExpireUndo ) {
2018-08-06 15:40:20 -04:00
insertSupportIntoMap ( itSupportExpireUndo - > first , itSupportExpireUndo - > second , false ) ;
2019-07-09 18:02:54 +03:00
if ( nNextHeight = = itSupportExpireUndo - > second . nHeight + expirationTime ( ) ) {
2019-07-01 12:42:45 -06:00
auto itSupportExpireRow = getSupportExpirationQueueCacheRow ( nNextHeight , true ) ;
itSupportExpireRow - > second . emplace_back ( itSupportExpireUndo - > first , itSupportExpireUndo - > second . outPoint ) ;
}
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
for ( auto itSupportUndo = insertSupportUndo . crbegin ( ) ; itSupportUndo ! = insertSupportUndo . crend ( ) ; + + itSupportUndo ) {
2018-08-06 15:40:20 -04:00
CSupportValue support ;
assert ( removeSupportFromMap ( itSupportUndo - > name , itSupportUndo - > outPoint , support , false ) ) ;
2019-07-01 12:42:45 -06:00
if ( itSupportUndo - > nHeight > = 0 ) {
2018-08-06 15:40:20 -04:00
// support.nValidHeight may have been changed if this was inserted before activation height
// due to a triggered takeover, change it back to original nValidAtHeight
support . nValidAtHeight = itSupportUndo - > nHeight ;
2019-07-01 12:42:45 -06:00
auto itSupportRow = getSupportQueueCacheRow ( itSupportUndo - > nHeight , true ) ;
auto itSupportNameRow = getSupportQueueCacheNameRow ( itSupportUndo - > name , true ) ;
itSupportRow - > second . emplace_back ( itSupportUndo - > name , support ) ;
itSupportNameRow - > second . emplace_back ( support . outPoint , support . nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
}
}
2019-07-01 12:42:45 -06:00
if ( ! expireUndo . empty ( ) ) {
for ( auto itExpireUndo = expireUndo . crbegin ( ) ; itExpireUndo ! = expireUndo . crend ( ) ; + + itExpireUndo ) {
2018-08-06 15:40:20 -04:00
insertClaimIntoTrie ( itExpireUndo - > first , itExpireUndo - > second , false ) ;
2019-07-01 12:42:45 -06:00
CClaimIndexElement element = { itExpireUndo - > first , itExpireUndo - > second } ;
2018-08-06 15:40:20 -04:00
claimsToAdd . push_back ( element ) ;
2019-07-09 18:02:54 +03:00
if ( nNextHeight = = itExpireUndo - > second . nHeight + expirationTime ( ) ) {
2019-07-01 12:42:45 -06:00
auto itExpireRow = getExpirationQueueCacheRow ( nNextHeight , true ) ;
itExpireRow - > second . 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 ) {
2018-08-06 15:40:20 -04:00
CClaimValue claim ;
assert ( removeClaimFromTrie ( itInsertUndo - > name , itInsertUndo - > outPoint , claim , false ) ) ;
2019-07-01 12:42:45 -06:00
if ( itInsertUndo - > nHeight > = 0 ) { // aka it became valid at height rather than being rename/normalization
// claim.nValidHeight may have been changed if this was inserted before activation height
// due to a triggered takeover, change it back to original nValidAtHeight
2018-08-06 15:40:20 -04:00
claim . nValidAtHeight = itInsertUndo - > nHeight ;
2019-07-01 12:42:45 -06:00
auto itQueueRow = getQueueCacheRow ( itInsertUndo - > nHeight , true ) ;
auto itQueueNameRow = getQueueCacheNameRow ( itInsertUndo - > name , true ) ;
itQueueRow - > second . emplace_back ( itInsertUndo - > name , claim ) ;
itQueueNameRow - > second . emplace_back ( itInsertUndo - > outPoint , claim . nValidAtHeight ) ;
} else {
2018-08-06 15:40:20 -04:00
claimsToDelete . insert ( claim ) ;
}
}
return true ;
}
2019-07-01 12:42:45 -06:00
bool CClaimTrieCacheBase : : finalizeDecrement ( std : : vector < std : : pair < std : : string , int > > & takeoverHeightUndo ) {
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-01 12:42:45 -06:00
int CClaimTrieCacheBase : : getNumBlocksOfContinuousOwnership ( const std : : string & name )
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
const auto hit = removalWorkaround . find ( name ) ;
if ( hit ! = removalWorkaround . end ( ) ) {
removalWorkaround . erase ( hit ) ;
2018-08-06 15:40:20 -04:00
return 0 ;
}
2019-07-01 12:42:45 -06:00
auto it = find ( name ) ;
return it & & ! it - > empty ( ) ? nNextHeight - it - > nHeightOfLastTakeover : 0 ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
int CClaimTrieCacheBase : : getDelayForName ( const std : : string & name )
2018-08-06 15:40:20 -04:00
{
if ( ! fRequireTakeoverHeights )
return 0 ;
int nBlocksOfContinuousOwnership = getNumBlocksOfContinuousOwnership ( name ) ;
return std : : min ( nBlocksOfContinuousOwnership / base - > nProportionalDelayFactor , 4032 ) ;
}
2019-07-01 12:42:45 -06:00
int CClaimTrieCacheBase : : getDelayForName ( const std : : string & name , const uint160 & claimId )
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 ;
} else {
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
{
cache . clear ( ) ;
2019-07-01 12:42:45 -06:00
claimsToAdd . clear ( ) ;
cacheSupports . clear ( ) ;
nodesToDelete . clear ( ) ;
claimsToDelete . clear ( ) ;
takeoverCache . clear ( ) ;
2018-08-06 15:40:20 -04:00
claimQueueCache . clear ( ) ;
2019-07-01 12:42:45 -06:00
supportQueueCache . clear ( ) ;
alreadyCachedNodes . clear ( ) ;
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
{
COutPoint outPoint ;
2019-07-01 12:42:45 -06:00
// cache the parent nodes
cacheData ( name , false ) ;
getMerkleHash ( ) ;
bool fNameHasValue = false ;
2018-08-06 15:40:20 -04:00
int nHeightOfLastTakeover = 0 ;
2019-07-01 12:42:45 -06:00
std : : vector < CClaimTrieProofNode > nodes ;
for ( const auto & it : cache . 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-01 12:42:45 -06:00
if ( fNodeHasValue ) {
valueHash = getValueHash ( claim . outPoint , it - > nHeightOfLastTakeover ) ;
}
const auto pos = key . size ( ) ;
std : : vector < std : : pair < unsigned char , uint256 > > children ;
for ( const auto & child : it . children ( ) ) {
auto childKey = child . key ( ) ;
if ( name . find ( childKey ) = = 0 ) {
for ( auto i = pos ; i + 1 < childKey . size ( ) ; + + i ) {
children . emplace_back ( childKey [ i ] , uint256 { } ) ;
nodes . emplace_back ( std : : move ( children ) , fNodeHasValue , valueHash ) ;
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 ) {
2018-08-06 15:40:20 -04:00
fNameHasValue = fNodeHasValue ;
2019-07-01 12:42:45 -06:00
if ( fNameHasValue ) {
2018-08-06 15:40:20 -04:00
outPoint = claim . outPoint ;
2019-07-01 12:42:45 -06:00
nHeightOfLastTakeover = it - > nHeightOfLastTakeover ;
2018-08-06 15:40:20 -04:00
}
valueHash . SetNull ( ) ;
}
nodes . emplace_back ( std : : move ( children ) , fNodeHasValue , valueHash ) ;
}
proof = CClaimTrieProof ( std : : move ( nodes ) , fNameHasValue , outPoint , nHeightOfLastTakeover ) ;
return true ;
}