Browse Source

Core, GUI:
- Added helper unit
- Show Account/Operation info on right-click

Herman Schoenfeld 7 years ago
parent
commit
9b700fe918

+ 7 - 0
src/core/UBlockChain.pas

@@ -235,6 +235,7 @@ Type
     Class function DecodeOperationHash(Const operationHash : TRawBytes; var block, account,n_operation : Cardinal; var md160Hash : TRawBytes) : Boolean;
     Class function DecodeOperationHash(Const operationHash : TRawBytes; var block, account,n_operation : Cardinal; var md160Hash : TRawBytes) : Boolean;
     Class function EqualOperationHashes(Const operationHash1, operationHash2 : TRawBytes) : Boolean;
     Class function EqualOperationHashes(Const operationHash1, operationHash2 : TRawBytes) : Boolean;
     Class function FinalOperationHashAsHexa(Const operationHash : TRawBytes) : AnsiString;
     Class function FinalOperationHashAsHexa(Const operationHash : TRawBytes) : AnsiString;
+    class function OperationHashAsHexa(const operationHash : TRawBytes) : AnsiString;
     function Sha256 : TRawBytes;
     function Sha256 : TRawBytes;
   End;
   End;
 
 
@@ -2295,6 +2296,7 @@ begin
     Exit(false);
     Exit(false);
   If not TPCOperation.DecodeOperationHash(ophash,block,account,n_operation,md160Hash) then
   If not TPCOperation.DecodeOperationHash(ophash,block,account,n_operation,md160Hash) then
     Exit(false);
     Exit(false);
+  Result := true;
 end;
 end;
 
 
 class function TPCOperation.EqualOperationHashes(const operationHash1,operationHash2: TRawBytes): Boolean;
 class function TPCOperation.EqualOperationHashes(const operationHash1,operationHash2: TRawBytes): Boolean;
@@ -2316,6 +2318,11 @@ begin
   Result := TCrypto.ToHexaString(Copy(operationHash,5,28));
   Result := TCrypto.ToHexaString(Copy(operationHash,5,28));
 end;
 end;
 
 
+class function TPCOperation.OperationHashAsHexa(const operationHash: TRawBytes): AnsiString;
+begin
+  Result := TCrypto.ToHexaString(operationHash);
+end;
+
 procedure TPCOperation.InitializeData;
 procedure TPCOperation.InitializeData;
 begin
 begin
   FTag := 0;
   FTag := 0;

+ 119 - 0
src/core/UCoreHelpers.pas

@@ -0,0 +1,119 @@
+unit UCoreHelpers;
+
+{ Copyright (c) 2018 by PascalCoin Project
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+    Herman Schoenfeld <[email protected]>: unit creator
+}
+
+{$mode delphi}
+
+interface
+
+uses
+  Classes, SysUtils, UCrypto, UAccounts, UBlockChain;
+
+type
+
+TAccountHelper = record helper for TAccount
+  function GetAccountString : AnsiString;
+  function GetInfoText(const ABank : TPCBank) : utf8string;
+end;
+
+TOperationResumeHelper = record helper for TOperationResume
+  function GetPrintableOPHASH : AnsiString;
+  function GetInfoText(const ABank : TPCBank) : utf8string;
+end;
+
+implementation
+
+uses
+  UCommon, UMemory;
+
+{ TAccountHelper }
+
+function TAccountHelper.GetAccountString : AnsiString;
+begin
+  Result := TAccountComp.AccountNumberToAccountTxtNumber(Self.account);
+end;
+
+function TAccountHelper.GetInfoText(const ABank : TPCBank) : utf8string;
+var
+  builder : TStrings;
+  GC : TDisposables;
+begin
+  builder := GC.AddObject(TStringList.Create) as TStrings;
+  builder.Append(Format('Account: %s %s Type:%d',[TAccountComp.AccountNumberToAccountTxtNumber(self.account), IIF(Self.name<>'','Name: '+Self.name,'') ,Self.account_type]));
+   builder.Append('');
+   builder.Append(Format('Current balance: %s',[TAccountComp.FormatMoney(Self.balance)]));
+   builder.Append('');
+   builder.Append(Format('Updated on block: %d  (%d blocks ago)',[Self.updated_block, ABank.BlocksCount-Self.updated_block]));
+   builder.Append(Format('Public key type: %s',[TAccountComp.GetECInfoTxt(Self.accountInfo.accountKey.EC_OpenSSL_NID)]));
+   builder.Append(Format('Base58 Public key: %s',[TAccountComp.AccountPublicKeyExport(Self.accountInfo.accountKey)]));
+  if TAccountComp.IsAccountForSale(Self.accountInfo) then begin
+     builder.Append('');
+     builder.Append('** Account is for sale: **');
+     builder.Append(Format('Price: %s',[TAccountComp.FormatMoney(Self.accountInfo.price)]));
+     builder.Append(Format('Seller account (where to pay): %s',[TAccountComp.AccountNumberToAccountTxtNumber(Self.accountInfo.account_to_pay)]));
+    if TAccountComp.IsAccountForSaleAcceptingTransactions(Self.accountInfo) then begin
+       builder.Append('');
+       builder.Append('** Private sale **');
+       builder.Append(Format('New Base58 Public key: %s',[TAccountComp.AccountPublicKeyExport(Self.accountInfo.new_publicKey)]));
+       builder.Append('');
+      if TAccountComp.IsAccountLocked(Self.accountInfo, ABank.BlocksCount) then begin
+         builder.Append(Format('PURCHASE IS SECURE UNTIL BLOCK %d (current %d, remains %d)',
+          [Self.accountInfo.locked_until_block, ABank.BlocksCount,Self.accountInfo.locked_until_block - ABank.BlocksCount]));
+      end else begin
+         builder.Append(Format('PURCHASE IS NOT SECURE (Expired on block %d, current %d)',
+          [Self.accountInfo.locked_until_block, ABank.BlocksCount]));
+      end;
+    end;
+  end;
+  Result :=  builder.Text;
+end;
+
+{ TOperationResumeHelper }
+
+function TOperationResumeHelper.GetPrintableOPHASH : AnsiString;
+begin
+  Result := TCrypto.ToHexaString(Self.OperationHash);
+end;
+
+function TOperationResumeHelper.GetInfoText(const ABank : TPCBank) : utf8string;
+var
+  builder : TStrings;
+  GC : TDisposables;
+begin
+  If (not Self.valid) then exit;
+  builder := GC.AddObject(TStringList.Create) as TStrings;
+  If Self.Block < ABank.BlocksCount then
+    if (Self.NOpInsideBlock>=0) then begin
+      builder.Add(Format('Block: %d/%d',[Self.Block,Self.NOpInsideBlock]))
+    end else begin
+      builder.Add(Format('Block: %d',[Self.Block]))
+    end
+  else builder.Add('** Pending operation not included on blockchain **');
+  builder.Add(Format('%s',[Self.OperationTxt]));
+  builder.Add(Format('OpType:%d Subtype:%d',[Self.OpType,Self.OpSubtype]));
+  builder.Add(Format('Operation Hash (ophash): %s',[TCrypto.ToHexaString(Self.OperationHash)]));
+  If (Self.OperationHash_OLD<>'') then begin
+    builder.Add(Format('Old Operation Hash (old_ophash): %s',[TCrypto.ToHexaString(Self.OperationHash_OLD)]));
+  end;
+  if (Self.OriginalPayload<>'') then begin
+    builder.Add(Format('Payload length:%d',[length(Self.OriginalPayload)]));
+    If Self.PrintablePayload<>'' then begin
+      builder.Add(Format('Payload (human): %s',[Self.PrintablePayload]));
+    end;
+    builder.Add(Format('Payload (Hexadecimal): %s',[TCrypto.ToHexaString(Self.OriginalPayload)]));
+  end;
+  If Self.Balance>=0 then begin
+    builder.Add(Format('Final balance: %s',[TAccountComp.FormatMoney(Self.Balance)]));
+  end;
+  Result := builder.Text;
+end;
+
+end.
+

+ 1 - 0
src/gui/UCTRLWallet.lfm

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

+ 4 - 3
src/gui/UCTRLWallet.pas

@@ -361,7 +361,9 @@ end;
 
 
 procedure TCTRLWallet.miAccountInfoClick(Sender: TObject);
 procedure TCTRLWallet.miAccountInfoClick(Sender: TObject);
 begin
 begin
-  raise ENotImplemented.Create('Not Implemented');
+  if FAccountsGrid.Selection.RowCount <> 1 then
+    exit;
+  TUserInterface.ShowAccountInfoDialog(Self, FAccountsGrid.SelectedRows[0].__KEY);
 end;
 end;
 
 
 procedure TCTRLWallet.miSendPASCClick(Sender: TObject);
 procedure TCTRLWallet.miSendPASCClick(Sender: TObject);
@@ -447,8 +449,7 @@ procedure TCTRLWallet.miOperationInfoClick(Sender: TObject);
 begin
 begin
   if FOperationsGrid.Selection.RowCount = 0 then
   if FOperationsGrid.Selection.RowCount = 0 then
     exit;
     exit;
-  TUserInterface.ShowOperationInfoDialog(Self,
-    FOperationsGrid.SelectedRows[0].EntityKey);
+  TUserInterface.ShowOperationInfoDialog(Self, FOperationsGrid.SelectedRows[0].__KEY);
 end;
 end;
 
 
 end.
 end.

+ 12 - 11
src/gui/UFRMAccountExplorer.lfm

@@ -12,10 +12,11 @@ object FRMAccountExplorer: TFRMAccountExplorer
   OnCreate = FormCreate
   OnCreate = FormCreate
   OnDestroy = FormDestroy
   OnDestroy = FormDestroy
   Position = poOwnerFormCenter
   Position = poOwnerFormCenter
+  LCLVersion = '1.8.2.0'
   Visible = False
   Visible = False
   object Splitter1: TSplitter
   object Splitter1: TSplitter
     Left = 380
     Left = 380
-    Height = 385
+    Height = 365
     Top = 66
     Top = 66
     Width = 5
     Width = 5
   end
   end
@@ -141,17 +142,17 @@ object FRMAccountExplorer: TFRMAccountExplorer
   end
   end
   object pnlAccounts: TPanel
   object pnlAccounts: TPanel
     Left = 0
     Left = 0
-    Height = 385
+    Height = 365
     Top = 66
     Top = 66
     Width = 380
     Width = 380
     Align = alLeft
     Align = alLeft
     BevelOuter = bvNone
     BevelOuter = bvNone
-    ClientHeight = 385
+    ClientHeight = 365
     ClientWidth = 380
     ClientWidth = 380
     TabOrder = 1
     TabOrder = 1
     object dgAccounts: TDrawGrid
     object dgAccounts: TDrawGrid
       Left = 0
       Left = 0
-      Height = 351
+      Height = 331
       Top = 0
       Top = 0
       Width = 380
       Width = 380
       Align = alClient
       Align = alClient
@@ -165,7 +166,7 @@ object FRMAccountExplorer: TFRMAccountExplorer
     object pnlAccountsInfo: TPanel
     object pnlAccountsInfo: TPanel
       Left = 0
       Left = 0
       Height = 34
       Height = 34
-      Top = 351
+      Top = 331
       Width = 380
       Width = 380
       Align = alBottom
       Align = alBottom
       BevelOuter = bvNone
       BevelOuter = bvNone
@@ -246,7 +247,7 @@ object FRMAccountExplorer: TFRMAccountExplorer
   end
   end
   object pcAccountsOptions: TPageControl
   object pcAccountsOptions: TPageControl
     Left = 385
     Left = 385
-    Height = 385
+    Height = 365
     Top = 66
     Top = 66
     Width = 483
     Width = 483
     ActivePage = tsMultiSelectAccounts
     ActivePage = tsMultiSelectAccounts
@@ -274,12 +275,12 @@ object FRMAccountExplorer: TFRMAccountExplorer
     end
     end
     object tsMultiSelectAccounts: TTabSheet
     object tsMultiSelectAccounts: TTabSheet
       Caption = 'Selected accounts for massive operations'
       Caption = 'Selected accounts for massive operations'
-      ClientHeight = 357
+      ClientHeight = 337
       ClientWidth = 475
       ClientWidth = 475
       ImageIndex = 1
       ImageIndex = 1
       object dgSelectedAccounts: TDrawGrid
       object dgSelectedAccounts: TDrawGrid
         Left = 41
         Left = 41
-        Height = 300
+        Height = 280
         Top = 31
         Top = 31
         Width = 325
         Width = 325
         Align = alLeft
         Align = alLeft
@@ -317,7 +318,7 @@ object FRMAccountExplorer: TFRMAccountExplorer
       object pnlSelectedAccountsBottom: TPanel
       object pnlSelectedAccountsBottom: TPanel
         Left = 0
         Left = 0
         Height = 26
         Height = 26
-        Top = 331
+        Top = 311
         Width = 475
         Width = 475
         Align = alBottom
         Align = alBottom
         BevelOuter = bvNone
         BevelOuter = bvNone
@@ -359,12 +360,12 @@ object FRMAccountExplorer: TFRMAccountExplorer
       end
       end
       object pnlSelectedAccountsLeft: TPanel
       object pnlSelectedAccountsLeft: TPanel
         Left = 0
         Left = 0
-        Height = 300
+        Height = 280
         Top = 31
         Top = 31
         Width = 41
         Width = 41
         Align = alLeft
         Align = alLeft
         BevelOuter = bvNone
         BevelOuter = bvNone
-        ClientHeight = 300
+        ClientHeight = 280
         ClientWidth = 41
         ClientWidth = 41
         TabOrder = 3
         TabOrder = 3
         object sbSelectedAccountsAdd: TSpeedButton
         object sbSelectedAccountsAdd: TSpeedButton

+ 19 - 89
src/gui/UFRMAccountExplorer.pas

@@ -190,8 +190,6 @@ type
     FOrderedAccountsKeyList : TOrderedAccountKeysList;
     FOrderedAccountsKeyList : TOrderedAccountKeysList;
     FMinAccountBalance : Int64;
     FMinAccountBalance : Int64;
     FMaxAccountBalance : Int64;
     FMaxAccountBalance : Int64;
-    Procedure FillAccountInformation(Const Strings : TStrings; Const AccountNumber : Cardinal);
-    Procedure FillOperationInformation(Const Strings : TStrings; Const OperationResume : TOperationResume);
     procedure OnPrivateKeysChanged(Sender: TObject);
     procedure OnPrivateKeysChanged(Sender: TObject);
   public
   public
     { public declarations }
     { public declarations }
@@ -265,69 +263,6 @@ end;
 
 
 {%region For auxillary methods}
 {%region For auxillary methods}
 
 
-procedure TFRMAccountExplorer.FillAccountInformation(const Strings: TStrings; Const AccountNumber: Cardinal);
-Var account : TAccount;
-  s : String;
-begin
-  account := TUserInterface.Node.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,TUserInterface.Node.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,TUserInterface.Node.Bank.BlocksCount) then begin
-        Strings.Add(Format('PURCHASE IS SECURE UNTIL BLOCK %d (current %d, remains %d)',
-          [account.accountInfo.locked_until_block,TUserInterface.Node.Bank.BlocksCount,account.accountInfo.locked_until_block-TUserInterface.Node.Bank.BlocksCount]));
-      end else begin
-        Strings.Add(Format('PURCHASE IS NOT SECURE (Expired on block %d, current %d)',
-          [account.accountInfo.locked_until_block,TUserInterface.Node.Bank.BlocksCount]));
-      end;
-    end;
-  end;
-end;
-
-procedure TFRMAccountExplorer.FillOperationInformation(const Strings: TStrings; Const OperationResume: TOperationResume);
-begin
-  If (not OperationResume.valid) then exit;
-  If OperationResume.Block<TUserInterface.Node.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;
-
 procedure TFRMAccountExplorer.RefreshAccountsGrid(RefreshData : Boolean);
 procedure TFRMAccountExplorer.RefreshAccountsGrid(RefreshData : Boolean);
 Var accl : TOrderedCardinalList;
 Var accl : TOrderedCardinalList;
   l : TOrderedCardinalList;
   l : TOrderedCardinalList;
@@ -736,34 +671,30 @@ end;
 procedure TFRMAccountExplorer.miAccountInformationClick(Sender: TObject);
 procedure TFRMAccountExplorer.miAccountInformationClick(Sender: TObject);
 Var F : TFRMMemoText;
 Var F : TFRMMemoText;
   accn : Int64 =-1;
   accn : Int64 =-1;
-  title : String;
-  strings : TStrings;
+  acc : TAccount;
   i : Integer;
   i : Integer;
   opr : TOperationResume;
   opr : TOperationResume;
 begin
 begin
   accn := -1;
   accn := -1;
-  title := '';
-  strings := TStringList.Create;
-  try
-    opr := CT_TOperationResume_NUL;
-    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 := FAccountOperationsGrid.DrawGrid.Row;
-    if (i>0) and (i<=FAccountOperationsGrid.OperationsResume.Count) then begin
-      opr := FAccountOperationsGrid.OperationsResume.OperationResume[i-1];
-    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');
-    TUserInterface.ShowMemoText(Self, title, strings);
-  finally
-    strings.free;
+  opr := CT_TOperationResume_NUL;
+  accn := FAccountsGrid.AccountNumber(dgAccounts.Row);
+  if accn<0 then
+    raise Exception.Create('Select an account');
+
+  if accn >= TUserInterface.Node.Bank.AccountsCount then
+    raise Exception.Create('Account not found');
+
+  acc := TUserInterface.Node.Operations.SafeBoxTransaction.Account(accn);
+
+  i := FAccountOperationsGrid.DrawGrid.Row;
+  if (i>0) and (i<=FAccountOperationsGrid.OperationsResume.Count) then begin
+    opr := FAccountOperationsGrid.OperationsResume.OperationResume[i-1];
   end;
   end;
+
+  If opr.valid then
+    TUserInterface.ShowAccountOperationInfoDialog(Self, acc, opr)
+  else
+    TUserInterface.ShowAccountInfoDialog(Self, acc);
 end;
 end;
 
 
 procedure TFRMAccountExplorer.miAddAccountToSelectedClick(Sender: TObject);
 procedure TFRMAccountExplorer.miAddAccountToSelectedClick(Sender: TObject);
@@ -786,6 +717,5 @@ end;
 
 
 {%endregion}
 {%endregion}
 
 
-
 end.
 end.
 
 

+ 1 - 1
src/gui/UFRMPayloadDecoder.lfm

@@ -15,7 +15,7 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
   Font.Name = 'Tahoma'
   Font.Name = 'Tahoma'
   OnCreate = FormCreate
   OnCreate = FormCreate
   Position = poOwnerFormCenter
   Position = poOwnerFormCenter
-  LCLVersion = '1.8.0.6'
+  LCLVersion = '1.8.2.0'
   Visible = False
   Visible = False
   object Label1: TLabel
   object Label1: TLabel
     Left = 20
     Left = 20

+ 3 - 2
src/gui/UFRMPayloadDecoder.pas

@@ -140,6 +140,7 @@ begin
   end;
   end;
   try
   try
     // Build 2.1.4 new decoder option: Check if OpHash is a posible double spend
     // Build 2.1.4 new decoder option: Check if OpHash is a posible double spend
+    r := TCrypto.HexaToRaw(trim(OpHash));
     If not TPCOperation.TryParseOperationHash(OpHash,nBlock,nAccount,nN_Operation,md160) then begin
     If not TPCOperation.TryParseOperationHash(OpHash,nBlock,nAccount,nN_Operation,md160) then begin
       raise Exception.Create('Invalid OPHASH');
       raise Exception.Create('Invalid OPHASH');
     end;
     end;
@@ -157,7 +158,7 @@ begin
       // Not found!
       // Not found!
       strings := TStringList.Create;
       strings := TStringList.Create;
       try
       try
-        strings.Add('Posible double spend detected!');
+        strings.Add('Possible double spend detected!');
         strings.Add(Format('OpHash: %s',[OpHash]));
         strings.Add(Format('OpHash: %s',[OpHash]));
         strings.Add(Format('Decode OpHash info: Block:%d Account:%s N_Operation:%d',[nBlock,TAccountComp.AccountNumberToAccountTxtNumber(nAccount),nN_Operation]));
         strings.Add(Format('Decode OpHash info: Block:%d Account:%s N_Operation:%d',[nBlock,TAccountComp.AccountNumberToAccountTxtNumber(nAccount),nN_Operation]));
         strings.Add('');
         strings.Add('');
@@ -170,7 +171,7 @@ begin
         OpResume := opr; // Do show operation resume!
         OpResume := opr; // Do show operation resume!
         FRM := TFRMMemoText.Create(Self);
         FRM := TFRMMemoText.Create(Self);
         try
         try
-          FRM.InitData('Posible double spend detected',strings.Text);
+          FRM.InitData('Possible double spend detected',strings.Text);
           FRM.ShowModal;
           FRM.ShowModal;
         finally
         finally
           FRM.Free;
           FRM.Free;

+ 44 - 3
src/gui/UUserInterface.pas

@@ -115,12 +115,16 @@ type
       // Show Dialogs
       // Show Dialogs
       class procedure ShowAboutBox(parentForm : TForm);
       class procedure ShowAboutBox(parentForm : TForm);
       class procedure ShowOptionsDialog(parentForm: TForm);
       class procedure ShowOptionsDialog(parentForm: TForm);
-      class procedure ShowOperationInfoDialog(parentForm: TForm; const ophash : AnsiString);
+      class procedure ShowAccountInfoDialog(parentForm: TForm; const account : Cardinal); overload;
+      class procedure ShowAccountInfoDialog(parentForm: TForm; const account : TAccount); overload;
+      class procedure ShowOperationInfoDialog(parentForm: TForm; const ophash : AnsiString); overload;
       class procedure ShowOperationInfoDialog(parentForm: TForm; const operation : TOperationResume); overload;
       class procedure ShowOperationInfoDialog(parentForm: TForm; const operation : TOperationResume); overload;
+      class procedure ShowAccountOperationInfoDialog(parentForm: TForm; const account : TAccount; const operation : TOperationResume); overload;
       class procedure ShowNewOperationDialog(parentForm : TForm; accounts : TOrderedCardinalList; defaultFee : Cardinal);
       class procedure ShowNewOperationDialog(parentForm : TForm; accounts : TOrderedCardinalList; defaultFee : Cardinal);
       class procedure ShowSeedNodesDialog(parentForm : TForm);
       class procedure ShowSeedNodesDialog(parentForm : TForm);
       class procedure ShowPrivateKeysDialog(parentForm: TForm);
       class procedure ShowPrivateKeysDialog(parentForm: TForm);
-      class procedure ShowMemoText(parentForm: TForm; const ATitle : AnsiString; text : TStrings);
+      class procedure ShowMemoText(parentForm: TForm; const ATitle : AnsiString; text : utf8string); overload;
+      class procedure ShowMemoText(parentForm: TForm; const ATitle : AnsiString; text : TStrings); overload;
       class procedure UnlockWallet(parentForm: TForm);
       class procedure UnlockWallet(parentForm: TForm);
       class procedure ChangeWalletPassword(parentForm: TForm);
       class procedure ChangeWalletPassword(parentForm: TForm);
       class procedure ShowInfo(parentForm : TForm; const ACaption, APrompt : String);
       class procedure ShowInfo(parentForm : TForm; const ACaption, APrompt : String);
@@ -149,11 +153,15 @@ type
     procedure BCExecute; override;
     procedure BCExecute; override;
   End;
   End;
 
 
+  { Exceptions }
+
+  EUserInterface = class(Exception);
+
 implementation
 implementation
 
 
 uses
 uses
   UFRMAbout, UFRMNodesIp, UFRMPascalCoinWalletConfig, UFRMPayloadDecoder, UFRMMemoText,
   UFRMAbout, UFRMNodesIp, UFRMPascalCoinWalletConfig, UFRMPayloadDecoder, UFRMMemoText,
-  UOpenSSL, UFileStorage, UTime, UCommon, USettings;
+  UOpenSSL, UFileStorage, UTime, UCommon, USettings, UCoreHelpers;
 
 
 {%region UI Lifecyle}
 {%region UI Lifecyle}
 
 
@@ -444,6 +452,26 @@ begin
   end;
   end;
 end;
 end;
 
 
+class procedure TUserInterface.ShowAccountInfoDialog(parentForm: TForm; const account: Cardinal);
+begin
+  if account >= TUserInterface.Node.Bank.AccountsCount then
+    raise EUserInterface.Create('Account not found');
+  ShowAccountInfoDialog(parentForm, TUserInterface.Node.Operations.SafeBoxTransaction.Account(account));
+end;
+
+class procedure TUserInterface.ShowAccountInfoDialog(parentForm: TForm; const account : TAccount); overload;
+begin
+  ShowMemoText(parentForm, Format('Account: %s', [account.GetAccountString]), account.GetInfoText(Self.Node.Bank));
+end;
+
+class procedure TUserInterface.ShowAccountOperationInfoDialog(parentForm: TForm; const account: TAccount; const operation : TOperationResume);
+var text : utf8string;
+begin
+  text := account.GetInfoText(Self.Node.Bank) + sLineBreak + sLineBreak + operation.GetInfoText(Self.Node.Bank);
+  ShowMemoText(parentForm, Format('Account/Operation: %s/%s', [account.GetAccountString, operation.GetPrintableOPHASH]), text);
+end;
+
+
 // TODO - refactor with accounts as ARRAY
 // TODO - refactor with accounts as ARRAY
 class procedure TUserInterface.ShowNewOperationDialog(parentForm : TForm; accounts : TOrderedCardinalList; defaultFee : Cardinal);
 class procedure TUserInterface.ShowNewOperationDialog(parentForm : TForm; accounts : TOrderedCardinalList; defaultFee : Cardinal);
 begin
 begin
@@ -482,6 +510,19 @@ begin
   end;
   end;
 end;
 end;
 
 
+class procedure TUserInterface.ShowMemoText(parentForm: TForm; const ATitle : AnsiString; text : utf8string);
+begin
+  with TFRMMemoText.Create(parentForm) do begin
+    try
+      Caption := ATitle;
+      Memo.Append(text);
+      ShowModal;
+    finally
+      Free;
+    end;
+  end;
+end;
+
 class procedure TUserInterface.ShowMemoText(parentForm: TForm; const ATitle : AnsiString; text : TStrings);
 class procedure TUserInterface.ShowMemoText(parentForm: TForm; const ATitle : AnsiString; text : TStrings);
 begin
 begin
   with TFRMMemoText.Create(parentForm) do begin
   with TFRMMemoText.Create(parentForm) do begin

+ 5 - 1
src/pascalcoin_wallet.lpi

@@ -33,7 +33,7 @@
         <PackageName Value="LCL"/>
         <PackageName Value="LCL"/>
       </Item1>
       </Item1>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="74">
+    <Units Count="75">
       <Unit0>
       <Unit0>
         <Filename Value="pascalcoin_wallet.dpr"/>
         <Filename Value="pascalcoin_wallet.dpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -419,6 +419,10 @@
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit73>
       </Unit73>
+      <Unit74>
+        <Filename Value="core\UCoreHelpers.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit74>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>