Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Commit

Permalink
Hotfix/store pending storage bug (#46)
Browse files Browse the repository at this point in the history
First item in batch was not removed from pending store items
  • Loading branch information
dangershony authored Mar 9, 2017
1 parent 2140095 commit 6d4f19f
Showing 1 changed file with 65 additions and 62 deletions.
127 changes: 65 additions & 62 deletions Stratis.Bitcoin/BlockStore/BlockStoreLoop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,72 +95,75 @@ public Task Flush()

public void Loop(CancellationToken cancellationToken)
{
// A loop that writes pending blocks to store
// or downloads missing blocks then writing to store
AsyncLoop.Run("BlockStoreLoop.DownloadBlocks", async token =>
// A loop that writes pending blocks to store
// or downloads missing blocks then writing to store
AsyncLoop.Run("BlockStoreLoop.DownloadBlocks", async token =>
{
await DownloadAndStoreBlocks(cancellationToken);
},
cancellationToken,
repeateEvery: TimeSpans.Second,
startAfter: TimeSpans.FiveSeconds);
}
},
cancellationToken,
repeateEvery: TimeSpans.Second,
startAfter: TimeSpans.FiveSeconds);
}

public async Task DownloadAndStoreBlocks(CancellationToken token, bool disposemode = false)
{
while (!token.IsCancellationRequested)
{
if (StoredBlock.Height >= this.ChainState.HighestValidatedPoW?.Height)
break;
public async Task DownloadAndStoreBlocks(CancellationToken token, bool disposemode = false)
{
while (!token.IsCancellationRequested)
{
if (StoredBlock.Height >= this.ChainState.HighestValidatedPoW?.Height)
break;

// find next block to download
var next = this.chain.GetBlock(StoredBlock.Height + 1);
if (next == null)
break; //no blocks to store
if (next == null)
break; //no blocks to store

// reorg logic
if (this.StoredBlock.HashBlock != next.Header.HashPrevBlock)
{
if (this.StoredBlock.HashBlock != next.Header.HashPrevBlock)
{
if(disposemode)
break;

var blockstoremove = new List<uint256>();
var remove = this.StoredBlock;
var remove = this.StoredBlock;
// reorg - we need to delete blocks, start walking back the chain
while (this.chain.GetBlock(remove.HashBlock) == null)
{
blockstoremove.Add(remove.HashBlock);
remove = remove.Previous;
}
while (this.chain.GetBlock(remove.HashBlock) == null)
{
blockstoremove.Add(remove.HashBlock);
remove = remove.Previous;
}

await this.BlockRepository.DeleteAsync(remove.HashBlock, blockstoremove);
this.StoredBlock = remove;
this.ChainState.HighestPersistedBlock = this.StoredBlock;
break;
}

if (await this.BlockRepository.ExistAsync(next.HashBlock))
{
// next block is in storage update StoredBlock
await this.BlockRepository.SetBlockHash(next.HashBlock);
this.StoredBlock = next;
this.ChainState.HighestPersistedBlock = this.StoredBlock;
continue;
}

// check if the next block is in pending storage
BlockPair insert;
if (this.PendingStorage.TryGetValue(next.HashBlock, out insert))
{
}

if (await this.BlockRepository.ExistAsync(next.HashBlock))
{
// next block is in storage update StoredBlock
await this.BlockRepository.SetBlockHash(next.HashBlock);
this.StoredBlock = next;
this.ChainState.HighestPersistedBlock = this.StoredBlock;
continue;
}

// check if the next block is in pending storage
BlockPair insert;
if (this.PendingStorage.TryGetValue(next.HashBlock, out insert))
{
// if in IBD and batch will not be full then wait for more blocks
if (this.ChainState.IsInitialBlockDownload && !disposemode)
if (this.PendingStorage.Skip(0).Count() < batchsize) // ConcurrentDictionary perf
break;

if (!this.PendingStorage.TryRemove(next.HashBlock, out insert))
break;

var tostore = new List<BlockPair>(new[] { insert });
var storebest = next;
foreach (var index in Enumerable.Range(1, batchsize - 1))
{
{
var old = next;
next = this.chain.GetBlock(next.Height + 1);

Expand All @@ -183,38 +186,38 @@ public async Task DownloadAndStoreBlocks(CancellationToken token, bool disposemo
await Task.Delay(pushIntervalIBD, token);

continue;
}
}

if(disposemode)
break;

// block is not in store and not in pending
// download the block or blocks
// find a batch of blocks to download
var todownload = new List<ChainedBlock>(new[] {next});
var downloadbest = next;
foreach (var index in Enumerable.Range(1, batchsize - 1))
{
var old = next;
next = this.chain.GetBlock(old.Height + 1);

// stop if at the tip or block is already in store or pending insertion
if (next == null) break;
// block is not in store and not in pending
// download the block or blocks
// find a batch of blocks to download
var todownload = new List<ChainedBlock>(new[] {next});
var downloadbest = next;
foreach (var index in Enumerable.Range(1, batchsize - 1))
{
var old = next;
next = this.chain.GetBlock(old.Height + 1);

// stop if at the tip or block is already in store or pending insertion
if (next == null) break;
if (next.Header.HashPrevBlock != old.HashBlock) break;
if (next.Height > this.ChainState.HighestValidatedPoW?.Height) break;
if (this.PendingStorage.ContainsKey(next.HashBlock)) break;
if (await this.BlockRepository.ExistAsync(next.HashBlock)) break;

todownload.Add(next);
todownload.Add(next);
downloadbest = next;
}

// download and store missing blocks
var blocks = await this.blockPuller.AskBlocks(token, todownload.ToArray());
await this.BlockRepository.PutAsync(downloadbest.HashBlock, blocks);
this.StoredBlock = downloadbest;
this.ChainState.HighestPersistedBlock = this.StoredBlock;
}
}

// download and store missing blocks
var blocks = await this.blockPuller.AskBlocks(token, todownload.ToArray());
await this.BlockRepository.PutAsync(downloadbest.HashBlock, blocks);
this.StoredBlock = downloadbest;
this.ChainState.HighestPersistedBlock = this.StoredBlock;
}
}
}
}

0 comments on commit 6d4f19f

Please sign in to comment.