|
@@ -0,0 +1,1942 @@
|
|
|
+unit UFRMWallet;
|
|
|
+
|
|
|
+{$IFDEF FPC}
|
|
|
+ {$MODE Delphi}
|
|
|
+{$ENDIF}
|
|
|
+
|
|
|
+{ Copyright (c) 2016 by Albert Molina
|
|
|
+
|
|
|
+ Distributed under the MIT software license, see the accompanying file LICENSE
|
|
|
+ or visit http://www.opensource.org/licenses/mit-license.php.
|
|
|
+
|
|
|
+ This unit is a part of Pascal Coin, a P2P crypto currency without need of
|
|
|
+ historical operations.
|
|
|
+
|
|
|
+ If you like it, consider a donation using BitCoin:
|
|
|
+ 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+interface
|
|
|
+
|
|
|
+{$I ../config.inc}
|
|
|
+
|
|
|
+uses
|
|
|
+{$IFnDEF FPC}
|
|
|
+ pngimage, Windows, AppEvnts, ShlObj,
|
|
|
+{$ELSE}
|
|
|
+ LCLIntf, LCLType, LMessages,
|
|
|
+{$ENDIF}
|
|
|
+ Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
|
|
|
+ Dialogs, ExtCtrls, ComCtrls, UWallet, StdCtrls,
|
|
|
+ ULog, Grids, UAppParams,
|
|
|
+ UBlockChain, UNode, UGridUtils, UAccounts, Menus, ImgList,
|
|
|
+ UNetProtocol, UCrypto, Buttons, UPoolMining, URPC, UFRMAccountSelect,
|
|
|
+ UConst;
|
|
|
+
|
|
|
+Const
|
|
|
+ CM_PC_WalletKeysChanged = WM_USER + 1;
|
|
|
+ CM_PC_NetConnectionUpdated = WM_USER + 2;
|
|
|
+
|
|
|
+type
|
|
|
+ TMinerPrivateKey = (mpk_NewEachTime, mpk_Random, mpk_Selected);
|
|
|
+
|
|
|
+ { TFRMWallet }
|
|
|
+
|
|
|
+ TFRMWallet = class(TForm)
|
|
|
+ pnlTop: TPanel;
|
|
|
+ Image1: TImage;
|
|
|
+ sbSearchAccount: TSpeedButton;
|
|
|
+ StatusBar: TStatusBar;
|
|
|
+ PageControl: TPageControl;
|
|
|
+ tsMyAccounts: TTabSheet;
|
|
|
+ tsOperations: TTabSheet;
|
|
|
+ TrayIcon: TTrayIcon;
|
|
|
+ TimerUpdateStatus: TTimer;
|
|
|
+ tsLogs: TTabSheet;
|
|
|
+ pnlTopLogs: TPanel;
|
|
|
+ cbShowDebugLogs: TCheckBox;
|
|
|
+ memoLogs: TMemo;
|
|
|
+ pnlMyAccountsTop: TPanel;
|
|
|
+ dgAccounts: TDrawGrid;
|
|
|
+ cbMyPrivateKeys: TComboBox;
|
|
|
+ Splitter1: TSplitter;
|
|
|
+ MainMenu: TMainMenu;
|
|
|
+ miProject: TMenuItem;
|
|
|
+ miOptions: TMenuItem;
|
|
|
+ miPrivatekeys: TMenuItem;
|
|
|
+ miN1: TMenuItem;
|
|
|
+ miAbout: TMenuItem;
|
|
|
+ miAboutPascalCoin: TMenuItem;
|
|
|
+ miNewOperation: TMenuItem;
|
|
|
+ Panel1: TPanel;
|
|
|
+ Label2: TLabel;
|
|
|
+ ebFilterOperationsStartBlock: TEdit;
|
|
|
+ ebFilterOperationsEndBlock: TEdit;
|
|
|
+ tsNodeStats: TTabSheet;
|
|
|
+ memoNetConnections: TMemo;
|
|
|
+ memoNetServers: TMemo;
|
|
|
+ memoNetBlackLists: TMemo;
|
|
|
+ Label3: TLabel;
|
|
|
+ Label6: TLabel;
|
|
|
+ Label7: TLabel;
|
|
|
+ lblCurrentBlockCaption: TLabel;
|
|
|
+ lblCurrentBlock: TLabel;
|
|
|
+ lblCurrentBlockTimeCaption: TLabel;
|
|
|
+ lblCurrentBlockTime: TLabel;
|
|
|
+ lblOperationsPendingCaption: TLabel;
|
|
|
+ lblOperationsPending: TLabel;
|
|
|
+ lblMiningStatusCaption: TLabel;
|
|
|
+ lblMinersClients: TLabel;
|
|
|
+ lblCurrentDifficultyCaption: TLabel;
|
|
|
+ lblCurrentDifficulty: TLabel;
|
|
|
+ lblTimeAverage: TLabel;
|
|
|
+ Label4: TLabel;
|
|
|
+ tsBlockChain: TTabSheet;
|
|
|
+ Panel2: TPanel;
|
|
|
+ Label9: TLabel;
|
|
|
+ ebBlockChainBlockStart: TEdit;
|
|
|
+ ebBlockChainBlockEnd: TEdit;
|
|
|
+ Label8: TLabel;
|
|
|
+ lblNodeStatus: TLabel;
|
|
|
+ tsPendingOperations: TTabSheet;
|
|
|
+ dgPendingOperations: TDrawGrid;
|
|
|
+ pnlPendingOperations: TPanel;
|
|
|
+ Label10: TLabel;
|
|
|
+ cbExploreMyAccounts: TCheckBox;
|
|
|
+ N1: TMenuItem;
|
|
|
+ MiClose: TMenuItem;
|
|
|
+ MiDecodePayload: TMenuItem;
|
|
|
+ ImageListIcons: TImageList;
|
|
|
+ ApplicationEvents: {$IFDEF FPC}TApplicationProperties{$ELSE}TApplicationEvents{$ENDIF};
|
|
|
+ Label5: TLabel;
|
|
|
+ lblCurrentAccounts: TLabel;
|
|
|
+ lblTimeAverageAux: TLabel;
|
|
|
+ tsMessages: TTabSheet;
|
|
|
+ lbNetConnections: TListBox;
|
|
|
+ bbSendAMessage: TButton;
|
|
|
+ Label11: TLabel;
|
|
|
+ memoMessages: TMemo;
|
|
|
+ memoMessageToSend: TMemo;
|
|
|
+ Label12: TLabel;
|
|
|
+ Label13: TLabel;
|
|
|
+ Label14: TLabel;
|
|
|
+ Label16: TLabel;
|
|
|
+ lblBlocksFound: TLabel;
|
|
|
+ pnlAccounts: TPanel;
|
|
|
+ pnlAccountsInfo: TPanel;
|
|
|
+ Label17: TLabel;
|
|
|
+ Label19: TLabel;
|
|
|
+ lblAccountsCount: TLabel;
|
|
|
+ lblAccountsBalance: TLabel;
|
|
|
+ lblReceivedMessages: TLabel;
|
|
|
+ lblBuild: TLabel;
|
|
|
+ ebFindAccountNumber: TEdit;
|
|
|
+ Label18: TLabel;
|
|
|
+ IPnodes1: TMenuItem;
|
|
|
+ bbChangeKeyName: TBitBtn;
|
|
|
+ pcAccountsOptions: TPageControl;
|
|
|
+ tsAccountOperations: TTabSheet;
|
|
|
+ dgAccountOperations: TDrawGrid;
|
|
|
+ tsMultiSelectAccounts: TTabSheet;
|
|
|
+ dgSelectedAccounts: TDrawGrid;
|
|
|
+ pnlSelectedAccountsTop: TPanel;
|
|
|
+ pnlSelectedAccountsBottom: TPanel;
|
|
|
+ pnlSelectedAccountsLeft: TPanel;
|
|
|
+ sbSelectedAccountsAdd: TSpeedButton;
|
|
|
+ sbSelectedAccountsAddAll: TSpeedButton;
|
|
|
+ sbSelectedAccountsDel: TSpeedButton;
|
|
|
+ sbSelectedAccountsDelAll: TSpeedButton;
|
|
|
+ Label20: TLabel;
|
|
|
+ lblSelectedAccountsCount: TLabel;
|
|
|
+ Label22: TLabel;
|
|
|
+ lblSelectedAccountsBalance: TLabel;
|
|
|
+ bbSelectedAccountsOperation: TBitBtn;
|
|
|
+ Label15: TLabel;
|
|
|
+ MiOperations: TMenuItem;
|
|
|
+ MiAddaccounttoSelected: TMenuItem;
|
|
|
+ MiRemoveaccountfromselected: TMenuItem;
|
|
|
+ N2: TMenuItem;
|
|
|
+ MiMultiaccountoperation: TMenuItem;
|
|
|
+ N3: TMenuItem;
|
|
|
+ MiFindnextaccountwithhighbalance: TMenuItem;
|
|
|
+ MiFindpreviousaccountwithhighbalance: TMenuItem;
|
|
|
+ MiFindaccount: TMenuItem;
|
|
|
+ cbFilterAccounts: TCheckBox;
|
|
|
+ ebFilterAccountByBalanceMin: TEdit;
|
|
|
+ ebFilterAccountByBalanceMax: TEdit;
|
|
|
+ bbAccountsRefresh: TBitBtn;
|
|
|
+ dgBlockChainExplorer: TDrawGrid;
|
|
|
+ dgOperationsExplorer: TDrawGrid;
|
|
|
+ MiFindOperationbyOpHash: TMenuItem;
|
|
|
+ MiAccountInformation: TMenuItem;
|
|
|
+ procedure FormCreate(Sender: TObject);
|
|
|
+ procedure FormDestroy(Sender: TObject);
|
|
|
+ procedure sbSearchAccountClick(Sender: TObject);
|
|
|
+ procedure TimerUpdateStatusTimer(Sender: TObject);
|
|
|
+ procedure cbMyPrivateKeysChange(Sender: TObject);
|
|
|
+ procedure dgAccountsClick(Sender: TObject);
|
|
|
+ procedure miOptionsClick(Sender: TObject);
|
|
|
+ procedure miAboutPascalCoinClick(Sender: TObject);
|
|
|
+ procedure miNewOperationClick(Sender: TObject);
|
|
|
+ procedure miPrivatekeysClick(Sender: TObject);
|
|
|
+ procedure dgAccountsColumnMoved(Sender: TObject; FromIndex,
|
|
|
+ ToIndex: Integer);
|
|
|
+ procedure dgAccountsFixedCellClick(Sender: TObject; ACol, ARow: Integer);
|
|
|
+ procedure PageControlChange(Sender: TObject);
|
|
|
+ procedure ebFilterOperationsAccountExit(Sender: TObject);
|
|
|
+ procedure ebFilterOperationsAccountKeyPress(Sender: TObject; var Key: Char);
|
|
|
+ procedure ebBlockChainBlockStartExit(Sender: TObject);
|
|
|
+ procedure ebBlockChainBlockStartKeyPress(Sender: TObject; var Key: Char);
|
|
|
+ procedure cbExploreMyAccountsClick(Sender: TObject);
|
|
|
+ procedure MiCloseClick(Sender: TObject);
|
|
|
+ procedure MiDecodePayloadClick(Sender: TObject);
|
|
|
+ procedure TrayIconDblClick(Sender: TObject);
|
|
|
+ procedure ApplicationEventsMinimize(Sender: TObject);
|
|
|
+ procedure bbSendAMessageClick(Sender: TObject);
|
|
|
+ procedure lblReceivedMessagesClick(Sender: TObject);
|
|
|
+ procedure ebFindAccountNumberChange(Sender: TObject);
|
|
|
+ procedure ebFindAccountNumberExit(Sender: TObject);
|
|
|
+ procedure IPnodes1Click(Sender: TObject);
|
|
|
+ procedure bbChangeKeyNameClick(Sender: TObject);
|
|
|
+ procedure sbSelectedAccountsAddClick(Sender: TObject);
|
|
|
+ procedure sbSelectedAccountsAddAllClick(Sender: TObject);
|
|
|
+ procedure sbSelectedAccountsDelClick(Sender: TObject);
|
|
|
+ procedure sbSelectedAccountsDelAllClick(Sender: TObject);
|
|
|
+ procedure bbSelectedAccountsOperationClick(Sender: TObject);
|
|
|
+ procedure MiAddaccounttoSelectedClick(Sender: TObject);
|
|
|
+ procedure MiRemoveaccountfromselectedClick(Sender: TObject);
|
|
|
+ procedure MiMultiaccountoperationClick(Sender: TObject);
|
|
|
+ procedure MiFindnextaccountwithhighbalanceClick(Sender: TObject);
|
|
|
+ procedure MiFindpreviousaccountwithhighbalanceClick(Sender: TObject);
|
|
|
+ procedure MiFindaccountClick(Sender: TObject);
|
|
|
+ procedure bbAccountsRefreshClick(Sender: TObject);
|
|
|
+ procedure ebFilterAccountByBalanceMinExit(Sender: TObject);
|
|
|
+ procedure ebFilterAccountByBalanceMinKeyPress(Sender: TObject;
|
|
|
+ var Key: Char);
|
|
|
+ procedure cbFilterAccountsClick(Sender: TObject);
|
|
|
+ procedure MiFindOperationbyOpHashClick(Sender: TObject);
|
|
|
+ procedure MiAccountInformationClick(Sender: TObject);
|
|
|
+ private
|
|
|
+ FLastNodesCacheUpdatedTS : TDateTime;
|
|
|
+ FBackgroundPanel : TPanel;
|
|
|
+ FMinersBlocksFound: Integer;
|
|
|
+ procedure SetMinersBlocksFound(const Value: Integer);
|
|
|
+ Procedure CheckIsReady;
|
|
|
+ Procedure FinishedLoadingApp;
|
|
|
+ Procedure FillAccountInformation(Const Strings : TStrings; Const AccountNumber : Cardinal);
|
|
|
+ Procedure FillOperationInformation(Const Strings : TStrings; Const OperationResume : TOperationResume);
|
|
|
+ protected
|
|
|
+ { Private declarations }
|
|
|
+ FNode : TNode;
|
|
|
+ FIsActivated : Boolean;
|
|
|
+ FWalletKeys : TWalletKeysExt;
|
|
|
+ FLog : TLog;
|
|
|
+ FAppParams : TAppParams;
|
|
|
+ FNodeNotifyEvents : TNodeNotifyEvents;
|
|
|
+ FAccountsGrid : TAccountsGrid;
|
|
|
+ FSelectedAccountsGrid : TAccountsGrid;
|
|
|
+ FOperationsAccountGrid : TOperationsGrid;
|
|
|
+ FPendingOperationsGrid : TOperationsGrid;
|
|
|
+ FOrderedAccountsKeyList : TOrderedAccountKeysList;
|
|
|
+ FOperationsExplorerGrid : TOperationsGrid;
|
|
|
+ FBlockChainGrid : TBlockChainGrid;
|
|
|
+ FMinerPrivateKeyType : TMinerPrivateKey;
|
|
|
+ FUpdating : Boolean;
|
|
|
+ FMessagesUnreadCount : Integer;
|
|
|
+ FMinAccountBalance : Int64;
|
|
|
+ FMaxAccountBalance : Int64;
|
|
|
+ FPoolMiningServer : TPoolMiningServer;
|
|
|
+ FRPCServer : TRPCServer;
|
|
|
+ FMustProcessWalletChanged : Boolean;
|
|
|
+ FMustProcessNetConnectionUpdated : Boolean;
|
|
|
+ Procedure OnNewAccount(Sender : TObject);
|
|
|
+ Procedure OnReceivedHelloMessage(Sender : TObject);
|
|
|
+ Procedure OnNetStatisticsChanged(Sender : TObject);
|
|
|
+ procedure OnNewLog(logtype : TLogType; Time : TDateTime; ThreadID : TThreadID; Const sender, logtext : AnsiString);
|
|
|
+ procedure OnWalletChanged(Sender : TObject);
|
|
|
+ procedure OnNetConnectionsUpdated(Sender : TObject);
|
|
|
+ procedure OnNetNodeServersUpdated(Sender : TObject);
|
|
|
+ procedure OnNetBlackListUpdated(Sender : TObject);
|
|
|
+ Procedure OnNodeMessageEvent(NetConnection : TNetConnection; MessageData : TRawBytes);
|
|
|
+ Procedure OnSelectedAccountsGridUpdated(Sender : TObject);
|
|
|
+ Procedure OnMiningServerNewBlockFound(Sender : TObject);
|
|
|
+ Procedure UpdateConnectionStatus;
|
|
|
+ Procedure UpdateAccounts(RefreshData : Boolean);
|
|
|
+ Procedure UpdateBlockChainState;
|
|
|
+ Procedure UpdatePrivateKeys;
|
|
|
+ Procedure UpdateOperations;
|
|
|
+ Procedure LoadAppParams;
|
|
|
+ Procedure SaveAppParams;
|
|
|
+ Procedure UpdateConfigChanged;
|
|
|
+ Procedure UpdateNodeStatus;
|
|
|
+ Procedure UpdateAvailableConnections;
|
|
|
+ procedure Activate; override;
|
|
|
+ Function ForceMining : Boolean; virtual;
|
|
|
+ Function GetAccountKeyForMiner : TAccountKey;
|
|
|
+ Procedure DoUpdateAccounts;
|
|
|
+ Function DoUpdateAccountsFilter : Boolean;
|
|
|
+ procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
|
|
|
+ procedure CM_NetConnectionUpdated(var Msg: TMessage); message CM_PC_NetConnectionUpdated;
|
|
|
+ public
|
|
|
+ { Public declarations }
|
|
|
+ Property WalletKeys : TWalletKeysExt read FWalletKeys;
|
|
|
+ Property MinersBlocksFound : Integer read FMinersBlocksFound write SetMinersBlocksFound;
|
|
|
+ end;
|
|
|
+
|
|
|
+var
|
|
|
+ FRMWallet: TFRMWallet;
|
|
|
+
|
|
|
+implementation
|
|
|
+
|
|
|
+{$IFnDEF FPC}
|
|
|
+ {$R *.dfm}
|
|
|
+{$ELSE}
|
|
|
+ {$R *.lfm}
|
|
|
+{$ENDIF}
|
|
|
+
|
|
|
+Uses UFolderHelper, UOpenSSL, UOpenSSLdef, UTime, UFileStorage,
|
|
|
+ UThread, UOpTransaction, UECIES, UFRMPascalCoinWalletConfig,
|
|
|
+ UFRMAbout, UFRMOperation, UFRMWalletKeys, UFRMPayloadDecoder, UFRMNodesIp, UFRMMemoText, USettings, UCommon;
|
|
|
+
|
|
|
+Type
|
|
|
+ TThreadActivate = Class(TPCThread)
|
|
|
+ protected
|
|
|
+ procedure BCExecute; override;
|
|
|
+ End;
|
|
|
+
|
|
|
+{ TThreadActivate }
|
|
|
+
|
|
|
+procedure TThreadActivate.BCExecute;
|
|
|
+begin
|
|
|
+ // Read Operations saved from disk
|
|
|
+ TNode.Node.InitSafeboxAndOperations; // New Build 2.1.4 to load pending operations buffer
|
|
|
+ TNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
|
|
|
+ TNode.Node.NetServer.Active := true;
|
|
|
+ Synchronize( FRMWallet.DoUpdateAccounts );
|
|
|
+ Synchronize( FRMWallet.FinishedLoadingApp );
|
|
|
+end;
|
|
|
+
|
|
|
+{ TFRMWallet }
|
|
|
+
|
|
|
+procedure TFRMWallet.Activate;
|
|
|
+Var ips : AnsiString;
|
|
|
+ nsarr : TNodeServerAddressArray;
|
|
|
+begin
|
|
|
+ inherited;
|
|
|
+ if FIsActivated then exit;
|
|
|
+ FIsActivated := true;
|
|
|
+ try
|
|
|
+ // Check OpenSSL dll
|
|
|
+ if Not LoadSSLCrypt then raise Exception.Create('Cannot load '+SSL_C_LIB+#10+'To use this software make sure this file is available on you system or reinstall the application');
|
|
|
+ TCrypto.InitCrypto;
|
|
|
+ // Read Wallet
|
|
|
+ Try
|
|
|
+ FWalletKeys.WalletFileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'WalletKeys.dat';
|
|
|
+ Except
|
|
|
+ On E:Exception do begin
|
|
|
+ E.Message := 'Cannot open your wallet... Perhaps another instance of Pascal Coin is active!'+#10+#10+E.Message;
|
|
|
+ Raise;
|
|
|
+ end;
|
|
|
+ End;
|
|
|
+ ips := FAppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].GetAsString('');
|
|
|
+ TNode.DecodeIpStringToNodeServerAddressArray(ips,nsarr);
|
|
|
+ TNetData.NetData.DiscoverFixedServersOnly(nsarr);
|
|
|
+ setlength(nsarr,0);
|
|
|
+ // Creating Node:
|
|
|
+ FNode := TNode.Node;
|
|
|
+ FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
|
|
|
+ FNode.PeerCache := FAppParams.ParamByName[CT_PARAM_PeerCache].GetAsString('')+';'+CT_Discover_IPs;
|
|
|
+ // Create RPC server
|
|
|
+ FRPCServer := TRPCServer.Create;
|
|
|
+ FRPCServer.WalletKeys := WalletKeys;
|
|
|
+ FRPCServer.Active := FAppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
|
|
|
+ FRPCServer.ValidIPs := FAppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1');
|
|
|
+ WalletKeys.SafeBox := FNode.Bank.SafeBox;
|
|
|
+ // Check Database
|
|
|
+ FNode.Bank.StorageClass := TFileStorage;
|
|
|
+ TFileStorage(FNode.Bank.Storage).DatabaseFolder := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'Data';
|
|
|
+ TFileStorage(FNode.Bank.Storage).Initialize;
|
|
|
+ // Init Grid
|
|
|
+ //FAccountsGrid.Node := FNode;
|
|
|
+ FSelectedAccountsGrid.Node := FNode;
|
|
|
+ FWalletKeys.OnChanged.Add( OnWalletChanged );
|
|
|
+ FAccountsGrid.Node := FNode;
|
|
|
+ FOperationsAccountGrid.Node := FNode;
|
|
|
+ // Reading database
|
|
|
+ TThreadActivate.Create(false).FreeOnTerminate := true;
|
|
|
+ FNodeNotifyEvents.Node := FNode;
|
|
|
+ // Init
|
|
|
+ TNetData.NetData.OnReceivedHelloMessage := OnReceivedHelloMessage;
|
|
|
+ TNetData.NetData.OnStatisticsChanged := OnNetStatisticsChanged;
|
|
|
+ TNetData.NetData.OnNetConnectionsUpdated := onNetConnectionsUpdated;
|
|
|
+ TNetData.NetData.OnNodeServersUpdated := OnNetNodeServersUpdated;
|
|
|
+ TNetData.NetData.OnBlackListUpdated := OnNetBlackListUpdated;
|
|
|
+ //
|
|
|
+ TimerUpdateStatus.Interval := 1000;
|
|
|
+ TimerUpdateStatus.Enabled := true;
|
|
|
+ UpdateConfigChanged;
|
|
|
+ Except
|
|
|
+ On E:Exception do begin
|
|
|
+ E.Message := 'An error occurred during initialization. Application cannot continue:'+#10+#10+E.Message+#10+#10+'Application will close...';
|
|
|
+ Application.MessageBox(PChar(E.Message),PChar(Application.Title),MB_ICONERROR+MB_OK);
|
|
|
+ Halt;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ UpdatePrivateKeys;
|
|
|
+ UpdateAccounts(false);
|
|
|
+ if FAppParams.ParamByName[CT_PARAM_FirstTime].GetAsBoolean(true) then begin
|
|
|
+ FAppParams.ParamByName[CT_PARAM_FirstTime].SetAsBoolean(false);
|
|
|
+ miAboutPascalCoinClick(Nil);
|
|
|
+ end;
|
|
|
+
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ApplicationEventsMinimize(Sender: TObject);
|
|
|
+begin
|
|
|
+ {$IFnDEF FPC}
|
|
|
+ Hide();
|
|
|
+ WindowState := wsMinimized;
|
|
|
+ TimerUpdateStatus.Enabled := false;
|
|
|
+ { Show the animated tray icon and also a hint balloon. }
|
|
|
+ TrayIcon.Visible := True;
|
|
|
+ TrayIcon.ShowBalloonHint;
|
|
|
+ {$ENDIF}
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.bbAccountsRefreshClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ UpdateAccounts(true);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.bbChangeKeyNameClick(Sender: TObject);
|
|
|
+var i : Integer;
|
|
|
+ name : String;
|
|
|
+begin
|
|
|
+ if (cbMyPrivateKeys.ItemIndex<0) then exit;
|
|
|
+ i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex]);
|
|
|
+ if (i<0) Or (i>=FWalletKeys.Count) then raise Exception.Create('Must select a Key');
|
|
|
+ name := FWalletKeys.Key[i].Name;
|
|
|
+ if InputQuery('Change Key name','Input new name',name) then begin
|
|
|
+ FWalletKeys.SetName(i,name);
|
|
|
+ end;
|
|
|
+ UpdatePrivateKeys;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.bbSelectedAccountsOperationClick(Sender: TObject);
|
|
|
+var l : TOrderedCardinalList;
|
|
|
+begin
|
|
|
+ CheckIsReady;
|
|
|
+ if FSelectedAccountsGrid.AccountsCount<=0 then raise Exception.Create('Must select at least 1 account');
|
|
|
+ With TFRMOperation.Create(Self) do
|
|
|
+ Try
|
|
|
+ l := FSelectedAccountsGrid.LockAccountsList;
|
|
|
+ try
|
|
|
+ SenderAccounts.CopyFrom(l);
|
|
|
+ finally
|
|
|
+ FSelectedAccountsGrid.UnlockAccountsList;
|
|
|
+ end;
|
|
|
+ DefaultFee := FAppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInt64(0);
|
|
|
+ WalletKeys := FWalletKeys;
|
|
|
+ ShowModal;
|
|
|
+ Finally
|
|
|
+ Free;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.bbSendAMessageClick(Sender: TObject);
|
|
|
+Var basem,m : String;
|
|
|
+ them, errors : AnsiString;
|
|
|
+ i,n : Integer;
|
|
|
+ nc : TNetConnection;
|
|
|
+begin
|
|
|
+ CheckIsReady;
|
|
|
+ if (lbNetConnections.SelCount<=0) Or (lbNetConnections.ItemIndex<0) then raise Exception.Create('Select at least one connection');
|
|
|
+ if lbNetConnections.SelCount<=0 then n := 1
|
|
|
+ else n := lbNetConnections.SelCount;
|
|
|
+
|
|
|
+ basem := memoMessageToSend.Lines.Text;
|
|
|
+ m := '';
|
|
|
+ // Clear non valid characters:
|
|
|
+ for i := 1 to length(basem) do begin
|
|
|
+ if basem[i] in [#32..#127] then m := m + basem[i]
|
|
|
+ else m:=m+'.';
|
|
|
+ end;
|
|
|
+
|
|
|
+ if trim(m)='' then raise Exception.Create('No message');
|
|
|
+
|
|
|
+ if Application.MessageBox(PChaR('Send this message to '+inttostr(n)+' nodes?'+#10+
|
|
|
+ 'NOTE: Sending unauthorized messages will be considered spam and you will be banned'+#10+
|
|
|
+ #10+
|
|
|
+ 'Message: '+#10+
|
|
|
+ m),PChar(Application.Title),MB_ICONQUESTION+MB_YESNO+MB_DEFBUTTON1)<>IdYes then exit;
|
|
|
+ them := m;
|
|
|
+ if n>1 then begin
|
|
|
+ for i := 0 to lbNetConnections.Items.Count - 1 do begin
|
|
|
+ if lbNetConnections.Selected[i] then begin
|
|
|
+ nc := TNetConnection(lbNetconnections.Items.Objects[i]);
|
|
|
+ if TNetData.NetData.ConnectionExistsAndActive(nc) then begin
|
|
|
+ FNode.SendNodeMessage(nc,m,errors);
|
|
|
+ memoMessages.Lines.Add(DateTimeToStr(now)+' Sent to '+nc.ClientRemoteAddr+' > '+m);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ nc := TNetConnection(lbNetconnections.Items.Objects[lbNetconnections.ItemIndex]);
|
|
|
+ if TNetData.NetData.ConnectionExistsAndActive(nc) then begin
|
|
|
+ FNode.SendNodeMessage(nc,m,errors);
|
|
|
+ memoMessages.Lines.Add(DateTimeToStr(now)+' Sent to '+nc.ClientRemoteAddr+' > '+m);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ Application.MessageBox(PChaR('Message sent to '+inttostr(n)+' nodes'+#10+
|
|
|
+ 'Message: '+#10+m),PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.cbExploreMyAccountsClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ cbMyPrivateKeys.Enabled := cbExploreMyAccounts.Checked;
|
|
|
+ UpdateAccounts(true);
|
|
|
+ UpdateOperations;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.cbFilterAccountsClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ If not DoUpdateAccountsFilter then UpdateAccounts(true);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.cbMyPrivateKeysChange(Sender: TObject);
|
|
|
+begin
|
|
|
+ UpdateAccounts(true);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.CheckIsReady;
|
|
|
+Var isready : AnsiString;
|
|
|
+begin
|
|
|
+ if Not Assigned(FNode) then Abort;
|
|
|
+
|
|
|
+ if Not FNode.IsReady(isready) then begin
|
|
|
+ Raise Exception.Create('You cannot do this operation now:'+#10+#10+isready);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.CM_NetConnectionUpdated(var Msg: TMessage);
|
|
|
+Const CT_BooleanToString : Array[Boolean] of String = ('False','True');
|
|
|
+Var i : integer;
|
|
|
+ NC : TNetConnection;
|
|
|
+ l : TList;
|
|
|
+ sClientApp, sLastConnTime : String;
|
|
|
+ strings, sNSC, sRS, sDisc : TStrings;
|
|
|
+ hh,nn,ss,ms : Word;
|
|
|
+begin
|
|
|
+ Try
|
|
|
+ if Not TNetData.NetData.NetConnections.TryLockList(100,l) then exit;
|
|
|
+ try
|
|
|
+ strings := memoNetConnections.Lines;
|
|
|
+ sNSC := TStringList.Create;
|
|
|
+ sRS := TStringList.Create;
|
|
|
+ sDisc := TStringList.Create;
|
|
|
+ strings.BeginUpdate;
|
|
|
+ Try
|
|
|
+ for i := 0 to l.Count - 1 do begin
|
|
|
+ NC := l[i];
|
|
|
+ If NC.Client.BytesReceived>0 then begin
|
|
|
+ sClientApp := '['+IntToStr(NC.NetProtocolVersion.protocol_version)+'-'+IntToStr(NC.NetProtocolVersion.protocol_available)+'] '+NC.ClientAppVersion;
|
|
|
+ end else begin
|
|
|
+ sClientApp := '(no data)';
|
|
|
+ end;
|
|
|
+
|
|
|
+ if NC.Connected then begin
|
|
|
+ if NC.Client.LastCommunicationTime>1000 then begin
|
|
|
+ DecodeTime(now - NC.Client.LastCommunicationTime,hh,nn,ss,ms);
|
|
|
+ if (hh=0) and (nn=0) And (ss<10) then begin
|
|
|
+ sLastConnTime := ' - Last comunication <10 sec.';
|
|
|
+ end else begin
|
|
|
+ sLastConnTime := Format(' - Last comunication %.2dm%.2ds',[(hh*60)+nn,ss]);
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ sLastConnTime := '';
|
|
|
+ end;
|
|
|
+ if NC is TNetServerClient then begin
|
|
|
+ sNSC.Add(Format('Client: IP:%s Block:%d Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
|
|
|
+ [NC.ClientRemoteAddr,NC.RemoteOperationBlock.block,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]));
|
|
|
+ end else begin
|
|
|
+ if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
|
|
|
+ [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]))
|
|
|
+ else begin
|
|
|
+ sRS.Add(Format('Remote Server: IP:%s Block:%d Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
|
|
|
+ [NC.ClientRemoteAddr,NC.RemoteOperationBlock.block,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ if NC is TNetServerClient then begin
|
|
|
+ sDisc.Add(Format('Disconnected client: IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
|
|
|
+ end else if NC.IsMyselfServer then begin
|
|
|
+ sDisc.Add(Format('Disconnected MySelf IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
|
|
|
+ end else begin
|
|
|
+ sDisc.Add(Format('Disconnected Remote Server: IP:%s %s - %s',[NC.ClientRemoteAddr,CT_BooleanToString[NC.Connected],sClientApp]));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ strings.Clear;
|
|
|
+ strings.Add(Format('Connections Updated %s Clients:%d Servers:%d (valid servers:%d)',[DateTimeToStr(now),sNSC.Count,sRS.Count,TNetData.NetData.NetStatistics.ServersConnectionsWithResponse]));
|
|
|
+ strings.AddStrings(sRS);
|
|
|
+ strings.AddStrings(sNSC);
|
|
|
+ if sDisc.Count>0 then begin
|
|
|
+ strings.Add('');
|
|
|
+ strings.Add('Disconnected connections: '+Inttostr(sDisc.Count));
|
|
|
+ strings.AddStrings(sDisc);
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ strings.EndUpdate;
|
|
|
+ sNSC.Free;
|
|
|
+ sRS.Free;
|
|
|
+ sDisc.Free;
|
|
|
+ End;
|
|
|
+ //CheckMining;
|
|
|
+ finally
|
|
|
+ TNetData.NetData.NetConnections.UnlockList;
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ FMustProcessNetConnectionUpdated := false;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.CM_WalletChanged(var Msg: TMessage);
|
|
|
+begin
|
|
|
+ UpdatePrivateKeys;
|
|
|
+ FMustProcessWalletChanged := false;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.dgAccountsClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ UpdateOperations;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.dgAccountsColumnMoved(Sender: TObject; FromIndex, ToIndex: Integer);
|
|
|
+begin
|
|
|
+ SaveAppParams;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.dgAccountsFixedCellClick(Sender: TObject; ACol,
|
|
|
+ ARow: Integer);
|
|
|
+begin
|
|
|
+ SaveAppParams;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.DoUpdateAccounts;
|
|
|
+begin
|
|
|
+ UpdateAccounts(true);
|
|
|
+end;
|
|
|
+
|
|
|
+function TFRMWallet.DoUpdateAccountsFilter: Boolean;
|
|
|
+Var m,bmin,bmax:Int64;
|
|
|
+ doupd : Boolean;
|
|
|
+begin
|
|
|
+ if FUpdating then exit;
|
|
|
+ FUpdating := true;
|
|
|
+ Try
|
|
|
+ If Not TAccountComp.TxtToMoney(ebFilterAccountByBalanceMin.Text,bmin) then bmin := 0;
|
|
|
+ If not TAccountComp.TxtToMoney(ebFilterAccountByBalanceMax.Text,bmax) then bmax := CT_MaxWalletAmount;
|
|
|
+ if (bmax<bmin) or (bmax=0) then bmax := CT_MaxWalletAmount;
|
|
|
+ if bmin>bmax then bmin := 0;
|
|
|
+ doupd := (bmin<>FMinAccountBalance) Or (bmax<>FMaxAccountBalance);
|
|
|
+ FMinAccountBalance := bmin;
|
|
|
+ FMaxAccountBalance := bmax;
|
|
|
+ if bmin>0 then
|
|
|
+ ebFilterAccountByBalanceMin.Text:=TAccountComp.FormatMoney(bmin)
|
|
|
+ else ebFilterAccountByBalanceMin.Text := '';
|
|
|
+ if bmax<CT_MaxWalletAmount then
|
|
|
+ ebFilterAccountByBalanceMax.Text := TAccountComp.FormatMoney(bmax)
|
|
|
+ else ebFilterAccountByBalanceMax.Text := '';
|
|
|
+ if cbFilterAccounts.Checked then begin
|
|
|
+ ebFilterAccountByBalanceMin.ParentFont := true;
|
|
|
+ ebFilterAccountByBalanceMax.ParentFont := true;
|
|
|
+ end else begin
|
|
|
+ ebFilterAccountByBalanceMin.font.Color := clDkGray;
|
|
|
+ ebFilterAccountByBalanceMax.font.Color := clDkGray;
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ FUpdating := false;
|
|
|
+ End;
|
|
|
+ if doupd then UpdateAccounts(true);
|
|
|
+ Result := doupd;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ebBlockChainBlockStartExit(Sender: TObject);
|
|
|
+var bstart,bend : Int64;
|
|
|
+begin
|
|
|
+ If FUpdating then exit;
|
|
|
+ FUpdating := True;
|
|
|
+ Try
|
|
|
+ bstart := StrToInt64Def(ebBlockChainBlockStart.Text,-1);
|
|
|
+ bend := StrToInt64Def(ebBlockChainBlockEnd.Text,-1);
|
|
|
+ FBlockChainGrid.SetBlocks(bstart,bend);
|
|
|
+ if FBlockChainGrid.BlockStart>=0 then ebBlockChainBlockStart.Text := Inttostr(FBlockChainGrid.BlockStart) else ebBlockChainBlockStart.Text := '';
|
|
|
+ if FBlockChainGrid.BlockEnd>=0 then ebBlockChainBlockEnd.Text := Inttostr(FBlockChainGrid.BlockEnd) else ebBlockChainBlockEnd.Text := '';
|
|
|
+ Finally
|
|
|
+ FUpdating := false;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ebBlockChainBlockStartKeyPress(Sender: TObject;
|
|
|
+ var Key: Char);
|
|
|
+begin
|
|
|
+ if key=#13 then ebBlockChainBlockStartExit(Nil);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ebFilterAccountByBalanceMinExit(Sender: TObject);
|
|
|
+begin
|
|
|
+ DoUpdateAccountsFilter;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ebFilterAccountByBalanceMinKeyPress(Sender: TObject;
|
|
|
+ var Key: Char);
|
|
|
+begin
|
|
|
+ if key=#13 then DoUpdateAccountsFilter;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ebFilterOperationsAccountExit(Sender: TObject);
|
|
|
+Var bstart,bend : Int64;
|
|
|
+begin
|
|
|
+ If FUpdating then exit;
|
|
|
+ FUpdating := True;
|
|
|
+ Try
|
|
|
+ bstart := StrToInt64Def(ebFilterOperationsStartBlock.Text,-1);
|
|
|
+ if bstart>=0 then ebFilterOperationsStartBlock.Text := Inttostr(bstart) else ebFilterOperationsStartBlock.Text := '';
|
|
|
+ bend := StrToInt64Def(ebFilterOperationsEndBlock.Text,-1);
|
|
|
+ if bend>=0 then ebFilterOperationsEndBlock.Text := Inttostr(bend) else ebFilterOperationsEndBlock.Text := '';
|
|
|
+ FOperationsExplorerGrid.SetBlocks(bstart,bend);
|
|
|
+ Finally
|
|
|
+ FUpdating := false;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ebFilterOperationsAccountKeyPress(Sender: TObject;
|
|
|
+ var Key: Char);
|
|
|
+begin
|
|
|
+ if key=#13 then ebFilterOperationsAccountExit(Nil);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ebFindAccountNumberChange(Sender: TObject);
|
|
|
+Var an : Cardinal;
|
|
|
+begin
|
|
|
+ if Trim(ebFindAccountNumber.Text)='' then begin
|
|
|
+ ebFindAccountNumber.Color := clWindow;
|
|
|
+ ebFindAccountNumber.Font.Color := clDkGray;
|
|
|
+ end else if TAccountComp.AccountTxtNumberToAccountNumber(ebFindAccountNumber.Text,an) then begin
|
|
|
+ ebFindAccountNumber.Color := clWindow;
|
|
|
+ if FAccountsGrid.MoveRowToAccount(an) then begin
|
|
|
+ ebFindAccountNumber.Font.Color := clWindowText;
|
|
|
+ end else begin
|
|
|
+ ebFindAccountNumber.Font.Color := clRed;
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ // Invalid value
|
|
|
+ ebFindAccountNumber.Color := clRed;
|
|
|
+ ebFindAccountNumber.Font.Color := clWindowText;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.ebFindAccountNumberExit(Sender: TObject);
|
|
|
+begin
|
|
|
+ ebFindAccountNumber.Text := '';
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.FinishedLoadingApp;
|
|
|
+begin
|
|
|
+ FPoolMiningServer := TPoolMiningServer.Create;
|
|
|
+ FPoolMiningServer.Port := FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port);
|
|
|
+ FPoolMiningServer.MinerAccountKey := GetAccountKeyForMiner;
|
|
|
+ FPoolMiningServer.MinerPayload := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
|
|
|
+ FNode.Operations.AccountKey := GetAccountKeyForMiner;
|
|
|
+ FPoolMiningServer.Active := FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].GetAsBoolean(true);
|
|
|
+ FPoolMiningServer.OnMiningServerNewBlockFound := OnMiningServerNewBlockFound;
|
|
|
+ If Assigned(FBackgroundPanel) then begin
|
|
|
+ FreeAndNil(FBackgroundPanel);
|
|
|
+ end;
|
|
|
+ PageControl.Visible:=True;
|
|
|
+ PageControl.Enabled:=True;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.FillAccountInformation(const Strings: TStrings; Const AccountNumber: Cardinal);
|
|
|
+Var account : TAccount;
|
|
|
+ s : String;
|
|
|
+begin
|
|
|
+ if AccountNumber<0 then exit;
|
|
|
+ account := FNode.Operations.SafeBoxTransaction.Account(AccountNumber);
|
|
|
+ if account.name<>'' then s:='Name: '+account.name
|
|
|
+ else s:='';
|
|
|
+ Strings.Add(Format('Account: %s %s Type:%d',[TAccountComp.AccountNumberToAccountTxtNumber(AccountNumber),s,account.account_type]));
|
|
|
+ Strings.Add('');
|
|
|
+ Strings.Add(Format('Current balance: %s',[TAccountComp.FormatMoney(account.balance)]));
|
|
|
+ Strings.Add('');
|
|
|
+ Strings.Add(Format('Updated on block: %d (%d blocks ago)',[account.updated_block,FNode.Bank.BlocksCount-account.updated_block]));
|
|
|
+ Strings.Add(Format('Public key type: %s',[TAccountComp.GetECInfoTxt(account.accountInfo.accountKey.EC_OpenSSL_NID)]));
|
|
|
+ Strings.Add(Format('Base58 Public key: %s',[TAccountComp.AccountPublicKeyExport(account.accountInfo.accountKey)]));
|
|
|
+ if TAccountComp.IsAccountForSale(account.accountInfo) then begin
|
|
|
+ Strings.Add('');
|
|
|
+ Strings.Add('** Account is for sale: **');
|
|
|
+ Strings.Add(Format('Price: %s',[TAccountComp.FormatMoney(account.accountInfo.price)]));
|
|
|
+ Strings.Add(Format('Seller account (where to pay): %s',[TAccountComp.AccountNumberToAccountTxtNumber(account.accountInfo.account_to_pay)]));
|
|
|
+ if TAccountComp.IsAccountForSaleAcceptingTransactions(account.accountInfo) then begin
|
|
|
+ Strings.Add('');
|
|
|
+ Strings.Add('** Private sale **');
|
|
|
+ Strings.Add(Format('New Base58 Public key: %s',[TAccountComp.AccountPublicKeyExport(account.accountInfo.new_publicKey)]));
|
|
|
+ Strings.Add('');
|
|
|
+ if TAccountComp.IsAccountLocked(account.accountInfo,FNode.Bank.BlocksCount) then begin
|
|
|
+ Strings.Add(Format('PURCHASE IS SECURE UNTIL BLOCK %d (current %d, remains %d)',
|
|
|
+ [account.accountInfo.locked_until_block,FNode.Bank.BlocksCount,account.accountInfo.locked_until_block-FNode.Bank.BlocksCount]));
|
|
|
+ end else begin
|
|
|
+ Strings.Add(Format('PURCHASE IS NOT SECURE (Expired on block %d, current %d)',
|
|
|
+ [account.accountInfo.locked_until_block,FNode.Bank.BlocksCount]));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.FillOperationInformation(const Strings: TStrings; Const OperationResume: TOperationResume);
|
|
|
+begin
|
|
|
+ If (not OperationResume.valid) then exit;
|
|
|
+ If OperationResume.Block<FNode.Bank.BlocksCount then
|
|
|
+ if (OperationResume.NOpInsideBlock>=0) then begin
|
|
|
+ Strings.Add(Format('Block: %d/%d',[OperationResume.Block,OperationResume.NOpInsideBlock]))
|
|
|
+ end else begin
|
|
|
+ Strings.Add(Format('Block: %d',[OperationResume.Block]))
|
|
|
+ end
|
|
|
+ else Strings.Add('** Pending operation not included on blockchain **');
|
|
|
+ Strings.Add(Format('%s',[OperationResume.OperationTxt]));
|
|
|
+ Strings.Add(Format('OpType:%d Subtype:%d',[OperationResume.OpType,OperationResume.OpSubtype]));
|
|
|
+ Strings.Add(Format('Operation Hash (ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash)]));
|
|
|
+ If (OperationResume.OperationHash_OLD<>'') then begin
|
|
|
+ Strings.Add(Format('Old Operation Hash (old_ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash_OLD)]));
|
|
|
+ end;
|
|
|
+ if (OperationResume.OriginalPayload<>'') then begin
|
|
|
+ Strings.Add(Format('Payload length:%d',[length(OperationResume.OriginalPayload)]));
|
|
|
+ If OperationResume.PrintablePayload<>'' then begin
|
|
|
+ Strings.Add(Format('Payload (human): %s',[OperationResume.PrintablePayload]));
|
|
|
+ end;
|
|
|
+ Strings.Add(Format('Payload (Hexadecimal): %s',[TCrypto.ToHexaString(OperationResume.OriginalPayload)]));
|
|
|
+ end;
|
|
|
+ If OperationResume.Balance>=0 then begin
|
|
|
+ Strings.Add(Format('Final balance: %s',[TAccountComp.FormatMoney(OperationResume.Balance)]));
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFRMWallet.ForceMining: Boolean;
|
|
|
+begin
|
|
|
+ Result := false;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.FormCreate(Sender: TObject);
|
|
|
+Var i : Integer;
|
|
|
+begin
|
|
|
+ FLastNodesCacheUpdatedTS := Now;
|
|
|
+ FBackgroundPanel := Nil;
|
|
|
+ FMustProcessWalletChanged := false;
|
|
|
+ FMustProcessNetConnectionUpdated := false;
|
|
|
+ FRPCServer := Nil;
|
|
|
+ FNode := Nil;
|
|
|
+ FPoolMiningServer := Nil;
|
|
|
+ FMinAccountBalance := 0;
|
|
|
+ FMaxAccountBalance := CT_MaxWalletAmount;
|
|
|
+ FMessagesUnreadCount := 0;
|
|
|
+ lblReceivedMessages.Visible := false;
|
|
|
+ memoNetConnections.Lines.Clear;
|
|
|
+ memoNetServers.Lines.Clear;
|
|
|
+ memoNetBlackLists.Lines.Clear;
|
|
|
+ memoMessages.Lines.Clear;
|
|
|
+ memoMessageToSend.Lines.Clear;
|
|
|
+ FUpdating := false;
|
|
|
+ FOrderedAccountsKeyList := Nil;
|
|
|
+ TimerUpdateStatus.Enabled := false;
|
|
|
+ FIsActivated := false;
|
|
|
+ FWalletKeys := TWalletKeysExt.Create(Self);
|
|
|
+ for i := 0 to StatusBar.Panels.Count - 1 do begin
|
|
|
+ StatusBar.Panels[i].Text := '';
|
|
|
+ end;
|
|
|
+ FLog := TLog.Create(Self);
|
|
|
+ FLog.OnNewLog := OnNewLog;
|
|
|
+ FLog.SaveTypes := [];
|
|
|
+ If Not ForceDirectories(TFolderHelper.GetPascalCoinDataFolder) then raise Exception.Create('Cannot create dir: '+TFolderHelper.GetPascalCoinDataFolder);
|
|
|
+ FAppParams := TAppParams.Create(self);
|
|
|
+ FAppParams.FileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'AppParams.prm';
|
|
|
+ FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
|
|
|
+ FNodeNotifyEvents.OnBlocksChanged := OnNewAccount;
|
|
|
+ FNodeNotifyEvents.OnNodeMessageEvent := OnNodeMessageEvent;
|
|
|
+ FAccountsGrid := TAccountsGrid.Create(Self);
|
|
|
+ FAccountsGrid.DrawGrid := dgAccounts;
|
|
|
+ FAccountsGrid.AllowMultiSelect := True;
|
|
|
+ FSelectedAccountsGrid := TAccountsGrid.Create(Self);
|
|
|
+ FSelectedAccountsGrid.DrawGrid := dgSelectedAccounts;
|
|
|
+ FSelectedAccountsGrid.OnUpdated := OnSelectedAccountsGridUpdated;
|
|
|
+ FOperationsAccountGrid := TOperationsGrid.Create(Self);
|
|
|
+ FOperationsAccountGrid.DrawGrid := dgAccountOperations;
|
|
|
+ FOperationsAccountGrid.MustShowAlwaysAnAccount := true;
|
|
|
+ FPendingOperationsGrid := TOperationsGrid.Create(Self);
|
|
|
+ FPendingOperationsGrid.DrawGrid := dgPendingOperations;
|
|
|
+ FPendingOperationsGrid.AccountNumber := -1; // all
|
|
|
+ FPendingOperationsGrid.PendingOperations := true;
|
|
|
+ FOperationsExplorerGrid := TOperationsGrid.Create(Self);
|
|
|
+ FOperationsExplorerGrid.DrawGrid := dgOperationsExplorer;
|
|
|
+ FOperationsExplorerGrid.AccountNumber := -1;
|
|
|
+ FOperationsExplorerGrid.PendingOperations := False;
|
|
|
+ FBlockChainGrid := TBlockChainGrid.Create(Self);
|
|
|
+ FBlockChainGrid.DrawGrid := dgBlockChainExplorer;
|
|
|
+ // FWalletKeys.OnChanged.Add( OnWalletChanged );
|
|
|
+ LoadAppParams;
|
|
|
+ UpdatePrivateKeys;
|
|
|
+ UpdateBlockChainState;
|
|
|
+ UpdateConnectionStatus;
|
|
|
+ PageControl.ActivePage := tsMyAccounts;
|
|
|
+ pcAccountsOptions.ActivePage := tsAccountOperations;
|
|
|
+ ebFilterOperationsStartBlock.Text := '';
|
|
|
+ ebFilterOperationsEndBlock.Text := '';
|
|
|
+ cbExploreMyAccountsClick(nil);
|
|
|
+
|
|
|
+ TrayIcon.Visible := true;
|
|
|
+ TrayIcon.Hint := Self.Caption;
|
|
|
+ TrayIcon.BalloonTitle := 'Restoring the window.';
|
|
|
+ TrayIcon.BalloonHint :=
|
|
|
+ 'Double click the system tray icon to restore Pascal Coin';
|
|
|
+ TrayIcon.BalloonFlags := bfInfo;
|
|
|
+ MinersBlocksFound := 0;
|
|
|
+ lblBuild.Caption := 'Build: '+CT_ClientAppVersion;
|
|
|
+ {$IFDEF TESTNET}
|
|
|
+ Image1.visible := false;
|
|
|
+ {$ENDIF}
|
|
|
+ PageControl.Enabled := False;
|
|
|
+ PageControl.Visible := False;
|
|
|
+ FBackgroundPanel := TPanel.Create(Self);
|
|
|
+ FBackgroundPanel.Parent:=Self;
|
|
|
+ FBackgroundPanel.Align:=alClient;
|
|
|
+ FBackgroundPanel.Font.Size:=15;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.FormDestroy(Sender: TObject);
|
|
|
+Var i : Integer;
|
|
|
+ step : String;
|
|
|
+begin
|
|
|
+ TLog.NewLog(ltinfo,Classname,'Destroying form - START');
|
|
|
+ Try
|
|
|
+ FreeAndNil(FRPCServer);
|
|
|
+ FreeAndNil(FPoolMiningServer);
|
|
|
+ step := 'Saving params';
|
|
|
+ SaveAppParams;
|
|
|
+ FreeAndNil(FAppParams);
|
|
|
+ //
|
|
|
+ step := 'Assigning nil events';
|
|
|
+ FLog.OnNewLog :=Nil;
|
|
|
+ FNodeNotifyEvents.Node := Nil;
|
|
|
+ FOperationsAccountGrid.Node := Nil;
|
|
|
+ FOperationsExplorerGrid.Node := Nil;
|
|
|
+ FPendingOperationsGrid.Node := Nil;
|
|
|
+ FAccountsGrid.Node := Nil;
|
|
|
+ FSelectedAccountsGrid.Node := Nil;
|
|
|
+ TNetData.NetData.OnReceivedHelloMessage := Nil;
|
|
|
+ TNetData.NetData.OnStatisticsChanged := Nil;
|
|
|
+ TNetData.NetData.OnNetConnectionsUpdated := Nil;
|
|
|
+ TNetData.NetData.OnNodeServersUpdated := Nil;
|
|
|
+ TNetData.NetData.OnBlackListUpdated := Nil;
|
|
|
+ //
|
|
|
+
|
|
|
+ step := 'Destroying NodeNotifyEvents';
|
|
|
+ FreeAndNil(FNodeNotifyEvents);
|
|
|
+ //
|
|
|
+ step := 'Assigning Nil to TNetData';
|
|
|
+ TNetData.NetData.OnReceivedHelloMessage := Nil;
|
|
|
+ TNetData.NetData.OnStatisticsChanged := Nil;
|
|
|
+
|
|
|
+ step := 'Destroying grids operators';
|
|
|
+ FreeAndNil(FOperationsAccountGrid);
|
|
|
+ FreeAndNil(FOperationsExplorerGrid);
|
|
|
+ FreeAndNil(FBlockChainGrid);
|
|
|
+
|
|
|
+ step := 'Ordered Accounts Key list';
|
|
|
+ FreeAndNil(FOrderedAccountsKeyList);
|
|
|
+
|
|
|
+ step := 'Desactivating Node';
|
|
|
+ TNode.Node.NetServer.Active := false;
|
|
|
+ FNode := Nil;
|
|
|
+
|
|
|
+ TNetData.NetData.Free;
|
|
|
+
|
|
|
+ step := 'Processing messages 1';
|
|
|
+ Application.ProcessMessages;
|
|
|
+
|
|
|
+ step := 'Destroying Node';
|
|
|
+ TNode.Node.Free;
|
|
|
+
|
|
|
+ step := 'Destroying Wallet';
|
|
|
+ FreeAndNil(FWalletKeys);
|
|
|
+ step := 'Processing messages 2';
|
|
|
+ Application.ProcessMessages;
|
|
|
+ step := 'Destroying stringslist';
|
|
|
+ Except
|
|
|
+ On E:Exception do begin
|
|
|
+ TLog.NewLog(lterror,Classname,'Error destroying Form step: '+step+' Errors ('+E.ClassName+'): ' +E.Message);
|
|
|
+ end;
|
|
|
+ End;
|
|
|
+ TLog.NewLog(ltinfo,Classname,'Destroying form - END');
|
|
|
+ FreeAndNil(FLog);
|
|
|
+ Sleep(100);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.sbSearchAccountClick(Sender: TObject);
|
|
|
+Var F : TFRMAccountSelect;
|
|
|
+begin
|
|
|
+ F := TFRMAccountSelect.Create(Self);
|
|
|
+ try
|
|
|
+ F.Node := FNode;
|
|
|
+ F.WalletKeys := FWalletKeys;
|
|
|
+ F.ShowModal;
|
|
|
+ finally
|
|
|
+ F.Free;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFRMWallet.GetAccountKeyForMiner: TAccountKey;
|
|
|
+Var PK : TECPrivateKey;
|
|
|
+ i : Integer;
|
|
|
+ PublicK : TECDSA_Public;
|
|
|
+begin
|
|
|
+ Result := CT_TECDSA_Public_Nul;
|
|
|
+ if Not Assigned(FWalletKeys) then exit;
|
|
|
+ if Not Assigned(FAppParams) then exit;
|
|
|
+ case FMinerPrivateKeyType of
|
|
|
+ mpk_NewEachTime: PublicK := CT_TECDSA_Public_Nul;
|
|
|
+ mpk_Selected: begin
|
|
|
+ PublicK := TAccountComp.RawString2Accountkey(FAppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].GetAsString(''));
|
|
|
+ end;
|
|
|
+ else
|
|
|
+ // Random
|
|
|
+ PublicK := CT_TECDSA_Public_Nul;
|
|
|
+ if FWalletKeys.Count>0 then PublicK := FWalletKeys.Key[Random(FWalletKeys.Count)].AccountKey;
|
|
|
+ end;
|
|
|
+ i := FWalletKeys.IndexOfAccountKey(PublicK);
|
|
|
+ if i>=0 then begin
|
|
|
+ if (FWalletKeys.Key[i].CryptedKey='') then i:=-1;
|
|
|
+ end;
|
|
|
+ if i<0 then begin
|
|
|
+ PK := TECPrivateKey.Create;
|
|
|
+ try
|
|
|
+ PK.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
|
|
|
+ FWalletKeys.AddPrivateKey('New for miner '+DateTimeToStr(Now), PK);
|
|
|
+ PublicK := PK.PublicKey;
|
|
|
+ finally
|
|
|
+ PK.Free;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ Result := PublicK;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.IPnodes1Click(Sender: TObject);
|
|
|
+Var FRM : TFRMNodesIp;
|
|
|
+begin
|
|
|
+ FRM := TFRMNodesIp.Create(Self);
|
|
|
+ Try
|
|
|
+ FRM.AppParams := FAppParams;
|
|
|
+ FRM.ShowModal;
|
|
|
+ Finally
|
|
|
+ FRM.Free;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.lblReceivedMessagesClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ PageControl.ActivePage := tsMessages;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.LoadAppParams;
|
|
|
+Var ms : TMemoryStream;
|
|
|
+ s : AnsiString;
|
|
|
+ fvi : TFileVersionInfo;
|
|
|
+begin
|
|
|
+ ms := TMemoryStream.Create;
|
|
|
+ Try
|
|
|
+ s := FAppParams.ParamByName[CT_PARAM_GridAccountsStream].GetAsString('');
|
|
|
+ ms.WriteBuffer(s[1],length(s));
|
|
|
+ ms.Position := 0;
|
|
|
+ // Disabled on V2: FAccountsGrid.LoadFromStream(ms);
|
|
|
+ Finally
|
|
|
+ ms.Free;
|
|
|
+ End;
|
|
|
+ If FAppParams.FindParam(CT_PARAM_MinerName)=Nil then begin
|
|
|
+ // New configuration... assigning a new random value
|
|
|
+ fvi := TFolderHelper.GetTFileVersionInfo(Application.ExeName);
|
|
|
+ FAppParams.ParamByName[CT_PARAM_MinerName].SetAsString('New Node '+DateTimeToStr(Now)+' - '+
|
|
|
+ fvi.InternalName+' Build:'+fvi.FileVersion);
|
|
|
+ end;
|
|
|
+ FBlockChainGrid.ShowTimeAverageColumns:={$IFDEF SHOW_AVERAGE_TIME_STATS}True;{$ELSE}False;{$ENDIF}
|
|
|
+ UpdateConfigChanged;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.miAboutPascalCoinClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ With TFRMAbout.Create(Self) do
|
|
|
+ try
|
|
|
+ showmodal;
|
|
|
+ finally
|
|
|
+ free;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiAccountInformationClick(Sender: TObject);
|
|
|
+Var F : TFRMMemoText;
|
|
|
+ accn : Int64;
|
|
|
+ s,title : String;
|
|
|
+ account : TAccount;
|
|
|
+ strings : TStrings;
|
|
|
+ i : Integer;
|
|
|
+ opr : TOperationResume;
|
|
|
+begin
|
|
|
+ accn := -1;
|
|
|
+ title := '';
|
|
|
+ strings := TStringList.Create;
|
|
|
+ try
|
|
|
+ opr := CT_TOperationResume_NUL;
|
|
|
+ if PageControl.ActivePage=tsOperations then begin
|
|
|
+ i := FOperationsExplorerGrid.DrawGrid.Row;
|
|
|
+ if (i>0) and (i<=FOperationsExplorerGrid.OperationsResume.Count) then begin
|
|
|
+ opr := FOperationsExplorerGrid.OperationsResume.OperationResume[i-1];
|
|
|
+ end;
|
|
|
+ end else if PageControl.ActivePage=tsPendingOperations then begin
|
|
|
+ i := FPendingOperationsGrid.DrawGrid.Row;
|
|
|
+ if (i>0) and (i<=FPendingOperationsGrid.OperationsResume.Count) then begin
|
|
|
+ opr := FPendingOperationsGrid.OperationsResume.OperationResume[i-1];
|
|
|
+ end;
|
|
|
+ end else if PageControl.ActivePage=tsMyAccounts then begin
|
|
|
+ accn := FAccountsGrid.AccountNumber(dgAccounts.Row);
|
|
|
+ if accn<0 then raise Exception.Create('Select an account');
|
|
|
+ FillAccountInformation(strings,accn);
|
|
|
+ title := 'Account '+TAccountComp.AccountNumberToAccountTxtNumber(accn)+' info';
|
|
|
+ i := FOperationsAccountGrid.DrawGrid.Row;
|
|
|
+ if (i>0) and (i<=FOperationsAccountGrid.OperationsResume.Count) then begin
|
|
|
+ opr := FOperationsAccountGrid.OperationsResume.OperationResume[i-1];
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ If (opr.valid) then begin
|
|
|
+ if accn>=0 then strings.Add('')
|
|
|
+ else title := 'Operation info';
|
|
|
+ strings.Add('Operation info:');
|
|
|
+ FillOperationInformation(strings,opr);
|
|
|
+ end else if accn<0 then Raise Exception.Create('No info available');
|
|
|
+ F := TFRMMemoText.Create(Self);
|
|
|
+ Try
|
|
|
+ F.Caption := title;
|
|
|
+ F.Memo.Lines.Assign(strings);
|
|
|
+ F.ShowModal;
|
|
|
+ Finally
|
|
|
+ F.Free;
|
|
|
+ End;
|
|
|
+ finally
|
|
|
+ strings.free;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiAddaccounttoSelectedClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ PageControl.ActivePage := tsMyAccounts;
|
|
|
+ PageControlChange(Nil);
|
|
|
+ pcAccountsOptions.ActivePage := tsMultiSelectAccounts;
|
|
|
+ sbSelectedAccountsAddClick(Sender);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiCloseClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ Close;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiDecodePayloadClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ if PageControl.ActivePage=tsOperations then begin
|
|
|
+ FOperationsExplorerGrid.ShowModalDecoder(FWalletKeys,FAppParams);
|
|
|
+ end else if PageControl.ActivePage=tsPendingOperations then begin
|
|
|
+ FPendingOperationsGrid.ShowModalDecoder(FWalletKeys,FAppParams);
|
|
|
+ end else if PageControl.ActivePage=tsMyAccounts then begin
|
|
|
+ FOperationsAccountGrid.ShowModalDecoder(FWalletKeys,FAppParams);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiFindaccountClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ PageControl.ActivePage := tsMyAccounts;
|
|
|
+ PageControlChange(Nil);
|
|
|
+ ebFindAccountNumber.SetFocus;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiFindnextaccountwithhighbalanceClick(Sender: TObject);
|
|
|
+Var an : Cardinal;
|
|
|
+ an64 : Int64;
|
|
|
+ start : TAccount;
|
|
|
+begin
|
|
|
+ PageControl.ActivePage := tsMyAccounts;
|
|
|
+ PageControlChange(Nil);
|
|
|
+ an64 := FAccountsGrid.AccountNumber(dgAccounts.Row);
|
|
|
+ if an64<0 then an := 0
|
|
|
+ else an := an64;
|
|
|
+ If an>=FNode.Bank.SafeBox.AccountsCount then exit;
|
|
|
+ start := FNode.Bank.SafeBox.Account(an);
|
|
|
+ while (an<FNode.Bank.SafeBox.AccountsCount) do begin
|
|
|
+ if FNode.Bank.SafeBox.Account(an).balance>start.balance then break
|
|
|
+ else inc(an);
|
|
|
+ end;
|
|
|
+ if (an<FNode.Bank.SafeBox.AccountsCount) then FAccountsGrid.MoveRowToAccount(an)
|
|
|
+ else raise Exception.Create('Not found any account higher than '+TAccountComp.AccountNumberToAccountTxtNumber(start.account)+' with balance higher than '+
|
|
|
+ TAccountComp.FormatMoney(start.balance));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiFindOperationbyOpHashClick(Sender: TObject);
|
|
|
+Var FRM : TFRMPayloadDecoder;
|
|
|
+ oph : String;
|
|
|
+begin
|
|
|
+ oph := '';
|
|
|
+ if Not InputQuery('Search operation by OpHash','Insert Operation Hash value (OpHash)',oph) then exit;
|
|
|
+ //
|
|
|
+ FRM := TFRMPayloadDecoder.Create(Self);
|
|
|
+ try
|
|
|
+ FRM.Init(CT_TOperationResume_NUL,WalletKeys,FAppParams);
|
|
|
+ FRM.DoFind(oph);
|
|
|
+ FRM.ShowModal;
|
|
|
+ finally
|
|
|
+ FRM.Free;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiFindpreviousaccountwithhighbalanceClick(Sender: TObject);
|
|
|
+Var an : Cardinal;
|
|
|
+ an64 : Int64;
|
|
|
+ start : TAccount;
|
|
|
+begin
|
|
|
+ PageControl.ActivePage := tsMyAccounts;
|
|
|
+ PageControlChange(Nil);
|
|
|
+ an64 := FAccountsGrid.AccountNumber(dgAccounts.Row);
|
|
|
+ if an64<0 then an := FNode.Bank.SafeBox.AccountsCount-1
|
|
|
+ else an := an64;
|
|
|
+ If an>=FNode.Bank.SafeBox.AccountsCount then exit;
|
|
|
+ start := FNode.Bank.SafeBox.Account(an);
|
|
|
+ while (an>0) do begin
|
|
|
+ if FNode.Bank.SafeBox.Account(an).balance>start.balance then break
|
|
|
+ else dec(an);
|
|
|
+ end;
|
|
|
+ if (FNode.Bank.SafeBox.Account(an).balance>start.balance) then FAccountsGrid.MoveRowToAccount(an)
|
|
|
+ else raise Exception.Create('Not found any account lower than '+TAccountComp.AccountNumberToAccountTxtNumber(start.account)+' with balance higher than '+
|
|
|
+ TAccountComp.FormatMoney(start.balance));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiMultiaccountoperationClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ PageControl.ActivePage := tsMyAccounts;
|
|
|
+ pcAccountsOptions.ActivePage := tsMultiSelectAccounts;
|
|
|
+ bbSelectedAccountsOperationClick(Sender);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.miNewOperationClick(Sender: TObject);
|
|
|
+var l : TOrderedCardinalList;
|
|
|
+begin
|
|
|
+ CheckIsReady;
|
|
|
+ With TFRMOperation.Create(Self) do
|
|
|
+ Try
|
|
|
+ l := TOrderedCardinalList.Create;
|
|
|
+ try
|
|
|
+ If FAccountsGrid.SelectedAccounts(l)<1 then raise Exception.Create('No row selected');
|
|
|
+ SenderAccounts.CopyFrom(l);
|
|
|
+ finally
|
|
|
+ l.Free;
|
|
|
+ end;
|
|
|
+ DefaultFee := FAppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInt64(0);
|
|
|
+ WalletKeys := FWalletKeys;
|
|
|
+ ShowModal;
|
|
|
+ Finally
|
|
|
+ Free;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.miOptionsClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ With TFRMPascalCoinWalletConfig.Create(Self) do
|
|
|
+ try
|
|
|
+ AppParams := Self.FAppParams;
|
|
|
+ WalletKeys := Self.FWalletKeys;
|
|
|
+ if ShowModal=MrOk then begin
|
|
|
+ SaveAppParams;
|
|
|
+ UpdateConfigChanged;
|
|
|
+ end;
|
|
|
+ finally
|
|
|
+ free;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.miPrivatekeysClick(Sender: TObject);
|
|
|
+Var FRM : TFRMWalletKeys;
|
|
|
+begin
|
|
|
+ FRM := TFRMWalletKeys.Create(Self);
|
|
|
+ Try
|
|
|
+ FRM.WalletKeys := FWalletKeys;
|
|
|
+ FRM.ShowModal;
|
|
|
+ UpdatePrivateKeys;
|
|
|
+ Finally
|
|
|
+ FRM.Free;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.MiRemoveaccountfromselectedClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ PageControl.ActivePage := tsMyAccounts;
|
|
|
+ PageControlChange(Nil);
|
|
|
+ pcAccountsOptions.ActivePage := tsMultiSelectAccounts;
|
|
|
+ sbSelectedAccountsDelClick(Sender);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnMiningServerNewBlockFound(Sender: TObject);
|
|
|
+begin
|
|
|
+ FPoolMiningServer.MinerAccountKey := GetAccountKeyForMiner;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnNetBlackListUpdated(Sender: TObject);
|
|
|
+Const CT_TRUE_FALSE : Array[Boolean] Of AnsiString = ('FALSE','TRUE');
|
|
|
+Var i,j,n : integer;
|
|
|
+ P : PNodeServerAddress;
|
|
|
+ l : TList;
|
|
|
+ strings : TStrings;
|
|
|
+begin
|
|
|
+ l := TNetData.NetData.NodeServersAddresses.LockList;
|
|
|
+ try
|
|
|
+ strings := memoNetBlackLists.Lines;
|
|
|
+ strings.BeginUpdate;
|
|
|
+ Try
|
|
|
+ strings.Clear;
|
|
|
+ strings.Add('BlackList Updated: '+DateTimeToStr(now)+' by TID:'+IntToHex(PtrInt(TThread.CurrentThread.ThreadID),8));
|
|
|
+ j := 0; n:=0;
|
|
|
+ for i := 0 to l.Count - 1 do begin
|
|
|
+ P := l[i];
|
|
|
+ if (P^.is_blacklisted) then begin
|
|
|
+ inc(n);
|
|
|
+ if Not P^.its_myself then begin
|
|
|
+ inc(j);
|
|
|
+ strings.Add(Format('Blacklist IP:%s:%d LastConnection:%s Reason: %s',
|
|
|
+ [
|
|
|
+ P^.ip,P^.port,
|
|
|
+ DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection))),P^.BlackListText]));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ Strings.Add(Format('Total Blacklisted IPs: %d (Total %d)',[j,n]));
|
|
|
+ Finally
|
|
|
+ strings.EndUpdate;
|
|
|
+ End;
|
|
|
+ finally
|
|
|
+ TNetData.NetData.NodeServersAddresses.UnlockList;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnNetConnectionsUpdated(Sender: TObject);
|
|
|
+begin
|
|
|
+ if FMustProcessNetConnectionUpdated then exit;
|
|
|
+ FMustProcessNetConnectionUpdated := true;
|
|
|
+ PostMessage(Self.Handle,CM_PC_NetConnectionUpdated,0,0);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnNetNodeServersUpdated(Sender: TObject);
|
|
|
+Var i : integer;
|
|
|
+ P : PNodeServerAddress;
|
|
|
+ l : TList;
|
|
|
+ strings : TStrings;
|
|
|
+ s : String;
|
|
|
+begin
|
|
|
+ l := TNetData.NetData.NodeServersAddresses.LockList;
|
|
|
+ try
|
|
|
+ strings := memoNetServers.Lines;
|
|
|
+ strings.BeginUpdate;
|
|
|
+ Try
|
|
|
+ strings.Clear;
|
|
|
+ strings.Add('NodeServers Updated: '+DateTimeToStr(now) +' Count: '+inttostr(l.Count));
|
|
|
+ for i := 0 to l.Count - 1 do begin
|
|
|
+ P := l[i];
|
|
|
+ if Not (P^.is_blacklisted) then begin
|
|
|
+ s := Format('Server IP:%s:%d',[P^.ip,P^.port]);
|
|
|
+ if (P^.last_connection_by_me>0) then begin
|
|
|
+ s := s + ' [Server] ';
|
|
|
+ end;
|
|
|
+
|
|
|
+ if Assigned(P.netConnection) then begin
|
|
|
+ If P.last_connection>0 then s := s+ ' ** ACTIVE **'
|
|
|
+ else s := s+' ** TRYING TO CONNECT **';
|
|
|
+ end;
|
|
|
+ if P.its_myself then begin
|
|
|
+ s := s+' ** NOT VALID ** '+P.BlackListText;
|
|
|
+ end;
|
|
|
+ if P.last_connection>0 then begin
|
|
|
+ s := s + ' Last connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection)));
|
|
|
+ end;
|
|
|
+ if P.last_connection_by_server>0 then begin
|
|
|
+ s := s + ' Last server connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection_by_server)));
|
|
|
+ end;
|
|
|
+ if (P.last_attempt_to_connect>0) then begin
|
|
|
+ s := s + ' Last attempt to connect: '+DateTimeToStr(P^.last_attempt_to_connect);
|
|
|
+ end;
|
|
|
+ if (P.total_failed_attemps_to_connect>0) then begin
|
|
|
+ s := s + ' (Attempts: '+inttostr(P^.total_failed_attemps_to_connect)+')';
|
|
|
+ end;
|
|
|
+
|
|
|
+ strings.Add(s);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ strings.EndUpdate;
|
|
|
+ End;
|
|
|
+ finally
|
|
|
+ TNetData.NetData.NodeServersAddresses.UnlockList;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnNetStatisticsChanged(Sender: TObject);
|
|
|
+Var NS : TNetStatistics;
|
|
|
+begin
|
|
|
+ //CheckMining;
|
|
|
+ if Assigned(FNode) then begin
|
|
|
+ If FNode.NetServer.Active then begin
|
|
|
+ StatusBar.Panels[0].Text := 'Active (Port '+Inttostr(FNode.NetServer.Port)+')';
|
|
|
+ end else StatusBar.Panels[0].Text := 'Server stopped';
|
|
|
+ NS := TNetData.NetData.NetStatistics;
|
|
|
+ StatusBar.Panels[1].Text := Format('Connections:%d Clients:%d Servers:%d - Rcvd:%d Kb Send:%d Kb',
|
|
|
+ [NS.ActiveConnections,NS.ClientsConnections,NS.ServersConnections,NS.BytesReceived DIV 1024,NS.BytesSend DIV 1024]);
|
|
|
+ end else begin
|
|
|
+ StatusBar.Panels[0].Text := '';
|
|
|
+ StatusBar.Panels[1].Text := '';
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnNewAccount(Sender: TObject);
|
|
|
+begin
|
|
|
+ Try
|
|
|
+ UpdateAccounts(false);
|
|
|
+ UpdateBlockChainState;
|
|
|
+ Except
|
|
|
+ On E:Exception do begin
|
|
|
+ E.Message := 'Error at OnNewAccount '+E.Message;
|
|
|
+ Raise;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnNewLog(logtype: TLogType; Time : TDateTime; ThreadID : TThreadID; const sender,logtext: AnsiString);
|
|
|
+Var s : AnsiString;
|
|
|
+begin
|
|
|
+ if (logtype=ltdebug) And (Not cbShowDebugLogs.Checked) then exit;
|
|
|
+ if ThreadID=MainThreadID then s := ' MAIN:' else s:=' TID:';
|
|
|
+ if MemoLogs.Lines.Count>300 then begin
|
|
|
+ // Limit max lines in logs...
|
|
|
+ memoLogs.Lines.BeginUpdate;
|
|
|
+ try
|
|
|
+ while memoLogs.Lines.Count>250 do memoLogs.Lines.Delete(0);
|
|
|
+ finally
|
|
|
+ memoLogs.Lines.EndUpdate;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ memoLogs.Lines.Add(formatDateTime('dd/mm/yyyy hh:nn:ss.zzz',Time)+s+IntToHex(PtrInt(ThreadID),8)+' ['+CT_LogType[Logtype]+'] <'+sender+'> '+logtext);
|
|
|
+ //
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnNodeMessageEvent(NetConnection: TNetConnection; MessageData: TRawBytes);
|
|
|
+Var s : String;
|
|
|
+begin
|
|
|
+ inc(FMessagesUnreadCount);
|
|
|
+ if Assigned(NetConnection) then begin
|
|
|
+ s := DateTimeToStr(now)+' Message received from '+NetConnection.ClientRemoteAddr;
|
|
|
+ memoMessages.Lines.Add(DateTimeToStr(now)+' Message received from '+NetConnection.ClientRemoteAddr+' Length '+inttostr(Length(MessageData))+' bytes');
|
|
|
+ memoMessages.Lines.Add('RECEIVED> '+MessageData);
|
|
|
+ if FAppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false) then begin
|
|
|
+ s := DateTimeToStr(now)+' Message from '+NetConnection.ClientRemoteAddr+#10+
|
|
|
+ 'Length '+inttostr(length(MessageData))+' bytes'+#10+#10;
|
|
|
+ if TCrypto.IsHumanReadable(MessageData) then begin
|
|
|
+ s := s + MessageData;
|
|
|
+ end else begin
|
|
|
+ s := s +'Value in hexadecimal:'+#10+
|
|
|
+ TCrypto.ToHexaString(MessageData);
|
|
|
+ end;
|
|
|
+ Application.MessageBox(PChar(s),PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ memoMessages.Lines.Add(DateTimeToStr(now)+' Internal message: '+MessageData);
|
|
|
+ end;
|
|
|
+ if FMessagesUnreadCount>1 then lblReceivedMessages.Caption := Format('You have received %d messages',[FMessagesUnreadCount])
|
|
|
+ else lblReceivedMessages.Caption := 'You have received 1 message';
|
|
|
+ lblReceivedMessages.Visible := true;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnReceivedHelloMessage(Sender: TObject);
|
|
|
+Var nsarr : TNodeServerAddressArray;
|
|
|
+ i : Integer;
|
|
|
+ s : AnsiString;
|
|
|
+begin
|
|
|
+ If (FLastNodesCacheUpdatedTS + EncodeTime(0,5,0,0) > Now) then exit; // Prevent continuous saving
|
|
|
+ FLastNodesCacheUpdatedTS := Now;
|
|
|
+ // Update node servers Peer Cache
|
|
|
+ nsarr := TNetData.NetData.NodeServersAddresses.GetValidNodeServers(true,0);
|
|
|
+ s := '';
|
|
|
+ for i := low(nsarr) to High(nsarr) do begin
|
|
|
+ if (s<>'') then s := s+';';
|
|
|
+ s := s + nsarr[i].ip+':'+IntToStr( nsarr[i].port );
|
|
|
+ end;
|
|
|
+ FAppParams.ParamByName[CT_PARAM_PeerCache].SetAsString(s);
|
|
|
+ TNode.Node.PeerCache := s;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnSelectedAccountsGridUpdated(Sender: TObject);
|
|
|
+begin
|
|
|
+ lblSelectedAccountsCount.Caption := Inttostr(FSelectedAccountsGrid.AccountsCount);
|
|
|
+ lblSelectedAccountsBalance.Caption := TAccountComp.FormatMoney( FSelectedAccountsGrid.AccountsBalance );
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.OnWalletChanged(Sender: TObject);
|
|
|
+begin
|
|
|
+ if FMustProcessWalletChanged then exit;
|
|
|
+ FMustProcessWalletChanged := true;
|
|
|
+ PostMessage(Self.Handle,CM_PC_WalletKeysChanged,0,0);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.PageControlChange(Sender: TObject);
|
|
|
+begin
|
|
|
+ MiDecodePayload.Enabled := false;
|
|
|
+ if PageControl.ActivePage=tsMyAccounts then begin
|
|
|
+ //FAccountsGrid.Node := FNode;
|
|
|
+ MiDecodePayload.Enabled := true;
|
|
|
+ FSelectedAccountsGrid.Node := FNode;
|
|
|
+ end else begin
|
|
|
+ //FAccountsGrid.Node := Nil;
|
|
|
+ FSelectedAccountsGrid.Node := Nil;
|
|
|
+ end;
|
|
|
+ if PageControl.ActivePage=tsPendingOperations then begin
|
|
|
+ FPendingOperationsGrid.Node := FNode;
|
|
|
+ MiDecodePayload.Enabled := true;
|
|
|
+ end else FPendingOperationsGrid.Node := Nil;
|
|
|
+ if PageControl.ActivePage=tsBlockChain then FBlockChainGrid.Node := FNode
|
|
|
+ else FBlockChainGrid.Node := Nil;
|
|
|
+ if PageControl.ActivePage=tsOperations then begin
|
|
|
+ FOperationsExplorerGrid.Node := FNode;
|
|
|
+ MiDecodePayload.Enabled := true;
|
|
|
+ end else FOperationsExplorerGrid.Node := Nil;
|
|
|
+ if PageControl.ActivePage=tsMessages then begin
|
|
|
+ UpdateAvailableConnections;
|
|
|
+ FMessagesUnreadCount := 0;
|
|
|
+ lblReceivedMessages.Visible := false;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.SaveAppParams;
|
|
|
+Var ms : TMemoryStream;
|
|
|
+ s : AnsiString;
|
|
|
+begin
|
|
|
+ ms := TMemoryStream.Create;
|
|
|
+ Try
|
|
|
+ FAccountsGrid.SaveToStream(ms);
|
|
|
+ ms.Position := 0;
|
|
|
+ setlength(s,ms.Size);
|
|
|
+ ms.ReadBuffer(s[1],ms.Size);
|
|
|
+ FAppParams.ParamByName[CT_PARAM_GridAccountsStream].SetAsString(s);
|
|
|
+ Finally
|
|
|
+ ms.Free;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.sbSelectedAccountsAddAllClick(Sender: TObject);
|
|
|
+Var lsource,ltarget : TOrderedCardinalList;
|
|
|
+ i : Integer;
|
|
|
+begin
|
|
|
+ lsource := FAccountsGrid.LockAccountsList;
|
|
|
+ Try
|
|
|
+ ltarget := FSelectedAccountsGrid.LockAccountsList;
|
|
|
+ Try
|
|
|
+ for i := 0 to lsource.Count-1 do begin
|
|
|
+ if FWalletKeys.IndexOfAccountKey(FNode.Bank.SafeBox.Account(lsource.Get(i)).accountInfo.accountKey)<0 then raise Exception.Create(Format('You cannot operate with account %d because private key not found in your wallet',[lsource.Get(i)]));
|
|
|
+ ltarget.Add(lsource.Get(i));
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ FSelectedAccountsGrid.UnlockAccountsList;
|
|
|
+ End;
|
|
|
+ Finally
|
|
|
+ FAccountsGrid.UnlockAccountsList;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.sbSelectedAccountsAddClick(Sender: TObject);
|
|
|
+Var l, selected : TOrderedCardinalList;
|
|
|
+ an : Int64;
|
|
|
+ i : Integer;
|
|
|
+begin
|
|
|
+ an := FAccountsGrid.AccountNumber(dgAccounts.Row);
|
|
|
+ if (an<0) then raise Exception.Create('No account selected');
|
|
|
+ if FWalletKeys.IndexOfAccountKey(FNode.Bank.SafeBox.Account(an).accountInfo.accountkey)<0 then
|
|
|
+ raise Exception.Create(Format('You cannot add %s account because private key not found in your wallet.'#10+#10+'You''re not the owner!',
|
|
|
+ [TAccountComp.AccountNumberToAccountTxtNumber(an)]));
|
|
|
+ // Add
|
|
|
+ l := FSelectedAccountsGrid.LockAccountsList;
|
|
|
+ selected := TOrderedCardinalList.Create;
|
|
|
+ Try
|
|
|
+ FAccountsGrid.SelectedAccounts(selected);
|
|
|
+ for i := 0 to selected.Count-1 do begin
|
|
|
+ l.Add(selected.Get(i));
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ selected.Free;
|
|
|
+ FSelectedAccountsGrid.UnlockAccountsList;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.sbSelectedAccountsDelAllClick(Sender: TObject);
|
|
|
+Var l : TOrderedCardinalList;
|
|
|
+begin
|
|
|
+ l := FSelectedAccountsGrid.LockAccountsList;
|
|
|
+ try
|
|
|
+ l.Clear;
|
|
|
+ finally
|
|
|
+ FSelectedAccountsGrid.UnlockAccountsList;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.sbSelectedAccountsDelClick(Sender: TObject);
|
|
|
+Var an : Int64;
|
|
|
+ l : TOrderedCardinalList;
|
|
|
+begin
|
|
|
+ l := FSelectedAccountsGrid.LockAccountsList;
|
|
|
+ try
|
|
|
+ an := FSelectedAccountsGrid.AccountNumber(dgSelectedAccounts.Row);
|
|
|
+ if an>=0 then l.Remove(an);
|
|
|
+ finally
|
|
|
+ FSelectedAccountsGrid.UnlockAccountsList;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.SetMinersBlocksFound(const Value: Integer);
|
|
|
+begin
|
|
|
+ FMinersBlocksFound := Value;
|
|
|
+ lblBlocksFound.Caption := Inttostr(Value);
|
|
|
+ if Value>0 then lblBlocksFound.Font.Color := clGreen
|
|
|
+ else lblBlocksFound.Font.Color := clDkGray;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.TimerUpdateStatusTimer(Sender: TObject);
|
|
|
+begin
|
|
|
+ Try
|
|
|
+ UpdateConnectionStatus;
|
|
|
+ UpdateBlockChainState;
|
|
|
+ UpdateNodeStatus;
|
|
|
+ Except
|
|
|
+ On E:Exception do begin
|
|
|
+ E.Message := 'Exception at TimerUpdate '+E.ClassName+': '+E.Message;
|
|
|
+ TLog.NewLog(lterror,ClassName,E.Message);
|
|
|
+ end;
|
|
|
+ End;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.TrayIconDblClick(Sender: TObject);
|
|
|
+begin
|
|
|
+ TrayIcon.Visible := False;
|
|
|
+ TimerUpdateStatus.Enabled := true;
|
|
|
+ Show();
|
|
|
+ WindowState := wsNormal;
|
|
|
+ Application.BringToFront();
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.UpdateAccounts(RefreshData : Boolean);
|
|
|
+Var accl : TOrderedCardinalList;
|
|
|
+ l : TOrderedCardinalList;
|
|
|
+ i,j,k : Integer;
|
|
|
+ c : Cardinal;
|
|
|
+ applyfilter : Boolean;
|
|
|
+ acc : TAccount;
|
|
|
+begin
|
|
|
+ If Not Assigned(FOrderedAccountsKeyList) Then exit;
|
|
|
+ if Not RefreshData then begin
|
|
|
+ dgAccounts.Invalidate;
|
|
|
+ exit;
|
|
|
+ end;
|
|
|
+ applyfilter := (cbFilterAccounts.Checked) and ((FMinAccountBalance>0) Or (FMaxAccountBalance<CT_MaxWalletAmount));
|
|
|
+ FAccountsGrid.ShowAllAccounts := (Not cbExploreMyAccounts.Checked) And (not applyfilter);
|
|
|
+ if Not FAccountsGrid.ShowAllAccounts then begin
|
|
|
+ accl := FAccountsGrid.LockAccountsList;
|
|
|
+ Try
|
|
|
+ accl.Clear;
|
|
|
+ if cbExploreMyAccounts.Checked then begin
|
|
|
+ if cbMyPrivateKeys.ItemIndex<0 then exit;
|
|
|
+ if cbMyPrivateKeys.ItemIndex=0 then begin
|
|
|
+ // All keys in the wallet
|
|
|
+ for i := 0 to FWalletKeys.Count - 1 do begin
|
|
|
+ j := FOrderedAccountsKeyList.IndexOfAccountKey(FWalletKeys[i].AccountKey);
|
|
|
+ if (j>=0) then begin
|
|
|
+ l := FOrderedAccountsKeyList.AccountKeyList[j];
|
|
|
+ for k := 0 to l.Count - 1 do begin
|
|
|
+ if applyfilter then begin
|
|
|
+ acc := FNode.Bank.SafeBox.Account(l.Get(k));
|
|
|
+ if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
|
|
|
+ end else accl.Add(l.Get(k));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex]);
|
|
|
+ if (i>=0) And (i<FWalletKeys.Count) then begin
|
|
|
+ j := FOrderedAccountsKeyList.IndexOfAccountKey(FWalletKeys[i].AccountKey);
|
|
|
+ if (j>=0) then begin
|
|
|
+ l := FOrderedAccountsKeyList.AccountKeyList[j];
|
|
|
+ for k := 0 to l.Count - 1 do begin
|
|
|
+ if applyfilter then begin
|
|
|
+ acc := FNode.Bank.SafeBox.Account(l.Get(k));
|
|
|
+ if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
|
|
|
+ end else accl.Add(l.Get(k));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ // There is a filter... check every account...
|
|
|
+ c := 0;
|
|
|
+ while (c<FNode.Bank.SafeBox.AccountsCount) do begin
|
|
|
+ acc := FNode.Bank.SafeBox.Account(c);
|
|
|
+ if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
|
|
|
+ inc(c);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ FAccountsGrid.UnlockAccountsList;
|
|
|
+ End;
|
|
|
+ lblAccountsCount.Caption := inttostr(accl.Count);
|
|
|
+ end else begin
|
|
|
+ lblAccountsCount.Caption := inttostr(FNode.Bank.AccountsCount);
|
|
|
+ end;
|
|
|
+ bbChangeKeyName.Enabled := cbExploreMyAccounts.Checked;
|
|
|
+ // Show Totals:
|
|
|
+ lblAccountsBalance.Caption := TAccountComp.FormatMoney(FAccountsGrid.AccountsBalance);
|
|
|
+ UpdateOperations;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.UpdateAvailableConnections;
|
|
|
+Var i : integer;
|
|
|
+ NC : TNetConnection;
|
|
|
+ l : TList;
|
|
|
+begin
|
|
|
+ if Not TNetData.NetData.NetConnections.TryLockList(100,l) then exit;
|
|
|
+ try
|
|
|
+ lbNetConnections.Items.BeginUpdate;
|
|
|
+ Try
|
|
|
+ lbNetConnections.Items.Clear;
|
|
|
+ for i := 0 to l.Count - 1 do begin
|
|
|
+ NC := l[i];
|
|
|
+ if NC.Connected then begin
|
|
|
+ if NC is TNetServerClient then begin
|
|
|
+ if Not NC.IsMyselfServer then begin
|
|
|
+ lbNetConnections.Items.AddObject(Format('Client: IP:%s',[NC.ClientRemoteAddr]),NC);
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ if Not NC.IsMyselfServer then begin
|
|
|
+ lbNetConnections.Items.AddObject(Format('Server: IP:%s',[NC.ClientRemoteAddr]),NC);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ Finally
|
|
|
+ lbNetConnections.Items.EndUpdate;
|
|
|
+ End;
|
|
|
+ finally
|
|
|
+ TNetData.NetData.NetConnections.UnlockList;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.UpdateBlockChainState;
|
|
|
+Var isMining : boolean;
|
|
|
+// hr : Int64;
|
|
|
+ i,mc : Integer;
|
|
|
+ s : String;
|
|
|
+ mtl : TList;
|
|
|
+ f, favg : real;
|
|
|
+begin
|
|
|
+ UpdateNodeStatus;
|
|
|
+ mc := 0;
|
|
|
+// hr := 0;
|
|
|
+ if Assigned(FNode) then begin
|
|
|
+ if FNode.Bank.BlocksCount>0 then begin
|
|
|
+ lblCurrentBlock.Caption := Inttostr(FNode.Bank.BlocksCount)+' (0..'+Inttostr(FNode.Bank.BlocksCount-1)+')'; ;
|
|
|
+ end else lblCurrentBlock.Caption := '(none)';
|
|
|
+ lblCurrentAccounts.Caption := Inttostr(FNode.Bank.AccountsCount);
|
|
|
+ lblCurrentBlockTime.Caption := UnixTimeToLocalElapsedTime(FNode.Bank.LastOperationBlock.timestamp);
|
|
|
+ lblOperationsPending.Caption := Inttostr(FNode.Operations.Count);
|
|
|
+ lblCurrentDifficulty.Caption := InttoHex(FNode.Operations.OperationBlock.compact_target,8);
|
|
|
+ favg := FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage);
|
|
|
+ f := (CT_NewLineSecondsAvg - favg) / CT_NewLineSecondsAvg;
|
|
|
+ lblTimeAverage.Caption := 'Last '+Inttostr(CT_CalcNewTargetBlocksAverage)+': '+FormatFloat('0.0',favg)+' sec. (Optimal '+Inttostr(CT_NewLineSecondsAvg)+'s) Deviation '+FormatFloat('0.00%',f*100);
|
|
|
+ if favg>=CT_NewLineSecondsAvg then begin
|
|
|
+ lblTimeAverage.Font.Color := clNavy;
|
|
|
+ end else begin
|
|
|
+ lblTimeAverage.Font.Color := clOlive;
|
|
|
+ end;
|
|
|
+ lblTimeAverageAux.Caption := Format('Last %d: %s sec. - %d: %s sec. - %d: %s sec. - %d: %s sec. - %d: %s sec.',[
|
|
|
+ CT_CalcNewTargetBlocksAverage * 2 ,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage * 2)),
|
|
|
+ ((CT_CalcNewTargetBlocksAverage * 3) DIV 2) ,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage((CT_CalcNewTargetBlocksAverage * 3) DIV 2)),
|
|
|
+ ((CT_CalcNewTargetBlocksAverage DIV 4)*3),FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(((CT_CalcNewTargetBlocksAverage DIV 4)*3))),
|
|
|
+ CT_CalcNewTargetBlocksAverage DIV 2,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage DIV 2)),
|
|
|
+ CT_CalcNewTargetBlocksAverage DIV 4,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage DIV 4))]);
|
|
|
+ end else begin
|
|
|
+ isMining := false;
|
|
|
+ lblCurrentBlock.Caption := '';
|
|
|
+ lblCurrentAccounts.Caption := '';
|
|
|
+ lblCurrentBlockTime.Caption := '';
|
|
|
+ lblOperationsPending.Caption := '';
|
|
|
+ lblCurrentDifficulty.Caption := '';
|
|
|
+ lblTimeAverage.Caption := '';
|
|
|
+ lblTimeAverageAux.Caption := '';
|
|
|
+ end;
|
|
|
+ if (Assigned(FPoolMiningServer)) And (FPoolMiningServer.Active) then begin
|
|
|
+ If FPoolMiningServer.ClientsCount>0 then begin
|
|
|
+ lblMinersClients.Caption := IntToStr(FPoolMiningServer.ClientsCount)+' connected JSON-RPC clients';
|
|
|
+ lblMinersClients.Font.Color := clNavy;
|
|
|
+ end else begin
|
|
|
+ lblMinersClients.Caption := 'No JSON-RPC clients';
|
|
|
+ lblMinersClients.Font.Color := clDkGray;
|
|
|
+ end;
|
|
|
+ MinersBlocksFound := FPoolMiningServer.ClientsWins;
|
|
|
+ end else begin
|
|
|
+ MinersBlocksFound := 0;
|
|
|
+ lblMinersClients.Caption := 'JSON-RPC server not active';
|
|
|
+ lblMinersClients.Font.Color := clRed;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.UpdateConfigChanged;
|
|
|
+Var wa : Boolean;
|
|
|
+ i : Integer;
|
|
|
+begin
|
|
|
+ tsLogs.TabVisible := FAppParams.ParamByName[CT_PARAM_ShowLogs].GetAsBoolean(false);
|
|
|
+ if (Not tsLogs.TabVisible) then begin
|
|
|
+ FLog.OnNewLog := Nil;
|
|
|
+ if PageControl.ActivePage = tsLogs then PageControl.ActivePage := tsMyAccounts;
|
|
|
+ end else FLog.OnNewLog := OnNewLog;
|
|
|
+ if FAppParams.ParamByName[CT_PARAM_SaveLogFiles].GetAsBoolean(false) then begin
|
|
|
+ if FAppParams.ParamByName[CT_PARAM_SaveDebugLogs].GetAsBoolean(false) then FLog.SaveTypes := CT_TLogTypes_ALL
|
|
|
+ else FLog.SaveTypes := CT_TLogTypes_DEFAULT;
|
|
|
+ FLog.FileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'PascalCointWallet.log';
|
|
|
+ end else begin
|
|
|
+ FLog.SaveTypes := [];
|
|
|
+ FLog.FileName := '';
|
|
|
+ end;
|
|
|
+ if Assigned(FNode) then begin
|
|
|
+ wa := FNode.NetServer.Active;
|
|
|
+ FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
|
|
|
+ FNode.NetServer.Active := wa;
|
|
|
+ FNode.Operations.BlockPayload := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
|
|
|
+ FNode.NodeLogFilename := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'blocks.log';
|
|
|
+ end;
|
|
|
+ if Assigned(FPoolMiningServer) then begin
|
|
|
+ if FPoolMiningServer.Port<>FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port) then begin
|
|
|
+ FPoolMiningServer.Active := false;
|
|
|
+ FPoolMiningServer.Port := FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port);
|
|
|
+ end;
|
|
|
+ FPoolMiningServer.Active :=FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].GetAsBoolean(true);
|
|
|
+ FPoolMiningServer.UpdateAccountAndPayload(GetAccountKeyForMiner,FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString(''));
|
|
|
+ end;
|
|
|
+ if Assigned(FRPCServer) then begin
|
|
|
+ FRPCServer.Active := FAppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
|
|
|
+ FRPCServer.ValidIPs := FAppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1');
|
|
|
+ end;
|
|
|
+ i := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random));
|
|
|
+ if (i>=Integer(Low(TMinerPrivatekey))) And (i<=Integer(High(TMinerPrivatekey))) then FMinerPrivateKeyType := TMinerPrivateKey(i)
|
|
|
+ else FMinerPrivateKeyType := mpk_Random;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.UpdateConnectionStatus;
|
|
|
+var errors : AnsiString;
|
|
|
+begin
|
|
|
+ UpdateNodeStatus;
|
|
|
+ OnNetStatisticsChanged(Nil);
|
|
|
+ if Assigned(FNode) then begin
|
|
|
+ if FNode.IsBlockChainValid(errors) then begin
|
|
|
+ StatusBar.Panels[2].Text := Format('Last account time:%s',
|
|
|
+ [FormatDateTime('dd/mm/yyyy hh:nn:ss',UnivDateTime2LocalDateTime(UnixToUnivDateTime( FNode.Bank.LastOperationBlock.timestamp )))]);
|
|
|
+ end else begin
|
|
|
+ StatusBar.Panels[2].Text := 'NO BLOCKCHAIN: '+errors;
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ StatusBar.Panels[2].Text := '';
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.UpdateNodeStatus;
|
|
|
+Var status : AnsiString;
|
|
|
+begin
|
|
|
+ If Not Assigned(FNode) then begin
|
|
|
+ lblNodeStatus.Font.Color := clRed;
|
|
|
+ lblNodeStatus.Caption := 'Initializing...';
|
|
|
+ end else begin
|
|
|
+ If FNode.IsReady(status) then begin
|
|
|
+ if TNetData.NetData.NetStatistics.ActiveConnections>0 then begin
|
|
|
+ lblNodeStatus.Font.Color := clGreen;
|
|
|
+ if TNetData.NetData.IsDiscoveringServers then begin
|
|
|
+ lblNodeStatus.Caption := 'Discovering servers';
|
|
|
+ end else if TNetData.NetData.IsGettingNewBlockChainFromClient then begin
|
|
|
+ lblNodeStatus.Caption := 'Obtaining new blockchain';
|
|
|
+ end else begin
|
|
|
+ lblNodeStatus.Caption := 'Running';
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ lblNodeStatus.Font.Color := clRed;
|
|
|
+ lblNodeStatus.Caption := 'Alone in the world...';
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ lblNodeStatus.Font.Color := clRed;
|
|
|
+ lblNodeStatus.Caption := status;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ If Assigned(FBackgroundPanel) then begin
|
|
|
+ FBackgroundPanel.Font.Color:=lblNodeStatus.Font.Color;
|
|
|
+ FBackgroundPanel.Caption:='Please wait until finished: '+lblNodeStatus.Caption;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.UpdateOperations;
|
|
|
+Var accn : Int64;
|
|
|
+begin
|
|
|
+ accn := FAccountsGrid.AccountNumber(dgAccounts.Row);
|
|
|
+ FOperationsAccountGrid.AccountNumber := accn;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFRMWallet.UpdatePrivateKeys;
|
|
|
+Var i,last_i : Integer;
|
|
|
+ wk : TWalletKey;
|
|
|
+ s : AnsiString;
|
|
|
+begin
|
|
|
+ If (Not Assigned(FOrderedAccountsKeyList)) And (Assigned(FNode)) Then begin
|
|
|
+ FOrderedAccountsKeyList := TOrderedAccountKeysList.Create(FNode.Bank.SafeBox,false);
|
|
|
+ end;
|
|
|
+ if (cbMyPrivateKeys.ItemIndex>=0) then last_i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex])
|
|
|
+ else last_i := -1;
|
|
|
+ cbMyPrivateKeys.items.BeginUpdate;
|
|
|
+ Try
|
|
|
+ cbMyPrivateKeys.Items.Clear;
|
|
|
+ For i:=0 to FWalletKeys.Count-1 do begin
|
|
|
+ wk := FWalletKeys.Key[i];
|
|
|
+ if assigned(FOrderedAccountsKeyList) then begin
|
|
|
+ FOrderedAccountsKeyList.AddAccountKey(wk.AccountKey);
|
|
|
+ end;
|
|
|
+ if (wk.Name='') then begin
|
|
|
+ s := 'Sha256='+TCrypto.ToHexaString( TCrypto.DoSha256( TAccountComp.AccountKey2RawString(wk.AccountKey) ) );
|
|
|
+ end else begin
|
|
|
+ s := wk.Name;
|
|
|
+ end;
|
|
|
+ if Not Assigned(wk.PrivateKey) then s := s + '(*)';
|
|
|
+ cbMyPrivateKeys.Items.AddObject(s,TObject(i));
|
|
|
+ end;
|
|
|
+ cbMyPrivateKeys.Sorted := true;
|
|
|
+ cbMyPrivateKeys.Sorted := false;
|
|
|
+ cbMyPrivateKeys.Items.InsertObject(0,'(All my private keys)',TObject(-1));
|
|
|
+ Finally
|
|
|
+ cbMyPrivateKeys.Items.EndUpdate;
|
|
|
+ End;
|
|
|
+ last_i := cbMyPrivateKeys.Items.IndexOfObject(TObject(last_i));
|
|
|
+ if last_i<0 then last_i := 0;
|
|
|
+ if cbMyPrivateKeys.Items.Count>last_i then cbMyPrivateKeys.ItemIndex := last_i
|
|
|
+ else if cbMyPrivateKeys.Items.Count>=0 then cbMyPrivateKeys.ItemIndex := 0;
|
|
|
+end;
|
|
|
+
|
|
|
+initialization
|
|
|
+ FRMWallet := Nil;
|
|
|
+end.
|