protected override async Task <ISet <TransactionWatch <TContext> > > ExecuteWatchesAsync( IEnumerable <TransactionWatch <TContext> > watches, Block block, int height, BlockEventType eventType, CancellationToken cancellationToken) { var confirmationType = GetConfirmationType(eventType); var completed = new HashSet <TransactionWatch <TContext> >(); foreach (var watch in watches) { var confirmation = await GetConfirmationAsync(watch, height, CancellationToken.None); var success = await this.handler.ConfirmationUpdateAsync( watch, confirmation, confirmationType, CancellationToken.None ); if (success && !completed.Add(watch)) { throw new ArgumentException("The collection contains duplicated items.", nameof(watches)); } } return(completed); }
protected override Task <ISet <Watch <object> > > ExecuteWatchesAsync( IEnumerable <Watch <object> > watches, Block block, int height, BlockEventType eventType, CancellationToken cancellationToken) { return(StubbedExecuteWatchesAsync.Object(watches, block, height, eventType, cancellationToken)); }
public async Task ExecuteAsync( Block block, int height, BlockEventType eventType, CancellationToken cancellationToken) { IEnumerable <TWatch> watches; if (block == null) { throw new ArgumentNullException(nameof(block)); } if (height < 0) { throw new ArgumentOutOfRangeException(nameof(height), height, "The value is not valid height."); } // First, inspect block and create new watches. if (eventType == BlockEventType.Added) { watches = await CreateWatchesAsync(block, height, cancellationToken); if (watches.Any()) { await this.handler.AddWatchesAsync(watches, cancellationToken); } } // Load watches that match with the block and execute it. watches = await GetWatchesAsync(block, height, cancellationToken); if (!watches.Any()) { return; } var completed = await ExecuteWatchesAsync(watches, block, height, eventType, cancellationToken); // First, remove completed watches. if (completed.Any()) { await this.handler.RemoveCompletedWatchesAsync(completed, CancellationToken.None); } // Then remove watches that belong to the block is being removing. if (eventType == BlockEventType.Removing) { await this.handler.RemoveUncompletedWatchesAsync(block.GetHash(), CancellationToken.None); } }
protected override async Task <ISet <BalanceWatch <TContext, TAmount> > > ExecuteWatchesAsync( IEnumerable <BalanceWatch <TContext, TAmount> > watches, Block block, int height, BlockEventType eventType, CancellationToken cancellationToken) { var confirmationType = GetConfirmationType(eventType); var completed = new HashSet <BalanceWatch <TContext, TAmount> >(); foreach (var group in watches.GroupBy(w => w.Address)) { // Get confirmation number for each change. var changes = new Collection <ConfirmedBalanceChange <TContext, TAmount> >(); foreach (var watch in group) // lgtm[cs/linq/missed-select] { var change = new ConfirmedBalanceChange <TContext, TAmount>( watch.Context, watch.BalanceChange, await GetConfirmationAsync(watch, height, CancellationToken.None) ); changes.Add(change); } // Invoke handler. var confirm = new BalanceConfirmation <TContext, TAmount>(group.Key, changes); var confirmationCount = changes.Min(c => c.Confirmation); var success = await this.handler.ConfirmationUpdateAsync( confirm, confirmationCount, confirmationType, CancellationToken.None ); if (success) { foreach (var watch in group) { if (!completed.Add(watch)) { throw new ArgumentException("The collection contains duplicated items.", nameof(watches)); } } } } return(completed); }
public Task ExecuteAsync_GetWatchesAsyncReturnEmptyList_ShouldDoNothing(BlockEventType eventType) { return(AsynchronousTesting.WithCancellationTokenAsync(async cancellationToken => { // Arrange. this.subject.StubbedGetWatchesAsync.Setup(f => f(TestBlock.Regtest0, 0, cancellationToken)) .Returns(Task.FromResult(Enumerable.Empty <Watch <object> >())); // Act. await this.subject.ExecuteAsync(TestBlock.Regtest0, 0, eventType, cancellationToken); // Assert. this.subject.StubbedGetWatchesAsync.Verify( f => f( TestBlock.Regtest0, 0, cancellationToken ), Times.Once() ); this.subject.StubbedExecuteWatchesAsync.Verify( f => f( It.IsAny <IEnumerable <Watch <object> > >(), It.IsAny <Block>(), It.IsAny <int>(), It.IsAny <BlockEventType>(), It.IsAny <CancellationToken>() ), Times.Never() ); this.handler.Verify( h => h.RemoveCompletedWatchesAsync( It.IsAny <IEnumerable <Watch <object> > >(), It.IsAny <CancellationToken>() ), Times.Never() ); this.handler.Verify( h => h.RemoveUncompletedWatchesAsync( It.IsAny <uint256>(), It.IsAny <CancellationToken>() ), Times.Never() ); })); }
protected static ConfirmationType GetConfirmationType(BlockEventType eventType) { switch (eventType) { case BlockEventType.Added: return(ConfirmationType.Confirmed); case BlockEventType.Removing: return(ConfirmationType.Unconfirming); default: throw new ArgumentOutOfRangeException( nameof(eventType), eventType, "The value is not a valid event type." ); } }
public static BlockEvent Parse(Level parent, BlockEventType type, string value) { var match = Parser.Match(value); if (!match.Success) { throw new FormatException(Localization.UnrecognizedEvent); } var result = new BlockEvent(parent) { Type = type, id = new IDReference(match.Groups[1].Value.Trim()) }; if (match.Groups[3].Success) { result.Payload = ushort.Parse(match.Groups[3].Value.Trim(), CultureInfo.InvariantCulture); } return(result); }
public Task ExecuteAsync_GetCurrentWatchesAsyncReturnNonEmptyList_ShouldInvokeConfirmationUpdateAsync(BlockEventType eventType) { return(AsynchronousTesting.WithCancellationTokenAsync(async cancellationToken => { // Arrange. var confirmationType = FakeConfirmationWatcher.GetConfirmationType(eventType); var block0 = TestBlock.Regtest0; var block1 = TestBlock.Regtest1; var ctx1 = new object(); var ctx2 = new object(); var ctx3 = new object(); var watch1 = new BalanceWatch <object, int>(ctx1, block0.GetHash(), block0.Transactions[0].GetHash(), TestAddress.Regtest1, 10); var watch2 = new BalanceWatch <object, int>(ctx2, block1.GetHash(), block1.Transactions[0].GetHash(), TestAddress.Regtest1, -10); var watch3 = new BalanceWatch <object, int>(ctx3, block1.GetHash(), block1.Transactions[0].GetHash(), TestAddress.Regtest2, 5); var watches = new[] { watch1, watch2, watch3 }; this.handler.Setup(h => h.GetBalanceChangesAsync(It.IsAny <Transaction>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new Dictionary <BitcoinAddress, BalanceChange <object, int> >()); this.handler.Setup(h => h.GetCurrentWatchesAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(watches); this.handler.Setup(h => h.ConfirmationUpdateAsync(It.Is <BalanceConfirmation <object, int> >(c => c.Address == TestAddress.Regtest1), 1, confirmationType, It.IsAny <CancellationToken>())) .ReturnsAsync(true); this.blocks.Setup(b => b.GetAsync(block0.GetHash(), It.IsAny <CancellationToken>())) .ReturnsAsync((block0, 0)); this.blocks.Setup(b => b.GetAsync(block1.GetHash(), It.IsAny <CancellationToken>())) .ReturnsAsync((block1, 1)); // Act. await this.subject.ExecuteAsync(block1, 1, eventType, cancellationToken); // Assert. this.handler.Verify( h => h.GetCurrentWatchesAsync(cancellationToken), Times.Once() ); this.handler.Verify( h => h.ConfirmationUpdateAsync( It.Is <BalanceConfirmation <object, int> >( c => c.Address == TestAddress.Regtest1 && c.Changes.Count() == 2 && c.Changes.Count(bc => bc.Amount == 10 && bc.Confirmation == 2 && bc.Context == ctx1) == 1 && c.Changes.Count(bc => bc.Amount == -10 && bc.Confirmation == 1 && bc.Context == ctx2) == 1 ), 1, confirmationType, CancellationToken.None ), Times.Once() ); this.handler.Verify( h => h.ConfirmationUpdateAsync( It.Is <BalanceConfirmation <object, int> >( c => c.Address == TestAddress.Regtest2 && c.Changes.Count() == 1 && c.Changes.Count(bc => bc.Amount == 5 && bc.Confirmation == 1 && bc.Context == ctx3) == 1 ), 1, confirmationType, CancellationToken.None ), Times.Once() ); this.handler.Verify( h => h.RemoveCompletedWatchesAsync( It.Is <IEnumerable <BalanceWatch <object, int> > >( l => l.Count() == 2 && l.Contains(watch1) && l.Contains(watch2) ), CancellationToken.None ), Times.Once() ); })); }
public BlockEvent(BlockAlias alias, BlockEventType type) { _value = alias.Value | (((uint)type) << Shift); }
protected abstract Task <ISet <TWatch> > ExecuteWatchesAsync( IEnumerable <TWatch> watches, Block block, int height, BlockEventType eventType, CancellationToken cancellationToken);
public void GetConfirmationType_WithValidBlockEventType_ShouldSuccess(BlockEventType eventType, ConfirmationType expected) { var result = FakeConfirmationWatcher.GetConfirmationType(eventType); Assert.Equal(expected, result); }
public static new ConfirmationType GetConfirmationType(BlockEventType eventType) { return(ConfirmationWatcher <object, Watch <object>, object> .GetConfirmationType(eventType)); }
public Task ExecuteAsync_ConfirmationUpdateAsyncReturnTrue_ShouldRemoveThatWatch(BlockEventType eventType) { return(AsynchronousTesting.WithCancellationTokenAsync(async cancellationToken => { // Arrange. var watch1 = new TransactionWatch <object>(null, TestBlock.Regtest0.GetHash(), uint256.One); var watch2 = new TransactionWatch <object>(null, TestBlock.Regtest1.GetHash(), uint256.One); var watches = new[] { watch1, watch2 }; var confirmationType = FakeConfirmationWatcher.GetConfirmationType(eventType); this.handler.Setup(h => h.GetCurrentWatchesAsync(It.IsAny <CancellationToken>())) .Returns(Task.FromResult <IEnumerable <TransactionWatch <object> > >(watches)); this.handler.Setup(h => h.ConfirmationUpdateAsync(watch1, 2, confirmationType, It.IsAny <CancellationToken>())) .Returns(Task.FromResult(false)); this.handler.Setup(h => h.ConfirmationUpdateAsync(watch2, 1, confirmationType, It.IsAny <CancellationToken>())) .Returns(Task.FromResult(true)); this.blocks.Setup(b => b.GetAsync(TestBlock.Regtest0.GetHash(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult((TestBlock.Regtest0, 0))); this.blocks.Setup(b => b.GetAsync(TestBlock.Regtest1.GetHash(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult((TestBlock.Regtest1, 1))); // Act. await this.subject.ExecuteAsync(TestBlock.Regtest1, 1, eventType, cancellationToken); // Assert. this.handler.Verify( h => h.ConfirmationUpdateAsync( watch1, 2, confirmationType, CancellationToken.None ), Times.Once() ); this.handler.Verify( h => h.ConfirmationUpdateAsync( watch2, 1, confirmationType, CancellationToken.None ), Times.Once() ); this.handler.Verify( h => h.RemoveCompletedWatchesAsync( new[] { watch2 }, CancellationToken.None ), Times.Once() ); })); }