diff --git a/src/Blockcore/Consensus/Chain/ChainRepository.cs b/src/Blockcore/Consensus/Chain/ChainRepository.cs index 8b0b43dd2..8e8ad60df 100644 --- a/src/Blockcore/Consensus/Chain/ChainRepository.cs +++ b/src/Blockcore/Consensus/Chain/ChainRepository.cs @@ -62,17 +62,17 @@ public Task LoadAsync(ChainedHeader genesisHeader) Guard.Assert(data.Hash == genesisHeader.HashBlock); // can't swap networks - int index = 0; - while (true) - { - data = this.chainStore.GetChainData((index)); + var list = this.chainStore.GetChainData(); - if (data == null) - break; + foreach (var chainedData in list) + { + // Create a new ChainedHeader with reference to previous. This will build a large object graph of all headers. + tip = new ChainedHeader(chainedData.Hash, chainedData.Work, tip); - tip = new ChainedHeader(data.Hash, data.Work, tip); - if (tip.Height == 0) tip.SetChainStore(this.chainStore); - index++; + if (tip.Height == 0) + { + tip.SetChainStore(this.chainStore); + } } if (tip == null) diff --git a/src/Blockcore/Consensus/Chain/ChainStore.cs b/src/Blockcore/Consensus/Chain/ChainStore.cs index 7b6a1dbac..8ae988e7e 100644 --- a/src/Blockcore/Consensus/Chain/ChainStore.cs +++ b/src/Blockcore/Consensus/Chain/ChainStore.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using Blockcore.Consensus.BlockInfo; using NBitcoin; @@ -12,6 +13,8 @@ public interface IChainStore bool PutHeader(BlockHeader blockHeader); + IEnumerable GetChainData(); + ChainData GetChainData(int height); void PutChainData(IEnumerable items); @@ -78,6 +81,12 @@ public bool PutHeader(BlockHeader blockHeader) return this.headers.TryAdd(blockHeader.GetHash(), blockHeader); } + public IEnumerable GetChainData() + { + // Order by height and return new array with ChainData. + return this.chainData.OrderBy(c => c.Key).Select(c => c.Value); + } + public ChainData GetChainData(int height) { if (!this.chainData.TryGetValue(height, out ChainData data)) diff --git a/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbChainStore.cs b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbChainStore.cs index 19d1070a2..18d71b24d 100644 --- a/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbChainStore.cs +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbChainStore.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Blockcore.Configuration; using Blockcore.Consensus; using Blockcore.Consensus.BlockInfo; @@ -99,6 +100,34 @@ public bool PutHeader(BlockHeader blockHeader) return true; } + public IEnumerable GetChainData() + { + Dictionary list = new Dictionary(); + + lock (this.locker) + { + using (var iterator = this.leveldb.CreateIterator()) + { + iterator.SeekToFirst(); + + while (iterator.IsValid() && iterator.Key()[0] == ChainTableName) + { + var height = BitConverter.ToInt32(iterator.Key().AsSpan(1)); + byte[] bytes = iterator.Value(); + + var data = new ChainData(); + data.FromBytes(bytes, this.network.Consensus.ConsensusFactory); + list.Add(height, data); + + iterator.Next(); + } + } + } + + // Order by height and return new array with ChainData. + return list.OrderBy(c => c.Key).Select(c => c.Value); + } + public ChainData GetChainData(int height) { byte[] bytes = null; diff --git a/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbChainStore.cs b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbChainStore.cs index 0593a5bf5..fcda5352b 100644 --- a/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbChainStore.cs +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbChainStore.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Blockcore.Configuration; using Blockcore.Consensus; using Blockcore.Consensus.BlockInfo; @@ -105,6 +106,34 @@ public bool PutHeader(BlockHeader blockHeader) return true; } + public IEnumerable GetChainData() + { + Dictionary list = new Dictionary(); + + lock (this.locker) + { + using (var iterator = this.rocksdb.NewIterator()) + { + iterator.SeekToFirst(); + + while (iterator.Valid() && iterator.Key()[0] == ChainTableName) + { + var height = BitConverter.ToInt32(iterator.Key().AsSpan(1)); + byte[] bytes = iterator.Value(); + + var data = new ChainData(); + data.FromBytes(bytes, this.network.Consensus.ConsensusFactory); + list.Add(height, data); + + iterator.Next(); + } + } + } + + // Order by height and return new array with ChainData. + return list.OrderBy(c => c.Key).Select(c => c.Value); + } + public ChainData GetChainData(int height) { byte[] bytes = null;