Ensure Filter Height integrity
MODIFY
WalletWasabi/Services/WasabiSynchronizer.cs
WalletWasabi/Services/WasabiSynchronizer.cs
@@ -175,6 +175,7 @@ namespace WalletWasabi.Services
{
DateTimeOffset lastFeeQueried = DateTimeOffset.UtcNow - feeQueryRequestInterval;
bool ignoreRequestInterval = false;
+ var hashChain = BitcoinStore.HashChain;
EnableRequests();
while (IsRunning)
{
@@ -200,7 +201,7 @@ namespace WalletWasabi.Services
return;
}
- response = await WasabiClient.GetSynchronizeAsync(BitcoinStore.HashChain.TipHash, maxFiltersToSyncAtInitialization, estimateMode, Cancel.Token).WithAwaitCancellationAsync(Cancel.Token, 300);
+ response = await WasabiClient.GetSynchronizeAsync(hashChain.TipHash, maxFiltersToSyncAtInitialization, estimateMode, Cancel.Token).WithAwaitCancellationAsync(Cancel.Token, 300);
// NOT GenSocksServErr
BackendStatus = BackendStatus.Connected;
TorStatus = TorStatus.Running;
@@ -243,7 +244,7 @@ namespace WalletWasabi.Services
ignoreRequestInterval = false;
}
- BitcoinStore.HashChain.UpdateServerTipHeight(response.BestHeight);
+ hashChain.UpdateServerTipHeight(response.BestHeight);
ExchangeRate exchangeRate = response.ExchangeRates.FirstOrDefault();
if (exchangeRate != default && exchangeRate.Rate != 0)
{
@@ -254,6 +255,24 @@ namespace WalletWasabi.Services
{
var filters = response.Filters;
+ var firstFilter = filters.First();
+ if (hashChain.TipHeight + 1 != firstFilter.BlockHeight)
+ {
+ // We have a problem.
+ // We have wrong filters, the heights are not in sync with the server's.
+ Logger.LogError<WasabiSynchronizer>($"Inconsistent index state detected.{Environment.NewLine}" +
+ $"{nameof(hashChain)}.{nameof(hashChain.TipHeight)}:{hashChain.TipHeight}{Environment.NewLine}" +
+ $"{nameof(hashChain)}.{nameof(hashChain.HashesLeft)}:{hashChain.HashesLeft}{Environment.NewLine}" +
+ $"{nameof(hashChain)}.{nameof(hashChain.TipHash)}:{hashChain.TipHash}{Environment.NewLine}" +
+ $"{nameof(hashChain)}.{nameof(hashChain.HashCount)}:{hashChain.HashCount}{Environment.NewLine}" +
+ $"{nameof(hashChain)}.{nameof(hashChain.ServerTipHeight)}:{hashChain.ServerTipHeight}{Environment.NewLine}" +
+ $"{nameof(firstFilter)}.{nameof(firstFilter.BlockHash)}:{firstFilter.BlockHash}{Environment.NewLine}" +
+ $"{nameof(firstFilter)}.{nameof(firstFilter.BlockHeight)}:{firstFilter.BlockHeight}");
+
+ await BitcoinStore.IndexStore.RemoveAllImmmatureFiltersAsync(Cancel.Token, deleteAndCrashIfMature: true);
+ }
+ else
+ {
await BitcoinStore.IndexStore.AddNewFiltersAsync(filters, Cancel.Token);
if (filters.Count() == 1)
@@ -265,6 +284,7 @@ namespace WalletWasabi.Services
Logger.LogInfo<WasabiSynchronizer>($"Downloaded filters for blocks from {filters.First().BlockHeight} to {filters.Last().BlockHeight}.");
}
}
+ }
else if (response.FiltersResponseState == FiltersResponseState.BestKnownHashNotFound)
{
// Reorg happened
@@ -277,6 +297,12 @@ namespace WalletWasabi.Services
else if (response.FiltersResponseState == FiltersResponseState.NoNewFilter)
{
// We are synced.
+ // Assert index state.
+ if (response.BestHeight > hashChain.TipHeight) // If the server's tip height is larger then ours, we're missing a filter, our index got corrupted.
+ {
+ await BitcoinStore.IndexStore.RemoveAllImmmatureFiltersAsync(Cancel.Token, deleteAndCrashIfMature: true);
+ // If still bad delete filters and crash the software?
+ }
}
LastResponse = response;

MODIFY
WalletWasabi/Stores/IndexStore.cs
WalletWasabi/Stores/IndexStore.cs
@@ -230,6 +230,43 @@ namespace WalletWasabi.Stores
return filter;
}
+ public async Task<IEnumerable<FilterModel>> RemoveAllImmmatureFiltersAsync(CancellationToken cancel, bool deleteAndCrashIfMature = false)
+ {
+ var removed = new List<FilterModel>();
+ using (await IndexLock.LockAsync(cancel))
+ {
+ if (ImmatureFilters.Any())
+ {
+ Logger.LogWarning<IndexStore>($"Filters got corrupted. Reorging {ImmatureFilters.Count} immature filters in an attempt to fix them.");
+ }
+ else
+ {
+ Logger.LogCritical<IndexStore>($"Filters got corrupted and have no more immature filters.");
+
+ if (deleteAndCrashIfMature)
+ {
+ Logger.LogCritical<IndexStore>($"Deleting all filters and crashing the software...");
+
+ using (await MatureIndexFileManager.Mutex.LockAsync(cancel))
+ using (await ImmatureIndexFileManager.Mutex.LockAsync(cancel))
+ {
+ ImmatureIndexFileManager.DeleteMe();
+ MatureIndexFileManager.DeleteMe();
+ }
+
+ Environment.Exit(2);
+ }
+ }
+ }
+
+ while (ImmatureFilters.Any())
+ {
+ removed.Add(await RemoveLastFilterAsync(cancel));
+ }
+
+ return removed;
+ }
+
private int _throttleId;
/// <summary>

Ensure Filter Height integrity