2019-07-09 17:02:54 +02:00
2019-07-19 17:36:53 +02:00
# include <consensus/merkle.h>
2019-07-09 17:02:54 +02:00
# include <chainparams.h>
# include <claimtrie.h>
2019-07-19 17:36:53 +02:00
# include <hash.h>
2018-08-06 21:40:20 +02:00
2019-07-01 20:42:45 +02:00
# include <boost/locale.hpp>
2018-08-06 21:40:20 +02:00
# include <boost/locale/conversion.hpp>
# include <boost/locale/localization_backend.hpp>
2019-08-02 02:35:58 +02:00
# include <boost/scoped_ptr.hpp>
2018-08-06 21:40:20 +02:00
2019-07-29 18:25:41 +02:00
CClaimTrieCacheExpirationFork : : CClaimTrieCacheExpirationFork ( CClaimTrie * base )
: CClaimTrieCacheBase ( base )
2019-07-09 17:02:54 +02:00
{
setExpirationTime ( Params ( ) . GetConsensus ( ) . GetExpirationTime ( nNextHeight ) ) ;
}
void CClaimTrieCacheExpirationFork : : setExpirationTime ( int time )
{
nExpirationTime = time ;
}
int CClaimTrieCacheExpirationFork : : expirationTime ( ) const
{
return nExpirationTime ;
}
2019-10-31 06:13:07 +01:00
bool CClaimTrieCacheExpirationFork : : incrementBlock ( insertUndoType & insertUndo , claimUndoType & expireUndo ,
insertUndoType & insertSupportUndo , supportUndoType & expireSupportUndo , takeoverUndoType & takeoverUndo )
2019-07-09 17:02:54 +02:00
{
2019-10-31 06:13:07 +01:00
if ( CClaimTrieCacheBase : : incrementBlock ( insertUndo , expireUndo , insertSupportUndo , expireSupportUndo , takeoverUndo ) ) {
2019-07-09 17:02:54 +02:00
setExpirationTime ( Params ( ) . GetConsensus ( ) . GetExpirationTime ( nNextHeight ) ) ;
return true ;
}
return false ;
}
2019-10-31 06:13:07 +01:00
bool CClaimTrieCacheExpirationFork : : decrementBlock ( insertUndoType & insertUndo , claimUndoType & expireUndo , insertUndoType & insertSupportUndo , supportUndoType & expireSupportUndo )
2019-07-09 17:02:54 +02:00
{
if ( CClaimTrieCacheBase : : decrementBlock ( insertUndo , expireUndo , insertSupportUndo , expireSupportUndo ) ) {
setExpirationTime ( Params ( ) . GetConsensus ( ) . GetExpirationTime ( nNextHeight ) ) ;
return true ;
}
return false ;
}
2019-07-19 17:36:53 +02:00
void CClaimTrieCacheExpirationFork : : initializeIncrement ( )
2019-07-09 17:02:54 +02:00
{
2019-07-19 17:36:53 +02:00
// we could do this in the constructor, but that would not allow for multiple increments in a row (as done in unit tests)
if ( nNextHeight ! = Params ( ) . GetConsensus ( ) . nExtendedClaimExpirationForkHeight )
return ;
forkForExpirationChange ( true ) ;
}
2019-10-31 06:13:07 +01:00
bool CClaimTrieCacheExpirationFork : : finalizeDecrement ( takeoverUndoType & takeoverUndo )
2019-07-19 17:36:53 +02:00
{
2019-10-31 06:13:07 +01:00
auto ret = CClaimTrieCacheBase : : finalizeDecrement ( takeoverUndo ) ;
2019-07-19 17:36:53 +02:00
if ( ret & & nNextHeight = = Params ( ) . GetConsensus ( ) . nExtendedClaimExpirationForkHeight )
forkForExpirationChange ( false ) ;
return ret ;
2019-07-09 17:02:54 +02:00
}
2019-07-01 20:42:45 +02:00
bool CClaimTrieCacheExpirationFork : : forkForExpirationChange ( bool increment )
2018-08-06 21:40:20 +02:00
{
2019-10-26 07:34:52 +02:00
if ( ! transacting ) { transacting = true ; db < < " begin " ; }
2018-08-06 21:40:20 +02:00
/*
If increment is True , we have forked to extend the expiration time , thus items in the expiration queue
will have their expiration extended by " new expiration time - original expiration time "
If increment is False , we are decremented a block to reverse the fork . Thus items in the expiration queue
will have their expiration extension removed .
*/
2019-10-23 22:15:37 +02:00
auto extension = Params ( ) . GetConsensus ( ) . nExtendedClaimExpirationTime - Params ( ) . GetConsensus ( ) . nOriginalClaimExpirationTime ;
2019-11-01 00:02:56 +01:00
if ( increment ) {
db < < " UPDATE claims SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ? "
< < extension < < nNextHeight ;
db < < " UPDATE supports SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ? "
< < extension < < nNextHeight ;
}
else {
db < < " UPDATE claims SET expirationHeight = expirationHeight - ? WHERE expirationHeight >= ? "
< < extension < < nNextHeight + extension ;
db < < " UPDATE supports SET expirationHeight = expirationHeight - ? WHERE expirationHeight >= ? "
< < extension < < nNextHeight + extension ;
}
2018-08-06 21:40:20 +02:00
return true ;
}
2019-07-01 20:42:45 +02:00
bool CClaimTrieCacheNormalizationFork : : shouldNormalize ( ) const
{
return nNextHeight > Params ( ) . GetConsensus ( ) . nNormalizedNameForkHeight ;
2018-08-06 21:40:20 +02:00
}
2019-07-01 20:42:45 +02:00
std : : string CClaimTrieCacheNormalizationFork : : normalizeClaimName ( const std : : string & name , bool force ) const
{
2018-08-06 21:40:20 +02:00
if ( ! force & & ! shouldNormalize ( ) )
return name ;
static std : : locale utf8 ;
static bool initialized = false ;
if ( ! initialized ) {
static boost : : locale : : localization_backend_manager manager =
2019-07-01 20:42:45 +02:00
boost : : locale : : localization_backend_manager : : global ( ) ;
2018-08-06 21:40:20 +02:00
manager . select ( " icu " ) ;
static boost : : locale : : generator curLocale ( manager ) ;
utf8 = curLocale ( " en_US.UTF8 " ) ;
initialized = true ;
}
std : : string normalized ;
try {
// Check if it is a valid utf-8 string. If not, it will throw a
// boost::locale::conv::conversion_error exception which we catch later
normalized = boost : : locale : : conv : : to_utf < char > ( name , " UTF-8 " , boost : : locale : : conv : : stop ) ;
if ( normalized . empty ( ) )
return name ;
// these methods supposedly only use the "UTF8" portion of the locale object:
normalized = boost : : locale : : normalize ( normalized , boost : : locale : : norm_nfd , utf8 ) ;
normalized = boost : : locale : : fold_case ( normalized , utf8 ) ;
2019-07-01 20:42:45 +02:00
} catch ( const boost : : locale : : conv : : conversion_error & e ) {
2018-08-06 21:40:20 +02:00
return name ;
2019-07-01 20:42:45 +02:00
} catch ( const std : : bad_cast & e ) {
2018-08-06 21:40:20 +02:00
LogPrintf ( " %s() is invalid or dependencies are missing: %s \n " , __func__ , e . what ( ) ) ;
throw ;
2019-07-01 20:42:45 +02:00
} catch ( const std : : exception & e ) { // TODO: change to use ... with current_exception() in c++11
2018-08-06 21:40:20 +02:00
LogPrintf ( " %s() had an unexpected exception: %s \n " , __func__ , e . what ( ) ) ;
return name ;
}
return normalized ;
}
2019-11-01 22:53:11 +01:00
bool CClaimTrieCacheNormalizationFork : : normalizeAllNamesInTrieIfNecessary ( takeoverUndoType & takeoverUndo )
2019-07-01 20:42:45 +02:00
{
2019-10-26 07:34:52 +02:00
if ( ! transacting ) { transacting = true ; db < < " begin " ; }
2019-07-01 20:42:45 +02:00
// run the one-time upgrade of all names that need to change
2019-10-24 23:21:36 +02:00
db . define ( " NORMALIZED " , [ this ] ( const std : : string & str ) { return normalizeClaimName ( str , true ) ; } ) ;
2019-10-23 22:15:37 +02:00
2019-11-01 22:53:11 +01:00
// make the new nodes
db < < " INSERT INTO nodes(name) SELECT NORMALIZED(name) AS nn FROM claims WHERE nn != nodeName "
2019-11-19 01:34:07 +01:00
" AND validHeight <= ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL " < < nNextHeight ;
2019-11-01 22:53:11 +01:00
db < < " UPDATE nodes SET hash = NULL WHERE name IN "
2019-11-19 01:34:07 +01:00
" (SELECT NORMALIZED(name) AS nn FROM supports WHERE nn != nodeName "
" AND validHeight <= ?1 AND expirationHeight > ?1) " < < nNextHeight ;
2019-11-01 22:53:11 +01:00
// update the claims and supports
2019-11-19 01:34:07 +01:00
db < < " UPDATE claims SET nodeName = NORMALIZED(name) WHERE validHeight <= ?1 AND expirationHeight > ?1 " < < nNextHeight ;
db < < " UPDATE supports SET nodeName = NORMALIZED(name) WHERE validHeight <= ?1 AND expirationHeight > ?1 " < < nNextHeight ;
2019-11-01 22:53:11 +01:00
// remove the old nodes
2019-11-19 01:34:07 +01:00
auto query = db < < " SELECT name, IFNULL(takeoverHeight, 0), takeoverID FROM nodes WHERE name NOT IN "
" (SELECT nodeName FROM claims WHERE validHeight <= ?1 AND expirationHeight > ?1) " ;
2019-11-01 22:53:11 +01:00
for ( auto & & row : query ) {
std : : string name ;
int takeoverHeight ;
std : : unique_ptr < uint160 > takeoverID ;
row > > name > > takeoverHeight > > takeoverID ;
if ( name . empty ( ) ) continue ; // preserve our root node
2019-11-19 01:34:07 +01:00
if ( takeoverHeight > 0 )
takeoverUndo . emplace_back ( name , std : : make_pair ( takeoverHeight , takeoverID ? * takeoverID : uint160 ( ) ) ) ;
2019-11-01 22:53:11 +01:00
// we need to let the tree structure method do the actual node delete:
db < < " UPDATE nodes SET hash = NULL WHERE name = ? " < < name ;
2018-08-06 21:40:20 +02:00
}
2019-11-19 01:34:07 +01:00
db < < " UPDATE nodes SET hash = NULL WHERE takeoverHeight IS NULL " ;
// work around a bug in the old implementation:
db < < " UPDATE claims SET validHeight = ?1 " // force a takeover on these
" WHERE blockHeight < ?1 AND validHeight > ?1 AND nodeName != name " < < nNextHeight ;
2019-10-23 22:15:37 +02:00
2019-07-01 20:42:45 +02:00
return true ;
2018-08-06 21:40:20 +02:00
}
2019-11-01 22:53:11 +01:00
bool CClaimTrieCacheNormalizationFork : : unnormalizeAllNamesInTrieIfNecessary ( )
{
if ( ! transacting ) { transacting = true ; db < < " begin " ; }
// run the one-time upgrade of all names that need to change
db . define ( " NORMALIZED " , [ this ] ( const std : : string & str ) { return normalizeClaimName ( str , true ) ; } ) ;
db < < " INSERT INTO nodes(name) SELECT name FROM claims WHERE name != nodeName "
2019-11-19 01:34:07 +01:00
" AND validHeight < ?1 AND expirationHeight > ?1 ON CONFLICT(name) DO UPDATE SET hash = NULL " < < nNextHeight ;
2019-11-01 22:53:11 +01:00
db < < " UPDATE nodes SET hash = NULL WHERE name IN "
" (SELECT name FROM supports WHERE name != nodeName UNION "
" SELECT nodeName FROM supports WHERE name != nodeName UNION "
" SELECT nodeName FROM claims WHERE name != nodeName) " ;
db < < " UPDATE claims SET nodeName = name " ;
db < < " UPDATE supports SET nodeName = name " ;
// we need to let the tree structure method do the actual node delete
db < < " UPDATE nodes SET hash = NULL WHERE name NOT IN "
" (SELECT name FROM claims) " ;
return true ;
}
2019-10-31 06:13:07 +01:00
bool CClaimTrieCacheNormalizationFork : : incrementBlock ( insertUndoType & insertUndo , claimUndoType & expireUndo ,
insertUndoType & insertSupportUndo , supportUndoType & expireSupportUndo , takeoverUndoType & takeoverUndo )
2019-07-01 20:42:45 +02:00
{
2019-11-01 22:53:11 +01:00
if ( nNextHeight = = Params ( ) . GetConsensus ( ) . nNormalizedNameForkHeight )
normalizeAllNamesInTrieIfNecessary ( takeoverUndo ) ;
2019-11-19 01:34:07 +01:00
auto ret = CClaimTrieCacheExpirationFork : : incrementBlock ( insertUndo , expireUndo , insertSupportUndo , expireSupportUndo , takeoverUndo ) ;
// if (nNextHeight == 588319) {
// getMerkleHash();
// auto q2 = db << "SELECT name, nodeName FROM claims WHERE nodeName NOT IN (SELECT name FROM nodes) "
// "AND validHeight < ?1 AND expirationHeight >= ?1" << nNextHeight;
// for (auto&& row: q2) {
// std::string name, nn;
// row >> name >> nn;
// LogPrintf("BAD NAME 2: %s, %s\n", name, nn);
// }
// std::ifstream input("dump588318.txt");
// std::string line;
// std::vector<std::string> lines;
// while (std::getline(input, line)) {
// lines.push_back(line);
// }
// std::sort(lines.begin(), lines.end());
// auto q3 = db << "SELECT n.name, n.hash, IFNULL(n.takeoverHeight, 0), "
// "(SELECT COUNT(*) FROM claims c WHERE c.nodeName = n.name "
// "AND validHeight < ?1 AND expirationHeight >= ?1) as cc FROM nodes n ORDER BY n.name" << nNextHeight;
// for (auto&& row: q3) {
// std::string name; int takeover, childs; uint256 hash;
// row >> name >> hash >> takeover >> childs;
// std::string m = name + ", " + std::to_string(name.size()) + ", " + hash.GetHex() + ", " + std::to_string(takeover) + ", " + std::to_string(childs);
// if (!std::binary_search(lines.begin(), lines.end(), m)) {
// LogPrintf("BAD BAD: %s\n", m);
// }
// }
// auto q4 = db << "SELECT n.name, n.parent FROM nodes n LEFT JOIN claims c ON n.name = c.nodeName LEFT JOIN nodes n2 ON n.name = n2.parent WHERE c.nodeName IS NULL AND n2.parent IS NULL";
// for (auto&& row: q4) {
// std::string name, nn;
// row >> name >> nn;
// LogPrintf("BAD NAME 3: %s, %s\n", name, nn);
// }
// }
return ret ;
2018-08-06 21:40:20 +02:00
}
2019-10-31 06:13:07 +01:00
bool CClaimTrieCacheNormalizationFork : : decrementBlock ( insertUndoType & insertUndo , claimUndoType & expireUndo , insertUndoType & insertSupportUndo , supportUndoType & expireSupportUndo )
2019-07-01 20:42:45 +02:00
{
2019-10-23 22:15:37 +02:00
auto ret = CClaimTrieCacheExpirationFork : : decrementBlock ( insertUndo , expireUndo , insertSupportUndo , expireSupportUndo ) ;
2019-11-01 22:53:11 +01:00
if ( ret & & nNextHeight = = Params ( ) . GetConsensus ( ) . nNormalizedNameForkHeight )
unnormalizeAllNamesInTrieIfNecessary ( ) ;
2019-10-23 22:15:37 +02:00
return ret ;
2018-08-06 21:40:20 +02:00
}
2019-10-23 22:15:37 +02:00
bool CClaimTrieCacheNormalizationFork : : getProofForName ( const std : : string & name , const uint160 & finalClaim , CClaimTrieProof & proof )
2019-07-01 20:42:45 +02:00
{
2019-10-23 22:15:37 +02:00
return CClaimTrieCacheExpirationFork : : getProofForName ( normalizeClaimName ( name ) , finalClaim , proof ) ;
2018-08-06 21:40:20 +02:00
}
2019-10-31 06:13:07 +01:00
bool CClaimTrieCacheNormalizationFork : : getInfoForName ( const std : : string & name , CClaimValue & claim , int offsetHeight ) const
2019-07-01 20:42:45 +02:00
{
2019-10-31 06:13:07 +01:00
return CClaimTrieCacheExpirationFork : : getInfoForName ( normalizeClaimName ( name ) , claim , offsetHeight ) ;
2018-08-06 21:40:20 +02:00
}
2019-08-08 15:39:57 +02:00
CClaimSupportToName CClaimTrieCacheNormalizationFork : : getClaimsForName ( const std : : string & name ) const
2019-07-01 20:42:45 +02:00
{
2018-08-06 21:40:20 +02:00
return CClaimTrieCacheExpirationFork : : getClaimsForName ( normalizeClaimName ( name ) ) ;
}
2019-07-02 17:49:02 +02:00
int CClaimTrieCacheNormalizationFork : : getDelayForName ( const std : : string & name , const uint160 & claimId ) const
2019-07-01 20:42:45 +02:00
{
2018-08-06 21:40:20 +02:00
return CClaimTrieCacheExpirationFork : : getDelayForName ( normalizeClaimName ( name ) , claimId ) ;
}
2019-07-01 20:42:45 +02:00
std : : string CClaimTrieCacheNormalizationFork : : adjustNameForValidHeight ( const std : : string & name , int validHeight ) const
{
2018-08-06 21:40:20 +02:00
return normalizeClaimName ( name , validHeight > Params ( ) . GetConsensus ( ) . nNormalizedNameForkHeight ) ;
}
2019-07-19 17:36:53 +02:00
CClaimTrieCacheHashFork : : CClaimTrieCacheHashFork ( CClaimTrie * base ) : CClaimTrieCacheNormalizationFork ( base )
{
}
static const uint256 leafHash = uint256S ( " 0000000000000000000000000000000000000000000000000000000000000002 " ) ;
static const uint256 emptyHash = uint256S ( " 0000000000000000000000000000000000000000000000000000000000000003 " ) ;
2019-10-31 06:13:07 +01:00
uint256 CClaimTrieCacheHashFork : : recursiveComputeMerkleHash ( const std : : string & name , int takeoverHeight , bool checkOnly )
2019-07-19 17:36:53 +02:00
{
2019-10-23 22:15:37 +02:00
if ( nNextHeight < Params ( ) . GetConsensus ( ) . nAllClaimsInMerkleForkHeight )
2019-10-31 06:13:07 +01:00
return CClaimTrieCacheNormalizationFork : : recursiveComputeMerkleHash ( name , takeoverHeight , checkOnly ) ;
2019-07-19 17:36:53 +02:00
2019-11-07 19:29:38 +01:00
// it may be that using RAM for this is more expensive than preparing a new query statement in each recursive call
struct Triple { std : : string name ; std : : unique_ptr < uint256 > hash ; int takeoverHeight ; } ;
std : : vector < Triple > children ;
for ( auto & & row : childHashQuery < < name ) {
children . emplace_back ( ) ;
auto & b = children . back ( ) ;
row > > b . name > > b . hash > > b . takeoverHeight ;
}
childHashQuery + + ;
2019-07-19 17:36:53 +02:00
std : : vector < uint256 > childHashes ;
2019-11-07 19:29:38 +01:00
for ( auto & child : children ) {
if ( child . hash = = nullptr ) child . hash = std : : make_unique < uint256 > ( ) ;
if ( child . hash - > IsNull ( ) ) {
* child . hash = recursiveComputeMerkleHash ( child . name , child . takeoverHeight , checkOnly ) ;
2019-10-23 22:15:37 +02:00
}
2019-11-07 19:29:38 +01:00
childHashes . push_back ( * child . hash ) ;
2019-10-23 22:15:37 +02:00
}
2019-07-19 17:36:53 +02:00
std : : vector < uint256 > claimHashes ;
2019-11-22 18:05:38 +01:00
//if (takeoverHeight > 0) {
for ( auto & & row : claimHashQuery < < nNextHeight < < name ) {
COutPoint p ;
row > > p . hash > > p . n ;
auto claimHash = getValueHash ( p , takeoverHeight ) ;
claimHashes . push_back ( claimHash ) ;
}
claimHashQuery + + ;
//}
2019-07-19 17:36:53 +02:00
auto left = childHashes . empty ( ) ? leafHash : ComputeMerkleRoot ( childHashes ) ;
auto right = claimHashes . empty ( ) ? emptyHash : ComputeMerkleRoot ( claimHashes ) ;
2019-10-23 22:15:37 +02:00
auto computedHash = Hash ( left . begin ( ) , left . end ( ) , right . begin ( ) , right . end ( ) ) ;
if ( ! checkOnly )
2019-10-24 23:21:36 +02:00
db < < " UPDATE nodes SET hash = ? WHERE name = ? " < < computedHash < < name ;
2019-10-23 22:15:37 +02:00
return computedHash ;
2019-09-30 20:13:05 +02:00
}
2019-07-19 17:36:53 +02:00
std : : vector < uint256 > ComputeMerklePath ( const std : : vector < uint256 > & hashes , uint32_t idx )
{
uint32_t count = 0 ;
int matchlevel = - 1 ;
bool matchh = false ;
uint256 inner [ 32 ] , h ;
const uint32_t one = 1 ;
std : : vector < uint256 > res ;
const auto iterateInner = [ & ] ( int & level ) {
for ( ; ! ( count & ( one < < level ) ) ; level + + ) {
const auto & ihash = inner [ level ] ;
if ( matchh ) {
res . push_back ( ihash ) ;
} else if ( matchlevel = = level ) {
res . push_back ( h ) ;
matchh = true ;
}
h = Hash ( ihash . begin ( ) , ihash . end ( ) , h . begin ( ) , h . end ( ) ) ;
}
} ;
while ( count < hashes . size ( ) ) {
h = hashes [ count ] ;
matchh = count = = idx ;
count + + ;
int level = 0 ;
iterateInner ( level ) ;
// Store the resulting hash at inner position level.
inner [ level ] = h ;
if ( matchh )
matchlevel = level ;
}
int level = 0 ;
while ( ! ( count & ( one < < level ) ) )
level + + ;
h = inner [ level ] ;
matchh = matchlevel = = level ;
while ( count ! = ( one < < level ) ) {
// If we reach this point, h is an inner value that is not the top.
if ( matchh )
res . push_back ( h ) ;
h = Hash ( h . begin ( ) , h . end ( ) , h . begin ( ) , h . end ( ) ) ;
// Increment count to the value it would have if two entries at this
count + = ( one < < level ) ;
level + + ;
iterateInner ( level ) ;
}
return res ;
}
2019-10-23 22:15:37 +02:00
bool CClaimTrieCacheHashFork : : getProofForName ( const std : : string & name , const uint160 & finalClaim , CClaimTrieProof & proof )
2019-07-19 17:36:53 +02:00
{
if ( nNextHeight < Params ( ) . GetConsensus ( ) . nAllClaimsInMerkleForkHeight )
2019-10-23 22:15:37 +02:00
return CClaimTrieCacheNormalizationFork : : getProofForName ( name , finalClaim , proof ) ;
2019-07-19 17:36:53 +02:00
auto fillPairs = [ & proof ] ( const std : : vector < uint256 > & hashes , uint32_t idx ) {
auto partials = ComputeMerklePath ( hashes , idx ) ;
for ( int i = partials . size ( ) - 1 ; i > = 0 ; - - i )
proof . pairs . emplace_back ( ( idx > > i ) & 1 , partials [ i ] ) ;
} ;
// cache the parent nodes
getMerkleHash ( ) ;
proof = CClaimTrieProof ( ) ;
2019-10-31 06:13:07 +01:00
auto nodeQuery = db < < " SELECT name, IFNULL(takeoverHeight, 0) FROM nodes WHERE "
2019-10-23 22:15:37 +02:00
" name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
2019-11-19 01:34:07 +01:00
" SELECT POPS(p) FROM prefix WHERE p != '') SELECT p FROM prefix) "
2019-11-01 23:59:47 +01:00
" ORDER BY name " < < name ;
2019-10-23 22:15:37 +02:00
for ( auto & & row : nodeQuery ) {
2019-10-24 21:09:56 +02:00
std : : string key ; ;
2019-10-31 06:13:07 +01:00
int takeoverHeight ;
row > > key > > takeoverHeight ;
2019-07-19 17:36:53 +02:00
std : : vector < uint256 > childHashes ;
uint32_t nextCurrentIdx = 0 ;
2019-11-07 19:29:38 +01:00
for ( auto & & child : childHashQuery < < key ) {
2019-10-23 22:15:37 +02:00
std : : string childKey ;
uint256 childHash ;
child > > childKey > > childHash ;
if ( name . find ( childKey ) = = 0 )
2019-07-19 17:36:53 +02:00
nextCurrentIdx = uint32_t ( childHashes . size ( ) ) ;
2019-10-23 22:15:37 +02:00
childHashes . push_back ( childHash ) ;
2019-07-19 17:36:53 +02:00
}
2019-11-07 19:29:38 +01:00
childHashQuery + + ;
2019-11-01 23:59:47 +01:00
2019-07-19 17:36:53 +02:00
std : : vector < uint256 > claimHashes ;
2019-10-23 22:15:37 +02:00
uint32_t finalClaimIdx = 0 ;
2019-11-07 19:29:38 +01:00
for ( auto & & child : claimHashQuery < < nNextHeight < < key ) {
2019-11-01 23:59:47 +01:00
COutPoint childOutPoint ;
uint160 childClaimID ;
child > > childOutPoint . hash > > childOutPoint . n > > childClaimID ;
if ( childClaimID = = finalClaim & & key = = name ) {
finalClaimIdx = uint32_t ( claimHashes . size ( ) ) ;
proof . outPoint = childOutPoint ;
proof . hasValue = true ;
2019-10-23 22:15:37 +02:00
}
2019-11-01 23:59:47 +01:00
claimHashes . push_back ( getValueHash ( childOutPoint , takeoverHeight ) ) ;
2019-10-23 22:15:37 +02:00
}
2019-11-07 19:29:38 +01:00
claimHashQuery + + ;
2019-07-19 17:36:53 +02:00
// I am on a node; I need a hash(children, claims)
// if I am the last node on the list, it will be hash(children, x)
// else it will be hash(x, claims)
2019-10-23 22:15:37 +02:00
if ( key = = name ) {
2019-11-01 23:59:47 +01:00
proof . nHeightOfLastTakeover = takeoverHeight ;
2019-07-19 17:36:53 +02:00
auto hash = childHashes . empty ( ) ? leafHash : ComputeMerkleRoot ( childHashes ) ;
proof . pairs . emplace_back ( true , hash ) ;
if ( ! claimHashes . empty ( ) )
2019-10-23 22:15:37 +02:00
fillPairs ( claimHashes , finalClaimIdx ) ;
2019-07-19 17:36:53 +02:00
} else {
auto hash = claimHashes . empty ( ) ? emptyHash : ComputeMerkleRoot ( claimHashes ) ;
proof . pairs . emplace_back ( false , hash ) ;
if ( ! childHashes . empty ( ) )
fillPairs ( childHashes , nextCurrentIdx ) ;
}
}
std : : reverse ( proof . pairs . begin ( ) , proof . pairs . end ( ) ) ;
return true ;
}
void CClaimTrieCacheHashFork : : initializeIncrement ( )
{
CClaimTrieCacheNormalizationFork : : initializeIncrement ( ) ;
// we could do this in the constructor, but that would not allow for multiple increments in a row (as done in unit tests)
2019-11-01 23:59:47 +01:00
if ( nNextHeight = = Params ( ) . GetConsensus ( ) . nAllClaimsInMerkleForkHeight - 1 ) {
if ( ! transacting ) { transacting = true ; db < < " begin " ; }
2019-10-24 23:21:36 +02:00
db < < " UPDATE nodes SET hash = NULL " ;
2019-11-01 23:59:47 +01:00
}
2019-07-19 17:36:53 +02:00
}
2019-10-31 06:13:07 +01:00
bool CClaimTrieCacheHashFork : : finalizeDecrement ( takeoverUndoType & takeoverUndo )
2019-07-19 17:36:53 +02:00
{
2019-10-31 06:13:07 +01:00
auto ret = CClaimTrieCacheNormalizationFork : : finalizeDecrement ( takeoverUndo ) ;
2019-11-01 23:59:47 +01:00
if ( ret & & nNextHeight = = Params ( ) . GetConsensus ( ) . nAllClaimsInMerkleForkHeight - 1 ) {
if ( ! transacting ) { transacting = true ; db < < " begin " ; }
2019-10-24 23:21:36 +02:00
db < < " UPDATE nodes SET hash = NULL " ;
2019-11-01 23:59:47 +01:00
}
2019-07-19 17:36:53 +02:00
return ret ;
}
2019-09-04 22:27:07 +02:00
2019-09-30 20:13:05 +02:00
bool CClaimTrieCacheHashFork : : allowSupportMetadata ( ) const
{
2019-09-04 22:27:07 +02:00
return nNextHeight > = Params ( ) . GetConsensus ( ) . nAllClaimsInMerkleForkHeight ;
}