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
# 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-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 ;
static_assert ( std : : is_same < typename std : : remove_const < 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-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-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
}
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-02 18:49:02 +03:00
return db & & db - > Sync ( ) ;
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-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 < >
std : : pair < const int , 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 < >
std : : pair < const int , 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 >
std : : pair < const int , 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 < >
typename queueNameType : : value_type * 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 < >
typename queueNameType : : value_type * 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 >
typename queueNameType : : value_type * CClaimTrieCacheBase : : getQueueCacheNameRow ( const std : : string & , bool )
{
supportedType < T > ( ) ;
return nullptr ;
}
template < >
typename expirationQueueType : : value_type * CClaimTrieCacheBase : : getExpirationQueueCacheRow < CClaimValue > ( int nHeight , bool createIfNotExists )
{
return getQueue ( * ( base - > db ) , EXP_QUEUE_ROW , nHeight , expirationQueueCache , createIfNotExists ) ;
}
template < >
typename expirationQueueType : : value_type * 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 >
typename expirationQueueType : : value_type * CClaimTrieCacheBase : : getExpirationQueueCacheRow ( int , bool )
{
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-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-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-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-02 18:49:02 +03:00
template < typename T >
bool CClaimTrieCacheBase : : haveInQueue ( const std : : string & name , const COutPoint & outPoint , int & nValidAtHeight )
2019-07-01 12:42:45 -06:00
{
2019-07-02 18:49:02 +03:00
supportedType < T > ( ) ;
if ( auto nameRow = getQueueCacheNameRow < T > ( name ) ) {
auto itNameRow = findOutPoint ( nameRow - > second , outPoint ) ;
if ( itNameRow ! = nameRow - > second . end ( ) ) {
nValidAtHeight = itNameRow - > nHeight ;
if ( auto row = getQueueCacheRow < T > ( nValidAtHeight ) ) {
2019-07-15 08:48:24 +03:00
auto iRow = findOutPoint ( row - > second , CNameOutPointType { name , outPoint } ) ;
2019-07-02 18:49:02 +03:00
if ( iRow ! = row - > second . end ( ) ) {
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-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : haveClaimInQueue ( const std : : string & name , const COutPoint & outPoint , int & nValidAtHeight )
{
return haveInQueue < CClaimValue > ( name , outPoint , nValidAtHeight ) ;
}
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-02 18:49:02 +03:00
return haveInQueue < CSupportValue > ( name , outPoint , nValidAtHeight ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-01 12:42:45 -06:00
std : : size_t CClaimTrieCacheBase : : getTotalNamesInTrie ( ) const
2018-08-06 15:40:20 -04:00
{
2019-07-02 18:49:02 +03:00
std : : size_t count = 0 ;
for ( auto it = base - > cbegin ( ) ; it ! = base - > cend ( ) ; + + it )
if ( ! it - > empty ( ) ) + + count ;
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 ;
2019-07-02 18:49:02 +03:00
for ( auto it = base - > cbegin ( ) ; it ! = base - > cend ( ) ; + + it )
2019-07-01 12:42:45 -06:00
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-02 18:49:02 +03:00
template < typename T >
using iCbType = std : : function < void ( T & ) > ;
template < typename TIterator >
uint256 recursiveMerkleHash ( TIterator & it , const iCbType < TIterator > & process , const iCbType < TIterator > & verify = { } )
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 ( ) ;
2019-07-02 18:49:02 +03:00
for ( auto & child : it . children ( ) ) {
process ( child ) ;
2019-07-01 12:42:45 -06:00
auto & key = child . key ( ) ;
auto hash = child - > hash ;
completeHash ( hash , key , pos ) ;
2019-07-02 18:49:02 +03:00
vchToHash . push_back ( key [ pos ] ) ;
2019-07-01 12:42:45 -06:00
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 ) ) {
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-02 18:49:02 +03:00
} else if ( verify ) {
verify ( it ) ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
return Hash ( vchToHash . begin ( ) , vchToHash . end ( ) ) ;
}
bool recursiveCheckConsistency ( CClaimTrie : : const_iterator & it , std : : string & failed )
{
struct CRecursiveBreak { } ;
using iterator = CClaimTrie : : const_iterator ;
iCbType < iterator > verify = [ & failed ] ( iterator & it ) {
if ( ! it . hasChildren ( ) ) {
// we don't allow a situation of no children and no claims; no empty leaf nodes allowed
failed = it . key ( ) ;
throw CRecursiveBreak ( ) ;
}
} ;
iCbType < iterator > process = [ & failed , & process , & verify ] ( iterator & it ) {
if ( it - > hash ! = recursiveMerkleHash ( it , process , verify ) ) {
failed = it . key ( ) ;
throw CRecursiveBreak ( ) ;
}
} ;
try {
process ( it ) ;
} catch ( const CRecursiveBreak & ) {
return false ;
2019-07-01 12:42:45 -06:00
}
2019-07-02 18:49:02 +03:00
return true ;
2018-08-06 15:40:20 -04:00
}
2019-07-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : checkConsistency ( ) 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 ;
2019-07-02 18:49:02 +03:00
auto consistent = recursiveCheckConsistency ( it , failed ) ;
2019-07-01 12:42:45 -06:00
if ( ! consistent ) {
2019-07-02 18:49:02 +03:00
LogPrintf ( " \n Printing base tree from its parent: \n " ) ;
2019-07-01 12:42:45 -06:00
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-02 18:49:02 +03:00
using iterator = CClaimTrie : : iterator ;
iCbType < iterator > process = [ & process ] ( iterator & it ) {
if ( it - > hash . IsNull ( ) )
it - > hash = recursiveMerkleHash ( it , process ) ;
} ;
process ( it ) ;
return it - > hash ;
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 ;
2019-07-02 18:49:02 +03:00
if ( it - > 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-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-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 ) ;
claimsToAdd . emplace_back ( name , claim ) ;
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
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-02 18:49:02 +03: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 ) ;
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 ) ;
itQueueCache - > second . emplace_back ( newName , value ) ;
auto itQueueName = getQueueCacheNameRow < T > ( newName , true ) ;
itQueueName - > second . emplace_back ( value . outPoint , value . nValidAtHeight ) ;
auto itQueueExpiration = getExpirationQueueCacheRow < T > ( value . nHeight + expirationTime ( ) , true ) ;
itQueueExpiration - > second . 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 ) ;
itQueueExpiration - > second . emplace_back ( adjustNameForValidHeight ( name , nValidAtHeight ) , value . outPoint ) ;
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 )
{
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 ) ;
CClaimValue claim ( outPoint , claimId , nAmount , nHeight , nValidAtHeight ) ;
claimsToAdd . emplace_back ( name , claim ) ;
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 )
{
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 ) ;
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 > ( ) ;
if ( auto itQueueNameRow = getQueueCacheNameRow < T > ( name ) ) {
auto itQueueName = findOutPoint ( itQueueNameRow - > second , outPoint ) ;
if ( itQueueName ! = itQueueNameRow - > second . end ( ) ) {
if ( auto itQueueRow = getQueueCacheRow < T > ( itQueueName - > nHeight ) ) {
2019-07-15 08:48:24 +03:00
auto itQueue = findOutPoint ( itQueueRow - > second , CNameOutPointType { name , outPoint } ) ;
2019-07-02 18:49:02 +03:00
if ( itQueue ! = itQueueRow - > second . end ( ) ) {
std : : swap ( value , itQueue - > second ) ;
itQueueNameRow - > second . erase ( itQueueName ) ;
itQueueRow - > second . erase ( itQueue ) ;
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-02 18:49:02 +03:00
bool CClaimTrieCacheBase : : removeClaimFromQueue ( const std : : string & name , const COutPoint & outPoint , CClaimValue & claim )
{
return removeFromQueue ( name , outPoint , claim ) ;
}
bool CClaimTrieCacheBase : : removeSupportFromQueue ( const std : : string & name , const COutPoint & outPoint , CSupportValue & support )
{
return removeFromQueue ( name , outPoint , support ) ;
}
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 )
{
LogPrintf ( " %s: name: %s, txhash: %s, nOut: %d, nHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nHeight , nNextHeight ) ;
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-02 18:49:02 +03:00
LogPrintf ( " %s: name: %s, txhash: %s, nOut: %d, nHeight: %d, nNextHeight: %d \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nHeight , nNextHeight ) ;
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 ( ) ;
if ( auto itQueueRow = getExpirationQueueCacheRow < T > ( expirationHeight ) )
2019-07-15 08:48:24 +03:00
eraseOutPoint ( itQueueRow - > second , 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-02 18:49:02 +03:00
LogPrintf ( " %s: name: %s, txhash: %s, nOut: %s, nNextHeight: %s \n " , __func__ , name , outPoint . hash . GetHex ( ) , outPoint . n , nNextHeight ) ;
CClaimValue claim ;
if ( remove ( claim , name , outPoint , nHeight , nValidAtHeight , fCheckTakeover ) ) {
claimsToDelete . insert ( claim ) ;
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-01 12:42:45 -06:00
auto sit = cacheSupports . find ( name ) ;
2019-07-02 18:49:02 +03:00
if ( sit = = cacheSupports . end ( ) )
2019-07-01 12:42:45 -06:00
sit = cacheSupports . 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-01 12:42:45 -06:00
auto sit = cacheSupports . find ( name ) ;
2019-07-02 18:49:02 +03:00
if ( sit = = cacheSupports . end ( ) )
2019-07-01 12:42:45 -06:00
sit = cacheSupports . 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-02 18:49:02 +03:00
LogPrintf ( " 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-07-02 18:49:02 +03:00
void CClaimTrieCacheBase : : dumpToLog ( CClaimTrie : : const_iterator it , bool diffFromBase ) const
2018-08-06 15:40:20 -04:00
{
2019-07-01 12:42:45 -06:00
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 ( ) ) ,
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
& & ! cache . contains ( key ) & & base - > contains ( key ) )
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 > ( ) ;
if ( auto itQueueRow = getQueueCacheRow < T > ( nNextHeight ) ) {
2019-07-01 12:42:45 -06:00
for ( const auto & itEntry : itQueueRow - > second ) {
2019-07-02 18:49:02 +03:00
if ( auto itQueueNameRow = getQueueCacheNameRow < T > ( itEntry . first ) ) {
auto & points = itQueueNameRow - > second ;
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-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 ) ;
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
}
itQueueRow - > second . clear ( ) ;
}
2019-07-01 12:42:45 -06:00
2019-07-02 18:49:02 +03:00
if ( auto itExpirationRow = getExpirationQueueCacheRow < T > ( nNextHeight ) ) {
2019-07-01 12:42:45 -06:00
for ( const auto & itEntry : itExpirationRow - > second ) {
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
}
itExpirationRow - > second . clear ( ) ;
}
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 > ( ) ;
if ( auto itQueueNameRow = getQueueCacheNameRow < T > ( name ) ) {
for ( const auto & itQueueName : itQueueNameRow - > second ) {
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
if ( auto itQueueRow = getQueueCacheRow < T > ( itQueueName . nHeight ) ) {
auto & points = itQueueRow - > second ;
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
itQueueNameRow - > second . 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 )
{
undoIncrement ( insertUndo , expireUndo , & claimsToDelete ) ;
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)
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
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 )
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-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 ( ) ) {
2019-07-02 18:49:02 +03:00
auto itExpireRow = getExpirationQueueCacheRow < T > ( nNextHeight , true ) ;
2019-07-01 12:42:45 -06:00
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 ) ;
if ( nNextHeight = = itExpireUndo - > second . nHeight + expirationTime ( ) )
2019-07-01 12:42:45 -06:00
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 ) {
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 ) ;
itQueueRow - > second . emplace_back ( itInsertUndo - > name , value ) ;
itQueueNameRow - > second . 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 ) ;
undoDecrement ( insertUndo , expireUndo , & claimsToAdd , & claimsToDelete ) ;
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 > ( ) ;
for ( auto e = row . begin ( ) ; e ! = row . end ( ) ; + + e ) {
// remove and insert with new expiration time
if ( auto itQueueRow = getExpirationQueueCacheRow < T > ( height ) )
2019-07-15 08:48:24 +03:00
eraseOutPoint ( itQueueRow - > second , 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 ) ;
itQueueExpiration - > second . emplace_back ( e - > name , e - > outPoint ) ;
}
}
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-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-02 18:49:02 +03:00
int CClaimTrieCacheBase : : getDelayForName ( const std : : string & name ) const
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-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
{
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-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 ;
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 ;
}