From ec92bbe33019fc83c77f70b9fe8c7611d2aca2a1 Mon Sep 17 00:00:00 2001 From: Francois de la Rouviere Date: Tue, 27 Apr 2021 15:08:33 +0100 Subject: [PATCH] Create WalletProcessedTransactionOfInterestClientEvent (#535) --- .../DaemonConfiguration.cs | 43 +++++++++++++++++++ ...ocessedTransactionOfInterestClientEvent.cs | 19 ++++++++ ...lletProcessedTransactionOfInterestEvent.cs | 18 ++++++++ .../WalletSyncManager.cs | 6 +-- src/Stratis.CirrusD/Program.cs | 19 +------- .../SQLiteWalletRepository.cs | 20 ++++++++- src/Stratis.StraxD/Program.cs | 22 +--------- 7 files changed, 102 insertions(+), 45 deletions(-) create mode 100644 src/Stratis.Bitcoin.Features.SignalR/DaemonConfiguration.cs create mode 100644 src/Stratis.Bitcoin.Features.SignalR/Events/WalletProcessedTransactionOfInterestClientEvent.cs create mode 100644 src/Stratis.Bitcoin.Features.Wallet/Events/WalletProcessedTransactionOfInterestEvent.cs diff --git a/src/Stratis.Bitcoin.Features.SignalR/DaemonConfiguration.cs b/src/Stratis.Bitcoin.Features.SignalR/DaemonConfiguration.cs new file mode 100644 index 0000000000..e569d2647d --- /dev/null +++ b/src/Stratis.Bitcoin.Features.SignalR/DaemonConfiguration.cs @@ -0,0 +1,43 @@ +using Stratis.Bitcoin.Features.SignalR.Broadcasters; +using Stratis.Bitcoin.Features.SignalR.Events; + +namespace Stratis.Bitcoin.Features.SignalR +{ + public static class DaemonConfiguration + { + private static readonly IClientEvent[] EventsToHandle = new IClientEvent[] + { + new BlockConnectedClientEvent(), + new ReconstructFederationClientEvent(), + new FullNodeClientEvent(), + new TransactionReceivedClientEvent(), + new WalletProcessedTransactionOfInterestClientEvent() + }; + + private static ClientEventBroadcasterSettings Settings = new ClientEventBroadcasterSettings + { + BroadcastFrequencySeconds = 5 + }; + + public static void ConfigureSignalRForCirrus(SignalROptions options) + { + options.EventsToHandle = EventsToHandle; + + options.ClientEventBroadcasters = new[] + { + (Broadcaster: typeof(CirrusWalletInfoBroadcaster), ClientEventBroadcasterSettings: Settings) + }; + } + + public static void ConfigureSignalRForStrax(SignalROptions options) + { + options.EventsToHandle = EventsToHandle; + + options.ClientEventBroadcasters = new[] + { + (Broadcaster: typeof(StakingBroadcaster), ClientEventBroadcasterSettings: Settings), + (Broadcaster: typeof(WalletInfoBroadcaster), ClientEventBroadcasterSettings:Settings) + }; + } + } +} diff --git a/src/Stratis.Bitcoin.Features.SignalR/Events/WalletProcessedTransactionOfInterestClientEvent.cs b/src/Stratis.Bitcoin.Features.SignalR/Events/WalletProcessedTransactionOfInterestClientEvent.cs new file mode 100644 index 0000000000..1973a380de --- /dev/null +++ b/src/Stratis.Bitcoin.Features.SignalR/Events/WalletProcessedTransactionOfInterestClientEvent.cs @@ -0,0 +1,19 @@ +using System; +using Stratis.Bitcoin.EventBus; +using Stratis.Bitcoin.Features.Wallet.Events; + +namespace Stratis.Bitcoin.Features.SignalR.Events +{ + public sealed class WalletProcessedTransactionOfInterestClientEvent : IClientEvent + { + public Type NodeEventType { get; } = typeof(WalletProcessedTransactionOfInterestEvent); + + public void BuildFrom(EventBase @event) + { + if (@event is WalletProcessedTransactionOfInterestEvent progressEvent) + return; + + throw new ArgumentException(); + } + } +} diff --git a/src/Stratis.Bitcoin.Features.Wallet/Events/WalletProcessedTransactionOfInterestEvent.cs b/src/Stratis.Bitcoin.Features.Wallet/Events/WalletProcessedTransactionOfInterestEvent.cs new file mode 100644 index 0000000000..c9077917f5 --- /dev/null +++ b/src/Stratis.Bitcoin.Features.Wallet/Events/WalletProcessedTransactionOfInterestEvent.cs @@ -0,0 +1,18 @@ +using Stratis.Bitcoin.EventBus; + +namespace Stratis.Bitcoin.Features.Wallet.Events +{ + /// + /// This event is raised when a transaction that relates to an address in the wallet has been received. + /// + /// This can happen either via the mempool or when a block is connected (syncing). + /// + /// + /// This ensures that the client UI calls back to the node via the API + /// to update it's balance. + /// + /// + public sealed class WalletProcessedTransactionOfInterestEvent : EventBase + { + } +} diff --git a/src/Stratis.Bitcoin.Features.Wallet/WalletSyncManager.cs b/src/Stratis.Bitcoin.Features.Wallet/WalletSyncManager.cs index e0c2e948a8..37a357e3b8 100644 --- a/src/Stratis.Bitcoin.Features.Wallet/WalletSyncManager.cs +++ b/src/Stratis.Bitcoin.Features.Wallet/WalletSyncManager.cs @@ -87,7 +87,7 @@ public void Start() this.logger.LogInformation("WalletSyncManager starting synchronisation loop."); // Start sync job for wallets - this.walletSynchronisationLoop = this.asyncProvider.CreateAndRunAsyncLoop("WalletSyncManager.OrchestrateWalletSync", + this.walletSynchronisationLoop = this.asyncProvider.CreateAndRunAsyncLoop(nameof(WalletSyncManager.OrchestrateWalletSync), token => { this.OrchestrateWalletSync(); @@ -110,8 +110,7 @@ private void OnTransactionAdded(TransactionAddedToMemoryPool transactionAddedToM private void OnTransactionRemoved(TransactionRemovedFromMemoryPool transactionRemovedFromMempool) { - this.logger.LogDebug("Transaction '{0}' was removed from the mempool. RemovedForBlock={1}", - transactionRemovedFromMempool.RemovedTransaction.GetHash(), transactionRemovedFromMempool.RemovedForBlock); + this.logger.LogDebug("Transaction '{0}' was removed from the mempool. RemovedForBlock={1}", transactionRemovedFromMempool.RemovedTransaction.GetHash(), transactionRemovedFromMempool.RemovedForBlock); // If the transaction was removed from the mempool because it's part of a block, we don't want to remove it. // It makes more sense to keep the current entry in the database and update it with the confirmation details @@ -169,7 +168,6 @@ public virtual void SyncFromDate(DateTime date, string walletName = null) } } - /// public virtual void SyncFromHeight(int height, string walletName = null) { diff --git a/src/Stratis.CirrusD/Program.cs b/src/Stratis.CirrusD/Program.cs index 3050c91661..f37beb0e4b 100644 --- a/src/Stratis.CirrusD/Program.cs +++ b/src/Stratis.CirrusD/Program.cs @@ -10,8 +10,6 @@ using Stratis.Bitcoin.Features.MemoryPool; using Stratis.Bitcoin.Features.RPC; using Stratis.Bitcoin.Features.SignalR; -using Stratis.Bitcoin.Features.SignalR.Broadcasters; -using Stratis.Bitcoin.Features.SignalR.Events; using Stratis.Bitcoin.Features.SmartContracts; using Stratis.Bitcoin.Features.SmartContracts.PoA; using Stratis.Bitcoin.Features.SmartContracts.Wallet; @@ -82,22 +80,7 @@ private static IFullNode GetSideChainFullNode(NodeSettings nodeSettings) .AddRPC() .AddSignalR(options => { - options.EventsToHandle = new[] - { - (IClientEvent) new BlockConnectedClientEvent(), - new FullNodeClientEvent(), - new ReconstructFederationClientEvent(), - new TransactionReceivedClientEvent(), - }; - - options.ClientEventBroadcasters = new[] - { - (Broadcaster: typeof(CirrusWalletInfoBroadcaster), - ClientEventBroadcasterSettings: new ClientEventBroadcasterSettings - { - BroadcastFrequencySeconds = 5 - }) - }; + DaemonConfiguration.ConfigureSignalRForCirrus(options); }) .UseDiagnosticFeature(); diff --git a/src/Stratis.Features.SQLiteWalletRepository/SQLiteWalletRepository.cs b/src/Stratis.Features.SQLiteWalletRepository/SQLiteWalletRepository.cs index 6bc3f3971e..2fdb488336 100644 --- a/src/Stratis.Features.SQLiteWalletRepository/SQLiteWalletRepository.cs +++ b/src/Stratis.Features.SQLiteWalletRepository/SQLiteWalletRepository.cs @@ -11,8 +11,10 @@ using NBitcoin.DataEncoders; using Stratis.Bitcoin.Configuration; using Stratis.Bitcoin.Features.Wallet; +using Stratis.Bitcoin.Features.Wallet.Events; using Stratis.Bitcoin.Features.Wallet.Interfaces; using Stratis.Bitcoin.Interfaces; +using Stratis.Bitcoin.Signals; using Stratis.Bitcoin.Utilities; using Stratis.Features.SQLiteWalletRepository.External; using Stratis.Features.SQLiteWalletRepository.Tables; @@ -60,6 +62,7 @@ internal string DBPath private readonly IDateTimeProvider dateTimeProvider; private ProcessBlocksInfo processBlocksInfo; private object lockObj; + private readonly ISignals signals; internal const int MaxBatchDurationSeconds = 10; internal const int MaxDataRowsProcessed = 10000; @@ -68,7 +71,7 @@ internal string DBPath public Func Bech32AddressFunc { get; set; } = null; - public SQLiteWalletRepository(ILoggerFactory loggerFactory, DataFolder dataFolder, Network network, IDateTimeProvider dateTimeProvider, IScriptAddressReader scriptAddressReader) + public SQLiteWalletRepository(ILoggerFactory loggerFactory, DataFolder dataFolder, Network network, IDateTimeProvider dateTimeProvider, IScriptAddressReader scriptAddressReader, ISignals signals = null) { this.TestMode = false; this.Network = network; @@ -78,6 +81,7 @@ public SQLiteWalletRepository(ILoggerFactory loggerFactory, DataFolder dataFolde this.WriteMetricsToFile = false; this.logger = loggerFactory.CreateLogger(this.GetType().FullName); this.lockObj = new object(); + this.signals = signals; Reset(); } @@ -998,7 +1002,13 @@ private bool ParallelProcessBlock(ProcessBlocksInfo round, Block block, ChainedH // Determine the scripts for creating temporary tables and inserting the block's information into them. ITransactionsToLists transactionsToLists = new TransactionsToLists(this.Network, this.ScriptAddressReader, round, this.dateTimeProvider); if (transactionsToLists.ProcessTransactions(block.Transactions, new HashHeightPair(chainedHeader), blockTime: block.Header.BlockTime.ToUnixTimeSeconds())) + { + // We only want to raise events for the UI (via SignalR) to query the wallet balance if a transaction pertaining to the wallet + // was processed. + this.signals?.Publish(new WalletProcessedTransactionOfInterestEvent()); + this.Metrics.ProcessCount++; + } this.Metrics.BlockTime += (DateTime.Now.Ticks - flagFall2); @@ -1204,7 +1214,13 @@ public void ProcessTransaction(string walletName, Transaction transaction, uint2 IEnumerable> txToScript; { var transactionsToLists = new TransactionsToLists(this.Network, this.ScriptAddressReader, processBlocksInfo, this.dateTimeProvider); - transactionsToLists.ProcessTransactions(new[] { transaction }, null, fixedTxId); + if (transactionsToLists.ProcessTransactions(new[] { transaction }, null, fixedTxId)) + { + // We only want to raise events for the UI (via SignalR) to query the wallet balance if a transaction pertaining to the wallet + // was processed. + this.signals?.Publish(new WalletProcessedTransactionOfInterestEvent()); + } + txToScript = (new[] { processBlocksInfo.Outputs, processBlocksInfo.PrevOuts }).Select(list => list.CreateScript()); } diff --git a/src/Stratis.StraxD/Program.cs b/src/Stratis.StraxD/Program.cs index d16f24fa07..fa263e6363 100644 --- a/src/Stratis.StraxD/Program.cs +++ b/src/Stratis.StraxD/Program.cs @@ -13,8 +13,6 @@ using Stratis.Bitcoin.Features.Miner; using Stratis.Bitcoin.Features.RPC; using Stratis.Bitcoin.Features.SignalR; -using Stratis.Bitcoin.Features.SignalR.Broadcasters; -using Stratis.Bitcoin.Features.SignalR.Events; using Stratis.Bitcoin.Networks; using Stratis.Bitcoin.Utilities; using Stratis.Features.Diagnostic; @@ -50,25 +48,7 @@ public static async Task Main(string[] args) .AddRPC() .AddSignalR(options => { - options.EventsToHandle = new[] - { - (IClientEvent) new BlockConnectedClientEvent(), - new ReconstructFederationClientEvent(), - new FullNodeClientEvent(), - new TransactionReceivedClientEvent() - }; - - options.ClientEventBroadcasters = new[] - { - (Broadcaster: typeof(StakingBroadcaster), ClientEventBroadcasterSettings: new ClientEventBroadcasterSettings - { - BroadcastFrequencySeconds = 5 - }), - (Broadcaster: typeof(WalletInfoBroadcaster), ClientEventBroadcasterSettings: new ClientEventBroadcasterSettings - { - BroadcastFrequencySeconds = 5 - }) - }; + DaemonConfiguration.ConfigureSignalRForStrax(options); }) .UseDiagnosticFeature();