public void DummyFilterMatchesToFalse() { var rnd = new Random(123456); var blockHash = new byte[32]; rnd.NextBytes(blockHash); var filter = IndexBuilderService.CreateDummyEmptyFilter(new uint256(blockHash)); var scriptPubKeys = Enumerable.Range(0, 1000).Select(x => { var buffer = new byte[20]; rnd.NextBytes(buffer); return(buffer); }); var key = blockHash[0..16];
public static FilterModel GetStartingFilter(Network network) { var startingHeader = SmartHeader.GetStartingHeader(network); if (network == Network.Main) { return(FilterModel.FromLine($"{startingHeader.Height}:{startingHeader.BlockHash}:02832810ec08a0:{startingHeader.PrevHash}:{startingHeader.EpochBlockTime}")); } else if (network == Network.TestNet) { return(FilterModel.FromLine($"{startingHeader.Height}:{startingHeader.BlockHash}:00000000000f0d5edcaeba823db17f366be49a80d91d15b77747c2e017b8c20a:{startingHeader.PrevHash}:{startingHeader.EpochBlockTime}")); } else if (network == Network.RegTest) { GolombRiceFilter filter = IndexBuilderService.CreateDummyEmptyFilter(startingHeader.BlockHash); return(FilterModel.FromLine($"{startingHeader.Height}:{startingHeader.BlockHash}:{filter}:{startingHeader.PrevHash}:{startingHeader.EpochBlockTime}")); } else { throw new NotSupportedNetworkException(network); } }
public async Task FilterDownloaderTestAsync() { (_, IRPCClient rpc, _, _, _, BitcoinStore bitcoinStore, _) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1); var httpClientFactory = new HttpClientFactory(torEndPoint: null, backendUriGetter: () => new Uri(RegTestFixture.BackendEndPoint)); var synchronizer = new WasabiSynchronizer(rpc.Network, bitcoinStore, httpClientFactory); try { synchronizer.Start(requestInterval: TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), 1000); var blockCount = await rpc.GetBlockCountAsync() + 1; // Plus one because of the zeroth. // Test initial synchronization. var times = 0; int filterCount; while ((filterCount = bitcoinStore.SmartHeaderChain.HashCount) < blockCount) { if (times > 500) // 30 sec { throw new TimeoutException($"{nameof(WasabiSynchronizer)} test timed out. Needed filters: {blockCount}, got only: {filterCount}."); } await Task.Delay(100); times++; } Assert.Equal(blockCount, bitcoinStore.SmartHeaderChain.HashCount); // Test later synchronization. await RegTestFixture.BackendRegTestNode.GenerateAsync(10); times = 0; while ((filterCount = bitcoinStore.SmartHeaderChain.HashCount) < blockCount + 10) { if (times > 500) // 30 sec { throw new TimeoutException($"{nameof(WasabiSynchronizer)} test timed out. Needed filters: {blockCount + 10}, got only: {filterCount}."); } await Task.Delay(100); times++; } // Test correct number of filters is received. Assert.Equal(blockCount + 10, bitcoinStore.SmartHeaderChain.HashCount); // Test filter block hashes are correct. var filterList = new List <FilterModel>(); await bitcoinStore.IndexStore.ForeachFiltersAsync(async x => { filterList.Add(x); await Task.CompletedTask; }, new Height(0)); FilterModel[] filters = filterList.ToArray(); for (int i = 0; i < 101; i++) { var expectedHash = await rpc.GetBlockHashAsync(i); var filter = filters[i]; Assert.Equal(i, (int)filter.Header.Height); Assert.Equal(expectedHash, filter.Header.BlockHash); Assert.Equal(IndexBuilderService.CreateDummyEmptyFilter(expectedHash).ToString(), filter.Filter.ToString()); } } finally { if (synchronizer is { })
public async Task ReorgTestAsync() { (string password, IRPCClient rpc, Network network, _, _, BitcoinStore bitcoinStore, Backend.Global global) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1); var keyManager = KeyManager.CreateNew(out _, password, network); // Mine some coins, make a few bech32 transactions then make it confirm. await rpc.GenerateAsync(1); var key = keyManager.GenerateNewKey(SmartLabel.Empty, KeyState.Clean, isInternal: false); var tx2 = await rpc.SendToAddressAsync(key.GetP2wpkhAddress(network), Money.Coins(0.1m)); key = keyManager.GenerateNewKey(SmartLabel.Empty, KeyState.Clean, isInternal: false); var tx3 = await rpc.SendToAddressAsync(key.GetP2wpkhAddress(network), Money.Coins(0.1m)); var tx4 = await rpc.SendToAddressAsync(key.GetP2pkhAddress(network), Money.Coins(0.1m)); var tx5 = await rpc.SendToAddressAsync(key.GetP2shOverP2wpkhAddress(network), Money.Coins(0.1m)); var tx1 = await rpc.SendToAddressAsync(key.GetP2wpkhAddress(network), Money.Coins(0.1m), replaceable : true); await rpc.GenerateAsync(2); // Generate two, so we can test for two reorg var node = RegTestFixture.BackendRegTestNode; using HttpClientFactory httpClientFactory = new(torEndPoint : null, backendUriGetter : () => new Uri(RegTestFixture.BackendEndPoint)); WasabiSynchronizer synchronizer = new(bitcoinStore, httpClientFactory); try { synchronizer.Start(requestInterval: TimeSpan.FromSeconds(3), 1000); var reorgAwaiter = new EventsAwaiter <FilterModel>( h => bitcoinStore.IndexStore.Reorged += h, h => bitcoinStore.IndexStore.Reorged -= h, 2); // Test initial synchronization. await WaitForIndexesToSyncAsync(global, TimeSpan.FromSeconds(90), bitcoinStore); var tip = await rpc.GetBestBlockHashAsync(); Assert.Equal(tip, bitcoinStore.SmartHeaderChain.TipHash); var tipBlock = await rpc.GetBlockHeaderAsync(tip); Assert.Equal(tipBlock.HashPrevBlock, bitcoinStore.SmartHeaderChain.GetChain().Select(x => x.header.BlockHash).ToArray()[bitcoinStore.SmartHeaderChain.HashCount - 2]); // Test synchronization after fork. await rpc.InvalidateBlockAsync(tip); // Reorg 1 tip = await rpc.GetBestBlockHashAsync(); await rpc.InvalidateBlockAsync(tip); // Reorg 2 var tx1bumpRes = await rpc.BumpFeeAsync(tx1); // RBF it await rpc.GenerateAsync(5); await WaitForIndexesToSyncAsync(global, TimeSpan.FromSeconds(90), bitcoinStore); var hashes = bitcoinStore.SmartHeaderChain.GetChain().Select(x => x.header.BlockHash).ToArray(); Assert.DoesNotContain(tip, hashes); Assert.DoesNotContain(tipBlock.HashPrevBlock, hashes); tip = await rpc.GetBestBlockHashAsync(); Assert.Equal(tip, bitcoinStore.SmartHeaderChain.TipHash); var filterList = new List <FilterModel>(); await bitcoinStore.IndexStore.ForeachFiltersAsync(async x => { filterList.Add(x); await Task.CompletedTask; }, new Height(0)); var filterTip = filterList.Last(); Assert.Equal(tip, filterTip.Header.BlockHash); // Test filter block hashes are correct after fork. var blockCountIncludingGenesis = await rpc.GetBlockCountAsync() + 1; filterList.Clear(); await bitcoinStore.IndexStore.ForeachFiltersAsync(async x => { filterList.Add(x); await Task.CompletedTask; }, new Height(0)); FilterModel[] filters = filterList.ToArray(); for (int i = 0; i < blockCountIncludingGenesis; i++) { var expectedHash = await rpc.GetBlockHashAsync(i); var filter = filters[i]; Assert.Equal(i, (int)filter.Header.Height); Assert.Equal(expectedHash, filter.Header.BlockHash); if (i < 101) // Later other tests may fill the filter. { Assert.Equal(IndexBuilderService.CreateDummyEmptyFilter(expectedHash).ToString(), filter.Filter.ToString()); } } // Test the serialization, too. tip = await rpc.GetBestBlockHashAsync(); var blockHash = tip; for (var i = 0; i < hashes.Length; i++) { var block = await rpc.GetBlockHeaderAsync(blockHash); Assert.Equal(blockHash, hashes[hashes.Length - i - 1]); blockHash = block.HashPrevBlock; } // Assert reorg happened exactly as many times as we reorged. await reorgAwaiter.WaitAsync(TimeSpan.FromSeconds(10)); } finally { await synchronizer.StopAsync(); } }