Jelajahi Sumber

GUI: throttle balance refresh when rapidly downloading blocks

Herman Schoenfeld 7 tahun lalu
induk
melakukan
88ac318a64

+ 1 - 0
src/gui/UCTRLWallet.lfm

@@ -10,6 +10,7 @@ object CTRLWallet: TCTRLWallet
   ClientWidth = 1151
   OnCreate = FormCreate
   OnResize = FormResize
+  LCLVersion = '1.8.4.0'
   Visible = False
   object PairSplitter1: TPairSplitter
     Left = 0

+ 29 - 8
src/gui/UCTRLWallet.pas

@@ -16,8 +16,9 @@ interface
 
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
-  ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI, Generics.Collections, ULog,
-  UAccounts, UDataSources, UNode, UCoreObjects, UCoreUtils, UCTRLNoAccount;
+  ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon, UCommon.UI, Generics.Collections,
+  ULog, UAccounts, UDataSources, UNode, UCoreObjects, UCoreUtils, UCTRLNoAccount;
+
 type
 
   { TCTRLWallet }
@@ -67,6 +68,7 @@ type
     procedure miDelistAccountsFromSaleClick(Sender: TObject);
   private
     FNodeNotifyEvents: TNodeNotifyEvents;
+    FBalanceUpdatedEvent : TThrottledEvent;
     FAccountsMode: TCTRLWalletAccountsMode;
     FOperationsMode: TCTRLWalletOperationsMode;
     FOperationsHistory: TCTRLWalletOperationsHistory;
@@ -80,6 +82,7 @@ type
     procedure SetOperationsMode(AMode: TCTRLWalletOperationsMode);
     procedure SetOperationsHistory(AHistory: TCTRLWalletOperationsHistory);
     procedure RefreshMyAccountsCombo;
+    procedure RefreshBalances;
     procedure RefreshTotals;
     procedure RefreshAccountsGrid;
     procedure RefreshOperationsGrid;
@@ -88,6 +91,7 @@ type
     procedure ActivateFirstTime; override;
     procedure OnPrivateKeysChanged(Sender: TObject);
     procedure OnUserKeyActivityDetected(Sender: TObject);
+    procedure OnUserBalanceChanged(Sender: TObject);
     procedure OnNodeBlocksChanged(Sender: TObject);
     procedure OnNodeNewOperation(Sender: TObject);
     procedure OnAccountsSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
@@ -106,7 +110,7 @@ implementation
 
 uses
   UUserInterface, UCellRenderers, UBlockChain, UWallet, UCrypto,
-  UCommon, UMemory, Generics.Defaults, UCommon.Data, UCommon.Collections, UWIZOperation;
+  UMemory, Generics.Defaults, UCommon.Data, UCommon.Collections, UWIZOperation;
 
 {$R *.lfm}
 
@@ -124,6 +128,10 @@ begin
   FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
   TWallet.Keys.OnChanged.Add(OnPrivateKeysChanged);
   TWallet.Keys.AccountsKeyList.ClearAccountKeyChanges;   // XXXXX CLEAR BUFFER on start
+  FBalanceUpdatedEvent := TThrottledEvent.Create(Self);
+  FBalanceUpdatedEvent.Mode := temNotifyOnEventBurstFinished;
+  FBalanceUpdatedEvent.Interval := TTimeSpan.FromSeconds(10);
+  FBalanceUpdatedEvent.Add(OnUserBalanceChanged);
 
   // fields
   FAccountsDataSource := TMyAccountsDataSource.Create(Self);
@@ -316,8 +324,14 @@ begin
   // add first time-init here
 end;
 
-procedure TCTRLWallet.RefreshTotals;
+procedure TCTRLWallet.RefreshBalances;
+begin
+  FAccountsGrid.RefreshGrid;
+  FOperationsGrid.RefreshGrid;
+  // Note: RefreshTotals is called after FAccountsGrid finishes updating (since it uses it's internal data)
+end;
 
+procedure TCTRLWallet.RefreshTotals;
 begin
   lblTotalPASC.Caption := TAccountComp.FormatMoney(FBalance.TotalPASC);
   lblTotalPASA.Caption := Format('%d', [FBalance.TotalPASA]);
@@ -504,10 +518,17 @@ end;
 
 procedure TCTRLWallet.OnUserKeyActivityDetected;
 begin
-//  if NOT TUserInterface.Node.HasBestKnownBlockchainTip then
-//    exit; // node syncing
-  FAccountsGrid.RefreshGrid;
-  FOperationsGrid.RefreshGrid;
+  // This handler is called every time a block is downloaded. If we refreshed GUI here it would
+  // result in severe back-end blocking and slow-down, as the GUI refreshed on every block during
+  // a syncronization. As a result, we throttle the GUI refresh via FBalanceUpdatedEvent which
+  // waits until 5 seconds of idle before calling OnUserBalanceChanged which then updates GUI.
+  FBalanceUpdatedEvent.Notify;
+end;
+
+procedure TCTRLWallet.OnUserBalanceChanged(Sender: TObject);
+begin
+  // Invocation of this event hander is throttled by FBalanceUpdatedEvent.
+  RefreshBalances;
 end;
 
 procedure TCTRLWallet.OnNodeBlocksChanged(Sender: TObject);

+ 6 - 7
src/gui/wizards/operations/UWIZOperation.pas

@@ -174,7 +174,7 @@ type
 implementation
 
 uses
-  UCrypto, UECIES, UAES, UConst, UCoreUtils, UOpTransaction;
+  UCrypto, UECIES, UAES, UConst, UCoreUtils, UOpTransaction, UUserInterface;
 
 { TWIZOperationsModel }
 
@@ -477,7 +477,7 @@ begin
       if LDoOperation then
       begin
         LPCOperation := TOpTransaction.CreateTransaction(
-          LCurrentAccount.account, LCurrentAccount.n_operation + 1, ADestinationAccount.account, LWalletKey.PrivateKey, LAmount, LFee, LPayloadEncodedBytes);
+           TUserInterface.Node.Bank.Safebox.CurrentProtocol, LCurrentAccount.account, LCurrentAccount.n_operation + 1, ADestinationAccount.account, LWalletKey.PrivateKey, LAmount, LFee, LPayloadEncodedBytes);
         try
           LOperationsTxt := Format('Transaction To "%s"', [ADestinationAccount.AccountString]);
 
@@ -629,12 +629,12 @@ begin
           LFee := AFee
         else
           LFee := LSignerAccount.balance - UInt64(LTotalSignerFee);
-        LPCOperation := TOpChangeKeySigned.Create(LSignerAccount.account,
+        LPCOperation := TOpChangeKeySigned.Create(TUserInterface.Node.Bank.Safebox.CurrentProtocol, LSignerAccount.account,
           LSignerAccount.n_operation + LNoOfOperations + 1, LCurrentAccount.account,
           LWalletKey.PrivateKey, APublicKey, LFee, LPayloadEncodedBytes);
       end
       else
-        LPCOperation := TOpChangeKey.Create(LCurrentAccount.account, LCurrentAccount.n_operation +
+        LPCOperation := TOpChangeKey.Create(TUserInterface.Node.Bank.Safebox.CurrentProtocol, LCurrentAccount.account, LCurrentAccount.n_operation +
           1, LCurrentAccount.account, LWalletKey.PrivateKey, APublicKey, LFee, LPayloadEncodedBytes);
 
       try
@@ -780,17 +780,16 @@ begin
         akaPublicSale:
 
           LPCOperation := TOpListAccountForSale.CreateListAccountForSale(
-            ASignerAccount.account, ASignerAccount.n_operation + 1 + LAccountIdx,
+            TUserInterface.Node.Bank.Safebox.CurrentProtocol, ASignerAccount.account, ASignerAccount.n_operation + 1 + LAccountIdx,
             LCurrentAccount.account, ASalePrice, LFee, ASellerAccount.account,
             APublicKey, 0, LWalletKey.PrivateKey, LPayloadEncodedBytes);
 
         akaPrivateSale:
 
           LPCOperation := TOpListAccountForSale.CreateListAccountForSale(
-            ASignerAccount.account, ASignerAccount.n_operation + 1 + LAccountIdx,
+            TUserInterface.Node.Bank.Safebox.CurrentProtocol, ASignerAccount.account, ASignerAccount.n_operation + 1 + LAccountIdx,
             LCurrentAccount.account, ASalePrice, LFee, ASellerAccount.account,
             APublicKey, ALockedUntilBlock, LWalletKey.PrivateKey, LPayloadEncodedBytes)
-
         else
           raise Exception.Create('Invalid Account Sale Type')
       end;