@@ -5660,69 +5660,81 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
5660
5660
return false ;
5661
5661
}
5662
5662
5663
- COutPoint outpoint;
5664
- Coin coin;
5665
5663
const uint64_t coins_count = metadata.m_coins_count ;
5666
5664
uint64_t coins_left = metadata.m_coins_count ;
5667
5665
5668
- LogPrintf (" [snapshot] loading coins from snapshot %s\n " , base_blockhash.ToString ());
5666
+ LogPrintf (" [snapshot] loading %d coins from snapshot %s\n " , coins_left , base_blockhash.ToString ());
5669
5667
int64_t coins_processed{0 };
5670
5668
5671
5669
while (coins_left > 0 ) {
5672
5670
try {
5673
- coins_file >> outpoint;
5674
- coins_file >> coin;
5675
- } catch (const std::ios_base::failure&) {
5676
- LogPrintf (" [snapshot] bad snapshot format or truncated snapshot after deserializing %d coins\n " ,
5677
- coins_count - coins_left);
5678
- return false ;
5679
- }
5680
- if (coin.nHeight > base_height ||
5681
- outpoint.n >= std::numeric_limits<decltype (outpoint.n )>::max () // Avoid integer wrap-around in coinstats.cpp:ApplyHash
5682
- ) {
5683
- LogPrintf (" [snapshot] bad snapshot data after deserializing %d coins\n " ,
5684
- coins_count - coins_left);
5685
- return false ;
5686
- }
5687
- if (!MoneyRange (coin.out .nValue )) {
5688
- LogPrintf (" [snapshot] bad snapshot data after deserializing %d coins - bad tx out value\n " ,
5689
- coins_count - coins_left);
5690
- return false ;
5691
- }
5671
+ Txid txid;
5672
+ coins_file >> txid;
5673
+ size_t coins_per_txid{0 };
5674
+ coins_per_txid = ReadCompactSize (coins_file);
5675
+
5676
+ if (coins_per_txid > coins_left) {
5677
+ LogPrintf (" [snapshot] mismatch in coins count in snapshot metadata and actual snapshot data\n " );
5678
+ return false ;
5679
+ }
5692
5680
5693
- coins_cache.EmplaceCoinInternalDANGER (std::move (outpoint), std::move (coin));
5681
+ for (size_t i = 0 ; i < coins_per_txid; i++) {
5682
+ COutPoint outpoint;
5683
+ Coin coin;
5684
+ outpoint.n = static_cast <uint32_t >(ReadCompactSize (coins_file));
5685
+ outpoint.hash = txid;
5686
+ coins_file >> coin;
5687
+ if (coin.nHeight > base_height ||
5688
+ outpoint.n >= std::numeric_limits<decltype (outpoint.n )>::max () // Avoid integer wrap-around in coinstats.cpp:ApplyHash
5689
+ ) {
5690
+ LogPrintf (" [snapshot] bad snapshot data after deserializing %d coins\n " ,
5691
+ coins_count - coins_left);
5692
+ return false ;
5693
+ }
5694
+ if (!MoneyRange (coin.out .nValue )) {
5695
+ LogPrintf (" [snapshot] bad snapshot data after deserializing %d coins - bad tx out value\n " ,
5696
+ coins_count - coins_left);
5697
+ return false ;
5698
+ }
5699
+ coins_cache.EmplaceCoinInternalDANGER (std::move (outpoint), std::move (coin));
5694
5700
5695
- --coins_left;
5696
- ++coins_processed;
5701
+ --coins_left;
5702
+ ++coins_processed;
5697
5703
5698
- if (coins_processed % 1000000 == 0 ) {
5699
- LogPrintf (" [snapshot] %d coins loaded (%.2f%%, %.2f MB)\n " ,
5700
- coins_processed,
5701
- static_cast <float >(coins_processed) * 100 / static_cast <float >(coins_count),
5702
- coins_cache.DynamicMemoryUsage () / (1000 * 1000 ));
5703
- }
5704
+ if (coins_processed % 1000000 == 0 ) {
5705
+ LogPrintf (" [snapshot] %d coins loaded (%.2f%%, %.2f MB)\n " ,
5706
+ coins_processed,
5707
+ static_cast <float >(coins_processed) * 100 / static_cast <float >(coins_count),
5708
+ coins_cache.DynamicMemoryUsage () / (1000 * 1000 ));
5709
+ }
5704
5710
5705
- // Batch write and flush (if we need to) every so often.
5706
- //
5707
- // If our average Coin size is roughly 41 bytes, checking every 120,000 coins
5708
- // means <5MB of memory imprecision.
5709
- if (coins_processed % 120000 == 0 ) {
5710
- if (m_interrupt) {
5711
- return false ;
5712
- }
5711
+ // Batch write and flush (if we need to) every so often.
5712
+ //
5713
+ // If our average Coin size is roughly 41 bytes, checking every 120,000 coins
5714
+ // means <5MB of memory imprecision.
5715
+ if (coins_processed % 120000 == 0 ) {
5716
+ if (m_interrupt) {
5717
+ return false ;
5718
+ }
5713
5719
5714
- const auto snapshot_cache_state = WITH_LOCK (::cs_main,
5715
- return snapshot_chainstate.GetCoinsCacheSizeState ());
5720
+ const auto snapshot_cache_state = WITH_LOCK (::cs_main,
5721
+ return snapshot_chainstate.GetCoinsCacheSizeState ());
5716
5722
5717
- if (snapshot_cache_state >= CoinsCacheSizeState::CRITICAL) {
5718
- // This is a hack - we don't know what the actual best block is, but that
5719
- // doesn't matter for the purposes of flushing the cache here. We'll set this
5720
- // to its correct value (`base_blockhash`) below after the coins are loaded.
5721
- coins_cache.SetBestBlock (GetRandHash ());
5723
+ if (snapshot_cache_state >= CoinsCacheSizeState::CRITICAL) {
5724
+ // This is a hack - we don't know what the actual best block is, but that
5725
+ // doesn't matter for the purposes of flushing the cache here. We'll set this
5726
+ // to its correct value (`base_blockhash`) below after the coins are loaded.
5727
+ coins_cache.SetBestBlock (GetRandHash ());
5722
5728
5723
- // No need to acquire cs_main since this chainstate isn't being used yet.
5724
- FlushSnapshotToDisk (coins_cache, /* snapshot_loaded=*/ false );
5729
+ // No need to acquire cs_main since this chainstate isn't being used yet.
5730
+ FlushSnapshotToDisk (coins_cache, /* snapshot_loaded=*/ false );
5731
+ }
5732
+ }
5725
5733
}
5734
+ } catch (const std::ios_base::failure&) {
5735
+ LogPrintf (" [snapshot] bad snapshot format or truncated snapshot after deserializing %d coins\n " ,
5736
+ coins_processed);
5737
+ return false ;
5726
5738
}
5727
5739
}
5728
5740
@@ -5735,7 +5747,8 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
5735
5747
5736
5748
bool out_of_coins{false };
5737
5749
try {
5738
- coins_file >> outpoint;
5750
+ Txid txid;
5751
+ coins_file >> txid;
5739
5752
} catch (const std::ios_base::failure&) {
5740
5753
// We expect an exception since we should be out of coins.
5741
5754
out_of_coins = true ;
0 commit comments