Pārlūkot izejas kodu

GUI Classic

Updated GUI classic with last development
Contains new Forms:
- Operations Explorer  (Allows generate MultiOperations)
- RPC Calls (To test JSON RPC calls)
- Random Operations (Only on TESTNET allows generate random operations)
PascalCoin 7 gadi atpakaļ
vecāks
revīzija
d87f2d8352

+ 288 - 0
src/gui-classic/UFRMOperationsExplorer.dfm

@@ -0,0 +1,288 @@
+object FRMOperationsExplorer: TFRMOperationsExplorer
+  Left = 471
+  Top = 231
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Operations Explorer Tool'
+  ClientHeight = 406
+  ClientWidth = 786
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = mMenu
+  OldCreateOrder = True
+  Position = poOwnerFormCenter
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  PixelsPerInch = 96
+  TextHeight = 13
+  object splitter: TSplitter
+    Left = 427
+    Top = 56
+    Width = 5
+    Height = 320
+  end
+  object lbOperations: TListBox
+    Left = 0
+    Top = 56
+    Width = 427
+    Height = 320
+    Align = alLeft
+    ItemHeight = 13
+    MultiSelect = True
+    TabOrder = 0
+    OnClick = lbOperationsClick
+  end
+  object pnlTop: TPanel
+    Left = 0
+    Top = 0
+    Width = 786
+    Height = 56
+    Align = alTop
+    BorderWidth = 5
+    TabOrder = 1
+    object lblTopCaption: TLabel
+      Left = 6
+      Top = 6
+      Width = 774
+      Height = 44
+      Align = alClient
+      AutoSize = False
+      Caption = 
+        'You can use this tool to explore operations, also you can copy/p' +
+        'aste operations as a RAW (Use Ctrl+I to Import). This tool allow' +
+        's to generate a Multioperation, send to third party the RAW, add' +
+        ' more txs... and then sign. Once Everybody has signed, you will ' +
+        'be able to EXECUTE OPERATION to be added to network nodes. '
+      Color = clBtnFace
+      ParentColor = False
+      WordWrap = True
+    end
+  end
+  object pnlBottom: TPanel
+    Left = 0
+    Top = 376
+    Width = 786
+    Height = 30
+    Align = alBottom
+    TabOrder = 2
+  end
+  object pnlOpInfo: TPanel
+    Left = 432
+    Top = 56
+    Width = 354
+    Height = 320
+    Align = alClient
+    TabOrder = 3
+    object pnlExport: TPanel
+      Left = 1
+      Top = 216
+      Width = 352
+      Height = 103
+      Align = alClient
+      Caption = 'pnlExport'
+      TabOrder = 0
+      object Label1: TLabel
+        Left = 1
+        Top = 1
+        Width = 350
+        Height = 25
+        Align = alTop
+        AutoSize = False
+        Caption = 'Operation as RAW:'
+        Color = clBtnFace
+        ParentColor = False
+        Layout = tlCenter
+      end
+      object mOperationExport: TMemo
+        Left = 1
+        Top = 26
+        Width = 350
+        Height = 76
+        Align = alClient
+        ReadOnly = True
+        TabOrder = 0
+      end
+    end
+    object pnlInfo: TPanel
+      Left = 1
+      Top = 1
+      Width = 352
+      Height = 215
+      Align = alTop
+      Caption = 'pnlInfo'
+      TabOrder = 1
+      object mOperationInfo: TMemo
+        Left = 1
+        Top = 87
+        Width = 350
+        Height = 127
+        Align = alClient
+        ReadOnly = True
+        ScrollBars = ssBoth
+        TabOrder = 0
+      end
+      object pnlInfoOptions: TPanel
+        Left = 1
+        Top = 1
+        Width = 350
+        Height = 86
+        Align = alTop
+        TabOrder = 1
+        object Label2: TLabel
+          Left = 10
+          Top = 39
+          Width = 109
+          Height = 13
+          Caption = 'Multioperation actions:'
+          Color = clBtnFace
+          ParentColor = False
+        end
+        object bbAddTx: TButton
+          Left = 8
+          Top = 56
+          Width = 67
+          Height = 25
+          Action = ActAddTx
+          TabOrder = 0
+        end
+        object bbAddOpChange: TButton
+          Left = 80
+          Top = 56
+          Width = 104
+          Height = 25
+          Action = ActAddOpChange
+          TabOrder = 1
+        end
+        object bbSign: TButton
+          Left = 256
+          Top = 56
+          Width = 80
+          Height = 25
+          Action = ActSign
+          TabOrder = 2
+        end
+        object bbExecuteOperation: TButton
+          Left = 8
+          Top = 8
+          Width = 176
+          Height = 25
+          Action = ActExecuteOperation
+          TabOrder = 3
+        end
+        object bbRemove: TButton
+          Left = 188
+          Top = 57
+          Width = 60
+          Height = 25
+          Action = ActRemove
+          TabOrder = 4
+        end
+        object Button1: TButton
+          Left = 261
+          Top = 16
+          Width = 75
+          Height = 25
+          Caption = 'Button1'
+          TabOrder = 5
+        end
+      end
+    end
+  end
+  object mMenu: TMainMenu
+    Left = 112
+    Top = 30
+    object MiTools: TMenuItem
+      Caption = 'Tools'
+      object MiImportOperationsFromTxt: TMenuItem
+        Caption = 'Import Operations from RAW'
+        ShortCut = 16457
+        OnClick = MiImportOperationsFromTxtClick
+      end
+      object MiDivider1: TMenuItem
+        Caption = '-'
+      end
+      object miLoadFromBlockchain: TMenuItem
+        Caption = 'Load Operations from Blockchain'
+        ShortCut = 16460
+        OnClick = miLoadFromBlockchainClick
+      end
+      object MiLoadOperationsFromBlockchainFile: TMenuItem
+        Caption = 'Load Operations from Blockchain file'
+        OnClick = MiLoadOperationsFromBlockchainFileClick
+      end
+    end
+    object MiActions: TMenuItem
+      Caption = 'Actions'
+      object MenuItem5: TMenuItem
+        Action = ActExecuteOperation
+      end
+      object MenuItem6: TMenuItem
+        Caption = '-'
+      end
+      object MenuItem1: TMenuItem
+        Action = AddOpChangeToMultioperation
+      end
+      object MenuItem2: TMenuItem
+        Action = ActAddTxToMultioperation
+      end
+      object MenuItem3: TMenuItem
+        Action = ActRemoveAccountFromMultioperation
+      end
+      object MenuItem4: TMenuItem
+        Action = ActSignMultioperation
+      end
+    end
+  end
+  object ActionList: TActionList
+    Left = 299
+    Top = 34
+    object ActExecuteOperation: TAction
+      Caption = 'Execute Operation'
+      OnExecute = ActExecuteOperationExecute
+      OnUpdate = ActExecuteOperationUpdate
+    end
+    object ActAddTxToMultioperation: TAction
+      Caption = 'Add Tx to Multioperation'
+      OnExecute = ActAddTxToMultioperationExecute
+      OnUpdate = ActAddTxToMultioperationUpdate
+    end
+    object AddOpChangeToMultioperation: TAction
+      Caption = 'Add OpChange to Multioperation'
+      OnExecute = AddOpChangeToMultioperationExecute
+      OnUpdate = AddOpChangeToMultioperationUpdate
+    end
+    object ActRemoveAccountFromMultioperation: TAction
+      Caption = 'Remove Account from Multioperation'
+      OnExecute = ActRemoveAccountFromMultioperationExecute
+      OnUpdate = ActRemoveAccountFromMultioperationUpdate
+    end
+    object ActSignMultioperation: TAction
+      Caption = 'Sign Multioperation'
+      OnExecute = ActSignMultioperationExecute
+      OnUpdate = ActSignMultioperationUpdate
+    end
+    object ActAddTx: TAction
+      Caption = 'Add Tx'
+      OnExecute = ActAddTxToMultioperationExecute
+      OnUpdate = ActAddTxToMultioperationUpdate
+    end
+    object ActAddOpChange: TAction
+      Caption = 'Add OpChange'
+      OnExecute = AddOpChangeToMultioperationExecute
+      OnUpdate = AddOpChangeToMultioperationUpdate
+    end
+    object ActRemove: TAction
+      Caption = 'Remove'
+      OnExecute = ActRemoveAccountFromMultioperationExecute
+      OnUpdate = ActRemoveAccountFromMultioperationUpdate
+    end
+    object ActSign: TAction
+      Caption = 'Sign'
+      OnExecute = ActSignMultioperationExecute
+      OnUpdate = ActExecuteOperationUpdate
+    end
+  end
+end

+ 294 - 0
src/gui-classic/UFRMOperationsExplorer.lfm

@@ -0,0 +1,294 @@
+object FRMOperationsExplorer: TFRMOperationsExplorer
+  Left = 471
+  Height = 426
+  Top = 231
+  Width = 786
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Operations Explorer Tool'
+  ClientHeight = 406
+  ClientWidth = 786
+  Menu = mMenu
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  Position = poOwnerFormCenter
+  LCLVersion = '1.8.0.6'
+  object lbOperations: TListBox
+    Left = 0
+    Height = 320
+    Top = 56
+    Width = 427
+    Align = alLeft
+    ItemHeight = 0
+    MultiSelect = True
+    OnClick = lbOperationsClick
+    TabOrder = 0
+  end
+  object pnlTop: TPanel
+    Left = 0
+    Height = 56
+    Top = 0
+    Width = 786
+    Align = alTop
+    BorderWidth = 5
+    ClientHeight = 56
+    ClientWidth = 786
+    TabOrder = 1
+    object lblTopCaption: TLabel
+      Left = 6
+      Height = 44
+      Top = 6
+      Width = 774
+      Align = alClient
+      AutoSize = False
+      Caption = 'You can use this tool to explore operations, also you can copy/paste operations as a RAW (Use Ctrl+I to Import). This tool allows to generate a Multioperation, send to third party the RAW, add more txs... and then sign. Once Everybody has signed, you will be able to EXECUTE OPERATION to be added to network nodes. '
+      ParentColor = False
+      WordWrap = True
+    end
+  end
+  object pnlBottom: TPanel
+    Left = 0
+    Height = 30
+    Top = 376
+    Width = 786
+    Align = alBottom
+    TabOrder = 2
+  end
+  object pnlOpInfo: TPanel
+    Left = 432
+    Height = 320
+    Top = 56
+    Width = 354
+    Align = alClient
+    ClientHeight = 320
+    ClientWidth = 354
+    TabOrder = 3
+    object pnlExport: TPanel
+      Left = 1
+      Height = 127
+      Top = 192
+      Width = 352
+      Align = alBottom
+      Caption = 'pnlExport'
+      ClientHeight = 127
+      ClientWidth = 352
+      TabOrder = 0
+      object mOperationExport: TMemo
+        Left = 1
+        Height = 100
+        Top = 26
+        Width = 350
+        Align = alClient
+        ReadOnly = True
+        TabOrder = 0
+      end
+      object Label1: TLabel
+        Left = 1
+        Height = 25
+        Top = 1
+        Width = 350
+        Align = alTop
+        AutoSize = False
+        Caption = 'Operation as RAW:'
+        Layout = tlCenter
+        ParentColor = False
+      end
+    end
+    object pnlInfo: TPanel
+      Left = 1
+      Height = 191
+      Top = 1
+      Width = 352
+      Align = alClient
+      Caption = 'pnlInfo'
+      ClientHeight = 191
+      ClientWidth = 352
+      TabOrder = 1
+      object mOperationInfo: TMemo
+        Left = 1
+        Height = 103
+        Top = 87
+        Width = 350
+        Align = alClient
+        ReadOnly = True
+        ScrollBars = ssBoth
+        TabOrder = 0
+      end
+      object pnlInfoOptions: TPanel
+        Left = 1
+        Height = 86
+        Top = 1
+        Width = 350
+        Align = alTop
+        ClientHeight = 86
+        ClientWidth = 350
+        TabOrder = 1
+        object bbAddTx: TButton
+          Left = 8
+          Height = 25
+          Top = 56
+          Width = 67
+          Action = ActAddTx
+          TabOrder = 2
+        end
+        object bbAddOpChange: TButton
+          Left = 80
+          Height = 25
+          Top = 56
+          Width = 104
+          Action = ActAddOpChange
+          TabOrder = 3
+        end
+        object bbSign: TButton
+          Left = 256
+          Height = 25
+          Top = 56
+          Width = 80
+          Action = ActSign
+          TabOrder = 5
+        end
+        object bbExecuteOperation: TButton
+          Left = 8
+          Height = 25
+          Top = 8
+          Width = 176
+          Action = ActExecuteOperation
+          TabOrder = 0
+        end
+        object Label2: TLabel
+          Left = 10
+          Height = 15
+          Top = 39
+          Width = 123
+          Caption = 'Multioperation actions:'
+          ParentColor = False
+        end
+        object bbRemove: TButton
+          Left = 188
+          Height = 25
+          Top = 57
+          Width = 60
+          Action = ActRemove
+          TabOrder = 4
+        end
+        object bbRandom: TButton
+          Left = 192
+          Height = 25
+          Top = 8
+          Width = 136
+          Caption = 'TESTNET RANDOM'
+          Font.Color = clRed
+          OnClick = bbRandomClick
+          ParentFont = False
+          TabOrder = 1
+        end
+      end
+    end
+  end
+  object splitter: TSplitter
+    Left = 427
+    Height = 320
+    Top = 56
+    Width = 5
+  end
+  object mMenu: TMainMenu
+    left = 112
+    top = 30
+    object MiTools: TMenuItem
+      Caption = 'Tools'
+      object MiImportOperationsFromTxt: TMenuItem
+        Caption = 'Import Operations from RAW'
+        ShortCut = 16457
+        OnClick = MiImportOperationsFromTxtClick
+      end
+      object MiDivider1: TMenuItem
+        Caption = '-'
+      end
+      object miLoadFromBlockchain: TMenuItem
+        Caption = 'Load Operations from Blockchain'
+        ShortCut = 16460
+        OnClick = miLoadFromBlockchainClick
+      end
+      object MiLoadOperationsFromBlockchainFile: TMenuItem
+        Caption = 'Load Operations from Blockchain file'
+        OnClick = MiLoadOperationsFromBlockchainFileClick
+      end
+      object MenuItem7: TMenuItem
+        Caption = '-'
+      end
+      object MiRPCCalls: TMenuItem
+        Caption = 'RPC Calls'
+        OnClick = MiRPCCallsClick
+      end
+    end
+    object MiActions: TMenuItem
+      Caption = 'Actions'
+      object MenuItem5: TMenuItem
+        Action = ActExecuteOperation
+      end
+      object MenuItem6: TMenuItem
+        Caption = '-'
+      end
+      object MenuItem1: TMenuItem
+        Action = AddOpChangeToMultioperation
+      end
+      object MenuItem2: TMenuItem
+        Action = ActAddTxToMultioperation
+      end
+      object MenuItem3: TMenuItem
+        Action = ActRemoveAccountFromMultioperation
+      end
+      object MenuItem4: TMenuItem
+        Action = ActSignMultioperation
+      end
+    end
+  end
+  object ActionList: TActionList
+    left = 299
+    top = 34
+    object ActExecuteOperation: TAction
+      Caption = 'Execute Operation'
+      OnExecute = ActExecuteOperationExecute
+      OnUpdate = ActExecuteOperationUpdate
+    end
+    object ActAddTxToMultioperation: TAction
+      Caption = 'Add Tx to Multioperation'
+      OnExecute = ActAddTxToMultioperationExecute
+      OnUpdate = ActAddTxToMultioperationUpdate
+    end
+    object AddOpChangeToMultioperation: TAction
+      Caption = 'Add OpChange to Multioperation'
+      OnExecute = AddOpChangeToMultioperationExecute
+      OnUpdate = AddOpChangeToMultioperationUpdate
+    end
+    object ActRemoveAccountFromMultioperation: TAction
+      Caption = 'Remove Account from Multioperation'
+      OnExecute = ActRemoveAccountFromMultioperationExecute
+      OnUpdate = ActRemoveAccountFromMultioperationUpdate
+    end
+    object ActSignMultioperation: TAction
+      Caption = 'Sign Multioperation'
+      OnExecute = ActSignMultioperationExecute
+      OnUpdate = ActSignMultioperationUpdate
+    end
+    object ActAddTx: TAction
+      Caption = 'Add Tx'
+      OnExecute = ActAddTxToMultioperationExecute
+      OnUpdate = ActAddTxToMultioperationUpdate
+    end
+    object ActAddOpChange: TAction
+      Caption = 'Add OpChange'
+      OnExecute = AddOpChangeToMultioperationExecute
+      OnUpdate = AddOpChangeToMultioperationUpdate
+    end
+    object ActRemove: TAction
+      Caption = 'Remove'
+      OnExecute = ActRemoveAccountFromMultioperationExecute
+      OnUpdate = ActRemoveAccountFromMultioperationUpdate
+    end
+    object ActSign: TAction
+      Caption = 'Sign'
+      OnExecute = ActSignMultioperationExecute
+      OnUpdate = ActExecuteOperationUpdate
+    end
+  end
+end

+ 796 - 0
src/gui-classic/UFRMOperationsExplorer.pas

@@ -0,0 +1,796 @@
+unit UFRMOperationsExplorer;
+
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
+{ Copyright (c) 2016-2018 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}
+    Windows, AppEvnts,
+  {$ELSE}
+    LCLIntf, LCLType, LMessages, FileUtil,
+  {$ENDIF}
+  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
+  Menus, ActnList, UAccounts, UBlockChain, UNode, UCrypto, UBaseTypes,
+  UFileStorage, UWallet, UConst, UTxMultiOperation, UOpTransaction, URPC, UJSONFunctions;
+
+
+type
+
+  { TFRMOperationsExplorer }
+
+  TFRMOperationsExplorer = class(TForm)
+    ActExecuteOperation: TAction;
+    ActAddTxToMultioperation: TAction;
+    ActAddTx: TAction;
+    ActAddOpChange: TAction;
+    ActSign: TAction;
+    ActRemove: TAction;
+    ActSignMultioperation: TAction;
+    ActRemoveAccountFromMultioperation: TAction;
+    AddOpChangeToMultioperation: TAction;
+    ActionList: TActionList;
+    bbSign: TButton;
+    bbAddTx: TButton;
+    bbAddOpChange: TButton;
+    bbExecuteOperation: TButton;
+    bbRemove: TButton;
+    bbRandom: TButton;
+    Label1: TLabel;
+    Label2: TLabel;
+    lblTopCaption: TLabel;
+    lbOperations: TListBox;
+    MenuItem1: TMenuItem;
+    MenuItem2: TMenuItem;
+    MenuItem3: TMenuItem;
+    MenuItem4: TMenuItem;
+    MenuItem5: TMenuItem;
+    MenuItem6: TMenuItem;
+    MenuItem7: TMenuItem;
+    MiRPCCalls: TMenuItem;
+    MiActions: TMenuItem;
+    MiDivider1: TMenuItem;
+    MiImportOperationsFromTxt: TMenuItem;
+    miLoadFromBlockchain: TMenuItem;
+    MiLoadOperationsFromBlockchainFile: TMenuItem;
+    MiTools: TMenuItem;
+    mMenu: TMainMenu;
+    mOperationInfo: TMemo;
+    mOperationExport: TMemo;
+    pnlInfoOptions: TPanel;
+    pnlInfo: TPanel;
+    pnlExport: TPanel;
+    pnlOpInfo: TPanel;
+    pnlTop: TPanel;
+    pnlBottom: TPanel;
+    splitter: TSplitter;
+    procedure ActAddTxToMultioperationExecute(Sender: TObject);
+    procedure ActAddTxToMultioperationUpdate(Sender: TObject);
+    procedure ActExecuteOperationExecute(Sender: TObject);
+    procedure ActExecuteOperationUpdate(Sender: TObject);
+    procedure ActRemoveAccountFromMultioperationExecute(Sender: TObject);
+    procedure ActRemoveAccountFromMultioperationUpdate(Sender: TObject);
+    procedure ActSignMultioperationExecute(Sender: TObject);
+    procedure ActSignMultioperationUpdate(Sender: TObject);
+    procedure AddOpChangeToMultioperationExecute(Sender: TObject);
+    procedure AddOpChangeToMultioperationUpdate(Sender: TObject);
+    procedure bbAddOpChangeClick(Sender: TObject);
+    procedure bbAddTxClick(Sender: TObject);
+    procedure bbRandomClick(Sender: TObject);
+    procedure bbRemoveClick(Sender: TObject);
+    procedure bbSignClick(Sender: TObject);
+    procedure Button1Click(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure lbOperationsClick(Sender: TObject);
+    procedure MiImportOperationsFromTxtClick(Sender: TObject);
+    procedure miLoadFromBlockchainClick(Sender: TObject);
+    procedure MiLoadOperationsFromBlockchainFileClick(Sender: TObject);
+    procedure MiRPCCallsClick(Sender: TObject);
+  private
+    FOperationsHashTree : TOperationsHashTree;
+    FSourceNode: TNode;
+    FSourceWalletKeys: TWalletKeys;
+    procedure OnOperationsHashTreeChanged(Sender : TObject);
+    procedure SetSourceNode(AValue: TNode);
+    procedure DoLoadFromStorageAssistant(AStorage : TStorage);
+    procedure SetSourceWalletKeys(AValue: TWalletKeys);
+    procedure UpdateHashTreeList;
+    procedure UpdateSelectedOperationInfo;
+    Function GetSelectedOperation : TPCOperation;
+    Function GetSelectedMultiOperation : TOpMultiOperation;
+    procedure DoCheckWalletKeysPwd;
+  public
+    Property SourceNode : TNode read FSourceNode write SetSourceNode;
+    Property SourceWalletKeys : TWalletKeys read FSourceWalletKeys write SetSourceWalletKeys;
+  end;
+
+implementation
+
+{$IFnDEF FPC}
+  {$R *.dfm}
+{$ELSE}
+  {$R *.lfm}
+{$ENDIF}
+
+Uses
+{$IFDEF TESTNET}
+   UFRMRandomOperations,
+{$ENDIF}
+   UFRMRPCCalls;
+
+
+{ TFRMOperationsExplorer }
+
+procedure TFRMOperationsExplorer.FormCreate(Sender: TObject);
+begin
+   FOperationsHashTree := TOperationsHashTree.Create;
+   FOperationsHashTree.OnChanged:=OnOperationsHashTreeChanged;
+   FSourceNode := Nil;
+   FSourceWalletKeys:= Nil;
+   {$IFDEF TESTNET}
+   bbRandom.Visible:=True;
+   bbRandom.Enabled:=True;
+   {$ELSE}
+   bbRandom.Visible:=False;
+   bbRandom.Enabled:=False;
+   {$ENDIF}
+end;
+
+procedure TFRMOperationsExplorer.bbAddTxClick(Sender: TObject);
+Var op : TPCOperation;
+  mop : TOpMultiOperation;
+  i : Integer;
+  aux : String;
+  nSender,nReceiver,n_operation : Cardinal;
+  amount : Int64;
+  senders : TMultiOpSenders;
+  receivers : TMultiOpReceivers;
+label LBL_start_sender;
+label LBL_start_receiver;
+begin
+  op := GetSelectedOperation;
+  mop := Nil;
+  If Assigned(op) then begin
+    if (op is TOpMultiOperation) then mop := TOpMultiOperation(op);
+  end;
+  If Not Assigned(mop) then begin
+    mop := TOpMultiOperation.Create;
+    FOperationsHashTree.AddOperationToHashTree(mop);
+    mop.Free;
+    mop := FOperationsHashTree.GetOperation(FOperationsHashTree.OperationsCount-1) as TOpMultiOperation;
+  end;
+  Repeat
+LBL_start_sender:
+    aux := '';
+    If Not InputQuery(Caption,Format('Multioperation: New sender account %d:',[length(senders)+1]),aux) then Break;
+    If Not TAccountComp.AccountTxtNumberToAccountNumber(aux,nSender) then Break;
+
+    if (mop.IndexOfAccountSender(nSender)>=0) Or (mop.IndexOfAccountReceiver(nSender,0)>=0) Or (mop.IndexOfAccountSender(nSender,0,senders)>=0) Or (mop.IndexOfAccountChanger(nSender)>=0) then begin
+      Application.MessageBox(PChar(Format('Account %s is used!',[TAccountComp.AccountNumberToAccountTxtNumber(nSender)])),PChar(Caption),MB_ICONWARNING+MB_OK);
+      Goto LBL_start_sender;
+    end;
+
+    n_operation := 0;
+    amount := 0;
+    If Assigned(FSourceNode) then begin
+      If (nSender<FSourceNode.Bank.AccountsCount) then begin
+        n_operation := FSourceNode.Bank.SafeBox.Account(nSender).n_operation+1;
+        amount := FSourceNode.Bank.SafeBox.Account(nSender).balance;
+      end;
+    end;
+
+    aux := TAccountComp.FormatMoney(amount);
+    If Not InputQuery(Caption,Format('Multioperation sender (%s) amount to send:',[TAccountComp.AccountNumberToAccountTxtNumber(nSender)]),aux) then Break;
+    If Not TAccountComp.TxtToMoney(aux,amount) then Break;
+    If amount<=0 then Break;
+
+    aux := IntToStr(n_operation);
+    If Not InputQuery(Caption,'Sender n_operation + 1:',aux) then Break;
+    n_operation:=StrToIntDef(aux,0);
+    If n_operation<=0 then Break;
+
+    SetLength(senders,length(senders)+1);
+    senders[high(senders)] := CT_TMultiOpSender_NUL;
+    senders[high(senders)].Account:=nSender;
+    senders[high(senders)].Amount:=amount;
+    senders[high(senders)].N_Operation:=n_operation;
+    Application.MessageBox(PChar(FormaT('Multioperation new sender:%s Amount:%s N_Operation:%d - Total senders:%d',
+       [TAccountComp.AccountNumberToAccountTxtNumber(nSender),TAccountComp.FormatMoney(amount),n_operation,length(senders)])),PChar(Caption),MB_ICONINFORMATION+MB_OK);
+  until False;
+
+  Repeat
+LBL_start_receiver:
+    aux := '';
+    If Not InputQuery(Caption,Format('Multioperation: New receiver account %d:',[length(receivers)+1]),aux) then Break;
+    If Not TAccountComp.AccountTxtNumberToAccountNumber(aux,nReceiver) then Break;
+
+    amount := 1;
+    aux := TAccountComp.FormatMoney(amount);
+    If Not InputQuery(Caption,Format('Multioperation receiver (%s) amount to receive:',[TAccountComp.AccountNumberToAccountTxtNumber(nReceiver)]),aux) then Break;
+    If Not TAccountComp.TxtToMoney(aux,amount) then Break;
+    If amount<=0 then Break;
+
+    SetLength(receivers,length(receivers)+1);
+    receivers[high(receivers)] := CT_TMultiOpReceiver_NUL;
+    receivers[high(receivers)].Account:=nReceiver;
+    receivers[high(receivers)].Amount:=amount;
+    Application.MessageBox(PChar(Format('Multioperation new receiver:%s Amount:%s - Total receivers:%d',
+       [TAccountComp.AccountNumberToAccountTxtNumber(nReceiver),TAccountComp.FormatMoney(amount),length(receivers)])),PChar(Caption),MB_OK+MB_ICONINFORMATION);
+  until False;
+
+  If (length(senders)=0) and (length(receivers)=0) then Exit;
+
+  If Application.MessageBox(PChar(Format('Add %d new senders and %d new receivers to Multioperation with %d senders and %d receivers?',[length(senders),length(receivers),length(mop.Data.txSenders),length(mop.Data.txReceivers)])),
+    PChar(Caption),MB_YESNO+MB_ICONINFORMATION)<>IDYES then Exit;
+
+  If Not mop.AddTx(senders,receivers,True) then begin
+    Application.MessageBox(PChar('Cannot add senders and receivers!'),PChar(Caption),MB_ICONWARNING+MB_OK);
+  end;
+  UpdateSelectedOperationInfo;
+end;
+
+procedure TFRMOperationsExplorer.bbRandomClick(Sender: TObject);
+{$IFDEF TESTNET}
+Var FRM : TFRMRandomOperations;
+{$ENDIF}
+begin
+  {$IFDEF TESTNET}
+  FRM := TFRMRandomOperations.Create(Self);
+  Try
+    FRM.SourceNode := Self.SourceNode;
+    FRM.SourceWalletKeys := Self.SourceWalletKeys as TWalletKeysExt;
+    FRM.ShowModal;
+  finally
+    FRM.Free;
+  end;
+  {$ENDIF}
+end;
+
+procedure TFRMOperationsExplorer.bbRemoveClick(Sender: TObject);
+Var op : TPCOperation;
+  mop, newMop : TOpMultiOperation;
+  i,nDel, nAccount : Integer;
+  aux : String;
+  txs : TMultiOpSenders;
+  txr : TMultiOpReceivers;
+  chs : TMultiOpChangesInfo;
+begin
+  op := GetSelectedOperation;
+  If Not Assigned(op) then exit;
+  If Not (op is TOpMultiOperation) Then Raise Exception.Create('Is not a multioperation');
+  mop := TOpMultiOperation(op);
+  aux := '';
+  If Not InputQuery(Caption,Format('Multioperation: Remove account sender/receiver/changer. Which account?',[]),aux) then Exit;
+  nAccount := StrToIntDef(aux,-1);
+  If nAccount<0 then Exit;
+  newMop := TOpMultiOperation.Create;
+  Try
+    SetLength(txs,0);
+    SetLength(txr,0);
+    SetLength(chs,0);
+    nDel := 0;
+    For i:=low(mop.Data.txSenders) to high(mop.Data.txSenders) do begin
+      If mop.Data.txSenders[i].Account <> nAccount then begin
+        SetLength(txs,length(txs)+1);
+        txs[high(txs)] := mop.Data.txSenders[i];
+      end else inc(nDel);
+    end;
+    For i:=low(mop.Data.txReceivers) to high(mop.Data.txReceivers) do begin
+      If mop.Data.txReceivers[i].Account <> nAccount then begin
+        SetLength(txr,length(txr)+1);
+        txr[high(txr)] := mop.Data.txReceivers[i];
+      end else inc(nDel);
+    end;
+    For i:=low(mop.Data.changesInfo) to high(mop.Data.changesInfo) do begin
+      If mop.Data.changesInfo[i].Account <> nAccount then begin
+        SetLength(chs,length(chs)+1);
+        chs[high(chs)] := mop.Data.changesInfo[i];
+      end else inc(nDel);
+    end;
+    If (nDel)>0 then begin
+      Application.MessageBox(PChar(Format('Removed %d times account %s',[nDel,TAccountComp.AccountNumberToAccountTxtNumber(nAccount)])),PChar(Caption),MB_OK+MB_ICONINFORMATION);
+    end else begin
+      Raise Exception.Create(Format('Account %s not found in multioperation',[TAccountComp.AccountNumberToAccountTxtNumber(nAccount)]));
+    end;
+    newMop.AddTx(txs,txr,True);
+    newMop.AddChangeInfos(chs,True);
+    FOperationsHashTree.AddOperationToHashTree(newMop);
+  finally
+    newMop.Free;
+  end;
+
+end;
+
+procedure TFRMOperationsExplorer.bbSignClick(Sender: TObject);
+Var op : TPCOperation;
+  mop : TOpMultiOperation;
+  i,j,n : Integer;
+begin
+  DoCheckWalletKeysPwd;
+  If Not Assigned(FSourceNode) then Raise Exception.Create('No node to sign accounts');
+  op := GetSelectedOperation;
+  If Not Assigned(op) then exit;
+  If Not (op is TOpMultiOperation) Then Raise Exception.Create('Is not a multioperation');
+  mop := TOpMultiOperation(op);
+  n := 0;
+  For i:=0 to High(mop.Data.txSenders) do begin
+    j := FSourceWalletKeys.IndexOfAccountKey(FSourceNode.Bank.SafeBox.Account(mop.Data.txSenders[i].Account).accountInfo.accountKey);
+    If (j>=0) then begin
+      // Can sign
+      If (Assigned(FSourceWalletKeys.Key[j].PrivateKey)) then begin
+        inc(n, mop.DoSignMultiOperationSigner(mop.Data.txSenders[i].Account,FSourceWalletKeys.Key[j].PrivateKey));
+      end;
+    end;
+  end;
+  For i:=0 to High(mop.Data.changesInfo) do begin
+    j := FSourceWalletKeys.IndexOfAccountKey(FSourceNode.Bank.SafeBox.Account(mop.Data.changesInfo[i].Account).accountInfo.accountKey);
+    If (j>=0) then begin
+      // Can sign
+      If (Assigned(FSourceWalletKeys.Key[j].PrivateKey)) then begin
+        inc(n, mop.DoSignMultiOperationSigner(mop.Data.changesInfo[i].Account,FSourceWalletKeys.Key[j].PrivateKey));
+      end;
+    end;
+  end;
+  Application.MessageBox(PChar(Format('Signed %d accounts',[n])),PChar(Caption),MB_OK+MB_ICONINFORMATION);
+  UpdateSelectedOperationInfo;
+end;
+
+procedure TFRMOperationsExplorer.Button1Click(Sender: TObject);
+begin
+
+end;
+
+procedure TFRMOperationsExplorer.bbAddOpChangeClick(Sender: TObject);
+Var op : TPCOperation;
+  mop : TOpMultiOperation;
+  i : Integer;
+  aux : String;
+  nAccount,n_operation : Cardinal;
+  changes : TMultiOpChangesInfo;
+  new_name,errors : AnsiString;
+  new_type : Word;
+  new_account_key : TAccountKey;
+label LBL_start_changer;
+begin
+  op := GetSelectedOperation;
+  mop := Nil;
+  If Assigned(op) then begin
+    if (op is TOpMultiOperation) then mop := TOpMultiOperation(op);
+  end;
+  If Not Assigned(mop) then begin
+    mop := TOpMultiOperation.Create;
+    FOperationsHashTree.AddOperationToHashTree(mop);
+    mop.Free;
+    mop := FOperationsHashTree.GetOperation(FOperationsHashTree.OperationsCount-1) as TOpMultiOperation;
+  end;
+  Repeat
+LBL_start_changer:
+    aux := '';
+    If Not InputQuery(Caption,Format('Multioperation: New changer account %d:',[length(changes)+1]),aux) then Break;
+    If Not TAccountComp.AccountTxtNumberToAccountNumber(aux,nAccount) then Break;
+
+    if (mop.IndexOfAccountSender(nAccount)>=0) Or (mop.IndexOfAccountReceiver(nAccount,0)>=0) Or (mop.IndexOfAccountChanger(nAccount,0,changes)>=0) then begin
+      Application.MessageBox(PChar(Format('Account %s is used!',[TAccountComp.AccountNumberToAccountTxtNumber(nAccount)])),PChar(Caption),MB_ICONWARNING+MB_OK);
+      Goto LBL_start_changer;
+    end;
+
+    n_operation := 0;
+    new_name := '';
+    new_type := 0;
+    new_account_key := CT_TECDSA_Public_Nul;
+    If Assigned(FSourceNode) then begin
+      If (nAccount<FSourceNode.Bank.AccountsCount) then begin
+        n_operation := FSourceNode.Bank.SafeBox.Account(nAccount).n_operation+1;
+        new_name:= FSourceNode.Bank.SafeBox.Account(nAccount).name;
+        new_type:= FSourceNode.Bank.SafeBox.Account(nAccount).account_type;
+        new_account_key := FSourceNode.Bank.SafeBox.Account(nAccount).accountInfo.accountKey;
+      end;
+    end;
+
+    aux := IntToStr(n_operation);
+    If Not InputQuery(Caption,'Changer n_operation + 1:',aux) then Break;
+    n_operation:=StrToIntDef(aux,0);
+    If n_operation<=0 then Break;
+
+    errors := '';
+    Repeat
+      If (errors<>'') then Application.MessageBox(PChar(Format('Invalid name "%s": %s',[aux,errors])),PChar(Caption),MB_ICONERROR+MB_OK);
+      aux := new_name;
+      If Not InputQuery(Caption,Format('New name for account %s:',[TAccountComp.AccountNumberToAccountTxtNumber(nAccount)]),aux) then Break;
+      aux := LowerCase(aux);
+    Until (aux='') Or (TPCSafeBox.ValidAccountName(aux,errors));
+    new_name := aux;
+
+    aux := IntToStr(new_type);
+    If Not InputQuery(Caption,Format('New type for account %s:',[TAccountComp.AccountNumberToAccountTxtNumber(nAccount)]),aux) then Break;
+    new_type := StrToIntDef(aux,0);
+
+    If new_account_key.EC_OpenSSL_NID<>CT_TECDSA_Public_Nul.EC_OpenSSL_NID then aux := TAccountComp.AccountPublicKeyExport(new_account_key)
+    else aux := '';
+    If Not InputQuery(Caption,Format('New public key for account %s:',[TAccountComp.AccountNumberToAccountTxtNumber(nAccount)]),aux) then begin
+      If Not TAccountComp.AccountPublicKeyImport(aux,new_account_key,errors) then begin
+        new_account_key := CT_TECDSA_Public_Nul;
+        Application.MessageBox(PChar(errors),PChar(Caption),MB_ICONERROR+MB_OK);
+      end;
+    end;
+
+    SetLength(changes,length(changes)+1);
+    changes[high(changes)] := CT_TMultiOpChangeInfo_NUL;
+    changes[high(changes)].Account:=nAccount;
+    changes[high(changes)].Changes_type:=[account_name,account_type];
+    changes[high(changes)].New_Name:=new_name;
+    changes[high(changes)].New_Type:=new_type;
+    If new_account_key.EC_OpenSSL_NID<>CT_TECDSA_Public_Nul.EC_OpenSSL_NID then begin
+      changes[high(changes)].Changes_type:=changes[high(changes)].Changes_type + [public_key];
+      changes[high(changes)].New_Accountkey := new_account_key;
+    end;
+    changes[high(changes)].N_Operation:=n_operation;
+    Application.MessageBox(PChar(FormaT('Multioperation new changer account:%s N_Operation:%d Name:%s Type:%d - Total changes:%d',
+       [TAccountComp.AccountNumberToAccountTxtNumber(nAccount),n_operation,new_name,new_type,length(changes)])),PChar(Caption),MB_ICONINFORMATION+MB_OK);
+  until False;
+
+
+  If (length(changes)=0) then Exit;
+
+  If Application.MessageBox(PChar(Format('Add %d new changes to Multioperation with %d changes?',[length(changes),length(mop.Data.changesInfo)])),
+    PChar(Caption),MB_YESNO+MB_ICONINFORMATION)<>IDYES then Exit;
+
+  If Not mop.AddChangeInfos(changes,True) then begin
+    Application.MessageBox(PChar('Cannot add changes!'),PChar(Caption),MB_ICONWARNING+MB_OK);
+  end;
+  UpdateSelectedOperationInfo;
+end;
+
+procedure TFRMOperationsExplorer.ActExecuteOperationUpdate(Sender: TObject);
+Var obj : TObject;
+begin
+  obj := GetSelectedOperation;
+  TAction(Sender).Enabled:= ((Assigned(obj)) And (Assigned(FSourceNode)));
+end;
+
+procedure TFRMOperationsExplorer.ActRemoveAccountFromMultioperationExecute(Sender: TObject);
+begin
+  bbRemoveClick(Nil);
+end;
+
+procedure TFRMOperationsExplorer.ActRemoveAccountFromMultioperationUpdate(Sender: TObject);
+Var op : TOpMultiOperation;
+begin
+  op := GetSelectedMultiOperation;
+  TAction(Sender).Enabled:= (Assigned(FSourceNode)) And (Assigned(op));
+end;
+
+procedure TFRMOperationsExplorer.ActSignMultioperationExecute(Sender: TObject);
+begin
+  bbSignClick(Nil);
+end;
+
+procedure TFRMOperationsExplorer.ActSignMultioperationUpdate(Sender: TObject);
+Var op : TOpMultiOperation;
+begin
+  op := GetSelectedMultiOperation;
+  TAction(Sender).Enabled:= (Assigned(FSourceNode)) And (Assigned(op));
+end;
+
+procedure TFRMOperationsExplorer.AddOpChangeToMultioperationExecute(Sender: TObject);
+begin
+  bbAddOpChangeClick(Nil);
+end;
+
+procedure TFRMOperationsExplorer.AddOpChangeToMultioperationUpdate(Sender: TObject);
+begin
+  TAction(Sender).Enabled:= True;
+end;
+
+procedure TFRMOperationsExplorer.ActExecuteOperationExecute(Sender: TObject);
+Var op : TPCOperation;
+  errors : AnsiString;
+begin
+  If Not Assigned(FSourceNode) then Raise Exception.Create('No node to Execute');
+  op := GetSelectedOperation;
+  If Not Assigned(op) then exit;
+  If (FSourceNode.AddOperation(Nil,op,errors)) then begin
+    Application.MessageBox(PChar('Operation executed!'+#10+Op.ToString),PChar(Caption),MB_OK+MB_ICONINFORMATION);
+  end else begin
+    Application.MessageBox(PChar('ERROR EXECUTING!'+#10+Op.ToString+#10+#10+'ERROR:'+#10+errors),PChar(Caption),MB_OK+MB_ICONERROR);
+  end;
+end;
+
+procedure TFRMOperationsExplorer.ActAddTxToMultioperationUpdate(Sender: TObject);
+begin
+  TAction(Sender).Enabled:= True;
+end;
+
+procedure TFRMOperationsExplorer.ActAddTxToMultioperationExecute(Sender: TObject);
+begin
+  bbAddTxClick(Nil);
+end;
+
+procedure TFRMOperationsExplorer.FormDestroy(Sender: TObject);
+begin
+   FreeAndNil(FOperationsHashTree);
+end;
+
+procedure TFRMOperationsExplorer.lbOperationsClick(Sender: TObject);
+begin
+  UpdateSelectedOperationInfo;
+end;
+
+procedure TFRMOperationsExplorer.MiImportOperationsFromTxtClick(Sender: TObject);
+Var i : Integer;
+  raw : TRawBytes;
+  aux : AnsiString;
+  auxS : String;
+  errors : AnsiString;
+  opht : TOperationsHashTree;
+  ms : TMemoryStream;
+begin
+  aux := '';
+  If Not InputQuery(Caption,'Paste a RAW hexadecimal operations:',auxS) then exit;
+  aux := auxS;
+  If Not TCrypto.IsHexString(aux) then Raise Exception.Create('Invalid hexadecimal RAW');
+  raw := TCrypto.HexaToRaw(aux);
+  If Length(raw)=0 then Exit;
+  ms := TMemoryStream.Create;
+  opht := TOperationsHashTree.Create;
+  Try
+    ms.Write(raw[1],Length(raw));
+    ms.Position:=0;
+    If Not opht.LoadOperationsHashTreeFromStream(ms,false,0,Nil,errors) then Raise Exception.Create(errors);
+    For i:=0 to opht.OperationsCount-1 do begin
+      FOperationsHashTree.AddOperationToHashTree(opht.GetOperation(i));
+    end;
+  finally
+    ms.Free;
+    opht.Free;
+  end;
+end;
+
+procedure TFRMOperationsExplorer.miLoadFromBlockchainClick(Sender: TObject);
+begin
+  If Not Assigned(FSourceNode) then raise Exception.Create('No blockchain');
+  DoLoadFromStorageAssistant(FSourceNode.Bank.Storage);
+end;
+
+procedure TFRMOperationsExplorer.MiLoadOperationsFromBlockchainFileClick(Sender: TObject);
+Var fn : String;
+  od : TOpenDialog;
+  filest : TFileStorage;
+begin
+  od := TOpenDialog.Create(Self);
+  Try
+    od.Filter:='Blockchain file (*.blocks)|*.blocks|All files (*.*)|*.*|';
+    If od.Execute then begin
+      filest := TFileStorage.Create(Self);
+      Try
+        filest.ReadOnly:=True;
+        filest.SetBlockChainFile(od.FileName);
+        filest.Initialize;
+        DoLoadFromStorageAssistant(filest);
+      finally
+        filest.Free;
+      end;
+    end;
+  finally
+    od.Free;
+  end;
+end;
+
+procedure TFRMOperationsExplorer.MiRPCCallsClick(Sender: TObject);
+Var FRM : TFRMRPCCalls;
+begin
+  FRM := TFRMRPCCalls.Create(Self);
+  Try
+    FRM.ShowModal;
+  finally
+    FRM.Free;
+  end;
+end;
+
+procedure TFRMOperationsExplorer.OnOperationsHashTreeChanged(Sender: TObject);
+begin
+  UpdateHashTreeList;
+end;
+
+procedure TFRMOperationsExplorer.SetSourceNode(AValue: TNode);
+begin
+  if FSourceNode=AValue then Exit;
+  FSourceNode:=AValue;
+  If Assigned(FSourceNode) then begin
+    FOperationsHashTree.CopyFromHashTree(FSourceNode.Operations.OperationsHashTree);
+  end else FOperationsHashTree.ClearHastThree;
+end;
+
+procedure TFRMOperationsExplorer.DoLoadFromStorageAssistant(AStorage: TStorage);
+Var i : Integer;
+  s,aux : String;
+  opc : TPCOperationsComp;
+begin
+  s := Format('Input block from %d to %d',[AStorage.FirstBlock,AStorage.LastBlock]);
+  aux := '';
+  If Not InputQuery(Caption,s,aux) then Exit;
+  i := StrToIntDef(aux,-1);
+  If (i<AStorage.FirstBlock) Or (i>AStorage.LastBlock) then Raise Exception.Create(Format('Block %d does not exists',[i]));
+  opc := TPCOperationsComp.Create(Nil);
+  Try
+    If Not AStorage.LoadBlockChainBlock(opc,i) then Raise Exception.Create(Format('Cannot load block %d',[i]));
+    FOperationsHashTree.CopyFromHashTree(opc.OperationsHashTree);
+  finally
+    opc.Free;
+  end;
+end;
+
+procedure TFRMOperationsExplorer.SetSourceWalletKeys(AValue: TWalletKeys);
+begin
+  if FSourceWalletKeys=AValue then Exit;
+  FSourceWalletKeys:=AValue;
+end;
+
+procedure TFRMOperationsExplorer.UpdateHashTreeList;
+var i,lasti : Integer;
+begin
+  lbOperations.Items.BeginUpdate;
+  Try
+    lasti := lbOperations.ItemIndex;
+    lbOperations.Items.Clear;
+    For i:=0 to FOperationsHashTree.OperationsCount-1 do begin
+      lbOperations.Items.AddObject(Format('%d/%d %s',[i+1,FOperationsHashTree.OperationsCount,FOperationsHashTree.GetOperation(i).ToString]),FOperationsHashTree.GetOperation(i));
+    end;
+    If (lasti<=0) then lasti:=0;
+    If (lasti>=lbOperations.Count) then lasti := lbOperations.Count-1;
+    lbOperations.ItemIndex:=lasti;
+  finally
+    lbOperations.Items.EndUpdate;
+  end;
+  UpdateSelectedOperationInfo;
+
+end;
+
+procedure TFRMOperationsExplorer.UpdateSelectedOperationInfo;
+Var op : TPCOperation;
+  opht : TOperationsHashTree;
+  i : Integer;
+  l : TList;
+  aux : String;
+  raw : TRawBytes;
+  ms : TMemoryStream;
+  opr : TOperationResume;
+  jsonObj : TPCJSONObject;
+begin
+  setLength(raw,0);
+  If lbOperations.ItemIndex>=0 then begin
+    If lbOperations.SelCount>1 then op:=Nil
+    else op := TPCOperation( lbOperations.Items.Objects[lbOperations.ItemIndex] )
+  end else op := Nil;
+  mOperationInfo.Clear;
+  mOperationExport.Clear;
+  If Assigned(op) then begin
+    mOperationInfo.Lines.Add(Format('%s',[op.ToString]));
+    mOperationInfo.Lines.Add('');
+    mOperationInfo.Lines.Add(Format('OpType:%d ClassName:%s',[op.OpType,op.ClassName]));
+    l := TList.Create;
+    Try
+      op.AffectedAccounts(l); aux := '';
+      For i:=0 to l.Count-1 do begin
+        if (aux<>'') then aux := aux + ',';
+        aux := aux + Format('%s',[TAccountComp.AccountNumberToAccountTxtNumber(PtrInt(l[i]))]);
+      end;
+      mOperationInfo.Lines.Add(Format('Affected accounts: %s',[aux]));
+    finally
+      l.Free;
+    end;
+    If (op.HasValidSignature) then begin
+      mOperationInfo.Lines.Add(Format('Signed verified',[]));
+    end;
+    opht := TOperationsHashTree.Create;
+    ms := TMemoryStream.Create;
+    try
+      opht.AddOperationToHashTree(op);
+      opht.SaveOperationsHashTreeToStream(ms,false);
+      mOperationInfo.Lines.Add(Format('Size: %.2f Kb (%d bytes)',[ms.Size/1024,ms.Size]));
+      ms.Position:=0;
+      SetLength(raw,ms.Size);
+      ms.ReadBuffer(raw[1],ms.Size);
+      mOperationExport.Lines.Text := TCrypto.ToHexaString(raw);
+    finally
+      ms.Free;
+      opht.Free;
+    end;
+    If op.OperationToOperationResume(FSourceNode.Bank.BlocksCount,op,True,op.SignerAccount,opr) then begin
+      jsonObj := TPCJSONObject.Create;
+      Try
+        TPascalCoinJSONComp.FillOperationObject(opr,FSourceNode.Bank.BlocksCount,jsonObj);
+        mOperationInfo.Lines.Add('JSON:');
+        mOperationInfo.Lines.Add(jsonObj.ToJSON(False));
+      Finally
+        jsonObj.Free;
+      end;
+    end;
+  end else begin
+    opht := TOperationsHashTree.Create;
+    ms := TMemoryStream.Create;
+    try
+      For i:=0 to lbOperations.Count-1 do begin
+        If lbOperations.Selected[i] then begin
+          op := TPCOperation( lbOperations.Items.Objects[i] );
+          opht.AddOperationToHashTree(op);
+        end;
+      end;
+      opht.SaveOperationsHashTreeToStream(ms,false);
+      mOperationInfo.Lines.Add(Format('Selected %d operations',[opht.OperationsCount]));
+      mOperationInfo.Lines.Add(Format('Size: %.2f Kb (%d bytes)',[ms.Size/1024,ms.Size]));
+      if (opht.OperationsCount>0) then begin
+        ms.Position:=0;
+        SetLength(raw,ms.Size);
+        ms.ReadBuffer(raw[1],ms.Size);
+        mOperationExport.Lines.Text := TCrypto.ToHexaString(raw);
+        jsonObj := TPCJSONObject.Create;
+        Try
+          TPascalCoinJSONComp.FillOperationsHashTreeObject(opht,jsonObj);
+          mOperationInfo.Lines.Add('JSON:');
+          mOperationInfo.Lines.Add(jsonObj.ToJSON(False));
+        Finally
+          jsonObj.Free;
+        end;
+      end else mOperationExport.Lines.Clear;
+    finally
+      ms.Free;
+      opht.Free;
+    end;
+  end;
+end;
+
+function TFRMOperationsExplorer.GetSelectedOperation: TPCOperation;
+begin
+  Result := Nil;
+  if lbOperations.ItemIndex>=0 then begin
+    Result := TPCOperation( lbOperations.Items.Objects[lbOperations.ItemIndex] );
+  end;
+end;
+
+function TFRMOperationsExplorer.GetSelectedMultiOperation: TOpMultiOperation;
+begin
+  Result := Nil;
+  if lbOperations.ItemIndex>=0 then begin
+    If (lbOperations.Items.Objects[lbOperations.ItemIndex] is TOpMultiOperation) then begin
+      Result := TOpMultiOperation( lbOperations.Items.Objects[lbOperations.ItemIndex] );
+    end;
+  end;
+end;
+
+procedure TFRMOperationsExplorer.DoCheckWalletKeysPwd;
+Var s : String;
+  errors : AnsiString;
+begin
+  If Not Assigned(FSourceWalletKeys) then Raise Exception.Create('No wallet keys');
+  Try
+    While (Not FSourceWalletKeys.IsValidPassword) do begin
+      s := '';
+      if Not InputQuery('Wallet password','Enter wallet password',s) then exit;
+      FSourceWalletKeys.WalletPassword := s;
+    end;
+  finally
+    If Not FSourceWalletKeys.IsValidPassword then Raise Exception.Create('Wallet is protected!');
+  end;
+end;
+
+end.
+

+ 273 - 0
src/gui-classic/UFRMRPCCalls.lfm

@@ -0,0 +1,273 @@
+object FRMRPCCalls: TFRMRPCCalls
+  Left = 515
+  Height = 433
+  Top = 250
+  Width = 760
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'RPC Calls'
+  ClientHeight = 433
+  ClientWidth = 760
+  OnCreate = FormCreate
+  Position = poOwnerFormCenter
+  LCLVersion = '1.8.0.6'
+  object pnlTop: TPanel
+    Left = 0
+    Height = 50
+    Top = 0
+    Width = 760
+    Align = alTop
+    BevelOuter = bvNone
+    BorderWidth = 5
+    ClientHeight = 50
+    ClientWidth = 760
+    TabOrder = 0
+    object lblTopCaption: TLabel
+      Left = 5
+      Height = 40
+      Top = 5
+      Width = 750
+      Align = alClient
+      AutoSize = False
+      Caption = 'WARNING! Execute only calls you understand. Execute unknown calls provided by third person can cause that you lost your keys/balance!'
+      Font.Color = clRed
+      Font.Height = -16
+      Font.Style = [fsBold]
+      Layout = tlCenter
+      ParentColor = False
+      ParentFont = False
+      WordWrap = True
+    end
+  end
+  object pnlBottom: TPanel
+    Left = 0
+    Height = 17
+    Top = 416
+    Width = 760
+    Align = alBottom
+    BevelOuter = bvNone
+    TabOrder = 1
+  end
+  object pnlRight: TPanel
+    Left = 429
+    Height = 366
+    Top = 50
+    Width = 331
+    Align = alRight
+    BevelOuter = bvNone
+    ClientHeight = 366
+    ClientWidth = 331
+    TabOrder = 2
+    object Label1: TLabel
+      Left = 16
+      Height = 15
+      Top = 43
+      Width = 42
+      Caption = 'Method'
+      ParentColor = False
+    end
+    object ebMethod: TEdit
+      Left = 70
+      Height = 23
+      Top = 40
+      Width = 184
+      TabOrder = 1
+      Text = 'ebMethod'
+    end
+    object pageControl: TPageControl
+      Left = 16
+      Height = 222
+      Top = 75
+      Width = 289
+      ActivePage = tsKeyNames
+      Anchors = [akTop, akLeft, akRight, akBottom]
+      TabIndex = 0
+      TabOrder = 2
+      object tsKeyNames: TTabSheet
+        Caption = 'Key/Value Params'
+        ClientHeight = 194
+        ClientWidth = 281
+        object vlKeyParams: TValueListEditor
+          Left = 0
+          Height = 194
+          Top = 0
+          Width = 281
+          Align = alClient
+          FixedCols = 0
+          RowCount = 2
+          TabOrder = 0
+          KeyOptions = [keyEdit, keyAdd, keyDelete, keyUnique]
+          Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing, goEditing, goAutoAddRows, goAlwaysShowEditor, goThumbTracking]
+          Strings.Strings = (
+            ''
+          )
+          ColWidths = (
+            64
+            213
+          )
+        end
+      end
+      object tsJSONParams: TTabSheet
+        Caption = 'Params as JSON'
+        ClientHeight = 172
+        ClientWidth = 238
+        object mJSONParams: TMemo
+          Left = 0
+          Height = 172
+          Top = 0
+          Width = 238
+          Align = alClient
+          ScrollBars = ssVertical
+          TabOrder = 0
+        end
+      end
+    end
+    object bbSendCommand: TBitBtn
+      Left = 72
+      Height = 46
+      Top = 305
+      Width = 168
+      Anchors = [akLeft, akBottom]
+      Caption = '&Send'
+      Default = True
+      Glyph.Data = {
+        36040000424D3604000000000000360000002800000010000000100000000100
+        2000000000000004000064000000640000000000000000000000FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000
+        00000000000000000000FFFFFF0046986FFF379064FF0B774240FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000
+        000000000000FFFFFF0054A07AFF78BCA1FF7DB99EFF368F63FF0B774240FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000FFFF
+        FF00FFFFFF0054A07AFF7BBEA4FF39A681FF55B191FF7AB698FF399166FF0B77
+        4240FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0054A0
+        7A0054A07AFF7CC0A6FF3CA985FF76BDA1FF7FBBA0FF4FB592FF7BBEA2FF54A0
+        7AFF0B77424054A07A0054A07A00FFFFFF00FFFFFF00FFFFFF0054A07A0054A0
+        7AFF7DC1A7FF4DB391FF7FBB9FFF4D9C75FF3E946AFF7BC5A9FF40B18BFF7BBE
+        A2FF54A07AFF0B77424054A07A0054A07A00FFFFFF00FFFFFF0054A07AFF7FC3
+        A8FF5FBB9BFF7FBBA0FF3A9166FF0B7742600B7742404D9C75FF7BC5A9FF4EBC
+        97FF7BBEA2FF54A07AFF0B7742400B77421054A07A00FFFFFF000B7742303A91
+        66FC7FBBA0FF3A9166FC0B77423000000000000000000B77426054A07AFF7BC5
+        A9FF4EBE99FF5CC2A0FF54A07AFF0B77423F0B77421054A07A00000000000B77
+        42203A9166F60B774220000000000000000000000000FFFFFF000B77424054A0
+        7AFF7CCAAEFF52C39DFF81BDA2FF54A07AFF0B77423F54A07A00000000000000
+        0000000000000000000000000000000000000000000000000000000000000B77
+        424054A07AFF6DC9A8FF57C7A2FF7BCCAFFF54A07AFF0B774239000000000000
+        000000000000000000000000000000000000000000000000000000000000FFFF
+        FF000B77424C54A07AFF7BCCAFFF81CBAFFF54A07AFF0B77423F000000000000
+        000000000000000000000000000000000000000000000000000000000000FFFF
+        FF00FFFFFF000B77423D54A07AFF54A07AFF0B774247FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF000B77423F0B77423FFFFFFF00FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+        FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00
+      }
+      OnClick = bbSendCommandClick
+      TabOrder = 3
+    end
+    object Label2: TLabel
+      Left = 16
+      Height = 15
+      Top = 13
+      Width = 32
+      Caption = 'Server'
+      ParentColor = False
+    end
+    object ebServerURL: TEdit
+      Left = 70
+      Height = 23
+      Top = 8
+      Width = 184
+      TabStop = False
+      TabOrder = 0
+      Text = 'ebServerURL'
+    end
+  end
+  object Splitter1: TSplitter
+    Left = 424
+    Height = 366
+    Top = 50
+    Width = 5
+    Align = alRight
+    ResizeAnchor = akRight
+  end
+  object pnlInfo: TPanel
+    Left = 0
+    Height = 366
+    Top = 50
+    Width = 424
+    Align = alClient
+    BevelOuter = bvNone
+    ClientHeight = 366
+    ClientWidth = 424
+    TabOrder = 4
+    object pnlInfoBottom: TPanel
+      Left = 0
+      Height = 169
+      Top = 197
+      Width = 424
+      Align = alBottom
+      BevelOuter = bvNone
+      ClientHeight = 169
+      ClientWidth = 424
+      TabOrder = 0
+      object mLastResult: TMemo
+        Left = 0
+        Height = 145
+        Top = 24
+        Width = 424
+        Align = alClient
+        ScrollBars = ssVertical
+        TabOrder = 0
+      end
+      object pnlLastCall: TPanel
+        Left = 0
+        Height = 24
+        Top = 0
+        Width = 424
+        Align = alTop
+        BevelOuter = bvNone
+        ClientHeight = 24
+        ClientWidth = 424
+        TabOrder = 1
+        object Label3: TLabel
+          Left = 8
+          Height = 15
+          Top = 3
+          Width = 77
+          Caption = 'Last call result:'
+          ParentColor = False
+        end
+        object lblLastCallResultState: TLabel
+          Left = 112
+          Height = 15
+          Top = 3
+          Width = 32
+          Caption = 'STATE'
+          ParentColor = False
+        end
+      end
+    end
+    object mCalls: TMemo
+      Left = 0
+      Height = 192
+      Top = 0
+      Width = 424
+      Align = alClient
+      ScrollBars = ssVertical
+      TabOrder = 1
+    end
+    object Splitter2: TSplitter
+      Cursor = crVSplit
+      Left = 0
+      Height = 5
+      Top = 192
+      Width = 424
+      Align = alBottom
+      ResizeAnchor = akBottom
+    end
+  end
+end

+ 242 - 0
src/gui-classic/UFRMRPCCalls.pas

@@ -0,0 +1,242 @@
+unit UFRMRPCCalls;
+
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
+{ Copyright (c) 2016-2018 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}
+    Windows, AppEvnts,
+  {$ELSE}
+    LCLIntf, LCLType, LMessages, FileUtil,
+  {$ENDIF}
+  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,
+  StdCtrls, ValEdit, ComCtrls, Buttons, UJSONFunctions, blcksock, httpsend,
+  UConst,
+  UAccounts;
+
+type
+
+  TInfoType = (info,call,response,error);
+
+  { TFRMRPCCalls }
+
+  TFRMRPCCalls = class(TForm)
+    bbSendCommand: TBitBtn;
+    ebMethod: TEdit;
+    ebServerURL: TEdit;
+    Label1: TLabel;
+    Label2: TLabel;
+    Label3: TLabel;
+    lblLastCallResultState: TLabel;
+    lblTopCaption: TLabel;
+    mCalls: TMemo;
+    mLastResult: TMemo;
+    mJSONParams: TMemo;
+    pageControl: TPageControl;
+    pnlLastCall: TPanel;
+    pnlInfo: TPanel;
+    pnlInfoBottom: TPanel;
+    pnlTop: TPanel;
+    pnlBottom: TPanel;
+    pnlRight: TPanel;
+    Splitter1: TSplitter;
+    Splitter2: TSplitter;
+    tsJSONParams: TTabSheet;
+    tsKeyNames: TTabSheet;
+    vlKeyParams: TValueListEditor;
+    procedure bbSendCommandClick(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+  private
+    FServerURL: String;
+    procedure SetServerURL(AValue: String);
+    procedure ShowCallInfo(infoType : TInfoType; value : String);
+    procedure DoSendJSON(json : TPCJSONObject);
+    function DecodeJSONResult(jsonString : String; out jsonResult : TPCJSONObject) : Boolean;
+    Procedure UpdateLastCallResult(jsonResult : TPCJSONObject);
+  public
+    Property ServerURL : String read FServerURL write SetServerURL;
+  end;
+
+Const
+  CT_TIntoType_Str : Array[TInfoType] of String = ('info','call','response','error');
+
+implementation
+
+{$R *.lfm}
+
+{ TFRMRPCCalls }
+
+procedure TFRMRPCCalls.FormCreate(Sender: TObject);
+begin
+  FServerURL:='127.0.0.1:'+IntToStr(CT_JSONRPC_Port);
+  ebMethod.Text:='';
+  mJSONParams.Clear;
+  mCalls.Clear;
+  vlKeyParams.Clear;
+  vlKeyParams.TitleCaptions.Text:='Key'+#10+'Value';
+  ebServerURL.Text:=FServerURL;
+  pageControl.ActivePage:=tsKeyNames;
+  lblLastCallResultState.Caption:='';
+  mLastResult.Clear;
+end;
+
+procedure TFRMRPCCalls.SetServerURL(AValue: String);
+begin
+  if FServerURL=AValue then Exit;
+  FServerURL:=AValue;
+  ebServerURL.Text := Trim(AValue);
+end;
+
+procedure TFRMRPCCalls.bbSendCommandClick(Sender: TObject);
+Var obj : TPCJSONObject;
+  iRow : Integer;
+  decJSON : TPCJSONData;
+begin
+  obj := TPCJSONObject.Create;
+  try
+    obj.GetAsVariant('jsonrpc').Value:='2.0';
+    obj.GetAsVariant('id').Value:=100;
+    obj.GetAsVariant('method').Value:=ebMethod.Text;
+    //
+    If (pageControl.ActivePage = tsKeyNames) then begin
+      for iRow := 1 to vlKeyParams.RowCount-1 do begin
+        if (vlKeyParams.Keys[iRow]<>'') then begin
+          obj.GetAsObject('params').GetAsVariant( vlKeyParams.Keys[iRow] ).Value:= vlKeyParams.Values[vlKeyParams.Keys[iRow]];
+        end;
+      end;
+    end else begin
+      if (mJSONParams.Text<>'') then begin
+        decJSON := TPCJSONData.ParseJSONValue(mJSONParams.Text);
+        try
+          if (decJSON is TPCJSONObject) then begin
+            obj.GetAsObject('params').Assign(decJSON);
+          end else if (decJSON is TPCJSONArray) then begin
+            obj.GetAsArray('params').Assign(decJSON);
+          end else if (decJSON is TPCJSONVariantValue) then begin
+            obj.GetAsVariant('params').Assign(decJSON);
+          end else begin
+            Raise Exception.Create('Invalid JSON value: '+mJSONParams.Text);
+          end;
+        finally
+          decJSON.Free;
+        end;
+      end;
+    end;
+    //
+    DoSendJSON(obj);
+  finally
+    obj.Free;
+  end;
+end;
+
+procedure TFRMRPCCalls.ShowCallInfo(infoType: TInfoType; value: String);
+begin
+  mCalls.Lines.Add('%s [%s] %s',[FormatDateTime('hh:nn:ss.zzz',Now),CT_TIntoType_Str[infoType],value]);
+end;
+
+procedure TFRMRPCCalls.DoSendJSON(json: TPCJSONObject);
+  function DoHttpPostBinary(const URL: string; const Data: TStream): Boolean;
+  var
+    HTTP: THTTPSend;
+  begin
+    HTTP := THTTPSend.Create;
+    try
+      HTTP.Protocol:='1.1';
+      HTTP.Document.CopyFrom(Data, 0);
+      HTTP.MimeType := 'Application/octet-stream';
+      Result := HTTP.HTTPMethod('POST', URL);
+      Data.Size := 0;
+      if Result then
+      begin
+        Data.Seek(0, soFromBeginning);
+        Data.CopyFrom(HTTP.Document, 0);
+      end;
+    finally
+      HTTP.Free;
+    end;
+  end;
+Var
+  ms : TMemoryStream;
+  s : String;
+  jsonResult : TPCJSONObject;
+begin
+  ShowCallInfo(call,json.ToJSON(false));
+  ms := TMemoryStream.Create;
+  Try
+    ms.Size := 0;
+    TStreamOp.LoadStreamFromRaw(ms,json.ToJSON(False));
+    If Not DoHttpPostBinary(ebServerURL.Text,ms) then ShowCallInfo(error,'no valid response from '+ebServerURL.Text);
+    s := TStreamOp.SaveStreamToRaw(ms);
+    ShowCallInfo(response,s);
+    if DecodeJSONResult(s,jsonResult) then begin
+      Try
+        UpdateLastCallResult(jsonResult);
+      finally
+        jsonResult.Free;
+      end;
+    end else begin
+      ShowCallInfo(error,'Invalid JSON response');
+      UpdateLastCallResult(Nil);
+    end;
+  finally
+    ms.Free;
+  end;
+end;
+
+function TFRMRPCCalls.DecodeJSONResult(jsonString: String; out jsonResult: TPCJSONObject): Boolean;
+Var jsd : TPCJSONData;
+begin
+  jsonResult := Nil;
+  Result := false;
+  If (jsonString='') then Exit;
+  jsd := TPCJSONData.ParseJSONValue(jsonString);
+  Try
+    if jsd is TPCJSONObject then jsonResult := jsd as TPCJSONObject;
+  finally
+    if not Assigned(jsonResult) then begin
+      jsd.Free;
+      Result := False;
+    end else Result := True;
+  end;
+end;
+
+procedure TFRMRPCCalls.UpdateLastCallResult(jsonResult: TPCJSONObject);
+begin
+  If Assigned(jsonResult) then begin
+    if jsonResult.IndexOfName('result')>=0 then begin
+      // Has a valid result:
+      lblLastCallResultState.Font.Color:=clGreen;
+      lblLastCallResultState.Caption:=Format('%s OK',[FormatDateTime('hh:nn:ss.zzz',Now)]);
+      mLastResult.Lines.Text:=jsonResult.ToJSON(False);
+    end else begin
+      // Is an error
+      lblLastCallResultState.Font.Color:=clRed;
+      lblLastCallResultState.Caption:=Format('%s ERROR %d',[FormatDateTime('hh:nn:ss.zzz',Now),jsonResult.GetAsObject('error').AsInteger('code',0)]);
+      mLastResult.Lines.Text:=jsonResult.ToJSON(False);
+    end;
+  end else begin
+    lblLastCallResultState.Caption:='';
+    mLastResult.Clear;
+  end;
+end;
+
+end.
+

+ 87 - 0
src/gui-classic/UFRMRandomOperations.lfm

@@ -0,0 +1,87 @@
+object FRMRandomOperations: TFRMRandomOperations
+  Left = 876
+  Height = 229
+  Top = 391
+  Width = 439
+  Caption = 'Random Operations'
+  ClientHeight = 229
+  ClientWidth = 439
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  Position = poOwnerFormCenter
+  LCLVersion = '1.8.0.6'
+  object pnlTop: TPanel
+    Left = 0
+    Height = 66
+    Top = 0
+    Width = 439
+    Align = alTop
+    BevelOuter = bvNone
+    BorderWidth = 10
+    ClientHeight = 66
+    ClientWidth = 439
+    TabOrder = 0
+    object lblTopCaption: TLabel
+      Left = 10
+      Height = 46
+      Top = 10
+      Width = 419
+      Align = alClient
+      AutoSize = False
+      Caption = 'WARNING! This form will generate RANDOM operations using your private keys!!!'
+      Font.Color = clRed
+      Font.Height = -13
+      Font.Style = [fsBold]
+      Layout = tlCenter
+      ParentColor = False
+      ParentFont = False
+      WordWrap = True
+    end
+  end
+  object pnlClient: TPanel
+    Left = 0
+    Height = 163
+    Top = 66
+    Width = 439
+    Align = alClient
+    BevelOuter = bvNone
+    ClientHeight = 163
+    ClientWidth = 439
+    TabOrder = 1
+    object pnlTop1: TPanel
+      Left = 0
+      Height = 42
+      Top = 0
+      Width = 439
+      Align = alTop
+      BevelOuter = bvNone
+      ClientHeight = 42
+      ClientWidth = 439
+      TabOrder = 0
+      object bbRandomOperations: TButton
+        Left = 16
+        Height = 25
+        Top = 8
+        Width = 195
+        Caption = 'Random Operations'
+        OnClick = bbRandomOperationsClick
+        TabOrder = 0
+      end
+    end
+    object mLogs: TMemo
+      Left = 0
+      Height = 121
+      Top = 42
+      Width = 439
+      Align = alClient
+      Lines.Strings = (
+        'mLogs'
+      )
+      ScrollBars = ssBoth
+      TabOrder = 1
+      WordWrap = False
+    end
+  end
+end

+ 373 - 0
src/gui-classic/UFRMRandomOperations.pas

@@ -0,0 +1,373 @@
+unit UFRMRandomOperations;
+
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
+{ Copyright (c) 2016-2018 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}
+    Windows, AppEvnts,
+  {$ELSE}
+    LCLIntf, LCLType, LMessages, FileUtil,
+  {$ENDIF}
+  Classes, SysUtils,  Forms, Controls, Graphics, Dialogs, StdCtrls,
+  ExtCtrls, Menus, ActnList, UAccounts, UBlockChain, UNode, UCrypto, UBaseTypes,
+  UWallet, UConst, UTxMultiOperation, UOpTransaction;
+
+type
+
+  { TFRMRandomOperations }
+
+  TFRMRandomOperations = class(TForm)
+    bbRandomOperations: TButton;
+    lblTopCaption: TLabel;
+    mLogs: TMemo;
+    pnlClient: TPanel;
+    pnlTop: TPanel;
+    pnlTop1: TPanel;
+    procedure bbRandomOperationsClick(Sender: TObject);
+    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+  private
+    FSourceNode: TNode;
+    FSourceWalletKeys: TWalletKeysExt;
+    FStopRandomOperations : Boolean;
+    FIsProcessingRandomOperations : Boolean;
+    FBankNotify : TPCBankNotify;
+    FCurrOperationsComp : TPCOperationsComp;
+    procedure SetSourceNode(AValue: TNode);
+    procedure SetSourceWalletKeys(AValue: TWalletKeysExt);
+    procedure DoRandomOperations(max : Integer; operationsComp : TPCOperationsComp);
+    procedure DoProcessRandomOperations;
+    procedure NewLog(logTxt : String);
+    procedure OnBankNewBlock(Sender : TObject);
+  public
+    Property SourceNode : TNode read FSourceNode write SetSourceNode;
+    Property SourceWalletKeys : TWalletKeysExt read FSourceWalletKeys write SetSourceWalletKeys;
+  end;
+
+  { TRandomGenerateOperation }
+
+  TRandomGenerateOperation = Class
+  private
+  public
+    class function GetRandomSigner(const operationsComp : TPCOperationsComp; const aWalletKeys : TWalletKeysExt; out iKey : Integer; out nAccount : Cardinal) : Boolean;
+    class function GenerateOpTransaction(const operationsComp : TPCOperationsComp; const aWalletKeys : TWalletKeysExt) : Boolean;
+    class function GenerateOpMultiOperation(const operationsComp : TPCOperationsComp; const aWalletKeys : TWalletKeysExt) : Boolean;
+  end;
+
+implementation
+
+{$R *.lfm}
+
+{ TRandomGenerateOperation }
+
+class function TRandomGenerateOperation.GetRandomSigner(const operationsComp: TPCOperationsComp; const aWalletKeys: TWalletKeysExt; out iKey: Integer; out nAccount: Cardinal): Boolean;
+var availAccounts : TOrderedCardinalList;
+  acc : TAccount;
+  i, nRounds : Integer;
+begin
+  Result := False; iKey := -1; nAccount:=0; nRounds := 0;
+  if (aWalletKeys.AccountsKeyList.Count<=0) then Exit;
+  Repeat
+    iKey := Random( aWalletKeys.AccountsKeyList.Count );
+    i := aWalletKeys.AccountsKeyList.Count;
+    if i<0 then Exit;
+    availAccounts := aWalletKeys.AccountsKeyList.AccountKeyList[iKey];
+    if availAccounts.Count<=0 then Exit; // No valid accounts
+    i := availAccounts.Count;
+    if (i<0) then Exit;
+    // Sender:
+    nAccount := availAccounts.Get( Random(availAccounts.Count) );
+    acc.balance := 0;
+    If Not TAccountComp.IsAccountBlockedByProtocol(nAccount,operationsComp.SafeBoxTransaction.FreezedSafeBox.BlocksCount) then begin
+      if (operationsComp.OperationsHashTree.CountOperationsBySameSignerWithoutFee(nAccount)<=0) then acc := operationsComp.SafeBoxTransaction.Account(nAccount);
+    end;
+    inc(nRounds);
+    if (nRounds>1000) then Exit;
+  until (acc.balance>0);
+  Result := True;
+end;
+
+class function TRandomGenerateOperation.GenerateOpTransaction(const operationsComp: TPCOperationsComp; const aWalletKeys: TWalletKeysExt): Boolean;
+var nAccount : Cardinal;
+  iKey : Integer;
+  opTx : TOpTransaction;
+  senderAcc,destAcc : TAccount;
+  amount,fees : Int64;
+  errors : AnsiString;
+begin
+  Result := False;
+  If Not GetRandomSigner(operationsComp,aWalletKeys,iKey,nAccount) then Exit;
+  senderAcc := operationsComp.SafeBoxTransaction.Account(nAccount);
+  amount := Random(Integer(senderAcc.balance));
+  if amount<=0 then Exit;
+  If (senderAcc.balance - amount)>0 then begin
+    fees := Random( senderAcc.balance - amount )
+  end else fees := 0;
+
+  iKey := aWalletKeys.IndexOfAccountKey( aWalletKeys.AccountsKeyList.AccountKey[iKey] );
+  if iKey<0 then Exit;
+  if Not aWalletKeys.Key[iKey].HasPrivateKey then Exit;
+  if Not Assigned(aWalletKeys.Key[iKey].PrivateKey) then Exit;
+  // Dest
+  Repeat
+    destAcc := operationsComp.SafeBoxTransaction.Account( Random(operationsComp.SafeBoxTransaction.FreezedSafeBox.AccountsCount) );
+  until (destAcc.account <> senderAcc.account);
+
+  // Search account
+  opTx := TOpTransaction.CreateTransaction(senderAcc.account,senderAcc.n_operation+1,destAcc.account,aWalletKeys.Key[iKey].PrivateKey,amount,fees,'');
+  Try
+    Result := operationsComp.AddOperation(True,opTx,errors);
+  finally
+    opTx.Free;
+  end;
+end;
+
+class function TRandomGenerateOperation.GenerateOpMultiOperation(const operationsComp: TPCOperationsComp; const aWalletKeys: TWalletKeysExt): Boolean;
+   procedure DoSign(opMulti : TOpMultiOperation);
+   var n : Integer;
+     i,j : Integer;
+   begin
+     n := 0;
+     For i:=0 to High(opMulti.Data.txSenders) do begin
+       j := aWalletKeys.IndexOfAccountKey(operationsComp.bank.SafeBox.Account(opMulti.Data.txSenders[i].Account).accountInfo.accountKey);
+       If (j>=0) then begin
+         // Can sign
+         If (Assigned(aWalletKeys.Key[j].PrivateKey)) then begin
+           inc(n, opMulti.DoSignMultiOperationSigner(opMulti.Data.txSenders[i].Account,aWalletKeys.Key[j].PrivateKey));
+         end;
+       end;
+     end;
+     For i:=0 to High(opMulti.Data.changesInfo) do begin
+       j := aWalletKeys.IndexOfAccountKey(operationsComp.bank.SafeBox.Account(opMulti.Data.changesInfo[i].Account).accountInfo.accountKey);
+       If (j>=0) then begin
+         // Can sign
+         If (Assigned(aWalletKeys.Key[j].PrivateKey)) then begin
+           inc(n, opMulti.DoSignMultiOperationSigner(opMulti.Data.changesInfo[i].Account,aWalletKeys.Key[j].PrivateKey));
+         end;
+       end;
+     end;
+   end;
+
+Var opMulti : TOpMultiOperation;
+  iKey : Integer;
+  nAccount : Cardinal;
+  sender : TMultiOpSender;
+  receiver : TMultiOpReceiver;
+  changer: TMultiOpChangeInfo;
+  acc : TAccount;
+  errors : AnsiString;
+begin
+  Result := False;
+  opMulti := TOpMultiOperation.Create;
+  Try
+    if (Random(100)<5) then begin
+      Repeat
+        If GetRandomSigner(operationsComp,aWalletKeys,iKey,nAccount) then begin
+          acc := operationsComp.SafeBoxTransaction.Account(nAccount);
+          if Not OpMulti.IsSignerAccount(nAccount) then begin
+            sender := CT_TMultiOpSender_NUL;
+            sender.Account:=nAccount;
+            sender.Amount:= Random( Integer(acc.balance) );
+            sender.N_Operation:=acc.n_operation+1;
+            opMulti.AddTxSender(sender);
+          end;
+        end;
+      until (Random(100)=0) Or ((Length(opMulti.Data.txSenders)>Random(1000)) And (opMulti.OperationFee>Random(1000000)));
+      Repeat
+        nAccount := Random( operationsComp.SafeBoxTransaction.FreezedSafeBox.AccountsCount );
+        If Not TAccountComp.IsAccountBlockedByProtocol(nAccount,operationsComp.SafeBoxTransaction.FreezedSafeBox.BlocksCount) then begin
+          receiver := CT_TMultiOpReceiver_NUL;
+          receiver.Account:=nAccount;
+          receiver.Amount:=Random( Integer(opMulti.OperationFee) );
+          opMulti.AddTxReceiver(receiver);
+        end;
+      until (Random(100)=0) Or (opMulti.OperationFee<=0);
+    end;
+    if (Random(100)<5) then begin
+      Repeat
+        changer := CT_TMultiOpChangeInfo_NUL;
+        If GetRandomSigner(operationsComp,aWalletKeys,iKey,nAccount) then begin
+          acc := operationsComp.SafeBoxTransaction.Account(nAccount);
+          if Not OpMulti.IsSignerAccount(nAccount) then begin
+            changer.Account:=nAccount;
+            changer.N_Operation:=acc.n_operation+1;
+            case Random(3) of // public_key,account_name,account_type
+              0 : begin
+                changer.Changes_type:=[public_key];
+                acc := operationsComp.SafeBoxTransaction.Account(Random(operationsComp.SafeBoxTransaction.FreezedSafeBox.AccountsCount));
+                changer.New_Accountkey := acc.accountInfo.accountKey;
+              end;
+              1 : begin
+                changer.Changes_type:=[account_name];
+                changer.New_Name:='random'+IntToStr(Random(100)); // <- This will generate collisions
+              end;
+            else
+              changer.Changes_type:=[account_type];
+              changer.New_Type:=Random(65535);
+            end;
+            opMulti.AddChangeInfo(changer);
+          end;
+        end;
+      until (Random(100)=0) Or (Length(opMulti.Data.changesInfo)>Random(1000));
+    end;
+    // If nothing added... invalid op.
+    if (Length(opMulti.Data.changesInfo)=0) And (Length(opMulti.Data.txSenders)=0) And (Length(opMulti.Data.txReceivers)=0) then Exit;
+    //
+    DoSign(opMulti);
+    if Not opMulti.CheckSignatures(operationsComp.SafeBoxTransaction,errors) then begin
+      errors := opMulti.toString + errors;
+      Exit;
+    end;
+    Result := operationsComp.AddOperation(True,opMulti,errors);
+  finally
+    opMulti.Free;
+  end;
+end;
+
+{ TFRMRandomOperations }
+
+procedure TFRMRandomOperations.FormCreate(Sender: TObject);
+begin
+  FSourceNode := Nil;
+  FSourceWalletKeys := Nil;
+  FIsProcessingRandomOperations := False;
+  FStopRandomOperations := True;
+  FBankNotify := TPCBankNotify.Create(Nil);
+  FBankNotify.OnNewBlock:=OnBankNewBlock;
+  FCurrOperationsComp := TPCOperationsComp.Create(Nil);
+  mLogs.Clear;
+end;
+
+procedure TFRMRandomOperations.FormDestroy(Sender: TObject);
+begin
+  FreeAndNil(FBankNotify);
+  FreeAndNil(FCurrOperationsComp);
+end;
+
+procedure TFRMRandomOperations.bbRandomOperationsClick(Sender: TObject);
+begin
+  {$IFDEF TESTNET}
+  If FIsProcessingRandomOperations then begin
+    FStopRandomOperations := True;
+  end else begin
+    DoProcessRandomOperations;
+  end;
+  {$ELSE}
+  Raise Exception.Create('Random operations not valid in PRODUCTION MODE');
+  {$ENDIF}
+end;
+
+procedure TFRMRandomOperations.FormClose(Sender: TObject; var CloseAction: TCloseAction);
+begin
+  FStopRandomOperations := True;
+  CloseAction := caFree;
+end;
+
+procedure TFRMRandomOperations.FormCloseQuery(Sender: TObject; var CanClose: boolean);
+begin
+  FStopRandomOperations := True;
+  CanClose := True;
+end;
+
+procedure TFRMRandomOperations.SetSourceNode(AValue: TNode);
+begin
+  if FSourceNode=AValue then Exit;
+  FBankNotify.Bank := Nil;
+  FSourceNode:=AValue;
+  If Assigned(AValue) then begin
+    FBankNotify.Bank := AValue.Bank;
+    FCurrOperationsComp.bank := AValue.Bank;
+  end;
+end;
+
+procedure TFRMRandomOperations.SetSourceWalletKeys(AValue: TWalletKeysExt);
+begin
+  if FSourceWalletKeys=AValue then Exit;
+  FSourceWalletKeys:=AValue;
+end;
+
+procedure TFRMRandomOperations.DoRandomOperations(max: Integer; operationsComp : TPCOperationsComp);
+Var
+  nCounter : Integer;
+begin
+  nCounter := 0;
+  While (nCounter<max) And (Not FStopRandomOperations) do begin
+    Case Random(30) of
+      0..20 : begin
+        If TRandomGenerateOperation.GenerateOpTransaction(operationsComp,FSourceWalletKeys) then inc(nCounter);
+      end;
+      21..25 : begin
+        If TRandomGenerateOperation.GenerateOpMultiOperation(operationsComp,FSourceWalletKeys) then inc(nCounter);
+      end;
+    else Sleep(10);
+    end;
+    Application.ProcessMessages;
+  end;
+end;
+
+procedure TFRMRandomOperations.DoProcessRandomOperations;
+Var errors : AnsiString;
+  i : Integer;
+begin
+  newLog('Start Random');
+  Try
+    FCurrOperationsComp.Clear(True);
+    FStopRandomOperations:=False;
+    FIsProcessingRandomOperations:=True;
+    Try
+      bbRandomOperations.Caption:='STOP';
+      Application.ProcessMessages;
+      While (FIsProcessingRandomOperations) And (Not FStopRandomOperations) do begin
+        //
+        FCurrOperationsComp.Clear(True);
+        FCurrOperationsComp.SafeBoxTransaction.CopyFrom(FSourceNode.Operations.SafeBoxTransaction);
+        //
+        DoRandomOperations(Random(50),FCurrOperationsComp);
+        i := FSourceNode.AddOperations(Nil,FCurrOperationsComp.OperationsHashTree,nil,errors);
+        //
+        newLog(Format('Added %d/%d operations - Errors: %s',[i,FCurrOperationsComp.Count, errors]));
+        Application.ProcessMessages;
+      end;
+    finally
+      FIsProcessingRandomOperations := False;
+      bbRandomOperations.Caption:='Random Operations';
+    end;
+  finally
+    newLog('End Random');
+  end;
+end;
+
+procedure TFRMRandomOperations.NewLog(logTxt: String);
+begin
+  mLogs.Lines.Add(Format('%s %s',[FormatDateTime('hh:nn:ss.zzz',Now),logTxt]));
+end;
+
+procedure TFRMRandomOperations.OnBankNewBlock(Sender: TObject);
+begin
+  NewLog(Format('Updating to new block %d',[FBankNotify.Bank.BlocksCount]));
+  FCurrOperationsComp.SanitizeOperations;
+end;
+
+end.
+

+ 6 - 31
src/gui-classic/UFRMWallet.dfm

@@ -636,10 +636,6 @@ object FRMWallet: TFRMWallet
         object tsMultiSelectAccounts: TTabSheet
         object tsMultiSelectAccounts: TTabSheet
           Caption = 'Selected accounts for massive operations'
           Caption = 'Selected accounts for massive operations'
           ImageIndex = 1
           ImageIndex = 1
-          ExplicitLeft = 0
-          ExplicitTop = 0
-          ExplicitWidth = 429
-          ExplicitHeight = 0
           object dgSelectedAccounts: TDrawGrid
           object dgSelectedAccounts: TDrawGrid
             Left = 41
             Left = 41
             Top = 31
             Top = 31
@@ -668,7 +664,6 @@ object FRMWallet: TFRMWallet
             Font.Style = [fsBold]
             Font.Style = [fsBold]
             ParentFont = False
             ParentFont = False
             TabOrder = 1
             TabOrder = 1
-            ExplicitWidth = 429
             object Label15: TLabel
             object Label15: TLabel
               Left = 41
               Left = 41
               Top = 4
               Top = 4
@@ -685,7 +680,6 @@ object FRMWallet: TFRMWallet
             Align = alBottom
             Align = alBottom
             BevelOuter = bvNone
             BevelOuter = bvNone
             TabOrder = 2
             TabOrder = 2
-            ExplicitWidth = 429
             object Label20: TLabel
             object Label20: TLabel
               Left = 41
               Left = 41
               Top = 6
               Top = 6
@@ -831,10 +825,6 @@ object FRMWallet: TFRMWallet
     object tsPendingOperations: TTabSheet
     object tsPendingOperations: TTabSheet
       Caption = 'Pending Operations'
       Caption = 'Pending Operations'
       ImageIndex = 5
       ImageIndex = 5
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object dgPendingOperations: TDrawGrid
       object dgPendingOperations: TDrawGrid
         Left = 0
         Left = 0
         Top = 86
         Top = 86
@@ -882,10 +872,6 @@ object FRMWallet: TFRMWallet
     object tsBlockChain: TTabSheet
     object tsBlockChain: TTabSheet
       Caption = 'BlockChain Explorer'
       Caption = 'BlockChain Explorer'
       ImageIndex = 1
       ImageIndex = 1
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object Panel2: TPanel
       object Panel2: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -931,10 +917,6 @@ object FRMWallet: TFRMWallet
     object tsOperations: TTabSheet
     object tsOperations: TTabSheet
       Caption = 'Operations Explorer'
       Caption = 'Operations Explorer'
       ImageIndex = 1
       ImageIndex = 1
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object Panel1: TPanel
       object Panel1: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -980,10 +962,6 @@ object FRMWallet: TFRMWallet
     object tsLogs: TTabSheet
     object tsLogs: TTabSheet
       Caption = 'Logs'
       Caption = 'Logs'
       ImageIndex = 2
       ImageIndex = 2
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object pnlTopLogs: TPanel
       object pnlTopLogs: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -1013,10 +991,6 @@ object FRMWallet: TFRMWallet
     object tsNodeStats: TTabSheet
     object tsNodeStats: TTabSheet
       Caption = 'Node Stats'
       Caption = 'Node Stats'
       ImageIndex = 3
       ImageIndex = 3
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       DesignSize = (
       DesignSize = (
         841
         841
         404)
         404)
@@ -1082,10 +1056,6 @@ object FRMWallet: TFRMWallet
     object tsMessages: TTabSheet
     object tsMessages: TTabSheet
       Caption = 'Messages'
       Caption = 'Messages'
       ImageIndex = 6
       ImageIndex = 6
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       DesignSize = (
       DesignSize = (
         841
         841
         404)
         404)
@@ -1281,6 +1251,11 @@ object FRMWallet: TFRMWallet
         ShortCut = 112
         ShortCut = 112
         OnClick = MiAccountInformationClick
         OnClick = MiAccountInformationClick
       end
       end
+      object MiOperationsExplorer: TMenuItem
+        Caption = 'Operations Explorer'
+        ShortCut = 16453
+        OnClick = MiOperationsExplorerClick
+      end
       object N2: TMenuItem
       object N2: TMenuItem
         Caption = '-'
         Caption = '-'
       end
       end
@@ -1325,7 +1300,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Left = 105
     Top = 180
     Top = 180
     Bitmap = {
     Bitmap = {
-      494C010102000800300210003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000800340210003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 67 - 15
src/gui-classic/UFRMWallet.lfm

@@ -1,6 +1,6 @@
 object FRMWallet: TFRMWallet
 object FRMWallet: TFRMWallet
   Left = 389
   Left = 389
-  Height = 580
+  Height = 600
   Top = 201
   Top = 201
   Width = 865
   Width = 865
   Caption = 'Pascal Coin Wallet, JSON-RPC Miner & Explorer'
   Caption = 'Pascal Coin Wallet, JSON-RPC Miner & Explorer'
@@ -17,7 +17,6 @@ object FRMWallet: TFRMWallet
   OnDestroy = FormDestroy
   OnDestroy = FormDestroy
   Position = poOwnerFormCenter
   Position = poOwnerFormCenter
   LCLVersion = '1.8.0.6'
   LCLVersion = '1.8.0.6'
-  Visible = False
   object pnlTop: TPanel
   object pnlTop: TPanel
     Left = 0
     Left = 0
     Height = 91
     Height = 91
@@ -366,7 +365,7 @@ object FRMWallet: TFRMWallet
   object StatusBar: TStatusBar
   object StatusBar: TStatusBar
     Left = 0
     Left = 0
     Height = 23
     Height = 23
-    Top = 537
+    Top = 557
     Width = 865
     Width = 865
     Panels = <    
     Panels = <    
       item
       item
@@ -386,21 +385,21 @@ object FRMWallet: TFRMWallet
   end
   end
   object PageControl: TPageControl
   object PageControl: TPageControl
     Left = 0
     Left = 0
-    Height = 446
+    Height = 466
     Top = 91
     Top = 91
     Width = 865
     Width = 865
-    ActivePage = tsMyAccounts
+    ActivePage = tsBlockChain
     Align = alClient
     Align = alClient
-    TabIndex = 0
+    TabIndex = 2
     TabOrder = 2
     TabOrder = 2
     OnChange = PageControlChange
     OnChange = PageControlChange
     object tsMyAccounts: TTabSheet
     object tsMyAccounts: TTabSheet
       Caption = 'Account Explorer'
       Caption = 'Account Explorer'
-      ClientHeight = 420
+      ClientHeight = 440
       ClientWidth = 857
       ClientWidth = 857
       object Splitter1: TSplitter
       object Splitter1: TSplitter
         Left = 400
         Left = 400
-        Height = 354
+        Height = 374
         Top = 66
         Top = 66
         Width = 5
         Width = 5
       end
       end
@@ -526,17 +525,17 @@ object FRMWallet: TFRMWallet
       end
       end
       object pnlAccounts: TPanel
       object pnlAccounts: TPanel
         Left = 0
         Left = 0
-        Height = 354
+        Height = 374
         Top = 66
         Top = 66
         Width = 400
         Width = 400
         Align = alLeft
         Align = alLeft
         BevelOuter = bvNone
         BevelOuter = bvNone
-        ClientHeight = 354
+        ClientHeight = 374
         ClientWidth = 400
         ClientWidth = 400
         TabOrder = 1
         TabOrder = 1
         object dgAccounts: TDrawGrid
         object dgAccounts: TDrawGrid
           Left = 0
           Left = 0
-          Height = 320
+          Height = 340
           Top = 0
           Top = 0
           Width = 400
           Width = 400
           Align = alClient
           Align = alClient
@@ -550,7 +549,7 @@ object FRMWallet: TFRMWallet
         object pnlAccountsInfo: TPanel
         object pnlAccountsInfo: TPanel
           Left = 0
           Left = 0
           Height = 34
           Height = 34
-          Top = 320
+          Top = 340
           Width = 400
           Width = 400
           Align = alBottom
           Align = alBottom
           BevelOuter = bvNone
           BevelOuter = bvNone
@@ -631,7 +630,7 @@ object FRMWallet: TFRMWallet
       end
       end
       object pcAccountsOptions: TPageControl
       object pcAccountsOptions: TPageControl
         Left = 405
         Left = 405
-        Height = 354
+        Height = 374
         Top = 66
         Top = 66
         Width = 452
         Width = 452
         ActivePage = tsAccountOperations
         ActivePage = tsAccountOperations
@@ -640,11 +639,11 @@ object FRMWallet: TFRMWallet
         TabOrder = 2
         TabOrder = 2
         object tsAccountOperations: TTabSheet
         object tsAccountOperations: TTabSheet
           Caption = 'Operations of selected Account'
           Caption = 'Operations of selected Account'
-          ClientHeight = 328
+          ClientHeight = 348
           ClientWidth = 444
           ClientWidth = 444
           object dgAccountOperations: TDrawGrid
           object dgAccountOperations: TDrawGrid
             Left = 0
             Left = 0
-            Height = 328
+            Height = 348
             Top = 0
             Top = 0
             Width = 444
             Width = 444
             Align = alClient
             Align = alClient
@@ -941,6 +940,50 @@ object FRMWallet: TFRMWallet
           OnKeyPress = ebBlockChainBlockStartKeyPress
           OnKeyPress = ebBlockChainBlockStartKeyPress
           TabOrder = 1
           TabOrder = 1
         end
         end
+        object lblHashRateBackBlocks: TLabel
+          Left = 280
+          Height = 13
+          Top = 10
+          Width = 104
+          Caption = 'HashRate back blocks'
+          ParentColor = False
+        end
+        object ebHashRateBackBlocks: TEdit
+          Left = 392
+          Height = 21
+          Top = 7
+          Width = 56
+          OnExit = ebHashRateBackBlocksExit
+          OnKeyPress = ebHashRateBackBlocksKeyPress
+          TabOrder = 2
+        end
+        object lblHashRateBackBlocks1: TLabel
+          Left = 463
+          Height = 13
+          Top = 10
+          Width = 24
+          Caption = 'Units'
+          ParentColor = False
+        end
+        object cbHashRateUnits: TComboBox
+          Left = 496
+          Height = 21
+          Top = 7
+          Width = 56
+          ItemHeight = 13
+          ItemIndex = 1
+          Items.Strings = (
+            'Kh/s'
+            'Mh/s'
+            'Gh/s'
+            'Th/s'
+          )
+          OnChange = cbHashRateUnitsClick
+          OnClick = cbHashRateUnitsClick
+          Style = csDropDownList
+          TabOrder = 3
+          Text = 'Mh/s'
+        end
       end
       end
       object dgBlockChainExplorer: TDrawGrid
       object dgBlockChainExplorer: TDrawGrid
         Left = 0
         Left = 0
@@ -1234,6 +1277,10 @@ object FRMWallet: TFRMWallet
         Caption = 'Available Node List'
         Caption = 'Available Node List'
         OnClick = IPnodes1Click
         OnClick = IPnodes1Click
       end
       end
+      object MiRPCCalls: TMenuItem
+        Caption = 'RPC Calls'
+        OnClick = MiRPCCallsClick
+      end
       object N1: TMenuItem
       object N1: TMenuItem
         Caption = '-'
         Caption = '-'
       end
       end
@@ -1269,6 +1316,11 @@ object FRMWallet: TFRMWallet
         ShortCut = 112
         ShortCut = 112
         OnClick = MiAccountInformationClick
         OnClick = MiAccountInformationClick
       end
       end
+      object MiOperationsExplorer: TMenuItem
+        Caption = 'Operations Explorer'
+        ShortCut = 16453
+        OnClick = MiOperationsExplorerClick
+      end
       object N2: TMenuItem
       object N2: TMenuItem
         Caption = '-'
         Caption = '-'
       end
       end

+ 108 - 6
src/gui-classic/UFRMWallet.pas

@@ -27,12 +27,11 @@ uses
 {$ELSE}
 {$ELSE}
   LCLIntf, LCLType, LMessages,
   LCLIntf, LCLType, LMessages,
 {$ENDIF}
 {$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;
+  Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,
+  ExtCtrls, ComCtrls, UWallet, StdCtrls, ULog, Grids, UAppParams, UBlockChain,
+  UNode, UGridUtils, UJSONFunctions, UAccounts, Menus, ImgList, UNetProtocol,
+  UCrypto, Buttons, UPoolMining, URPC, UFRMAccountSelect, UFRMRPCCalls, UConst,
+  UTxMultiOperation;
 
 
 Const
 Const
   CM_PC_WalletKeysChanged = WM_USER + 1;
   CM_PC_WalletKeysChanged = WM_USER + 1;
@@ -44,6 +43,11 @@ type
   { TFRMWallet }
   { TFRMWallet }
 
 
   TFRMWallet = class(TForm)
   TFRMWallet = class(TForm)
+    cbHashRateUnits: TComboBox;
+    ebHashRateBackBlocks: TEdit;
+    lblHashRateBackBlocks: TLabel;
+    lblHashRateBackBlocks1: TLabel;
+    MiRPCCalls: TMenuItem;
     pnlTop: TPanel;
     pnlTop: TPanel;
     Image1: TImage;
     Image1: TImage;
     sbSearchAccount: TSpeedButton;
     sbSearchAccount: TSpeedButton;
@@ -170,8 +174,14 @@ type
     dgOperationsExplorer: TDrawGrid;
     dgOperationsExplorer: TDrawGrid;
     MiFindOperationbyOpHash: TMenuItem;
     MiFindOperationbyOpHash: TMenuItem;
     MiAccountInformation: TMenuItem;
     MiAccountInformation: TMenuItem;
+    MiOperationsExplorer: TMenuItem;
+    procedure cbHashRateUnitsClick(Sender: TObject);
+    procedure ebHashRateBackBlocksExit(Sender: TObject);
+    procedure ebHashRateBackBlocksKeyPress(Sender: TObject; var Key: char);
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
+    procedure MiOperationsExplorerClick(Sender: TObject);
+    procedure MiRPCCallsClick(Sender: TObject);
     procedure sbSearchAccountClick(Sender: TObject);
     procedure sbSearchAccountClick(Sender: TObject);
     procedure TimerUpdateStatusTimer(Sender: TObject);
     procedure TimerUpdateStatusTimer(Sender: TObject);
     procedure cbMyPrivateKeysChange(Sender: TObject);
     procedure cbMyPrivateKeysChange(Sender: TObject);
@@ -297,6 +307,7 @@ implementation
 
 
 Uses UFolderHelper, UOpenSSL, UOpenSSLdef, UTime, UFileStorage,
 Uses UFolderHelper, UOpenSSL, UOpenSSLdef, UTime, UFileStorage,
   UThread, UOpTransaction, UECIES, UFRMPascalCoinWalletConfig,
   UThread, UOpTransaction, UECIES, UFRMPascalCoinWalletConfig,
+  UFRMOperationsExplorer,
   UFRMAbout, UFRMOperation, UFRMWalletKeys, UFRMPayloadDecoder, UFRMNodesIp, UFRMMemoText, USettings;
   UFRMAbout, UFRMOperation, UFRMWalletKeys, UFRMPayloadDecoder, UFRMNodesIp, UFRMMemoText, USettings;
 
 
 Type
 Type
@@ -796,6 +807,8 @@ begin
 end;
 end;
 
 
 procedure TFRMWallet.FillOperationInformation(const Strings: TStrings; Const OperationResume: TOperationResume);
 procedure TFRMWallet.FillOperationInformation(const Strings: TStrings; Const OperationResume: TOperationResume);
+var i : Integer;
+  jsonObj : TPCJSONObject;
 begin
 begin
   If (not OperationResume.valid) then exit;
   If (not OperationResume.valid) then exit;
   If OperationResume.Block<FNode.Bank.BlocksCount then
   If OperationResume.Block<FNode.Bank.BlocksCount then
@@ -806,6 +819,19 @@ begin
     end
     end
   else Strings.Add('** Pending operation not included on blockchain **');
   else Strings.Add('** Pending operation not included on blockchain **');
   Strings.Add(Format('%s',[OperationResume.OperationTxt]));
   Strings.Add(Format('%s',[OperationResume.OperationTxt]));
+  If (OperationResume.isMultiOperation) then begin
+    Strings.Add('Multioperation:');
+    For i := 0 to High(OperationResume.Senders) do begin
+      Strings.Add(Format('  Sender (%d/%d): %s %s PASC Payload:%s',[i+1,length(OperationResume.Senders),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Senders[i].Account),TAccountComp.FormatMoney(OperationResume.Senders[i].Amount),TCrypto.ToHexaString(OperationResume.Senders[i].Payload)]));
+    end;
+    For i := 0 to High(OperationResume.Receivers) do begin
+      Strings.Add(Format('  Receiver (%d/%d): %s %s PASC Payload:%s',[i+1,length(OperationResume.Receivers),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Receivers[i].Account),TAccountComp.FormatMoney(OperationResume.Receivers[i].Amount),TCrypto.ToHexaString(OperationResume.Receivers[i].Payload)]));
+    end;
+    For i := 0 to High(OperationResume.Changers) do begin
+      Strings.Add(Format('  Change info (%d/%d): %s [%s]',[i+1,length(OperationResume.Changers),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Changers[i].Account),TOpMultiOperation.OpChangeAccountInfoTypesToText(OperationResume.Changers[i].Changes_type)]));
+    end;
+
+  end;
   Strings.Add(Format('OpType:%d Subtype:%d',[OperationResume.OpType,OperationResume.OpSubtype]));
   Strings.Add(Format('OpType:%d Subtype:%d',[OperationResume.OpType,OperationResume.OpSubtype]));
   Strings.Add(Format('Operation Hash (ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash)]));
   Strings.Add(Format('Operation Hash (ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash)]));
   If (OperationResume.OperationHash_OLD<>'') then begin
   If (OperationResume.OperationHash_OLD<>'') then begin
@@ -821,6 +847,14 @@ begin
   If OperationResume.Balance>=0 then begin
   If OperationResume.Balance>=0 then begin
     Strings.Add(Format('Final balance: %s',[TAccountComp.FormatMoney(OperationResume.Balance)]));
     Strings.Add(Format('Final balance: %s',[TAccountComp.FormatMoney(OperationResume.Balance)]));
   end;
   end;
+  jsonObj := TPCJSONObject.Create;
+  Try
+    TPascalCoinJSONComp.FillOperationObject(OperationResume,FNode.Bank.BlocksCount,jsonObj);
+    Strings.Add('JSON:');
+    Strings.Add(jsonObj.ToJSON(False));
+  Finally
+    jsonObj.Free;
+  end;
 end;
 end;
 
 
 function TFRMWallet.ForceMining: Boolean;
 function TFRMWallet.ForceMining: Boolean;
@@ -913,6 +947,42 @@ begin
   FBackgroundPanel.Font.Size:=15;
   FBackgroundPanel.Font.Size:=15;
 end;
 end;
 
 
+procedure TFRMWallet.ebHashRateBackBlocksKeyPress(Sender: TObject; var Key: char);
+begin
+  if Key=#13 then ebHashRateBackBlocksExit(Nil);
+end;
+
+procedure TFRMWallet.ebHashRateBackBlocksExit(Sender: TObject);
+var i : Integer;
+begin
+  If FUpdating then exit;
+  FUpdating := True;
+  Try
+    i := StrToIntDef(ebHashRateBackBlocks.Text,-1);
+    FBlockChainGrid.HashRateAverageBlocksCount:=i;
+  Finally
+    ebHashRateBackBlocks.Text := IntToStr(FBlockChainGrid.HashRateAverageBlocksCount);
+    FUpdating := false;
+  End;
+end;
+
+procedure TFRMWallet.cbHashRateUnitsClick(Sender: TObject);
+begin
+  If FUpdating then Exit;
+  FUpdating := True;
+  Try
+    case cbHashRateUnits.ItemIndex of
+      0 : FBlockChainGrid.HashRateAs := hr_Kilo;
+      1 : FBlockChainGrid.HashRateAs := hr_Mega;
+      2 : FBlockChainGrid.HashRateAs := hr_Giga;
+      3 : FBlockChainGrid.HashRateAs := hr_Tera;
+    else FBlockChainGrid.HashRateAs := hr_Mega;
+    end;
+  Finally
+    FUpdating := false;
+  End;
+end;
+
 procedure TFRMWallet.FormDestroy(Sender: TObject);
 procedure TFRMWallet.FormDestroy(Sender: TObject);
 Var i : Integer;
 Var i : Integer;
   step : String;
   step : String;
@@ -982,6 +1052,30 @@ begin
   Sleep(100);
   Sleep(100);
 end;
 end;
 
 
+procedure TFRMWallet.MiOperationsExplorerClick(Sender: TObject);
+begin
+  With TFRMOperationsExplorer.Create(Self) do
+  try
+    SourceNode := FNode;
+    SourceWalletKeys := FWalletKeys;
+    ShowModal;
+  finally
+    Free;
+  end;
+end;
+
+procedure TFRMWallet.MiRPCCallsClick(Sender: TObject);
+Var FRM : TFRMRPCCalls;
+begin
+  FRM := TFRMRPCCalls.Create(Self);
+  Try
+    FRM.ServerURL:='127.0.0.1:'+IntToStr(FRPCServer.Port);
+    FRM.ShowModal;
+  finally
+    FRM.Free;
+  end;
+end;
+
 procedure TFRMWallet.sbSearchAccountClick(Sender: TObject);
 procedure TFRMWallet.sbSearchAccountClick(Sender: TObject);
 Var F : TFRMAccountSelect;
 Var F : TFRMAccountSelect;
 begin
 begin
@@ -1841,6 +1935,14 @@ begin
   i := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random));
   i := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random));
   if (i>=Integer(Low(TMinerPrivatekey))) And (i<=Integer(High(TMinerPrivatekey))) then FMinerPrivateKeyType := TMinerPrivateKey(i)
   if (i>=Integer(Low(TMinerPrivatekey))) And (i<=Integer(High(TMinerPrivatekey))) then FMinerPrivateKeyType := TMinerPrivateKey(i)
   else FMinerPrivateKeyType := mpk_Random;
   else FMinerPrivateKeyType := mpk_Random;
+  ebHashRateBackBlocks.Text := IntToStr(FBlockChainGrid.HashRateAverageBlocksCount);
+  Case FBlockChainGrid.HashRateAs of
+    hr_Kilo : cbHashRateUnits.ItemIndex:=0;
+    hr_Mega : cbHashRateUnits.ItemIndex:=1;
+    hr_Giga : cbHashRateUnits.ItemIndex:=2;
+    hr_Tera : cbHashRateUnits.ItemIndex:=3;
+  else cbHashRateUnits.ItemIndex:=-1;
+  end;
 end;
 end;
 
 
 procedure TFRMWallet.UpdateConnectionStatus;
 procedure TFRMWallet.UpdateConnectionStatus;

+ 50 - 20
src/gui-classic/UGridUtils.pas

@@ -19,6 +19,8 @@ unit UGridUtils;
 
 
 interface
 interface
 
 
+{$I ../config.inc}
+
 uses
 uses
 {$IFnDEF FPC}
 {$IFnDEF FPC}
   Windows,
   Windows,
@@ -129,6 +131,7 @@ Type
     Volume : Int64;
     Volume : Int64;
     Reward, Fee : Int64;
     Reward, Fee : Int64;
     Target : Cardinal;
     Target : Cardinal;
+    HashRateTargetKhs : Int64;
     HashRateKhs : Int64;
     HashRateKhs : Int64;
     MinerPayload : TRawBytes;
     MinerPayload : TRawBytes;
     PoW : TRawBytes;
     PoW : TRawBytes;
@@ -146,10 +149,13 @@ Type
 
 
   { TBlockChainGrid }
   { TBlockChainGrid }
 
 
+  TShowHashRateAs = (hr_Kilo, hr_Mega, hr_Giga, hr_Tera);
+
   TBlockChainGrid = Class(TComponent)
   TBlockChainGrid = Class(TComponent)
   private
   private
     FBlockChainDataArray : TBlockChainDataArray;
     FBlockChainDataArray : TBlockChainDataArray;
     FBlockStart: Int64;
     FBlockStart: Int64;
+    FHashRateAs: TShowHashRateAs;
     FMaxBlocks: Integer;
     FMaxBlocks: Integer;
     FBlockEnd: Int64;
     FBlockEnd: Int64;
     FDrawGrid: TDrawGrid;
     FDrawGrid: TDrawGrid;
@@ -163,6 +169,7 @@ Type
     procedure SetBlockEnd(const Value: Int64);
     procedure SetBlockEnd(const Value: Int64);
     procedure SetBlockStart(const Value: Int64);
     procedure SetBlockStart(const Value: Int64);
     procedure SetDrawGrid(const Value: TDrawGrid);
     procedure SetDrawGrid(const Value: TDrawGrid);
+    procedure SetHashRateAs(AValue: TShowHashRateAs);
     procedure SetMaxBlocks(const Value: Integer);
     procedure SetMaxBlocks(const Value: Integer);
     procedure SetNode(const Value: TNode);
     procedure SetNode(const Value: TNode);
     procedure SetHashRateAverageBlocksCount(const Value: Integer);
     procedure SetHashRateAverageBlocksCount(const Value: Integer);
@@ -182,10 +189,11 @@ Type
     Property MaxBlocks : Integer read FMaxBlocks write SetMaxBlocks;
     Property MaxBlocks : Integer read FMaxBlocks write SetMaxBlocks;
     Property HashRateAverageBlocksCount : Integer read FHashRateAverageBlocksCount write SetHashRateAverageBlocksCount;
     Property HashRateAverageBlocksCount : Integer read FHashRateAverageBlocksCount write SetHashRateAverageBlocksCount;
     Property ShowTimeAverageColumns : Boolean read FShowTimeAverageColumns write SetShowTimeAverageColumns;
     Property ShowTimeAverageColumns : Boolean read FShowTimeAverageColumns write SetShowTimeAverageColumns;
+    Property HashRateAs : TShowHashRateAs read FHashRateAs write SetHashRateAs;
   End;
   End;
 
 
 Const
 Const
-  CT_TBlockChainData_NUL : TBlockChainData = (Block:0;Timestamp:0;BlockProtocolVersion:0;BlockProtocolAvailable:0;OperationsCount:-1;Volume:-1;Reward:0;Fee:0;Target:0;HashRateKhs:0;MinerPayload:'';PoW:'';SafeBoxHash:'';AccumulatedWork:0;TimeAverage200:0;TimeAverage150:0;TimeAverage100:0;TimeAverage75:0;TimeAverage50:0;TimeAverage25:0;TimeAverage10:0);
+  CT_TBlockChainData_NUL : TBlockChainData = (Block:0;Timestamp:0;BlockProtocolVersion:0;BlockProtocolAvailable:0;OperationsCount:-1;Volume:-1;Reward:0;Fee:0;Target:0;HashRateTargetKhs:0;HashRateKhs:0;MinerPayload:'';PoW:'';SafeBoxHash:'';AccumulatedWork:0;TimeAverage200:0;TimeAverage150:0;TimeAverage100:0;TimeAverage75:0;TimeAverage50:0;TimeAverage25:0;TimeAverage10:0);
 
 
 
 
 implementation
 implementation
@@ -989,6 +997,7 @@ begin
   FHashRateAverageBlocksCount := 50;
   FHashRateAverageBlocksCount := 50;
   SetLength(FBlockChainDataArray,0);
   SetLength(FBlockChainDataArray,0);
   FShowTimeAverageColumns:=False;
   FShowTimeAverageColumns:=False;
+  FHashRateAs:={$IFDEF PRODUCTION}hr_Giga{$ELSE}hr_Mega{$ENDIF};
 end;
 end;
 
 
 destructor TBlockChainGrid.Destroy;
 destructor TBlockChainGrid.Destroy;
@@ -1012,7 +1021,7 @@ begin
   DrawGrid.FixedRows := 1;
   DrawGrid.FixedRows := 1;
   DrawGrid.DefaultDrawing := true;
   DrawGrid.DefaultDrawing := true;
   DrawGrid.FixedCols := 0;
   DrawGrid.FixedCols := 0;
-  If ShowTimeAverageColumns then DrawGrid.ColCount:=15
+  If ShowTimeAverageColumns then DrawGrid.ColCount:=14
   else DrawGrid.ColCount:=12;
   else DrawGrid.ColCount:=12;
   DrawGrid.ColWidths[0] := 50; // Block
   DrawGrid.ColWidths[0] := 50; // Block
   DrawGrid.ColWidths[1] := 110; // Time
   DrawGrid.ColWidths[1] := 110; // Time
@@ -1027,9 +1036,8 @@ begin
   DrawGrid.ColWidths[10] := 190; // SafeBox Hash
   DrawGrid.ColWidths[10] := 190; // SafeBox Hash
   DrawGrid.ColWidths[11] := 50; // Protocol
   DrawGrid.ColWidths[11] := 50; // Protocol
   If ShowTimeAverageColumns then begin
   If ShowTimeAverageColumns then begin
-    DrawGrid.ColWidths[12] := 95; // Accumulated work
-    DrawGrid.ColWidths[13] := 55; // Deviation
-    DrawGrid.ColWidths[14] := 340; // Time average
+    DrawGrid.ColWidths[12] := 55; // Deviation
+    DrawGrid.ColWidths[13] := 350; // Time average
   end;
   end;
   FDrawGrid.DefaultRowHeight := 18;
   FDrawGrid.DefaultRowHeight := 18;
   FDrawGrid.Invalidate;
   FDrawGrid.Invalidate;
@@ -1057,6 +1065,7 @@ procedure TBlockChainGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Longint;
 Var s : String;
 Var s : String;
   bcd : TBlockChainData;
   bcd : TBlockChainData;
   deviation : Real;
   deviation : Real;
+  hr_base : Int64;
 begin
 begin
   {.$IFDEF FPC}
   {.$IFDEF FPC}
   DrawGrid.Canvas.Font.Color:=clBlack;
   DrawGrid.Canvas.Font.Color:=clBlack;
@@ -1071,14 +1080,21 @@ begin
       4 : s := 'Reward';
       4 : s := 'Reward';
       5 : s := 'Fee';
       5 : s := 'Fee';
       6 : s := 'Target';
       6 : s := 'Target';
-      7 : s := 'Mh/s';
+      7 : begin
+        case HashRateAs of
+          hr_Kilo : s := 'Kh/s';
+          hr_Mega : s := 'Mh/s';
+          hr_Giga : s := 'Gh/s';
+          hr_Tera : s := 'Th/s';
+        else s := '?h/s';
+        end;
+      end;
       8 : s := 'Miner Payload';
       8 : s := 'Miner Payload';
       9 : s := 'Proof of Work';
       9 : s := 'Proof of Work';
       10 : s := 'SafeBox Hash';
       10 : s := 'SafeBox Hash';
       11 : s := 'Protocol';
       11 : s := 'Protocol';
-      12 : s := 'Acc.Work';
-      13 : s := 'Deviation';
-      14 : s := 'Time average';
+      12 : s := 'Deviation';
+      13 : s := 'Time average';
     else s:= '';
     else s:= '';
     end;
     end;
     Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
     Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
@@ -1131,7 +1147,14 @@ begin
         s := IntToHex(bcd.Target,8);
         s := IntToHex(bcd.Target,8);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter]);
       end else if ACol=7 then begin
       end else if ACol=7 then begin
-        s := Format('%.2n',[bcd.HashRateKhs/1024]);
+        case HashRateAs of
+          hr_Kilo : hr_base := 1;
+          hr_Mega : hr_base := 1000;
+          hr_Giga : hr_base := 1000000;
+          hr_Tera : hr_base := 1000000000;
+        else hr_base := 1;
+        end;
+        s := Format('%.2n (%.2n)',[bcd.HashRateKhs/hr_base,bcd.HashRateTargetKhs/hr_base]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
       end else if ACol=8 then begin
       end else if ACol=8 then begin
         if TCrypto.IsHumanReadable(bcd.MinerPayload) then
         if TCrypto.IsHumanReadable(bcd.MinerPayload) then
@@ -1148,19 +1171,10 @@ begin
         s := Inttostr(bcd.BlockProtocolVersion)+'-'+IntToStr(bcd.BlockProtocolAvailable);
         s := Inttostr(bcd.BlockProtocolVersion)+'-'+IntToStr(bcd.BlockProtocolAvailable);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
       end else if ACol=12 then begin
       end else if ACol=12 then begin
-        if bcd.AccumulatedWork>0 then begin
-          s := Inttostr(bcd.AccumulatedWork);
-          Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
-        end else begin
-          DrawGrid.Canvas.Font.Color := clGrayText;
-          s := '(no data)';
-          Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
-        end;
-      end else if ACol=13 then begin
         deviation := ((CT_NewLineSecondsAvg - bcd.TimeAverage100) / CT_NewLineSecondsAvg)*100;
         deviation := ((CT_NewLineSecondsAvg - bcd.TimeAverage100) / CT_NewLineSecondsAvg)*100;
         s := Format('%.2f',[deviation])+' %';
         s := Format('%.2f',[deviation])+' %';
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
-      end else if ACol=14 then begin
+      end else if ACol=13 then begin
         s := Format('200:%.1f 150:%.1f 100:%.1f 75:%.1f 50:%.1f 25:%.1f 10:%.1f',[bcd.TimeAverage200,
         s := Format('200:%.1f 150:%.1f 100:%.1f 75:%.1f 50:%.1f 25:%.1f 10:%.1f',[bcd.TimeAverage200,
            bcd.TimeAverage150,bcd.TimeAverage100,bcd.TimeAverage75,bcd.TimeAverage50,bcd.TimeAverage25,bcd.TimeAverage10]);
            bcd.TimeAverage150,bcd.TimeAverage100,bcd.TimeAverage75,bcd.TimeAverage50,bcd.TimeAverage25,bcd.TimeAverage10]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
@@ -1212,6 +1226,15 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TBlockChainGrid.SetHashRateAs(AValue: TShowHashRateAs);
+begin
+  if FHashRateAs=AValue then Exit;
+  FHashRateAs:=AValue;
+  if Assigned(FDrawGrid) then begin
+    FDrawGrid.Invalidate;
+  end;
+end;
+
 
 
 procedure TBlockChainGrid.SetHashRateAverageBlocksCount(const Value: Integer);
 procedure TBlockChainGrid.SetHashRateAverageBlocksCount(const Value: Integer);
 begin
 begin
@@ -1251,6 +1274,7 @@ Var nstart,nend : Cardinal;
   bcd : TBlockChainData;
   bcd : TBlockChainData;
   i : Integer;
   i : Integer;
   opb : TOperationBlock;
   opb : TOperationBlock;
+  bn : TBigNum;
 begin
 begin
   if (FBlockStart>FBlockEnd) And (FBlockStart>=0) then FBlockEnd := -1;
   if (FBlockStart>FBlockEnd) And (FBlockStart>=0) then FBlockEnd := -1;
   if (FBlockEnd>=0) And (FBlockEnd<FBlockStart) then FBlockStart:=-1;
   if (FBlockEnd>=0) And (FBlockEnd<FBlockStart) then FBlockStart:=-1;
@@ -1292,6 +1316,12 @@ begin
         bcd.Fee := opb.fee;
         bcd.Fee := opb.fee;
         bcd.Target := opb.compact_target;
         bcd.Target := opb.compact_target;
         bcd.HashRateKhs := Node.Bank.SafeBox.CalcBlockHashRateInKhs(bcd.Block,HashRateAverageBlocksCount);
         bcd.HashRateKhs := Node.Bank.SafeBox.CalcBlockHashRateInKhs(bcd.Block,HashRateAverageBlocksCount);
+        bn := TBigNum.TargetToHashRate(opb.compact_target);
+        Try
+          bcd.HashRateTargetKhs := bn.Divide(1024).Divide(CT_NewLineSecondsAvg).Value;
+        finally
+          bn.Free;
+        end;
         bcd.MinerPayload := opb.block_payload;
         bcd.MinerPayload := opb.block_payload;
         bcd.PoW := opb.proof_of_work;
         bcd.PoW := opb.proof_of_work;
         bcd.SafeBoxHash := opb.initial_safe_box_hash;
         bcd.SafeBoxHash := opb.initial_safe_box_hash;

+ 2 - 6
src/pascalcoin_miner.lpi

@@ -34,16 +34,12 @@
         <PackageName Value="LazUtils"/>
         <PackageName Value="LazUtils"/>
       </Item1>
       </Item1>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="2">
+    <Units Count="1">
       <Unit0>
       <Unit0>
         <Filename Value="pascalcoin_miner.pp"/>
         <Filename Value="pascalcoin_miner.pp"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="PascalCoinMiner"/>
         <UnitName Value="PascalCoinMiner"/>
       </Unit0>
       </Unit0>
-      <Unit1>
-        <Filename Value="libraries\pascalcoin\UJSONFunctions.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit1>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>
@@ -54,7 +50,7 @@
     </Target>
     </Target>
     <SearchPaths>
     <SearchPaths>
       <IncludeFiles Value="$(ProjOutDir)"/>
       <IncludeFiles Value="$(ProjOutDir)"/>
-      <OtherUnitFiles Value="common;core;libraries\pasopencl;libraries\synapse;libraries\generics.collections;libraries\sphere10;libraries\pascalcoin"/>
+      <OtherUnitFiles Value="core;libraries\pasopencl;libraries\synapse;libraries\pascalcoin"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
     </SearchPaths>
     </SearchPaths>
     <CodeGeneration>
     <CodeGeneration>

+ 1 - 1
src/pascalcoin_miner.pp

@@ -58,7 +58,7 @@ type
   end;
   end;
 
 
 Const
 Const
-  CT_MINER_VERSION = {$IFDEF PRODUCTION}'0.5'{$ELSE}{$IFDEF TESTNET}'0.5 TESTNET'{$ELSE}ERROR{$ENDIF}{$ENDIF};
+  CT_MINER_VERSION = {$IFDEF PRODUCTION}'0.6'{$ELSE}{$IFDEF TESTNET}'0.6 TESTNET'{$ELSE}ERROR{$ENDIF}{$ENDIF};
   CT_Line_DeviceStatus = 3;
   CT_Line_DeviceStatus = 3;
   CT_Line_ConnectionStatus = 4;
   CT_Line_ConnectionStatus = 4;
   CT_Line_MinerValues = 7;
   CT_Line_MinerValues = 7;

+ 27 - 31
src/pascalcoin_wallet_classic.dpr

@@ -11,37 +11,33 @@ uses
   Interfaces,
   Interfaces,
 {$ENDIF}
 {$ENDIF}
   Forms,
   Forms,
-  UBlockChain in 'Units\PascalCoin\UBlockChain.pas',
-  UCrypto in 'Units\PascalCoin\UCrypto.pas',
-  UTime in 'Units\PascalCoin\UTime.pas',
-  UWallet in 'Units\PascalCoin\UWallet.pas',
-  UOpTransaction in 'Units\PascalCoin\UOpTransaction.pas',
-  UNetProtocol in 'Units\PascalCoin\UNetProtocol.pas',
-  UAccounts in 'Units\PascalCoin\UAccounts.pas',
-  UConst in 'Units\PascalCoin\UConst.pas',
-  UThread in 'Units\PascalCoin\UThread.pas',
-  ULog in 'Units\PascalCoin\ULog.pas',
-  UNode in 'Units\PascalCoin\UNode.pas',
-  UECIES in 'Units\PascalCoin\UECIES.pas',
-  UAES in 'Units\PascalCoin\UAES.pas',
-  UFRMWallet in 'Units\Forms\UFRMWallet.pas' {FRMWallet},
-  UFileStorage in 'Units\PascalCoin\UFileStorage.pas',
-  UFolderHelper in 'Units\Utils\UFolderHelper.pas',
-  UAppParams in 'Units\Utils\UAppParams.pas',
-  UGridUtils in 'Units\Utils\UGridUtils.pas',
-  UFRMPascalCoinWalletConfig in 'Units\Forms\UFRMPascalCoinWalletConfig.pas' {FRMPascalCoinWalletConfig},
-  UFRMAbout in 'Units\Forms\UFRMAbout.pas' {FRMAbout},
-  UFRMOperation in 'Units\Forms\UFRMOperation.pas' {FRMOperation},
-  UFRMWalletKeys in 'Units\Forms\UFRMWalletKeys.pas' {FRMWalletKeys},
-  UFRMNewPrivateKeyType in 'Units\Forms\UFRMNewPrivateKeyType.pas' {FRMNewPrivateKeyType},
-  UFRMPayloadDecoder in 'Units\Forms\UFRMPayloadDecoder.pas' {FRMPayloadDecoder},
-  UFRMNodesIp in 'Units\Forms\UFRMNodesIp.pas' {FRMNodesIp},
-  UTCPIP in 'Units\PascalCoin\UTCPIP.pas',
-  UJSONFunctions in 'Units\Utils\UJSONFunctions.pas',
-  URPC in 'Units\PascalCoin\URPC.pas',
-  UPoolMining in 'Units\PascalCoin\UPoolMining.pas',
-  UOpenSSL in 'Units\PascalCoin\UOpenSSL.pas',
-  UOpenSSLdef in 'Units\PascalCoin\UOpenSSLdef.pas';
+  UBlockChain in 'core\UBlockChain.pas',
+  UCrypto in 'core\UCrypto.pas',
+  UTime in 'core\UTime.pas',
+  UWallet in 'core\UWallet.pas',
+  UOpTransaction in 'core\UOpTransaction.pas',
+  UNetProtocol in 'core\UNetProtocol.pas',
+  UAccounts in 'core\UAccounts.pas',
+  UConst in 'core\UConst.pas',
+  UThread in 'core\UThread.pas',
+  ULog in 'core\ULog.pas',
+  UNode in 'core\UNode.pas',
+  UECIES in 'core\UECIES.pas',
+  UAES in 'core\UAES.pas',
+  UFRMWallet in 'gui-classic\UFRMWallet.pas' {FRMWallet},
+  UFileStorage in 'core\UFileStorage.pas',
+  UFRMPascalCoinWalletConfig in 'gui-classic\UFRMPascalCoinWalletConfig.pas' {FRMPascalCoinWalletConfig},
+  UFRMAbout in 'gui-classic\UFRMAbout.pas' {FRMAbout},
+  UFRMOperation in 'gui-classic\UFRMOperation.pas' {FRMOperation},
+  UFRMWalletKeys in 'gui-classic\UFRMWalletKeys.pas' {FRMWalletKeys},
+  UFRMNewPrivateKeyType in 'gui-classic\UFRMNewPrivateKeyType.pas' {FRMNewPrivateKeyType},
+  UFRMPayloadDecoder in 'gui-classic\UFRMPayloadDecoder.pas' {FRMPayloadDecoder},
+  UFRMNodesIp in 'gui-classic\UFRMNodesIp.pas' {FRMNodesIp},
+  UTCPIP in 'core\UTCPIP.pas',
+  URPC in 'core\URPC.pas',
+  UPoolMining in 'core\UPoolMining.pas',
+  UOpenSSL in 'core\UOpenSSL.pas',
+  UOpenSSLdef in 'core\UOpenSSLdef.pas';
 
 
 {$R *.res}
 {$R *.res}
 
 

+ 36 - 55
src/pascalcoin_wallet_classic.lpi

@@ -42,10 +42,11 @@
         <PackageName Value="LCL"/>
         <PackageName Value="LCL"/>
       </Item1>
       </Item1>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="37">
+    <Units Count="32">
       <Unit0>
       <Unit0>
         <Filename Value="pascalcoin_wallet_classic.dpr"/>
         <Filename Value="pascalcoin_wallet_classic.dpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <UnitName Value="PascalCoin_wallet_classic"/>
       </Unit0>
       </Unit0>
       <Unit1>
       <Unit1>
         <Filename Value="core\UBlockChain.pas"/>
         <Filename Value="core\UBlockChain.pas"/>
@@ -103,121 +104,101 @@
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit13>
       </Unit13>
       <Unit14>
       <Unit14>
-        <Filename Value="common\UFolderHelper.pas"/>
+        <Filename Value="gui-classic\UFRMPascalCoinWalletConfig.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="FRMPascalCoinWalletConfig"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit14>
       </Unit14>
       <Unit15>
       <Unit15>
-        <Filename Value="common\UAppParams.pas"/>
+        <Filename Value="gui-classic\UFRMAbout.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="FRMAbout"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit15>
       </Unit15>
       <Unit16>
       <Unit16>
-        <Filename Value="common\UGridUtils.pas"/>
+        <Filename Value="gui-classic\UFRMOperation.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="FRMOperation"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit16>
       </Unit16>
       <Unit17>
       <Unit17>
-        <Filename Value="gui-classic\UFRMPascalCoinWalletConfig.pas"/>
+        <Filename Value="gui-classic\UFRMWalletKeys.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMPascalCoinWalletConfig"/>
+        <ComponentName Value="FRMWalletKeys"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit17>
       </Unit17>
       <Unit18>
       <Unit18>
-        <Filename Value="gui-classic\UFRMAbout.pas"/>
+        <Filename Value="gui-classic\UFRMNewPrivateKeyType.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMAbout"/>
+        <ComponentName Value="FRMNewPrivateKeyType"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit18>
       </Unit18>
       <Unit19>
       <Unit19>
-        <Filename Value="gui-classic\UFRMOperation.pas"/>
+        <Filename Value="gui-classic\UFRMPayloadDecoder.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMOperation"/>
+        <ComponentName Value="FRMPayloadDecoder"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit19>
       </Unit19>
       <Unit20>
       <Unit20>
-        <Filename Value="gui-classic\UFRMWalletKeys.pas"/>
+        <Filename Value="gui-classic\UFRMNodesIp.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMWalletKeys"/>
+        <ComponentName Value="FRMNodesIp"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
       </Unit20>
       </Unit20>
       <Unit21>
       <Unit21>
-        <Filename Value="gui-classic\UFRMNewPrivateKeyType.pas"/>
+        <Filename Value="core\UTCPIP.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMNewPrivateKeyType"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit21>
       </Unit21>
       <Unit22>
       <Unit22>
-        <Filename Value="gui-classic\UFRMPayloadDecoder.pas"/>
+        <Filename Value="core\URPC.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMPayloadDecoder"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit22>
       </Unit22>
       <Unit23>
       <Unit23>
-        <Filename Value="gui-classic\UFRMNodesIp.pas"/>
+        <Filename Value="core\UPoolMining.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-        <ComponentName Value="FRMNodesIp"/>
-        <HasResources Value="True"/>
-        <ResourceBaseClass Value="Form"/>
       </Unit23>
       </Unit23>
       <Unit24>
       <Unit24>
-        <Filename Value="core\UTCPIP.pas"/>
+        <Filename Value="core\UOpenSSL.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit24>
       </Unit24>
       <Unit25>
       <Unit25>
-        <Filename Value="common\UJSONFunctions.pas"/>
+        <Filename Value="core\UOpenSSLdef.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit25>
       </Unit25>
       <Unit26>
       <Unit26>
-        <Filename Value="core\URPC.pas"/>
+        <Filename Value="core\UFileStorage.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit26>
       </Unit26>
       <Unit27>
       <Unit27>
-        <Filename Value="core\UPoolMining.pas"/>
+        <Filename Value="core\UAES.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit27>
       </Unit27>
       <Unit28>
       <Unit28>
-        <Filename Value="core\UOpenSSL.pas"/>
+        <Filename Value="core\UChunk.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
       </Unit28>
       </Unit28>
       <Unit29>
       <Unit29>
-        <Filename Value="core\UOpenSSLdef.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit29>
-      <Unit30>
-        <Filename Value="core\UFileStorage.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit30>
-      <Unit31>
-        <Filename Value="core\UAES.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit31>
-      <Unit32>
-        <Filename Value="core\UChunk.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit32>
-      <Unit33>
         <Filename Value="gui-classic\UFRMAccountSelect.pas"/>
         <Filename Value="gui-classic\UFRMAccountSelect.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
         <ComponentName Value="FRMAccountSelect"/>
         <ComponentName Value="FRMAccountSelect"/>
         <HasResources Value="True"/>
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
         <ResourceBaseClass Value="Form"/>
-      </Unit33>
-      <Unit34>
+      </Unit29>
+      <Unit30>
         <Filename Value="core\UBaseTypes.pas"/>
         <Filename Value="core\UBaseTypes.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-      </Unit34>
-      <Unit35>
-        <Filename Value="libraries\sphere10\UCommon.pas"/>
-        <IsPartOfProject Value="True"/>
-      </Unit35>
-      <Unit36>
+      </Unit30>
+      <Unit31>
         <Filename Value="config.inc"/>
         <Filename Value="config.inc"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
-      </Unit36>
+      </Unit31>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>
@@ -228,7 +209,7 @@
     </Target>
     </Target>
     <SearchPaths>
     <SearchPaths>
       <IncludeFiles Value="$(ProjOutDir)"/>
       <IncludeFiles Value="$(ProjOutDir)"/>
-      <OtherUnitFiles Value="core;gui-classic;libraries\generics.collections;libraries\sphere10;libraries\synapse;libraries\pascalcoin"/>
+      <OtherUnitFiles Value="core;gui-classic;libraries\synapse;libraries\pascalcoin"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
     </SearchPaths>
     </SearchPaths>
     <Parsing>
     <Parsing>