PascalCoin 8 år sedan
förälder
incheckning
3117ef0463

BIN
PascalCoinWallet.res


+ 9 - 0
PascalCoinWalletLazarus.lpi

@@ -14,6 +14,7 @@
       <Title Value="PascalCoinWalletLazarus"/>
       <UseAppBundle Value="False"/>
       <ResourceType Value="res"/>
+      <Icon Value="0"/>
     </General>
     <i18n>
       <EnableI18N LFM="False"/>
@@ -212,7 +213,15 @@
         <SyntaxMode Value="Delphi"/>
       </SyntaxOptions>
     </Parsing>
+    <CodeGeneration>
+      <Optimizations>
+        <OptimizationLevel Value="2"/>
+      </Optimizations>
+    </CodeGeneration>
     <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+      </Debugging>
       <Options>
         <Win32>
           <GraphicApplication Value="True"/>

+ 27 - 0
README.md

@@ -34,6 +34,33 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.3.0.0 - 2016-11-24
+
+- JSON-RPC modifications:
+  - New param "b58_pubkey", can be used instead of "enc_pubkey": b58_pubkey is a Base58 encoded public key with checksum, is the value that Wallet exports/imports public key
+  - New JSON object type Public Key: "name","can_use","enc_pubkey","b58_pubkey","ec_nid","x" and "y" for each public key
+  - Added params "start" and "max" to "getaccountoperations". By default deep=100, max=100 and start=0, so will return last 100 operations made to an account
+  - Added params "start" and "max" to "getblockoperations". By default max=100 and start=0, so will return last 100 operations made to a block
+  - Added params "start" and "max" to "getwalletaccounts". By default max=100 and start=0, so will return first 100 accounts of the wallet
+  - Added params "start" and "max" to "getwalletpubkeys". By default max=100 and start=0, so will return first 100 public keys of the wallet
+    - Will return a Public key JSON object
+  - Method "decodepubkey" allows params "enc_pubkey" or "b58_pubkey" (if used together, returns error if not match)
+    - Will return a Public key JSON object
+  - Method "changekey" allows params "new_enc_pubkey" or "new_b58_pubkey" (if used together, returns error if not match)
+  - Method "getwalletaccounts" allows params "enc_pubkey" or "b58_pubkey" (if used together, returns error if not match)
+  - Method "getwalletaccountscount" allows params "enc_pubkey" or "b58_pubkey" (if used together, returns error if not match)
+  - Method "getwalletcoins" allows params "enc_pubkey" or "b58_pubkey" (if used together, returns error if not match)  
+  - Method "payloadencrypt"  allows params "enc_pubkey" or "b58_pubkey" when payload_method="pubkey" (if used together, returns error if not match)  
+  - Method "addnewkey" changed. Does not return an HEXASTRING with enc_pubkey, now returns a public key JSON object
+  - New methods:
+    - Method "changekeys". Similar to "changekey" but for multiple accounts at param "accounts" as a coma separated string (ex: "accounts"="1248,1753,85056"). Returns a JSON object with result information
+    - Method "lock" to lock wallet. Returns true if locked, returns false if wallet has no password (an empty string, must put a new password prior to lock)
+    - New method "getwalletpubkey". Search for "enc_pubkey" or "b58_pubkey" and returns a Public key JSON object
+- Corrected a issue saving last 5 .bank files
+- Improved protections for .bank corruption files
+- Added "open data folder" button on options form
+- Other minor changes
+
 ### Build 1.2.0.0 - 2016-11-16
 
 - Account checksum values modified to be more easy and more distributed: Checksum = ((N * 101) MOD 89)+10

+ 27 - 0
README.txt

@@ -34,6 +34,33 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.3.0.0 - 2016-11-24
+
+- JSON-RPC modifications:
+  - New param "b58_pubkey", can be used instead of "enc_pubkey": b58_pubkey is a Base58 encoded public key with checksum, is the value that Wallet exports/imports public key
+  - New JSON object type Public Key: "name","can_use","enc_pubkey","b58_pubkey","ec_nid","x" and "y" for each public key
+  - Added params "start" and "max" to "getaccountoperations". By default deep=100, max=100 and start=0, so will return last 100 operations made to an account
+  - Added params "start" and "max" to "getblockoperations". By default max=100 and start=0, so will return last 100 operations made to a block
+  - Added params "start" and "max" to "getwalletaccounts". By default max=100 and start=0, so will return first 100 accounts of the wallet
+  - Added params "start" and "max" to "getwalletpubkeys". By default max=100 and start=0, so will return first 100 public keys of the wallet
+    - Will return a Public key JSON object
+  - Method "decodepubkey" allows params "enc_pubkey" or "b58_pubkey" (if used together, returns error if not match)
+    - Will return a Public key JSON object
+  - Method "changekey" allows params "new_enc_pubkey" or "new_b58_pubkey" (if used together, returns error if not match)
+  - Method "getwalletaccounts" allows params "enc_pubkey" or "b58_pubkey" (if used together, returns error if not match)
+  - Method "getwalletaccountscount" allows params "enc_pubkey" or "b58_pubkey" (if used together, returns error if not match)
+  - Method "getwalletcoins" allows params "enc_pubkey" or "b58_pubkey" (if used together, returns error if not match)  
+  - Method "payloadencrypt"  allows params "enc_pubkey" or "b58_pubkey" when payload_method="pubkey" (if used together, returns error if not match)  
+  - Method "addnewkey" changed. Does not return an HEXASTRING with enc_pubkey, now returns a public key JSON object
+  - New methods:
+    - Method "changekeys". Similar to "changekey" but for multiple accounts at param "accounts" as a coma separated string (ex: "accounts"="1248,1753,85056"). Returns a JSON object with result information
+    - Method "lock" to lock wallet. Returns true if locked, returns false if wallet has no password (an empty string, must put a new password prior to lock)
+    - New method "getwalletpubkey". Search for "enc_pubkey" or "b58_pubkey" and returns a Public key JSON object
+- Corrected a issue saving last 5 .bank files
+- Improved protections for .bank corruption files
+- Added "open data folder" button on options form
+- Other minor changes
+
 ### Build 1.2.0.0 - 2016-11-16
 
 - Account checksum values modified to be more easy and more distributed: Checksum = ((N * 101) MOD 89)+10

+ 1 - 1
Units/Forms/UFRMAbout.pas

@@ -96,7 +96,7 @@ end;
 procedure TFRMAbout.OpenURL(Url: String);
 begin
   {$IFDEF FPC}
-   OpenDocument(pchar(URL)) { *Convertido desde ShellExecute* }
+  OpenDocument(pchar(URL))
   {$ELSE}
   shellexecute(0, 'open', pchar(URL), nil, nil, SW_SHOW)
   {$ENDIF}

+ 56 - 23
Units/Forms/UFRMOperation.pas

@@ -29,6 +29,9 @@ uses
   Dialogs, StdCtrls, UNode, UWalletKeys, UCrypto, Buttons, UBlockChain,
   UAccounts, ActnList, ComCtrls, Types;
 
+Const
+  CM_PC_WalletKeysChanged = WM_USER + 1;
+
 type
 
   { TFRMOperation }
@@ -107,13 +110,17 @@ type
     FTxAmount : Int64;
     FNewAccountPublicKey : TAccountKey;
     FSenderAccounts: TOrderedCardinalList;
+    FOldOnChanged : TNotifyEvent;
     procedure SetWalletKeys(const Value: TWalletKeys);
+    Procedure UpdateWalletKeys;
     { Private declarations }
     Procedure UpdateAccountsInfo;
     Function UpdateOperationOptions(var errors : AnsiString) : Boolean;
     Function UpdatePayload(Const SenderAccount : TAccount; var errors : AnsiString) : Boolean;
     procedure SetFee(const Value: Int64);
     Procedure OnSenderAccountsChanged(Sender : TObject);
+    procedure OnWalletKeysChanged(Sender : TObject);
+    procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
   public
     { Public declarations }
     Property SenderAccounts : TOrderedCardinalList read FSenderAccounts;
@@ -288,6 +295,11 @@ begin
   end;
 end;
 
+procedure TFRMOperation.CM_WalletChanged(var Msg: TMessage);
+begin
+   UpdateWalletKeys;
+end;
+
 procedure TFRMOperation.ebDestAccountChange(Sender: TObject);
 begin
   if FDisabled then exit;
@@ -370,6 +382,7 @@ end;
 
 procedure TFRMOperation.FormCreate(Sender: TObject);
 begin
+  FWalletKeys := Nil;
   FSenderAccounts := TOrderedCardinalList.Create;
   FSenderAccounts.OnListChanged := OnSenderAccountsChanged;
   FDisabled := true;
@@ -420,6 +433,7 @@ end;
 
 procedure TFRMOperation.FormDestroy(Sender: TObject);
 begin
+  if Assigned(FWalletKeys) then FWalletKeys.OnChanged := FOldOnChanged;
   FreeAndNil(FSenderAccounts);
 end;
 
@@ -447,6 +461,12 @@ begin
   UpdateOperationOptions(errors);
 end;
 
+procedure TFRMOperation.OnWalletKeysChanged(Sender: TObject);
+begin
+  PostMessage(Self.Handle,CM_PC_WalletKeysChanged,0,0);
+  if Assigned(FOldOnChanged) then FOldOnChanged(Sender);
+end;
+
 procedure TFRMOperation.rbTransactionClick(Sender: TObject);
 Var errors : AnsiString;
 begin
@@ -468,30 +488,15 @@ begin
 end;
 
 procedure TFRMOperation.SetWalletKeys(const Value: TWalletKeys);
-Var i : Integer;
-  wk : TWalletKey;
-  s : String;
 begin
+  if FWalletKeys=Value then exit;
+  if Assigned(FWalletKeys) then FWalletKeys.OnChanged := FOldOnChanged;
   FWalletKeys := Value;
-  cbNewPrivateKey.items.BeginUpdate;
-  Try
-    cbNewPrivateKey.Items.Clear;
-    //cbNewPrivateKey.Items.AddObject('Generate a new Private Key',TObject(-1));
-    For i:=0 to FWalletKeys.Count-1 do begin
-      wk := FWalletKeys.Key[i];
-      if (wk.Name='') then begin
-        s := TCrypto.ToHexaString( TAccountComp.AccountKey2RawString(wk.AccountKey));
-      end else begin
-        s := wk.Name;
-      end;
-      if Not Assigned(wk.PrivateKey) then s := s + '(*)';
-      cbNewPrivateKey.Items.AddObject(s,TObject(i));
-    end;
-  Finally
-    cbNewPrivateKey.Items.EndUpdate;
-  End;
-  rbTransactionClick(Nil);
-  memoPayloadClick(Nil);
+  if Assigned(FWalletKeys) then begin
+    FOldOnChanged := FWalletKeys.OnChanged;
+    FWalletKeys.OnChanged := OnWalletKeysChanged;
+  end;
+  UpdateWalletKeys;
 end;
 
 procedure TFRMOperation.UpdateAccountsInfo;
@@ -598,7 +603,9 @@ begin
         tsGlobalError.tabvisible := {$IFDEF LINUX}true{$ELSE}false{$ENDIF};
         tsOperation.TabVisible := false;
         PageControl.ActivePage := tsGlobalError;
-        ActiveControl := bbPassword;
+        if bbPassword.CanFocus then begin
+          ActiveControl := bbPassword;
+        end;
       end else begin
         tsOperation.visible := true;
         tsOperation.tabvisible := {$IFDEF LINUX}true{$ELSE}false{$ENDIF};
@@ -805,4 +812,30 @@ begin
   end;
 end;
 
+procedure TFRMOperation.UpdateWalletKeys;
+Var i : Integer;
+  wk : TWalletKey;
+  s : String;
+begin
+  cbNewPrivateKey.items.BeginUpdate;
+  Try
+    cbNewPrivateKey.Items.Clear;
+    //cbNewPrivateKey.Items.AddObject('Generate a new Private Key',TObject(-1));
+    For i:=0 to FWalletKeys.Count-1 do begin
+      wk := FWalletKeys.Key[i];
+      if (wk.Name='') then begin
+        s := TCrypto.ToHexaString( TAccountComp.AccountKey2RawString(wk.AccountKey));
+      end else begin
+        s := wk.Name;
+      end;
+      if Not Assigned(wk.PrivateKey) then s := s + '(*)';
+      cbNewPrivateKey.Items.AddObject(s,TObject(i));
+    end;
+  Finally
+    cbNewPrivateKey.Items.EndUpdate;
+  End;
+  rbTransactionClick(Nil);
+  memoPayloadClick(Nil);
+end;
+
 end.

+ 51 - 13
Units/Forms/UFRMPascalCoinWalletConfig.dfm

@@ -4,7 +4,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
   Caption = 'Options'
-  ClientHeight = 460
+  ClientHeight = 476
   ClientWidth = 374
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
@@ -86,7 +86,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Width = 56
     Height = 21
     Alignment = taRightJustify
-    TabOrder = 7
+    TabOrder = 8
     Text = '0'
   end
   object cbSaveLogFiles: TCheckBox
@@ -95,7 +95,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Width = 97
     Height = 17
     Caption = 'Save log file'
-    TabOrder = 8
+    TabOrder = 9
     OnClick = cbSaveLogFilesClick
   end
   object cbShowLogs: TCheckBox
@@ -104,28 +104,28 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Width = 97
     Height = 17
     Caption = 'Show logs'
-    TabOrder = 10
+    TabOrder = 11
   end
   object bbOk: TBitBtn
-    Left = 171
-    Top = 410
+    Left = 176
+    Top = 420
     Width = 75
     Height = 25
     DoubleBuffered = True
     Kind = bkOK
     ParentDoubleBuffered = False
-    TabOrder = 11
+    TabOrder = 14
     OnClick = bbOkClick
   end
   object bbCancel: TBitBtn
-    Left = 261
-    Top = 410
+    Left = 266
+    Top = 420
     Width = 75
     Height = 25
     DoubleBuffered = True
     Kind = bkCancel
     ParentDoubleBuffered = False
-    TabOrder = 12
+    TabOrder = 15
   end
   object udInternetServerPort: TUpDown
     Left = 226
@@ -232,7 +232,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Width = 171
     Height = 17
     Caption = 'Show modal messages'
-    TabOrder = 13
+    TabOrder = 12
   end
   object udJSONRPCMinerServerPort: TUpDown
     Left = 226
@@ -261,7 +261,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Width = 334
     Height = 121
     Caption = ' Miner Server Private Key: '
-    TabOrder = 14
+    TabOrder = 7
     object rbGenerateANewPrivateKeyEachBlock: TRadioButton
       Left = 20
       Top = 20
@@ -301,6 +301,44 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Width = 97
     Height = 17
     Caption = 'Save debug logs too'
-    TabOrder = 9
+    TabOrder = 10
+  end
+  object bbOpenDataFolder: TBitBtn
+    Left = 15
+    Top = 420
+    Width = 120
+    Height = 25
+    Caption = 'Open Data folder'
+    DoubleBuffered = True
+    Glyph.Data = {
+      36030000424D3603000000000000360000002800000010000000100000000100
+      18000000000000030000120B0000120B00000000000000000000FF00FF078DBE
+      078DBE078DBE078DBE078DBE078DBE078DBE078DBE078DBE078DBE078DBE078D
+      BEFF00FFFF00FFFF00FF078DBE25A1D171C6E884D7FA66CDF965CDF965CDF965
+      CDF965CDF865CDF965CDF866CEF93AADD81999C9FF00FFFF00FF078DBE4CBCE7
+      39A8D1A0E2FB6FD4FA6FD4F96ED4FA6FD4F96FD4FA6FD4FA6FD4FA6ED4F93EB1
+      D9C9F0F3078DBEFF00FF078DBE72D6FA078DBEAEE9FC79DCFB79DCFB79DCFB79
+      DCFB79DCFB7ADCFB79DCFA79DCFA44B5D9C9F0F3078DBEFF00FF078DBE79DDFB
+      1899C79ADFF392E7FC84E4FB83E4FC83E4FC84E4FC83E4FC83E4FB84E5FC48B9
+      DAC9F0F31496C4FF00FF078DBE82E3FC43B7DC65C2E0ABF0FC8DEBFC8DEBFC8D
+      EBFD8DEBFD8DEBFC8DEBFD8DEBFC4CBBDAC9F0F3C9F0F3078DBE078DBE8AEAFC
+      77DCF3219CC7FEFFFFC8F7FDC9F7FDC9F7FDC9F7FEC8F7FEC9F7FDC8F7FE9BD5
+      E6EAFEFED2F3F8078DBE078DBE93F0FE93F0FD1697C5078DBE078DBE078DBE07
+      8DBE078DBE078DBE078DBE078DBE078DBE078DBE078DBE078DBE078DBE9BF5FE
+      9AF6FE9AF6FE9BF5FD9BF6FE9AF6FE9BF5FE9AF6FD9BF5FE9AF6FE9AF6FE0989
+      BAFF00FFFF00FFFF00FF078DBEFEFEFEA0FBFFA0FBFEA0FBFEA1FAFEA1FBFEA0
+      FAFEA1FBFEA1FBFFA0FBFFA1FBFF0989BAFF00FFFF00FFFF00FFFF00FF078DBE
+      FEFEFEA5FEFFA5FEFFA5FEFF078DBE078DBE078DBE078DBE078DBE078DBEFF00
+      FFFF00FFFF00FFFF00FFFF00FFFF00FF078DBE078DBE078DBE078DBEFF00FFFF
+      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+      FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+      00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+    ParentDoubleBuffered = False
+    TabOrder = 13
+    OnClick = bbOpenDataFolderClick
   end
 end

+ 61 - 16
Units/Forms/UFRMPascalCoinWalletConfig.lfm

@@ -1,12 +1,12 @@
 object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   Left = 462
-  Height = 460
+  Height = 479
   Top = 234
   Width = 374
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
   Caption = 'Options'
-  ClientHeight = 460
+  ClientHeight = 479
   ClientWidth = 374
   Color = clBtnFace
   Font.Color = clWindowText
@@ -89,7 +89,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Top = 332
     Width = 56
     Alignment = taRightJustify
-    TabOrder = 7
+    TabOrder = 8
     Text = '0'
   end
   object cbSaveLogFiles: TCheckBox
@@ -99,7 +99,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Width = 78
     Caption = 'Save log file'
     OnClick = cbSaveLogFilesClick
-    TabOrder = 8
+    TabOrder = 9
   end
   object cbShowLogs: TCheckBox
     Left = 15
@@ -107,26 +107,26 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Top = 397
     Width = 68
     Caption = 'Show logs'
-    TabOrder = 10
+    TabOrder = 11
   end
   object bbOk: TBitBtn
-    Left = 171
-    Height = 25
-    Top = 410
+    Left = 184
+    Height = 30
+    Top = 432
     Width = 75
     Kind = bkOK
     OnClick = bbOkClick
-    TabOrder = 11
+    TabOrder = 14
   end
   object bbCancel: TBitBtn
-    Left = 261
-    Height = 25
-    Top = 410
+    Left = 274
+    Height = 30
+    Top = 432
     Width = 75
     Cancel = True
     Kind = bkCancel
     ModalResult = 2
-    TabOrder = 12
+    TabOrder = 15
   end
   object udInternetServerPort: TUpDown
     Left = 226
@@ -232,7 +232,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Top = 359
     Width = 127
     Caption = 'Show modal messages'
-    TabOrder = 13
+    TabOrder = 12
   end
   object udJSONRPCMinerServerPort: TUpDown
     Left = 226
@@ -264,7 +264,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Caption = ' Miner Server Private Key: '
     ClientHeight = 103
     ClientWidth = 330
-    TabOrder = 14
+    TabOrder = 7
     object rbGenerateANewPrivateKeyEachBlock: TRadioButton
       Left = 18
       Height = 19
@@ -305,6 +305,51 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Top = 377
     Width = 118
     Caption = 'Save debug logs too'
-    TabOrder = 9
+    TabOrder = 10
+  end
+  object bbOpenDataFolder: TBitBtn
+    Left = 16
+    Height = 30
+    Top = 432
+    Width = 131
+    Caption = 'Open Data Folder'
+    Glyph.Data = {
+      36040000424D3604000000000000360000002800000010000000100000000100
+      2000000000000004000064000000640000000000000000000000078DBE4D078D
+      BEFF078DBEFF078DBEFF078DBEFF078DBEFF078DBEFF078DBEFF078DBEFF078D
+      BEFF078DBEFF078DBEFF078DBEFF078DBEFFFFFFFF00FFFFFF00078DBEFF25A1
+      D1FF70C6E7FF6BCFF9FF66CDF9FF65CDF9FF65CDF9FF65CDF9FF65CDF8FF65CD
+      F9FF65CDF8FF66CEF9FF39ADD8FF078DBEFF078DBE4DFFFFFF00078DBEFF4CBC
+      E7FF5EB8DAFF94DFFBFF6FD4FAFF6FD4F9FF6ED4FAFF6FD4F9FF6FD4FAFF6FD4
+      FAFF6FD4FAFF6ED4F9FF3EB1D9FF84D7EBFF078DBEFFFFFFFF00078DBEFF72D6
+      FAFF1593C2FFB6ECFDFF7DDDFBFF79DCFBFF79DCFBFF79DCFBFF79DCFBFF7ADC
+      FBFF79DCFAFF79DCFAFF44B5D9FFAEF1F9FF078DBEFFFFFFFF00078DBEFF79DD
+      FBFF1899C7FF94DDF3FFA2EBFCFF84E4FBFF83E4FCFF83E4FCFF84E4FCFF83E4
+      FCFF83E4FBFF84E5FCFF48B9DAFFB3F4F9FF078DBEFF078DBE4D078DBEFF82E3
+      FCFF43B7DCFF4BB9DBFFBFF4FDFF8EEBFCFF8DEBFCFF8DEBFDFF8DEBFDFF8DEB
+      FCFF8DEBFDFF8DEBFCFF4CBBDAFFB6F7F9FF6DCAE0FF078DBEFF078DBEFF8AEA
+      FCFF77DCF3FF1496C3FFFFFFFFFFC9F8FEFFC9F8FEFFC9F8FEFFC9F8FFFFC9F7
+      FFFFC9F8FEFFC9F8FFFF9CD6E7FFDFFAFBFFDBF7FAFF078DBEFF078DBEFF93F0
+      FEFF93F0FDFF1697C5FF078DBEFF078DBEFF078DBEFF078DBEFF078DBEFF078D
+      BEFF078DBEFF078DBEFF078DBEFF078DBEFF078DBEFF078DBEFF078DBEFF9BF5
+      FEFF9AF6FEFF9AF6FEFF9BF5FDFF9BF6FEFF9AF6FEFF9BF5FEFF9AF6FDFF9BF5
+      FEFF9AF6FEFF9AF6FEFF0989BAFFFFFFFF00FFFFFF00FFFFFF00078DBEFFFEFE
+      FEFFA0FBFFFFA0FBFEFFA0FBFEFFA1FAFEFFA1FBFEFFA0FAFEFFA1FBFEFFA1FB
+      FFFFA0FBFFFFA1FBFFFF0989BAFFFFFFFF00FFFFFF00FFFFFF00078DBE4D078D
+      BEFFFEFEFEFFA5FEFFFFA5FEFFFFA5FEFFFF078DBEFF078DBEFF078DBEFF078D
+      BEFF078DBEFF078DBEFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00078D
+      BE4D078DBEFF078DBEFF078DBEFF078DBEFF078DBE4DFFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00
+    }
+    OnClick = bbOpenDataFolderClick
+    TabOrder = 13
   end
 end

+ 16 - 1
Units/Forms/UFRMPascalCoinWalletConfig.pas

@@ -22,6 +22,7 @@ interface
 uses
 {$IFnDEF FPC}
   Windows,
+  ShellApi,
 {$ELSE}
   LCLIntf, LCLType, LMessages,
 {$ENDIF}
@@ -29,6 +30,9 @@ uses
   Dialogs, StdCtrls, Buttons, ComCtrls, UAppParams, UWalletKeys;
 
 type
+
+  { TFRMPascalCoinWalletConfig }
+
   TFRMPascalCoinWalletConfig = class(TForm)
     cbJSONRPCMinerServerActive: TCheckBox;
     ebDefaultFee: TEdit;
@@ -56,10 +60,12 @@ type
     rbMineAllwaysWithThisKey: TRadioButton;
     cbPrivateKeyToMine: TComboBox;
     cbSaveDebugLogs: TCheckBox;
+    bbOpenDataFolder: TBitBtn;
     procedure FormCreate(Sender: TObject);
     procedure bbOkClick(Sender: TObject);
     procedure bbUpdatePasswordClick(Sender: TObject);
     procedure cbSaveLogFilesClick(Sender: TObject);
+    procedure bbOpenDataFolderClick(Sender: TObject);
   private
     FAppParams: TAppParams;
     FWalletKeys: TWalletKeys;
@@ -75,7 +81,7 @@ type
 
 implementation
 
-uses UConst, UAccounts, ULog, UCrypto, UMiner;
+uses UConst, UAccounts, ULog, UCrypto, UMiner, UFolderHelper;
 
 {$IFnDEF FPC}
   {$R *.dfm}
@@ -118,6 +124,15 @@ begin
   ModalResult := MrOk;
 end;
 
+procedure TFRMPascalCoinWalletConfig.bbOpenDataFolderClick(Sender: TObject);
+begin
+  {$IFDEF FPC}
+  OpenDocument(pchar(TFolderHelper.GetPascalCoinDataFolder))
+  {$ELSE}
+  shellexecute(0, 'open', pchar(TFolderHelper.GetPascalCoinDataFolder), nil, nil, SW_SHOW)
+  {$ENDIF}
+end;
+
 procedure TFRMPascalCoinWalletConfig.bbUpdatePasswordClick(Sender: TObject);
 Var s,s2 : String;
 begin

+ 87 - 69
Units/Forms/UFRMPayloadDecoder.lfm

@@ -1,6 +1,8 @@
 object FRMPayloadDecoder: TFRMPayloadDecoder
-  Left = 0
-  Top = 0
+  Left = 344
+  Height = 406
+  Top = 184
+  Width = 674
   ActiveControl = ebOphash
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
@@ -8,303 +10,317 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
   ClientHeight = 406
   ClientWidth = 674
   Color = clBtnFace
-  Font.Charset = DEFAULT_CHARSET
   Font.Color = clWindowText
   Font.Height = -11
   Font.Name = 'Tahoma'
-  Font.Style = []
-  Position = poOwnerFormCenter
   OnCreate = FormCreate
-  PixelsPerInch = 96
+  Position = poOwnerFormCenter
+  LCLVersion = '1.6.0.4'
   object Label1: TLabel
     Left = 20
+    Height = 13
     Top = 56
     Width = 46
-    Height = 13
     Caption = 'Block/Op:'
+    ParentColor = False
   end
   object lblBlock: TLabel
     Left = 72
+    Height = 19
     Top = 51
     Width = 109
-    Height = 19
     Caption = '000000/0000'
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    ParentColor = False
     ParentFont = False
   end
   object lblDateTime: TLabel
     Left = 255
+    Height = 19
     Top = 51
     Width = 30
-    Height = 19
     Caption = '000'
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    ParentColor = False
     ParentFont = False
   end
   object Label6: TLabel
     Left = 195
+    Height = 13
     Top = 56
     Width = 52
-    Height = 13
     Caption = 'Date Time:'
+    ParentColor = False
   end
   object Label2: TLabel
     Left = 20
+    Height = 13
     Top = 106
     Width = 52
-    Height = 13
     Caption = 'Operation:'
+    ParentColor = False
   end
   object lblOperationTxt: TLabel
     Left = 90
+    Height = 22
     Top = 101
     Width = 561
-    Height = 22
     AutoSize = False
     Caption = '000'
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    ParentColor = False
     ParentFont = False
     WordWrap = True
   end
   object lblAmountCaption: TLabel
     Left = 220
+    Height = 13
     Top = 81
     Width = 41
-    Height = 13
     Caption = 'Amount:'
+    ParentColor = False
   end
   object lblAmount: TLabel
     Left = 270
+    Height = 19
     Top = 76
     Width = 30
-    Height = 19
     Caption = '000'
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    ParentColor = False
     ParentFont = False
   end
   object lblFeeCaption: TLabel
     Left = 517
+    Height = 13
     Top = 56
     Width = 22
-    Height = 13
     Caption = 'Fee:'
+    ParentColor = False
   end
   object lblFee: TLabel
     Left = 547
+    Height = 19
     Top = 51
     Width = 30
-    Height = 19
     Caption = '000'
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    ParentColor = False
     ParentFont = False
   end
   object Label4: TLabel
     Left = 20
+    Height = 13
     Top = 24
     Width = 38
-    Height = 13
     Caption = 'OpHash'
+    ParentColor = False
   end
   object lblSenderCaption: TLabel
     Left = 20
+    Height = 13
     Top = 81
     Width = 38
-    Height = 13
     Caption = 'Sender:'
+    ParentColor = False
   end
   object lblSender: TLabel
     Left = 64
+    Height = 19
     Top = 76
     Width = 97
-    Height = 19
     Caption = '9999999-99'
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    ParentColor = False
     ParentFont = False
   end
   object lblReceiverCaption: TLabel
     Left = 411
+    Height = 13
     Top = 81
     Width = 46
-    Height = 13
     Caption = 'Receiver:'
+    ParentColor = False
   end
   object lblReceiver: TLabel
     Left = 463
+    Height = 19
     Top = 76
     Width = 30
-    Height = 19
     Caption = '000'
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clBlack
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    ParentColor = False
     ParentFont = False
   end
   object lblReceiverInfo: TLabel
     Left = 481
+    Height = 19
     Top = 50
     Width = 121
-    Height = 19
     Caption = '(Receiver info)'
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clRed
     Font.Height = -16
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    ParentColor = False
     ParentFont = False
   end
   object PageControl: TPageControl
     Left = 20
+    Height = 206
     Top = 140
     Width = 631
-    Height = 206
     ActivePage = tsDecoded
+    TabIndex = 0
     TabOrder = 2
     OnChanging = PageControlChanging
     object tsDecoded: TTabSheet
       Caption = 'Payload'
+      ClientHeight = 180
+      ClientWidth = 623
       object Label7: TLabel
         Left = 15
+        Height = 13
         Top = 94
         Width = 87
-        Height = 13
         Caption = 'Decoded Payload:'
+        ParentColor = False
       end
       object lblDecodedMethod: TLabel
-        Left = 562
-        Top = 94
-        Width = 44
+        Left = 192
         Height = 13
+        Top = 94
+        Width = 414
         Alignment = taRightJustify
+        AutoSize = False
         Caption = '(Method)'
-        Font.Charset = DEFAULT_CHARSET
         Font.Color = clGray
         Font.Height = -11
         Font.Name = 'Tahoma'
-        Font.Style = []
+        ParentColor = False
         ParentFont = False
       end
       object Label3: TLabel
         Left = 15
+        Height = 13
         Top = 9
         Width = 155
-        Height = 13
         Caption = 'Original Payload in Hexadecimal:'
+        ParentColor = False
       end
       object memoDecoded: TMemo
         Left = 15
+        Height = 55
         Top = 111
         Width = 591
-        Height = 55
-        TabStop = False
-        Font.Charset = DEFAULT_CHARSET
         Font.Color = clBlack
         Font.Height = -13
         Font.Name = 'Tahoma'
         Font.Style = [fsBold]
         Lines.Strings = (
-          'memoDecoded')
+          'memoDecoded'
+        )
+        OnKeyDown = memoDecodedKeyDown
         ParentFont = False
         ReadOnly = True
         TabOrder = 0
-        OnKeyDown = memoDecodedKeyDown
+        TabStop = False
       end
       object memoOriginalPayloadInHexa: TMemo
         Left = 15
+        Height = 55
         Top = 28
         Width = 591
-        Height = 55
-        TabStop = False
         Color = clBtnFace
-        Font.Charset = DEFAULT_CHARSET
         Font.Color = clBlack
         Font.Height = -13
         Font.Name = 'Tahoma'
         Font.Style = [fsBold]
         Lines.Strings = (
-          'memoDecoded')
+          'memoDecoded'
+        )
+        OnKeyDown = memoDecodedKeyDown
         ParentFont = False
         ReadOnly = True
         TabOrder = 1
-        OnKeyDown = memoDecodedKeyDown
+        TabStop = False
       end
     end
     object tsDecodeMethods: TTabSheet
       Caption = 'Decode methods'
+      ClientHeight = 0
+      ClientWidth = 0
       ImageIndex = 1
       object lblPasswordsInfo: TLabel
         Left = 235
+        Height = 13
         Top = 162
         Width = 81
-        Height = 13
         Caption = 'lblPasswordsInfo'
+        ParentColor = False
       end
       object cbMethodPublicPayload: TCheckBox
         Left = 16
+        Height = 17
         Top = 15
         Width = 225
-        Height = 17
         Caption = 'Not encrypted (Public payload)'
-        TabOrder = 0
         OnClick = cbMethodPublicPayloadClick
+        TabOrder = 0
       end
       object cbUsingPrivateKeys: TCheckBox
         Left = 16
+        Height = 17
         Top = 38
         Width = 225
-        Height = 17
         Caption = 'Using Private keys of my Wallet'
-        TabOrder = 1
         OnClick = cbMethodPublicPayloadClick
+        TabOrder = 1
       end
       object cbUsingPasswords: TCheckBox
         Left = 16
+        Height = 17
         Top = 61
         Width = 225
-        Height = 17
         Caption = 'Using Passwords of the list'
-        TabOrder = 2
         OnClick = cbMethodPublicPayloadClick
+        TabOrder = 2
       end
       object memoPasswords: TMemo
         Left = 235
+        Height = 146
         Top = 10
         Width = 371
-        Height = 146
+        OnChange = cbMethodPublicPayloadClick
         ScrollBars = ssBoth
         TabOrder = 3
-        OnChange = cbMethodPublicPayloadClick
       end
       object bbSaveMethods: TBitBtn
         Left = 60
+        Height = 25
         Top = 110
         Width = 75
-        Height = 25
         Caption = 'Save'
         Glyph.Data = {
           DE010000424DDE01000000000000760000002800000024000000120000000100
@@ -322,18 +338,19 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
           33333333A222433333333333338F338F00003333333333333A22433333333333
           3338F38F000033333333333333A223333333333333338F830000333333333333
           333A333333333333333338330000333333333333333333333333333333333333
-          0000}
+          0000
+        }
         NumGlyphs = 2
-        TabOrder = 4
         OnClick = bbSaveMethodsClick
+        TabOrder = 4
       end
     end
   end
   object bbClose: TBitBtn
     Left = 572
+    Height = 25
     Top = 362
     Width = 79
-    Height = 25
     Cancel = True
     Caption = 'Close'
     Glyph.Data = {
@@ -348,16 +365,17 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
       55557775555777FF5555555555599905555555555557777F5555555555559905
       555555555555777FF5555555555559905555555555555777FF55555555555579
       05555555555555777FF5555555555557905555555555555777FF555555555555
-      5990555555555555577755555555555555555555555555555555}
+      5990555555555555577755555555555555555555555555555555
+    }
     ModalResult = 2
     NumGlyphs = 2
     TabOrder = 3
   end
   object bbFind: TBitBtn
     Left = 599
+    Height = 25
     Top = 19
     Width = 52
-    Height = 25
     Caption = '&Find'
     Glyph.Data = {
       36030000424D3603000000000000360000002800000010000000100000000100
@@ -385,25 +403,25 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
       DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
       FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
       86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-      00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF}
+      00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF
+    }
+    OnClick = bbFindClick
     TabOrder = 1
     TabStop = False
-    OnClick = bbFindClick
   end
   object ebOphash: TEdit
     Left = 64
+    Height = 22
     Top = 20
     Width = 529
-    Height = 22
-    Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
     Font.Height = -12
     Font.Name = 'Tahoma'
     Font.Style = [fsBold]
+    OnExit = ebOphashExit
+    OnKeyPress = ebOphashKeyPress
     ParentFont = False
     TabOrder = 0
     Text = '12345678901234567890123456789012345678901234567890123456789012'
-    OnExit = ebOphashExit
-    OnKeyPress = ebOphashKeyPress
   end
 end

+ 38 - 2
Units/Forms/UFRMWallet.dfm

@@ -368,12 +368,16 @@ object FRMWallet: TFRMWallet
     Top = 91
     Width = 849
     Height = 432
-    ActivePage = tsMyAccounts
+    ActivePage = tsNodeStats
     Align = alClient
     TabOrder = 2
     OnChange = PageControlChange
     object tsMyAccounts: TTabSheet
       Caption = 'Accounts Explorer'
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object Splitter1: TSplitter
         Left = 380
         Top = 66
@@ -579,6 +583,10 @@ object FRMWallet: TFRMWallet
         TabOrder = 2
         object tsAccountOperations: TTabSheet
           Caption = 'Operations of selected Account'
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object dgAccountOperations: TDrawGrid
             Left = 0
             Top = 0
@@ -598,6 +606,10 @@ object FRMWallet: TFRMWallet
         object tsMultiSelectAccounts: TTabSheet
           Caption = 'Selected accounts for massive operations'
           ImageIndex = 1
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object dgSelectedAccounts: TDrawGrid
             Left = 41
             Top = 31
@@ -787,6 +799,10 @@ object FRMWallet: TFRMWallet
     object tsPendingOperations: TTabSheet
       Caption = 'Pending Operations'
       ImageIndex = 5
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object dgPendingOperations: TDrawGrid
         Left = 0
         Top = 86
@@ -834,6 +850,10 @@ object FRMWallet: TFRMWallet
     object tsBlockChain: TTabSheet
       Caption = 'BlockChain Explorer'
       ImageIndex = 1
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object Panel2: TPanel
         Left = 0
         Top = 0
@@ -879,6 +899,10 @@ object FRMWallet: TFRMWallet
     object tsOperations: TTabSheet
       Caption = 'Operations Explorer'
       ImageIndex = 1
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object Panel1: TPanel
         Left = 0
         Top = 0
@@ -924,6 +948,10 @@ object FRMWallet: TFRMWallet
     object tsLogs: TTabSheet
       Caption = 'Logs'
       ImageIndex = 2
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object pnlTopLogs: TPanel
         Left = 0
         Top = 0
@@ -953,6 +981,10 @@ object FRMWallet: TFRMWallet
     object tsNodeStats: TTabSheet
       Caption = 'Node Stats'
       ImageIndex = 3
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       DesignSize = (
         841
         404)
@@ -1015,6 +1047,10 @@ object FRMWallet: TFRMWallet
     object tsMessages: TTabSheet
       Caption = 'Messages'
       ImageIndex = 6
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       DesignSize = (
         841
         404)
@@ -1248,7 +1284,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Top = 180
     Bitmap = {
-      494C010102000800840110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000800940110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 110 - 122
Units/Forms/UFRMWallet.lfm

@@ -4,7 +4,7 @@ object FRMWallet: TFRMWallet
   Top = 328
   Width = 865
   Caption = 'Pascal Coin Wallet, JSON-RPC Miner & Explorer'
-  ClientHeight = 580
+  ClientHeight = 600
   ClientWidth = 865
   Color = clBtnFace
   Constraints.MinHeight = 600
@@ -162,15 +162,15 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 11
-      Width = 60
+      Width = 70
       Caption = 'Total Blocks:'
       ParentColor = False
     end
     object lblCurrentBlock: TLabel
-      Left = 156
+      Left = 166
       Height = 13
       Top = 11
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -178,15 +178,15 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 26
-      Width = 89
+      Width = 106
       Caption = 'Current Block age:'
       ParentColor = False
     end
     object lblCurrentBlockTime: TLabel
-      Left = 188
+      Left = 198
       Height = 13
       Top = 26
-      Width = 81
+      Width = 96
       Caption = '000 seconds ago'
       ParentColor = False
     end
@@ -194,15 +194,15 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 41
-      Width = 98
+      Width = 115
       Caption = 'Pending Operations:'
       ParentColor = False
     end
     object lblOperationsPending: TLabel
-      Left = 194
+      Left = 207
       Height = 13
       Top = 41
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -210,15 +210,15 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 56
-      Width = 68
+      Width = 81
       Caption = 'Miners clients:'
       ParentColor = False
     end
     object lblMinersClients: TLabel
-      Left = 163
+      Left = 177
       Height = 13
       Top = 56
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -226,23 +226,23 @@ object FRMWallet: TFRMWallet
       Left = 429
       Height = 13
       Top = 11
-      Width = 76
+      Width = 86
       Caption = 'Current Target:'
       ParentColor = False
     end
     object lblCurrentDifficulty: TLabel
-      Left = 511
+      Left = 518
       Height = 13
       Top = 11
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
     object lblTimeAverage: TLabel
-      Left = 360
+      Left = 370
       Height = 13
       Top = 26
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -250,7 +250,7 @@ object FRMWallet: TFRMWallet
       Left = 285
       Height = 13
       Top = 26
-      Width = 69
+      Width = 83
       Caption = 'Time average:'
       ParentColor = False
     end
@@ -258,15 +258,15 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 70
-      Width = 63
+      Width = 72
       Caption = 'Node Status:'
       ParentColor = False
     end
     object lblNodeStatus: TLabel
-      Left = 163
+      Left = 168
       Height = 13
       Top = 70
-      Width = 15
+      Width = 18
       Caption = '???'
       ParentColor = False
     end
@@ -274,23 +274,23 @@ object FRMWallet: TFRMWallet
       Left = 285
       Height = 13
       Top = 11
-      Width = 48
+      Width = 55
       Caption = 'Accounts:'
       ParentColor = False
     end
     object lblCurrentAccounts: TLabel
-      Left = 337
+      Left = 344
       Height = 13
       Top = 11
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
     object lblTimeAverageAux: TLabel
-      Left = 360
+      Left = 370
       Height = 13
       Top = 41
-      Width = 18
+      Width = 21
       Caption = '000'
       Font.Color = clGray
       Font.Height = -11
@@ -302,7 +302,7 @@ object FRMWallet: TFRMWallet
       Left = 360
       Height = 13
       Top = 56
-      Width = 74
+      Width = 86
       Caption = 'Blocks found:'
       Font.Color = clWindowText
       Font.Height = -11
@@ -312,11 +312,11 @@ object FRMWallet: TFRMWallet
       ParentFont = False
     end
     object lblBlocksFound: TLabel
-      Left = 440
+      Left = 450
       Height = 13
       Hint = 'Blocks found while Miner is running...'
       Top = 56
-      Width = 21
+      Width = 24
       Caption = '000'
       Font.Color = clWindowText
       Font.Height = -11
@@ -330,9 +330,9 @@ object FRMWallet: TFRMWallet
     object lblReceivedMessages: TLabel
       Cursor = crHandPoint
       Left = 360
-      Height = 23
+      Height = 22
       Top = 66
-      Width = 185
+      Width = 211
       Caption = 'Received messages'
       Font.Color = clRed
       Font.Height = -19
@@ -344,9 +344,9 @@ object FRMWallet: TFRMWallet
     end
     object lblBuild: TLabel
       Left = 586
-      Height = 23
+      Height = 22
       Top = 3
-      Width = 49
+      Width = 56
       Caption = 'Build'
       Font.Color = clWindowText
       Font.Height = -19
@@ -358,8 +358,8 @@ object FRMWallet: TFRMWallet
   end
   object StatusBar: TStatusBar
     Left = 0
-    Height = 23
-    Top = 557
+    Height = 21
+    Top = 579
     Width = 865
     Panels = <    
       item
@@ -379,21 +379,21 @@ object FRMWallet: TFRMWallet
   end
   object PageControl: TPageControl
     Left = 0
-    Height = 466
+    Height = 488
     Top = 91
     Width = 865
-    ActivePage = tsMyAccounts
+    ActivePage = tsMessages
     Align = alClient
-    TabIndex = 0
+    TabIndex = 6
     TabOrder = 2
     OnChange = PageControlChange
     object tsMyAccounts: TTabSheet
       Caption = 'Accounts Explorer'
-      ClientHeight = 440
-      ClientWidth = 857
+      ClientHeight = 461
+      ClientWidth = 861
       object Splitter1: TSplitter
         Left = 380
-        Height = 374
+        Height = 395
         Top = 66
         Width = 5
       end
@@ -401,41 +401,41 @@ object FRMWallet: TFRMWallet
         Left = 0
         Height = 66
         Top = 0
-        Width = 857
+        Width = 861
         Align = alTop
         ClientHeight = 66
-        ClientWidth = 857
+        ClientWidth = 861
         TabOrder = 0
         object Label18: TLabel
           Left = 11
           Height = 13
           Top = 35
-          Width = 61
+          Width = 70
           Caption = 'Find account'
           ParentColor = False
         end
         object cbMyPrivateKeys: TComboBox
           Left = 260
-          Height = 21
+          Height = 31
           Top = 7
           Width = 411
-          ItemHeight = 13
+          ItemHeight = 0
           OnChange = cbMyPrivateKeysChange
           Style = csDropDownList
           TabOrder = 0
         end
         object cbExploreMyAccounts: TCheckBox
           Left = 11
-          Height = 19
+          Height = 24
           Top = 10
-          Width = 235
+          Width = 329
           Caption = 'Explore accounts with one of my Wallet Keys'
           OnClick = cbExploreMyAccountsClick
           TabOrder = 1
         end
         object ebFindAccountNumber: TEdit
           Left = 87
-          Height = 21
+          Height = 23
           Top = 33
           Width = 83
           OnChange = ebFindAccountNumberChange
@@ -453,16 +453,16 @@ object FRMWallet: TFRMWallet
         end
         object cbFilterAccounts: TCheckBox
           Left = 260
-          Height = 19
+          Height = 24
           Top = 35
-          Width = 145
+          Width = 202
           Caption = 'Filter accounts by balance'
           OnClick = cbFilterAccountsClick
           TabOrder = 4
         end
         object ebFilterAccountByBalanceMin: TEdit
           Left = 412
-          Height = 21
+          Height = 23
           Hint = 'Min balance'
           Top = 33
           Width = 83
@@ -472,7 +472,7 @@ object FRMWallet: TFRMWallet
         end
         object ebFilterAccountByBalanceMax: TEdit
           Left = 503
-          Height = 21
+          Height = 23
           Hint = 'Max balance'
           Top = 33
           Width = 83
@@ -483,17 +483,17 @@ object FRMWallet: TFRMWallet
       end
       object pnlAccounts: TPanel
         Left = 0
-        Height = 374
+        Height = 395
         Top = 66
         Width = 380
         Align = alLeft
         BevelOuter = bvNone
-        ClientHeight = 374
+        ClientHeight = 395
         ClientWidth = 380
         TabOrder = 1
         object dgAccounts: TDrawGrid
           Left = 0
-          Height = 340
+          Height = 361
           Top = 0
           Width = 380
           Align = alLeft
@@ -507,7 +507,7 @@ object FRMWallet: TFRMWallet
         object pnlAccountsInfo: TPanel
           Left = 0
           Height = 34
-          Top = 340
+          Top = 361
           Width = 380
           Align = alBottom
           BevelOuter = bvNone
@@ -518,7 +518,7 @@ object FRMWallet: TFRMWallet
             Left = 5
             Height = 13
             Top = 10
-            Width = 48
+            Width = 55
             Caption = 'Accounts:'
             ParentColor = False
           end
@@ -526,7 +526,7 @@ object FRMWallet: TFRMWallet
             Left = 120
             Height = 13
             Top = 10
-            Width = 88
+            Width = 104
             Caption = 'Accounts Balance:'
             ParentColor = False
           end
@@ -534,7 +534,7 @@ object FRMWallet: TFRMWallet
             Left = 60
             Height = 13
             Top = 10
-            Width = 18
+            Width = 21
             Caption = '000'
             ParentColor = False
           end
@@ -542,7 +542,7 @@ object FRMWallet: TFRMWallet
             Left = 214
             Height = 13
             Top = 10
-            Width = 18
+            Width = 21
             Caption = '000'
             ParentColor = False
           end
@@ -588,22 +588,22 @@ object FRMWallet: TFRMWallet
       end
       object pcAccountsOptions: TPageControl
         Left = 385
-        Height = 374
+        Height = 395
         Top = 66
-        Width = 472
+        Width = 476
         ActivePage = tsAccountOperations
         Align = alClient
         TabIndex = 0
         TabOrder = 2
         object tsAccountOperations: TTabSheet
           Caption = 'Operations of selected Account'
-          ClientHeight = 348
-          ClientWidth = 464
+          ClientHeight = 368
+          ClientWidth = 472
           object dgAccountOperations: TDrawGrid
             Left = 0
-            Height = 348
+            Height = 368
             Top = 0
-            Width = 464
+            Width = 472
             Align = alClient
             ExtendedSelect = False
             TabOrder = 0
@@ -611,19 +611,12 @@ object FRMWallet: TFRMWallet
             TitleFont.Height = -11
             TitleFont.Name = 'Tahoma'
             OnDblClick = MiDecodePayloadClick
-            RowHeights = (
-              24
-              24
-              24
-              24
-              24
-            )
           end
         end
         object tsMultiSelectAccounts: TTabSheet
           Caption = 'Selected accounts for massive operations'
-          ClientHeight = 0
-          ClientWidth = 0
+          ClientHeight = 368
+          ClientWidth = 472
           ImageIndex = 1
           object dgSelectedAccounts: TDrawGrid
             Left = 41
@@ -636,13 +629,6 @@ object FRMWallet: TFRMWallet
             TitleFont.Color = clWindowText
             TitleFont.Height = -11
             TitleFont.Name = 'Tahoma'
-            RowHeights = (
-              24
-              24
-              24
-              24
-              24
-            )
           end
           object pnlSelectedAccountsTop: TPanel
             Left = 0
@@ -827,14 +813,14 @@ object FRMWallet: TFRMWallet
     end
     object tsPendingOperations: TTabSheet
       Caption = 'Pending Operations'
-      ClientHeight = 0
-      ClientWidth = 0
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 5
       object dgPendingOperations: TDrawGrid
         Left = 0
-        Height = 318
+        Height = 375
         Top = 86
-        Width = 841
+        Width = 861
         Align = alClient
         ExtendedSelect = False
         TabOrder = 0
@@ -847,18 +833,18 @@ object FRMWallet: TFRMWallet
         Left = 0
         Height = 86
         Top = 0
-        Width = 841
+        Width = 861
         Align = alTop
         BevelOuter = bvNone
         BorderWidth = 10
         ClientHeight = 86
-        ClientWidth = 841
+        ClientWidth = 861
         TabOrder = 1
         object Label10: TLabel
           Left = 10
           Height = 66
           Top = 10
-          Width = 821
+          Width = 841
           Align = alClient
           AutoSize = False
           Caption = 'Here you can see Operations transmited/received from other nodes that will be included in next block. There is no guarantee that other nodes will include them when mining, so it''s important that you mine too to help include Operations to the main BlockChain'
@@ -873,8 +859,8 @@ object FRMWallet: TFRMWallet
     end
     object tsBlockChain: TTabSheet
       Caption = 'BlockChain Explorer'
-      ClientHeight = 0
-      ClientWidth = 0
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 1
       object Panel2: TPanel
         Left = 0
@@ -927,8 +913,8 @@ object FRMWallet: TFRMWallet
     end
     object tsOperations: TTabSheet
       Caption = 'Operations Explorer'
-      ClientHeight = 0
-      ClientWidth = 0
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 1
       object Panel1: TPanel
         Left = 0
@@ -981,8 +967,8 @@ object FRMWallet: TFRMWallet
     end
     object tsLogs: TTabSheet
       Caption = 'Logs'
-      ClientHeight = 0
-      ClientWidth = 0
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 2
       object pnlTopLogs: TPanel
         Left = 0
@@ -1014,40 +1000,40 @@ object FRMWallet: TFRMWallet
     end
     object tsNodeStats: TTabSheet
       Caption = 'Node Stats'
-      ClientHeight = 0
-      ClientWidth = 0
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 3
       object Label3: TLabel
         Left = 15
         Height = 13
         Top = 15
-        Width = 177
+        Width = 207
         Caption = 'Active Net Connections of this Node:'
         ParentColor = False
       end
       object Label6: TLabel
         Left = 15
         Height = 13
-        Top = 250
-        Width = 169
-        Anchors = [akLeft, akBottom]
+        Top = 312
+        Width = 202
+        Anchors = [akLeft, akRight, akBottom]
         Caption = 'Available or possible Node Servers:'
         ParentColor = False
       end
       object Label7: TLabel
         Left = 15
         Height = 13
-        Top = 146
-        Width = 86
-        Anchors = [akLeft, akBottom]
+        Top = 208
+        Width = 103
+        Anchors = [akLeft, akRight, akBottom]
         Caption = 'BlackList of Nodes'
         ParentColor = False
       end
       object memoNetConnections: TMemo
         Left = 15
-        Height = 106
+        Height = 166
         Top = 34
-        Width = 810
+        Width = 834
         Anchors = [akTop, akLeft, akRight, akBottom]
         ReadOnly = True
         ScrollBars = ssVertical
@@ -1056,8 +1042,8 @@ object FRMWallet: TFRMWallet
       object memoNetServers: TMemo
         Left = 15
         Height = 116
-        Top = 269
-        Width = 810
+        Top = 331
+        Width = 834
         Anchors = [akLeft, akRight, akBottom]
         ReadOnly = True
         ScrollBars = ssVertical
@@ -1066,8 +1052,8 @@ object FRMWallet: TFRMWallet
       object memoNetBlackLists: TMemo
         Left = 15
         Height = 79
-        Top = 165
-        Width = 810
+        Top = 227
+        Width = 833
         Anchors = [akLeft, akRight, akBottom]
         ReadOnly = True
         ScrollBars = ssVertical
@@ -1076,14 +1062,14 @@ object FRMWallet: TFRMWallet
     end
     object tsMessages: TTabSheet
       Caption = 'Messages'
-      ClientHeight = 0
-      ClientWidth = 0
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 6
       object Label11: TLabel
         Left = 15
         Height = 13
         Top = 151
-        Width = 51
+        Width = 59
         Caption = 'Messages:'
         ParentColor = False
       end
@@ -1091,7 +1077,7 @@ object FRMWallet: TFRMWallet
         Left = 315
         Height = 13
         Top = 11
-        Width = 85
+        Width = 99
         Caption = 'Message to send:'
         ParentColor = False
       end
@@ -1099,7 +1085,7 @@ object FRMWallet: TFRMWallet
         Left = 15
         Height = 13
         Top = 11
-        Width = 107
+        Width = 126
         Caption = 'Available connections:'
         ParentColor = False
       end
@@ -1107,7 +1093,7 @@ object FRMWallet: TFRMWallet
         Left = 410
         Height = 13
         Top = 11
-        Width = 361
+        Width = 430
         Caption = '(Messages will be encrypted, so only dest connection will be able to read it)'
         Font.Color = clGrayText
         Font.Height = -11
@@ -1122,22 +1108,24 @@ object FRMWallet: TFRMWallet
         Width = 275
         ItemHeight = 0
         MultiSelect = True
+        ScrollWidth = 273
         TabOrder = 0
+        TopIndex = -1
       end
       object bbSendAMessage: TButton
         Left = 315
         Height = 25
         Top = 101
-        Width = 456
+        Width = 525
         Caption = 'Send a Message'
         OnClick = bbSendAMessageClick
         TabOrder = 1
       end
       object memoMessages: TMemo
         Left = 15
-        Height = 215
+        Height = 270
         Top = 170
-        Width = 810
+        Width = 825
         Anchors = [akTop, akLeft, akRight, akBottom]
         Font.Color = clWindowText
         Font.Height = -16
@@ -1155,7 +1143,7 @@ object FRMWallet: TFRMWallet
         Left = 315
         Height = 61
         Top = 30
-        Width = 456
+        Width = 525
         Lines.Strings = (
           'memoMessageToSend'
         )

+ 97 - 67
Units/Forms/UFRMWallet.pas

@@ -27,10 +27,14 @@ uses
 {$ENDIF}
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, ExtCtrls, ComCtrls, UWalletKeys, StdCtrls,
-  ULog, DB, Grids, DBGrids, UAppParams,
-  UBlockChain, UNode, DBCtrls, UGridUtils, UMiner, UAccounts, Menus, ImgList,
+  ULog, Grids, UAppParams,
+  UBlockChain, UNode, UGridUtils, UMiner, UAccounts, Menus, ImgList,
   UNetProtocol, UCrypto, Buttons, UPoolMining, URPC;
 
+Const
+  CM_PC_WalletKeysChanged = WM_USER + 1;
+  CM_PC_NetConnectionUpdated = WM_USER + 2;
+
 type
   TMinerPrivateKey = (mpk_NewEachTime, mpk_Random, mpk_Selected);
 
@@ -233,6 +237,8 @@ type
     FMaxAccountBalance : Int64;
     FPoolMiningServer : TPoolMiningServer;
     FRPCServer : TRPCServer;
+    FMustProcessWalletChanged : Boolean;
+    FMustProcessNetConnectionUpdated : Boolean;
     //Procedure CheckMining;
     Procedure OnNewAccount(Sender : TObject);
     Procedure OnReceivedHelloMessage(Sender : TObject);
@@ -260,6 +266,8 @@ type
     Function GetAccountKeyForMiner : TAccountKey;
     Procedure DoUpdateAccounts;
     Function DoUpdateAccountsFilter : Boolean;
+    procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
+    procedure CM_NetConnectionUpdated(var Msg: TMessage); message CM_PC_NetConnectionUpdated;
   public
     { Public declarations }
     Property WalletKeys : TWalletKeysExt read FWalletKeys;
@@ -498,6 +506,83 @@ begin
   end;
 end;
 
+procedure TFRMWallet.CM_NetConnectionUpdated(var Msg: TMessage);
+Const CT_BooleanToString : Array[Boolean] of String = ('False','True');
+Var i : integer;
+ NC : TNetConnection;
+ l : TList;
+ sClientApp : String;
+ strings, sNSC, sRS, sDisc : TStrings;
+begin
+  Try
+    if Not TNetData.NetData.NetConnections.TryLockList(100,l) then exit;
+    try
+      strings := memoNetConnections.Lines;
+      sNSC := TStringList.Create;
+      sRS := TStringList.Create;
+      sDisc := TStringList.Create;
+      strings.BeginUpdate;
+      Try
+        for i := 0 to l.Count - 1 do begin
+          NC := l[i];
+          If NC.Client.BytesReceived>0 then begin
+            sClientApp := '['+IntToStr(NC.NetProtocolVersion.protocol_version)+'-'+IntToStr(NC.NetProtocolVersion.protocol_available)+'] '+NC.ClientAppVersion;
+          end else begin
+            sClientApp := '(no data)';
+          end;
+
+          if NC.Connected then begin
+            if NC is TNetServerClient then begin
+              sNSC.Add(Format('Client: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
+            end else begin
+              if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]))
+              else begin
+                sRS.Add(Format('Remote Server: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
+              end;
+            end;
+          end else begin
+            if NC is TNetServerClient then begin
+              sDisc.Add(Format('Disconnected client: IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
+            end else if NC.IsMyselfServer then begin
+              sDisc.Add(Format('Disconnected MySelf IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
+            end else begin
+              sDisc.Add(Format('Disconnected Remote Server: IP:%s %s - %s',[NC.ClientRemoteAddr,CT_BooleanToString[NC.Connected],sClientApp]));
+            end;
+          end;
+        end;
+        strings.Clear;
+        strings.Add(Format('Connections Updated %s Clients:%d Servers:%d (valid servers:%d)',[DateTimeToStr(now),sNSC.Count,sRS.Count,TNetData.NetData.NetStatistics.ServersConnectionsWithResponse]));
+        strings.AddStrings(sRS);
+        strings.AddStrings(sNSC);
+        if sDisc.Count>0 then begin
+          strings.Add('');
+          strings.Add('Disconnected connections: '+Inttostr(sDisc.Count));
+          strings.AddStrings(sDisc);
+        end;
+      Finally
+        strings.EndUpdate;
+        sNSC.Free;
+        sRS.Free;
+        sDisc.Free;
+      End;
+      //CheckMining;
+    finally
+      TNetData.NetData.NetConnections.UnlockList;
+    end;
+  Finally
+    FMustProcessNetConnectionUpdated := false;
+  End;
+end;
+
+procedure TFRMWallet.CM_WalletChanged(var Msg: TMessage);
+begin
+  UpdatePrivateKeys;
+  FMustProcessWalletChanged := false;
+end;
+
 {
 procedure TFRMWallet.CheckMining;
   Procedure Stop;
@@ -714,6 +799,8 @@ end;
 procedure TFRMWallet.FormCreate(Sender: TObject);
 Var i : Integer;
 begin
+  FMustProcessWalletChanged := false;
+  FMustProcessNetConnectionUpdated := false;
   FRPCServer := Nil;
   FMinAccountBalance := 0;
   FMaxAccountBalance := CT_MaxWalletAmount;
@@ -749,6 +836,7 @@ begin
   FSelectedAccountsGrid.OnUpdated := OnSelectedAccountsGridUpdated;
   FOperationsAccountGrid := TOperationsGrid.Create(Self);
   FOperationsAccountGrid.DrawGrid := dgAccountOperations;
+  FOperationsAccountGrid.MustShowAlwaysAnAccount := true;
   FPendingOperationsGrid := TOperationsGrid.Create(Self);
   FPendingOperationsGrid.DrawGrid := dgPendingOperations;
   FPendingOperationsGrid.AccountNumber := -1; // all
@@ -1135,70 +1223,10 @@ begin
 end;
 
 procedure TFRMWallet.OnNetConnectionsUpdated(Sender: TObject);
-Const CT_BooleanToString : Array[Boolean] of String = ('False','True');
-Var i : integer;
- NC : TNetConnection;
- l : TList;
- sClientApp : String;
- strings, sNSC, sRS, sDisc : TStrings;
 begin
-  l := TNetData.NetData.NetConnections.LockList;
-  try
-    strings := memoNetConnections.Lines;
-    sNSC := TStringList.Create;
-    sRS := TStringList.Create;
-    sDisc := TStringList.Create;
-    strings.BeginUpdate;
-    Try
-      for i := 0 to l.Count - 1 do begin
-        NC := l[i];
-        If NC.Client.BytesReceived>0 then begin
-          sClientApp := '['+IntToStr(NC.NetProtocolVersion.protocol_version)+'-'+IntToStr(NC.NetProtocolVersion.protocol_available)+'] '+NC.ClientAppVersion;
-        end else begin
-          sClientApp := '(no data)';
-        end;
-
-        if NC.Connected then begin
-          if NC is TNetServerClient then begin
-            sNSC.Add(Format('Client: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-              [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
-          end else begin
-            if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-              [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]))
-            else begin
-              sRS.Add(Format('Remote Server: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-              [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
-            end;
-          end;
-        end else begin
-          if NC is TNetServerClient then begin
-            sDisc.Add(Format('Disconnected client: IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
-          end else if NC.IsMyselfServer then begin
-            sDisc.Add(Format('Disconnected MySelf IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
-          end else begin
-            sDisc.Add(Format('Disconnected Remote Server: IP:%s %s - %s',[NC.ClientRemoteAddr,CT_BooleanToString[NC.Connected],sClientApp]));
-          end;
-        end;
-      end;
-      strings.Clear;
-      strings.Add(Format('Connections Updated %s Clients:%d Servers:%d (valid servers:%d)',[DateTimeToStr(now),sNSC.Count,sRS.Count,TNetData.NetData.NetStatistics.ServersConnectionsWithResponse]));
-      strings.AddStrings(sRS);
-      strings.AddStrings(sNSC);
-      if sDisc.Count>0 then begin
-        strings.Add('');
-        strings.Add('Disconnected connections: '+Inttostr(sDisc.Count));
-        strings.AddStrings(sDisc);
-      end;
-    Finally
-      strings.EndUpdate;
-      sNSC.Free;
-      sRS.Free;
-      sDisc.Free;
-    End;
-    //CheckMining;
-  finally
-    TNetData.NetData.NetConnections.UnlockList;
-  end;
+  if FMustProcessNetConnectionUpdated then exit;
+  FMustProcessNetConnectionUpdated := true;
+  PostMessage(Self.Handle,CM_PC_NetConnectionUpdated,0,0);
 end;
 
 procedure TFRMWallet.OnNetNodeServersUpdated(Sender: TObject);
@@ -1348,7 +1376,9 @@ end;
 
 procedure TFRMWallet.OnWalletChanged(Sender: TObject);
 begin
-  UpdatePrivateKeys;
+  if FMustProcessWalletChanged then exit;
+  FMustProcessWalletChanged := true;
+  PostMessage(Self.Handle,CM_PC_WalletKeysChanged,0,0);
 end;
 
 procedure TFRMWallet.PageControlChange(Sender: TObject);
@@ -1564,7 +1594,7 @@ Var i : integer;
  NC : TNetConnection;
  l : TList;
 begin
-  l := TNetData.NetData.NetConnections.LockList;
+  if Not TNetData.NetData.NetConnections.TryLockList(100,l) then exit;
   try
     lbNetConnections.Items.BeginUpdate;
     Try

+ 35 - 3
Units/Forms/UFRMWalletKeys.pas

@@ -21,7 +21,12 @@ interface
 
 uses
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
-  Dialogs, StdCtrls, UWalletKeys, Buttons, clipbrd;
+  Dialogs, StdCtrls, UWalletKeys, Buttons,
+  {$IFDEF FPC}LMessages,{$ENDIF}
+  clipbrd;
+
+Const
+  CM_PC_WalletKeysChanged = {$IFDEF FPC}LM_USER{$ELSE}WM_USER{$ENDIF} + 1;
 
 type
   TFRMWalletKeys = class(TForm)
@@ -59,17 +64,21 @@ type
     procedure bbExportAllWalletKeysClick(Sender: TObject);
     procedure bbImportKeysFileClick(Sender: TObject);
   private
+    FOldOnChanged : TNotifyEvent;
     FWalletKeys: TWalletKeys;
     procedure SetWalletKeys(const Value: TWalletKeys);
+    procedure OnWalletKeysChanged(Sender : TObject);
     { Private declarations }
     Procedure UpdateWalletKeys;
     Procedure UpdateSelectedWalletKey;
     Function GetSelectedWalletKey(var WalletKey : TWalletKey) : Boolean;
     Function GetSelectedWalletKeyAndIndex(var WalletKey : TWalletKey; var index : Integer) : Boolean;
     Procedure CheckIsWalletKeyValidPassword;
+    procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
   public
     { Public declarations }
     Property WalletKeys : TWalletKeys read FWalletKeys write SetWalletKeys;
+    Destructor Destroy; override;
   end;
 
 implementation
@@ -78,7 +87,7 @@ uses
 {$IFnDEF FPC}
   Windows,
 {$ELSE}
-  LCLIntf, LCLType, LMessages,
+  LCLIntf, LCLType,
 {$ENDIF}
   UCrypto, UAccounts, UFRMNewPrivateKeyType, UAES;
 
@@ -371,6 +380,17 @@ begin
   end;
 end;
 
+procedure TFRMWalletKeys.CM_WalletChanged(var Msg: TMessage);
+begin
+  UpdateWalletKeys;
+end;
+
+destructor TFRMWalletKeys.Destroy;
+begin
+  if Assigned(FWalletKeys) then FWalletKeys.OnChanged := FOldOnChanged;
+  inherited;
+end;
+
 procedure TFRMWalletKeys.FormCreate(Sender: TObject);
 begin
   lbWalletKeys.Sorted := true;
@@ -402,9 +422,21 @@ begin
   UpdateSelectedWalletKey;
 end;
 
+procedure TFRMWalletKeys.OnWalletKeysChanged(Sender : TObject);
+begin
+  PostMessage(Self.Handle,CM_PC_WalletKeysChanged,0,0);
+  if Assigned(FOldOnChanged) then FOldOnChanged(Sender);
+end;
+
 procedure TFRMWalletKeys.SetWalletKeys(const Value: TWalletKeys);
 begin
+  if FWalletKeys=Value then exit;
+  if Assigned(FWalletKeys) then FWalletKeys.OnChanged := FOldOnChanged;
   FWalletKeys := Value;
+  if Assigned(FWalletKeys) then begin
+    FOldOnChanged := FWalletKeys.OnChanged;
+    FWalletKeys.OnChanged := OnWalletKeysChanged;
+  end;
   UpdateWalletKeys;
 end;
 
@@ -451,7 +483,7 @@ end;
 
 procedure TFRMWalletKeys.UpdateWalletKeys;
 Var lasti,i : Integer;
-  wk : TWalletKey;
+  selected_wk,wk : TWalletKey;
   s : AnsiString;
 begin
   GetSelectedWalletKeyAndIndex(wk,lasti);

+ 144 - 115
Units/PascalCoin/UAccounts.pas

@@ -136,12 +136,12 @@ Type
   private
     FBlockAccountsList : TList;
     FListOfOrderedAccountKeysList : TList;
-    FBufferBlocksHash: AnsiString;
+    FBufferBlocksHash: TRawBytes;
     FTotalBalance: Int64;
     FTotalFee: Int64;
     FSafeBoxHash : TRawBytes;
     FLock: TCriticalSection; // Thread safe
-    FIsLocked : Boolean;
+    FPreviousBlockSafeBoxHash : TRawBytes;
     Procedure SetAccount(account_number : Cardinal; newAccountkey: TAccountKey; newBalance: UInt64; newN_operation: Cardinal);
     Procedure AccountKeyListAddAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
     Procedure AccountKeyListRemoveAccount(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
@@ -166,7 +166,8 @@ Type
     Property TotalBalance : Int64 read FTotalBalance;
     Procedure StartThreadSafe;
     Procedure EndThreadSave;
-    Property IsLocked : Boolean read FIsLocked;
+    Property SafeBoxHash : TRawBytes read FSafeBoxHash;
+    Property PreviousBlockSafeBoxHash : TRawBytes read FPreviousBlockSafeBoxHash;
   End;
 
 
@@ -650,6 +651,7 @@ begin
   Dec(FTotalFee,FTotalFee);
   AccountKeyListAddAccounts(accountkey,accs);
   // Calculating new value of safebox
+  FPreviousBlockSafeBoxHash := FSafeBoxHash;
   FSafeBoxHash := CalcSafeBoxHash;
 end;
 
@@ -771,18 +773,24 @@ procedure TPCSafeBox.Clear;
 Var i : Integer;
   P : PBlockAccount;
 begin
-  for i := 0 to FBlockAccountsList.Count - 1 do begin
-    P := FBlockAccountsList.Items[i];
-    Dispose(P);
-  end;
-  FBlockAccountsList.Clear;
-  For i:=0 to FListOfOrderedAccountKeysList.count-1 do begin
-    TOrderedAccountKeysList( FListOfOrderedAccountKeysList[i] ).ClearAccounts(False);
+  StartThreadSafe;
+  Try
+    for i := 0 to FBlockAccountsList.Count - 1 do begin
+      P := FBlockAccountsList.Items[i];
+      Dispose(P);
+    end;
+    FBlockAccountsList.Clear;
+    For i:=0 to FListOfOrderedAccountKeysList.count-1 do begin
+      TOrderedAccountKeysList( FListOfOrderedAccountKeysList[i] ).ClearAccounts(False);
+    end;
+    FBufferBlocksHash := '';
+    FTotalBalance := 0;
+    FTotalFee := 0;
+    FSafeBoxHash := CalcSafeBoxHash;
+    FPreviousBlockSafeBoxHash := '';
+  Finally
+    EndThreadSave;
   end;
-  FBufferBlocksHash := '';
-  FTotalBalance := 0;
-  FTotalFee := 0;
-  FSafeBoxHash := CalcSafeBoxHash;
 end;
 
 procedure TPCSafeBox.CopyFrom(accounts: TPCSafeBox);
@@ -790,30 +798,40 @@ Var i,j : Cardinal;
   P : PBlockAccount;
   BA : TBlockAccount;
 begin
-  if accounts=Self then exit;
-  Clear;
-  if accounts.BlocksCount>0 then begin
-    for i := 0 to accounts.BlocksCount - 1 do begin
-      BA := accounts.Block(i);
-      New(P);
-      P^ := BA;
-      FBlockAccountsList.Add(P);
-      for j := Low(BA.accounts) to High(BA.accounts) do begin
-        AccountKeyListAddAccounts(BA.accounts[j].accountkey,[BA.accounts[j].account]);
+  StartThreadSafe;
+  Try
+    accounts.StartThreadSafe;
+    try
+      if accounts=Self then exit;
+      Clear;
+      if accounts.BlocksCount>0 then begin
+        for i := 0 to accounts.BlocksCount - 1 do begin
+          BA := accounts.Block(i);
+          New(P);
+          P^ := BA;
+          FBlockAccountsList.Add(P);
+          for j := Low(BA.accounts) to High(BA.accounts) do begin
+            AccountKeyListAddAccounts(BA.accounts[j].accountkey,[BA.accounts[j].account]);
+          end;
+        end;
       end;
+
+      FTotalBalance := accounts.TotalBalance;
+      FTotalFee := accounts.FTotalFee;
+      FBufferBlocksHash := accounts.FBufferBlocksHash;
+      FSafeBoxHash := accounts.FSafeBoxHash;
+      FPreviousBlockSafeBoxHash := accounts.FPreviousBlockSafeBoxHash;
+    finally
+      accounts.EndThreadSave;
     end;
+  finally
+    EndThreadSave;
   end;
-
-  FTotalBalance := accounts.TotalBalance;
-  FTotalFee := accounts.FTotalFee;
-  FBufferBlocksHash := accounts.FBufferBlocksHash;
-  FSafeBoxHash := accounts.FSafeBoxHash;
 end;
 
 constructor TPCSafeBox.Create;
 begin
   FLock := TCriticalSection.Create;
-  FIsLocked := false;
   FBlockAccountsList := TList.Create;
   FListOfOrderedAccountKeysList := TList.Create;
   Clear;
@@ -828,14 +846,12 @@ begin
   end;
   FreeAndNil(FBlockAccountsList);
   FreeAndNil(FListOfOrderedAccountKeysList);
-  FLock.Free;
+  FreeAndNil(FLock);
   inherited;
 end;
 
 procedure TPCSafeBox.EndThreadSave;
 begin
-  if Not FIsLocked then raise Exception.Create('Is not locked');
-  FIsLocked := False;
   FLock.Release;
 end;
 
@@ -848,70 +864,81 @@ Var w : Word;
   j : Integer;
   safeBoxBankVersion : Word;
 begin
-  Clear;
-  Result := false;
-  Try
-    errors := 'Invalid stream';
-    TStreamOp.ReadAnsiString(Stream,s);
-    if (s<>CT_MagicIdentificator) then exit;
-    errors := 'Invalid version or corrupted stream';
-    if Stream.Size<8 then exit;
-    Stream.Read(w,2);
-    if w<>CT_BlockChain_Protocol_Version then exit;
-    Stream.Read(safeBoxBankVersion,2);
-    if safeBoxBankVersion<>CT_SafeBoxBankVersion then begin
-      errors := 'Invalid SafeBoxBank version: '+InttostR(safeBoxBankVersion);
-      exit;
-    end;
-    Stream.Read(blockscount,4);
-    if blockscount>(CT_NewLineSecondsAvg*2000000) then exit; // Protection for corrupted data...
-    errors := 'Corrupted stream';
-    for iblock := 0 to blockscount-1 do begin
-      errors := 'Corrupted stream reading block '+inttostr(iblock+1)+'/'+inttostr(blockscount);
-      block := CT_BlockAccount_NUL;
-      if Stream.Read(block.blockaccount,4)<4 then exit;
-      if (block.blockaccount<>iblock) then exit; // Invalid value
-      for iacc := Low(block.accounts) to High(block.accounts) do begin
-        errors := 'Corrupted stream reading account '+inttostr(iacc+1)+'/'+inttostr(length(block.accounts))+' of block '+inttostr(iblock+1)+'/'+inttostr(blockscount);
-        if Stream.Read(block.accounts[iacc].account,4)<4 then exit;
+  StartThreadSafe;
+  try
+    Clear;
+    Result := false;
+    Try
+      errors := 'Invalid stream';
+      TStreamOp.ReadAnsiString(Stream,s);
+      if (s<>CT_MagicIdentificator) then exit;
+      errors := 'Invalid version or corrupted stream';
+      if Stream.Size<8 then exit;
+      Stream.Read(w,2);
+      if w<>CT_BlockChain_Protocol_Version then exit;
+      Stream.Read(safeBoxBankVersion,2);
+      if safeBoxBankVersion<>CT_SafeBoxBankVersion then begin
+        errors := 'Invalid SafeBoxBank version: '+InttostR(safeBoxBankVersion);
+        exit;
+      end;
+      Stream.Read(blockscount,4);
+      if blockscount>(CT_NewLineSecondsAvg*2000000) then exit; // Protection for corrupted data...
+      // Build 1.3.0 to increase reading speed:
+      FBlockAccountsList.Capacity := blockscount;
+      errors := 'Corrupted stream';
+      for iblock := 0 to blockscount-1 do begin
+        errors := 'Corrupted stream reading block '+inttostr(iblock+1)+'/'+inttostr(blockscount);
+        block := CT_BlockAccount_NUL;
+        if Stream.Read(block.blockaccount,4)<4 then exit;
+        if (block.blockaccount<>iblock) then exit; // Invalid value
+        for iacc := Low(block.accounts) to High(block.accounts) do begin
+          errors := 'Corrupted stream reading account '+inttostr(iacc+1)+'/'+inttostr(length(block.accounts))+' of block '+inttostr(iblock+1)+'/'+inttostr(blockscount);
+          if Stream.Read(block.accounts[iacc].account,4)<4 then exit;
+          if TStreamOp.ReadAnsiString(Stream,s)<0 then exit;
+          block.accounts[iacc].accountkey := TAccountComp.RawString2Accountkey(s);
+          if Stream.Read(block.accounts[iacc].balance,SizeOf(UInt64))<SizeOf(UInt64) then exit;
+          if Stream.Read(block.accounts[iacc].updated_block,4)<4 then exit;
+          if Stream.Read(block.accounts[iacc].n_operation,4)<4 then exit;
+          if safeBoxBankVersion>=1 then begin
+            if Stream.Read(block.accounts[iacc].previous_updated_block,4)<4 then exit;
+          end;
+          // check valid
+          if not TAccountComp.IsValidAccountKey(block.accounts[iacc].accountkey,s) then begin
+            errors := errors + ' > '+s;
+            exit;
+          end;
+          inc(FTotalBalance,block.accounts[iacc].balance);
+        end;
+        errors := 'Corrupted stream reading block hash '+inttostr(iblock+1)+'/'+inttostr(blockscount);
+        if Stream.Read(block.timestamp,4)<4 then exit;
         if TStreamOp.ReadAnsiString(Stream,s)<0 then exit;
-        block.accounts[iacc].accountkey := TAccountComp.RawString2Accountkey(s);
-        if Stream.Read(block.accounts[iacc].balance,SizeOf(UInt64))<SizeOf(UInt64) then exit;
-        if Stream.Read(block.accounts[iacc].updated_block,4)<4 then exit;
-        if Stream.Read(block.accounts[iacc].n_operation,4)<4 then exit;
-        if safeBoxBankVersion>=1 then begin
-          if Stream.Read(block.accounts[iacc].previous_updated_block,4)<4 then exit;
+        block.block_hash := s;
+        // Check is valid:
+        if CalcBlockHash(block)<>block.block_hash then exit;
+        if safeBoxBankVersion>=2 then begin
+          if Stream.Read(block.target,4)<4 then exit;
         end;
-        // check valid
-        if not TAccountComp.IsValidAccountKey(block.accounts[iacc].accountkey,s) then begin
-          errors := errors + ' > '+s;
-          exit;
+        // Add
+        New(P);
+        P^ := block;
+        FBlockAccountsList.Add(P);
+        for j := low(block.accounts) to High(block.accounts) do begin
+          AccountKeyListAddAccounts(block.accounts[j].accountkey,[block.accounts[j].account]);
         end;
-        inc(FTotalBalance,block.accounts[iacc].balance);
-      end;
-      errors := 'Corrupted stream reading block hash '+inttostr(iblock+1)+'/'+inttostr(blockscount);
-      if Stream.Read(block.timestamp,4)<4 then exit;
-      if TStreamOp.ReadAnsiString(Stream,s)<0 then exit;
-      block.block_hash := s;
-      // Check is valid:
-      if CalcBlockHash(block)<>block.block_hash then exit;
-      if safeBoxBankVersion>=2 then begin
-        if Stream.Read(block.target,4)<4 then exit;
-      end;
-      // Add
-      New(P);
-      P^ := block;
-      FBlockAccountsList.Add(P);
-      for j := low(block.accounts) to High(block.accounts) do begin
-        AccountKeyListAddAccounts(block.accounts[j].accountkey,[block.accounts[j].account]);
+        FBufferBlocksHash := FBufferBlocksHash+block.block_hash;
+        LastReadBlock := block;
       end;
-      FBufferBlocksHash := FBufferBlocksHash+block.block_hash;
-      LastReadBlock := block;
-    end;
-    Result := true;
+      // Build 1.3.0 adding previous block hash information
+      TStreamOp.ReadAnsiString(Stream,FPreviousBlockSafeBoxHash);
+      // Build 1.3.0 adding calculation
+      FSafeBoxHash := CalcSafeBoxHash;
+      Result := true;
+    Finally
+      if Not Result then Clear;
+    End;
   Finally
-    if Not Result then Clear;
-  End;
+    EndThreadSave;
+  end;
 end;
 
 class function TPCSafeBox.LoadSafeBoxStreamHeader(Stream: TStream; var BlocksCount: Cardinal): Boolean;
@@ -937,25 +964,32 @@ Var
   c,iblock,iacc : Cardinal;
   b : TBlockAccount;
 begin
-  TStreamOp.WriteAnsiString(Stream,CT_MagicIdentificator);
-  Stream.Write(CT_BlockChain_Protocol_Version,SizeOf(CT_BlockChain_Protocol_Version));
-  Stream.Write(CT_SafeBoxBankVersion,SizeOf(CT_SafeBoxBankVersion));
-  c := BlocksCount;
-  Stream.Write(c,Sizeof(c));
-  for iblock := 0 to c-1 do begin
-    b := Block(iblock);
-    Stream.Write(b.blockaccount,SizeOf(b.blockaccount)); // Little endian
-    for iacc := Low(b.accounts) to High(b.accounts) do begin
-      Stream.Write(b.accounts[iacc].account,Sizeof(b.accounts[iacc].account));
-      TStreamOp.WriteAnsiString(Stream,TAccountComp.AccountKey2RawString(b.accounts[iacc].accountkey));
-      Stream.Write(b.accounts[iacc].balance,Sizeof(b.accounts[iacc].balance));
-      Stream.Write(b.accounts[iacc].updated_block,Sizeof(b.accounts[iacc].updated_block));
-      Stream.Write(b.accounts[iacc].n_operation,Sizeof(b.accounts[iacc].n_operation));
-      Stream.Write(b.accounts[iacc].previous_updated_block,Sizeof(b.accounts[iacc].previous_updated_block));
+  StartThreadSafe;
+  Try
+    TStreamOp.WriteAnsiString(Stream,CT_MagicIdentificator);
+    Stream.Write(CT_BlockChain_Protocol_Version,SizeOf(CT_BlockChain_Protocol_Version));
+    Stream.Write(CT_SafeBoxBankVersion,SizeOf(CT_SafeBoxBankVersion));
+    c := BlocksCount;
+    Stream.Write(c,Sizeof(c));
+    for iblock := 0 to c-1 do begin
+      b := Block(iblock);
+      Stream.Write(b.blockaccount,SizeOf(b.blockaccount)); // Little endian
+      for iacc := Low(b.accounts) to High(b.accounts) do begin
+        Stream.Write(b.accounts[iacc].account,Sizeof(b.accounts[iacc].account));
+        TStreamOp.WriteAnsiString(Stream,TAccountComp.AccountKey2RawString(b.accounts[iacc].accountkey));
+        Stream.Write(b.accounts[iacc].balance,Sizeof(b.accounts[iacc].balance));
+        Stream.Write(b.accounts[iacc].updated_block,Sizeof(b.accounts[iacc].updated_block));
+        Stream.Write(b.accounts[iacc].n_operation,Sizeof(b.accounts[iacc].n_operation));
+        Stream.Write(b.accounts[iacc].previous_updated_block,Sizeof(b.accounts[iacc].previous_updated_block));
+      end;
+      Stream.Write(b.timestamp,Sizeof(b.timestamp));
+      TStreamOp.WriteAnsiString(Stream,b.block_hash);
+      Stream.Write(b.target,Sizeof(b.target));
     end;
-    Stream.Write(b.timestamp,Sizeof(b.timestamp));
-    TStreamOp.WriteAnsiString(Stream,b.block_hash);
-    Stream.Write(b.target,Sizeof(b.target));
+    // New Build 1.3.0
+    TStreamOp.WriteAnsiString(Stream,FPreviousBlockSafeBoxHash);
+  Finally
+    EndThreadSave;
   end;
 end;
 
@@ -991,12 +1025,7 @@ end;
 
 procedure TPCSafeBox.StartThreadSafe;
 begin
-  if FIsLocked then Begin
-    TLog.NewLog(lterror,Classname,'IS LOCKED !!!');
-    raise Exception.Create('IS LOCKED !!!');
-  end;
   TPCThread.ProtectEnterCriticalSection(Self,FLock);
-  FIsLocked := true;
 end;
 
 { TPCSafeBoxTransaction }

+ 31 - 18
Units/PascalCoin/UBlockChain.pas

@@ -620,7 +620,7 @@ begin
           Clear;
         end;
       end;
-      NewLog(Nil, ltinfo,'Start restoring from disk operations (Max '+inttostr(max_block)+') Orphan: ' +Storage.Orphan);
+      NewLog(Nil, ltinfo,'Start restoring from disk operations (Max '+inttostr(max_block)+') BlockCount: '+inttostr(BlocksCount)+' Orphan: ' +Storage.Orphan);
       Operations := TPCOperationsComp.Create(Self);
       try
         while ((BlocksCount<=max_block)) do begin
@@ -804,6 +804,16 @@ begin
       finally
         op.Free;
       end;
+      if (SafeBox.PreviousBlockSafeBoxHash<>'') then begin
+        if FLastOperationBlock.initial_safe_box_hash<>SafeBox.PreviousBlockSafeBoxHash then begin
+          errors := 'SafeBox Previous block safeboxhash <> operation safeboxhash. Invalid bank!';
+          TLog.NewLog(lterror,ClassName,'Previous SafeBoxHash <> Last operation block safebox hash on block '+
+            IntToStr(BlocksCount-1)+' '+TCrypto.ToHexaString(SafeBox.PreviousBlockSafeBoxHash)+'<>'+TCrypto.ToHexaString(FLastOperationBlock.initial_safe_box_hash));
+          Result := false;
+          Clear;
+          exit;
+        end;
+      end;
       FInitialSafeBoxHash := SafeBox.CalcSafeBoxHash;
       if (BlocksCount>0) then FActualTargetHash := TargetFromCompact( FLastOperationBlock.compact_target );
       // Initialize new target hash:
@@ -1782,8 +1792,6 @@ begin
   l := FHashTreeOperations.LockList;
   try
     InternalAddOperationToHashTree(l,op);
-    inc(FTotalAmount,op.OperationAmount);
-    inc(FTotalFee,op.OperationFee);
   finally
     FHashTreeOperations.UnlockList;
   end;
@@ -1822,15 +1830,18 @@ begin
   end;
   ClearHastThree;
   lme := FHashTreeOperations.LockList;
-  lsender := Sender.FHashTreeOperations.LockList;
   try
-    for i := 0 to lsender.Count - 1 do begin
-      opsender := lsender[i];
-      InternalAddOperationToHashTree(lme,opsender);
+    lsender := Sender.FHashTreeOperations.LockList;
+    try
+      for i := 0 to lsender.Count - 1 do begin
+        opsender := lsender[i];
+        InternalAddOperationToHashTree(lme,opsender);
+      end;
+    finally
+      Sender.FHashTreeOperations.UnlockList;
     end;
   finally
     FHashTreeOperations.UnlockList;
-    Sender.FHashTreeOperations.UnlockList;
   end;
 end;
 
@@ -1892,20 +1903,22 @@ Var ms : TMemoryStream;
 begin
   ms := TMemoryStream.Create;
   try
-      newOp := TPCOperation( op.NewInstance );
-      op.SaveToStream(ms);
-      ms.Position := 0;
-      newOp.LoadFromStream(ms);
-      newOp.FPrevious_Sender_updated_block := op.Previous_Sender_updated_block;
-      newOp.FPrevious_Destination_updated_block := op.FPrevious_Destination_updated_block;
-      h := TCrypto.DoSha256(ms.Memory,ms.Size);
-      newOp.tag := list.Count;
-      list.Add(newOp);
+    newOp := TPCOperation( op.NewInstance );
+    op.SaveToStream(ms);
+    ms.Position := 0;
+    newOp.LoadFromStream(ms);
+    newOp.FPrevious_Sender_updated_block := op.Previous_Sender_updated_block;
+    newOp.FPrevious_Destination_updated_block := op.FPrevious_Destination_updated_block;
+    h := TCrypto.DoSha256(ms.Memory,ms.Size);
+    newOp.tag := list.Count;
+    list.Add(newOp);
   finally
-      ms.Free;
+    ms.Free;
   end;
   // Include to hash tree
   FHashTree := TCrypto.DoSha256(FHashTree+h);
+  inc(FTotalAmount,op.OperationAmount);
+  inc(FTotalFee,op.OperationFee);
 end;
 
 function TOperationsHashTree.OperationsCount: Integer;

+ 2 - 2
Units/PascalCoin/UConst.pas

@@ -80,7 +80,7 @@ Const
 
   CT_MaxClientsConnected = 100;
 
-  CT_BankToDiskEveryNBlocks = 1000;
+  CT_BankToDiskEveryNBlocks = 500; // Build 1.3.0 Changed from 1000 to 500
 
   CT_Default_EC_OpenSSL_NID = NID_secp256k1;
 
@@ -104,7 +104,7 @@ Const
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
 
-  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.2.0'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.3.0'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.ddns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
 

+ 25 - 7
Units/PascalCoin/UFileStorage.pas

@@ -69,7 +69,7 @@ Type
 
 implementation
 
-Uses ULog, SysUtils, UThread;
+Uses ULog, SysUtils, UThread, UConst;
 
 { TFileStorage }
 
@@ -255,6 +255,7 @@ var
     folder : AnsiString;
     filename,auxfn : AnsiString;
     fs : TFileStream;
+    ms : TMemoryStream;
     errors : AnsiString;
     blockscount, c : Cardinal;
 begin
@@ -281,9 +282,17 @@ begin
     if (filename<>'') then begin
       fs := TFileStream.Create(filename,fmOpenRead);
       try
-        if not Bank.LoadBankFromStream(fs,errors) then begin
-          TLog.NewLog(lterror,ClassName,'Error reading bank from file: '+filename+ ' Error: '+errors);
-        end;
+        ms := TMemoryStream.Create;
+        Try
+          ms.CopyFrom(fs,0);
+          fs.Position := 0;
+          ms.Position := 0;
+          if not Bank.LoadBankFromStream(ms,errors) then begin
+            TLog.NewLog(lterror,ClassName,'Error reading bank from file: '+filename+ ' Error: '+errors);
+          end;
+        Finally
+          ms.Free;
+        End;
       finally
         fs.Free;
       end;
@@ -296,6 +305,7 @@ end;
 function TFileStorage.DoSaveBank: Boolean;
 var fs: TFileStream;
     bankfilename: AnsiString;
+    ms : TMemoryStream;
 begin
   Result := true;
   bankfilename := GetBankFileName(GetFolder(Orphan),Bank.BlocksCount);
@@ -303,7 +313,15 @@ begin
     fs := TFileStream.Create(bankfilename,fmCreate);
     try
       fs.Size := 0;
-      Bank.SaveBankToStream(fs);
+      ms := TMemoryStream.Create;
+      try
+        Bank.SaveBankToStream(ms);
+        ms.Position := 0;
+        fs.Position := 0;
+        fs.CopyFrom(ms,0);
+      finally
+        ms.Free;
+      end;
     finally
       fs.Free;
     end;
@@ -341,7 +359,7 @@ begin
   Result := '';
   If not ForceDirectories(BaseDataFolder) then exit;
   // We will store last 5 banks
-  Result := BaseDataFolder + PathDelim+'bank'+ inttostr(block MOD 5)+'.bank';
+  Result := BaseDataFolder + PathDelim+'bank'+ inttostr((block DIV CT_BankToDiskEveryNBlocks) MOD 5)+'.bank';
 end;
 
 function TFileStorage.GetBlockHeaderFirstBytePosition(Stream : TStream; Block: Cardinal; var StreamBlockHeaderStartPos: Int64; var BlockHeaderFirstBlock: Cardinal): Boolean;
@@ -579,7 +597,7 @@ begin
   if (BlockHeaderFirstBlock>Block) then raise Exception.Create('Dev error 20160917-1');
   if (BlockHeaderFirstBlock+CT_GroupBlockSize)<Block then raise Exception.Create('Dev error 20160917-2');
   if Stream.Size< (StreamBlockHeaderStartPos + (GetBlockHeaderFixedSize)) then begin
-    TLog.NewLog(ltError,Classname,'Invalid stream size');
+    // Not log... it's normal when finding block   TLog.NewLog(ltError,Classname,Format('Invalid stream size %d < (%d + %d) Reading block %d',[Stream.Size,StreamBlockHeaderStartPos,GetBlockHeaderFixedSize,Block]));
     exit;
   end;
   Stream.Position := StreamBlockHeaderStartPos + (CT_SizeOfBlockHeader*(Block-BlockHeaderFirstBlock));

+ 51 - 49
Units/PascalCoin/UNetProtocol.pas

@@ -1634,7 +1634,8 @@ begin
       ms.Free;
     end;
     If ((FLastDataReceivedTS>0) Or ( NOT (Self is TNetServerClient)))
-       AND ((FLastDataReceivedTS+(1000*60)<GetTickCount) AND (FLastDataSendedTS+(1000*60)<GetTickCount)) then begin
+       AND ((FLastDataReceivedTS+(1000*120)<GetTickCount) AND (FLastDataSendedTS+(1000*120)<GetTickCount)) then begin
+       // Build 1.3 -> Changing wait time from 60 to 120 secs.
       DebugStep := 'LastSend time old';
       If TNetData.NetData.PendingRequest(Self,ops)>=2 then begin
         TLog.NewLog(ltDebug,Classname,'Pending requests without response... closing connection to '+ClientRemoteAddr+' > '+ops);
@@ -2801,61 +2802,62 @@ begin
       netserverclientstop := Nil;
       needother := true;
       FLastCheckTS := GetTickCount;
-      l := FNetData.FNetConnections.LockList;
-      try
-        ntotal := l.Count;
-        newstats := CT_TNetStatistics_NUL;
-        for i := l.Count-1 downto 0 do begin
-          netconn := TNetConnection(l.Items[i]);
-          if (netconn is TNetClient) then begin
-            if (netconn.Connected) then begin
-              inc(newstats.ServersConnections);
-              if (netconn.FHasReceivedData) then inc(newstats.ServersConnectionsWithResponse);
-            end;
-            if (Not TNetClient(netconn).Connected) And (netconn.CreatedTime+EncodeTime(0,0,5,0)<now) then begin
-              // Free this!
-              TNetClient(netconn).FinalizeConnection;
-              inc(ndeleted);
-            end else inc(nactive);
-          end else if (netconn is TNetServerClient) then begin
-            if (netconn.Connected) then begin
-              inc(newstats.ClientsConnections);
-            end;
-            inc(nserverclients);
-            if (Not netconn.FDoFinalizeConnection) then begin
-              // Build 1.0.9 BUG-101 Only disconnect old versions prior to 1.0.9
-              if not assigned(netserverclientstop) then begin
-                netserverclientstop := TNetServerClient(netconn);
-                aux := Copy(netconn.FClientAppVersion,1,5);
-                needother := Not ((aux='1.0.6') or (aux='1.0.7') or (aux='1.0.8'));
-              end else begin
-                aux := Copy(netconn.FClientAppVersion,1,5);
-                if ((aux='1.0.6') or (aux='1.0.7') or (aux='1.0.8'))
-                  And ((needother) Or (netconn.CreatedTime<netserverclientstop.CreatedTime)) then begin
-                  needother := false;
+      If (FNetData.FNetConnections.TryLockList(100,l)) then begin
+        try
+          ntotal := l.Count;
+          newstats := CT_TNetStatistics_NUL;
+          for i := l.Count-1 downto 0 do begin
+            netconn := TNetConnection(l.Items[i]);
+            if (netconn is TNetClient) then begin
+              if (netconn.Connected) then begin
+                inc(newstats.ServersConnections);
+                if (netconn.FHasReceivedData) then inc(newstats.ServersConnectionsWithResponse);
+              end;
+              if (Not TNetClient(netconn).Connected) And (netconn.CreatedTime+EncodeTime(0,0,5,0)<now) then begin
+                // Free this!
+                TNetClient(netconn).FinalizeConnection;
+                inc(ndeleted);
+              end else inc(nactive);
+            end else if (netconn is TNetServerClient) then begin
+              if (netconn.Connected) then begin
+                inc(newstats.ClientsConnections);
+              end;
+              inc(nserverclients);
+              if (Not netconn.FDoFinalizeConnection) then begin
+                // Build 1.0.9 BUG-101 Only disconnect old versions prior to 1.0.9
+                if not assigned(netserverclientstop) then begin
                   netserverclientstop := TNetServerClient(netconn);
+                  aux := Copy(netconn.FClientAppVersion,1,5);
+                  needother := Not ((aux='1.0.6') or (aux='1.0.7') or (aux='1.0.8'));
+                end else begin
+                  aux := Copy(netconn.FClientAppVersion,1,5);
+                  if ((aux='1.0.6') or (aux='1.0.7') or (aux='1.0.8'))
+                    And ((needother) Or (netconn.CreatedTime<netserverclientstop.CreatedTime)) then begin
+                    needother := false;
+                    netserverclientstop := TNetServerClient(netconn);
+                  end;
                 end;
               end;
             end;
           end;
+          // Update stats:
+          FNetData.FNetStatistics.ActiveConnections := newstats.ClientsConnections + newstats.ServersConnections;
+          FNetData.FNetStatistics.ClientsConnections := newstats.ClientsConnections;
+          FNetData.FNetStatistics.ServersConnections := newstats.ServersConnections;
+          FNetData.FNetStatistics.ServersConnectionsWithResponse := newstats.ServersConnectionsWithResponse;
+          // Must stop clients?
+          if (nserverclients>CT_MaxServersConnected) And // This is to ensure there are more serverclients than clients
+             ((nserverclients + nactive + ndeleted)>=CT_MaxClientsConnected) And (Assigned(netserverclientstop)) then begin
+            TLog.NewLog(ltinfo,Classname,Format('Sending FinalizeConnection NetServerClients:%d Servers_active:%d Servers_deleted:%d',[nserverclients,nactive,ndeleted]));
+            netserverclientstop.FinalizeConnection;
+          end;
+        finally
+          FNetData.FNetConnections.UnlockList;
         end;
-        // Update stats:
-        FNetData.FNetStatistics.ActiveConnections := newstats.ClientsConnections + newstats.ServersConnections;
-        FNetData.FNetStatistics.ClientsConnections := newstats.ClientsConnections;
-        FNetData.FNetStatistics.ServersConnections := newstats.ServersConnections;
-        FNetData.FNetStatistics.ServersConnectionsWithResponse := newstats.ServersConnectionsWithResponse;
-        // Must stop clients?
-        if (nserverclients>CT_MaxServersConnected) And // This is to ensure there are more serverclients than clients
-           ((nserverclients + nactive + ndeleted)>=CT_MaxClientsConnected) And (Assigned(netserverclientstop)) then begin
-          TLog.NewLog(ltinfo,Classname,Format('Sending FinalizeConnection NetServerClients:%d Servers_active:%d Servers_deleted:%d',[nserverclients,nactive,ndeleted]));
-          netserverclientstop.FinalizeConnection;
+        if (nactive<=CT_MaxServersConnected) And (Not Terminated) then begin
+          // Discover
+          FNetData.DiscoverServers;
         end;
-      finally
-        FNetData.FNetConnections.UnlockList;
-      end;
-      if (nactive<=CT_MaxServersConnected) And (Not Terminated) then begin
-        // Discover
-        FNetData.DiscoverServers;
       end;
     end;
     sleep(100);

+ 5 - 3
Units/PascalCoin/UNode.pas

@@ -78,7 +78,7 @@ Type
     //
     Procedure NotifyBlocksChanged;
     //
-    procedure GetStoredOperationsFromAccount(const OperationsResume: TOperationsResumeList; account_number: Cardinal; MaxDeep : Integer);
+    procedure GetStoredOperationsFromAccount(const OperationsResume: TOperationsResumeList; account_number: Cardinal; MaxDeep, MaxOperations : Integer);
     Function FindOperation(Const OperationComp : TPCOperationsComp; Const OperationHash : TRawBytes; var block : Cardinal; var operation_block_index : Integer) : Boolean;
     //
     Procedure AutoDiscoverNodes(Const ips : AnsiString);
@@ -631,7 +631,7 @@ begin
   end;
 end;
 
-procedure TNode.GetStoredOperationsFromAccount(const OperationsResume: TOperationsResumeList; account_number: Cardinal; MaxDeep: Integer);
+procedure TNode.GetStoredOperationsFromAccount(const OperationsResume: TOperationsResumeList; account_number: Cardinal; MaxDeep, MaxOperations: Integer);
   Procedure DoGetFromBlock(block_number : Cardinal; last_balance : Int64; act_deep : Integer);
   var opc : TPCOperationsComp;
     op : TPCOperation;
@@ -683,7 +683,9 @@ procedure TNode.GetStoredOperationsFromAccount(const OperationsResume: TOperatio
         //
         opc.Clear(true);
         if (next_block_number>=0) And (next_block_number<block_number) And (act_deep>0)
-           And (next_block_number >= (account_number DIV CT_AccountsPerBlock)) then DoGetFromBlock(next_block_number,last_balance,act_deep-1);
+           And (next_block_number >= (account_number DIV CT_AccountsPerBlock))
+           And ((OperationsResume.Count<MaxOperations) Or (MaxOperations<=0))
+           then DoGetFromBlock(next_block_number,last_balance,act_deep-1);
       finally
         l.Free;
       end;

+ 303 - 52
Units/PascalCoin/URPC.pas

@@ -405,7 +405,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     jsonObject.GetAsVariant('ophash').Value := TCrypto.ToHexaString(OPR.OperationHash);
   end;
 
-  Function GetAccountOperations(AccountNumber : Cardinal; jsonArray : TPCJSONArray; MaxBlocksDeep : Integer) : Boolean;
+  Function GetAccountOperations(AccountNumber : Cardinal; jsonArray : TPCJSONArray; MaxBlocksDeep,start,max : Integer) : Boolean;
   var list : TList;
     Op : TPCOperation;
     OPR : TOperationResume;
@@ -430,12 +430,17 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       Finally
         list.Free;
       End;
-      TNode.Node.GetStoredOperationsFromAccount(OperationsResume,AccountNumber,MaxBlocksDeep);
+      if ((max<=0) Or (OperationsResume.Count<(max+start))) then begin
+        TNode.Node.GetStoredOperationsFromAccount(OperationsResume,AccountNumber,MaxBlocksDeep,max+start);
+      end;
       //
       for i:=0 to OperationsResume.Count-1 do begin
-        Obj := jsonArray.GetAsObject(i);
-        OPR := OperationsResume[i];
-        FillOperationResumeToJSONObject(OPR,Obj);
+        if (i>=start) then begin
+          Obj := jsonArray.GetAsObject(jsonArray.Count);
+          OPR := OperationsResume[i];
+          FillOperationResumeToJSONObject(OPR,Obj);
+          if ((max>0) And (jsonArray.Count>=max)) then break; // stop
+        end;
       end;
       Result := True;
     finally
@@ -602,6 +607,139 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     end;
   end;
 
+  Function GetCardinalsValues(ordinals_coma_separated : String; cardinals : TOrderedCardinalList; var errors : AnsiString) : Boolean;
+  Var i,istart : Integer;
+    ctxt : String;
+    an : Cardinal;
+  begin
+    result := false;
+    cardinals.Clear;
+    errors := '';
+    ctxt := '';
+    istart := 1;
+    for i := 1 to length(ordinals_coma_separated) do begin
+      case ordinals_coma_separated[i] of
+        '0'..'9','-' : ctxt := ctxt + ordinals_coma_separated[i];
+        ',',';' : begin
+          if trim(ctxt)<>'' then begin
+            if Not TAccountComp.AccountTxtNumberToAccountNumber(trim(ctxt),an) then begin
+              errors := 'Invalid account number at pos '+IntToStr(istart)+': '+ctxt;
+              exit;
+            end;
+            cardinals.Add(an);
+          end;
+          ctxt := '';
+          istart := i+1;
+        end;
+        ' ' : ; // Continue...
+      else
+        errors := 'Invalid char at pos '+inttostr(i)+': "'+ordinals_coma_separated[i]+'"';
+        exit;
+      end;
+    end;
+    //
+    if (trim(ctxt)<>'') then begin
+      if Not TAccountComp.AccountTxtNumberToAccountNumber(trim(ctxt),an) then begin
+        errors := 'Invalid account number at pos '+IntToStr(istart)+': '+ctxt;
+        exit;
+      end;
+      cardinals.Add(an);
+    end;
+    if cardinals.Count=0 then begin
+      errors := 'No valid value';
+      exit;
+    end;
+    Result := true;
+  end;
+
+  Function ChangeAccountsKey(accounts_txt : String; new_pub_key : TAccountKey; fee : UInt64; RawPayload : TRawBytes; Const Payload_method, EncodePwd : AnsiString) : Boolean;
+  // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+  Var opck : TOpChangeKey;
+    acc : TAccount;
+    i,ian : Integer;
+    errors : AnsiString;
+    opr : TOperationResume;
+    f_raw : TRawBytes;
+    accountsnumber : TOrderedCardinalList;
+    operationsht : TOperationsHashTree;
+  begin
+    Result := false;
+    accountsnumber := TOrderedCardinalList.Create;
+    try
+      if not GetCardinalsValues(accounts_txt,accountsnumber,errors) then begin
+        ErrorDesc := 'Error in accounts: '+errors;
+        ErrorNum := CT_RPC_ErrNum_InvalidAccount;
+        Exit;
+      end;
+      operationsht := TOperationsHashTree.Create;
+      try
+        for ian := 0 to accountsnumber.Count - 1 do begin
+
+          if (accountsnumber.Get(ian)<0) or (accountsnumber.Get(ian)>=TNode.Node.Bank.AccountsCount) then begin
+            ErrorDesc:='Invalid account '+Inttostr(accountsnumber.Get(ian));
+            ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
+            Exit;
+          end;
+          acc := TNode.Node.Operations.SafeBoxTransaction.Account(accountsnumber.Get(ian));
+          _RPCServer.FWalletKeys.AccountsKeyList.IndexOfAccountKey(acc.accountkey);
+          i := _RPCServer.FWalletKeys.IndexOfAccountKey(acc.accountkey);
+          if (i<0) then begin
+            ErrorDesc:='Private key of account '+Inttostr(acc.account)+' not found in wallet';
+            ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
+            Exit;
+          end;
+          if (Not assigned(_RPCServer.FWalletKeys.Key[i].PrivateKey)) then begin
+            if _RPCServer.FWalletKeys.Key[i].CryptedKey<>'' then begin
+              // Wallet is password protected
+              ErrorDesc := 'Wallet is password protected for account '+IntToStr(acc.account);
+              ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+            end else begin
+              ErrorDesc := 'Wallet private key not found in Wallet for account '+IntToStr(acc.account);
+              ErrorNum := CT_RPC_ErrNum_InvalidAccount;
+            end;
+            exit;
+          end;
+          if (length(RawPayload)>0) then begin
+            if (Payload_method='none') then f_raw:=RawPayload
+            else if (Payload_method='dest') then begin
+              f_raw := ECIESEncrypt(new_pub_key,RawPayload);
+            end else if (Payload_method='sender') then begin
+              f_raw := ECIESEncrypt(acc.accountkey,RawPayload);
+            end else if (Payload_method='aes') then begin
+              f_raw := TAESComp.EVP_Encrypt_AES256(RawPayload,EncodePwd);
+            end else begin
+              ErrorNum:=CT_RPC_ErrNum_InvalidOperation;
+              ErrorDesc:='Invalid encode payload method: '+Payload_method;
+              exit;
+            end;
+          end else f_raw := '';
+          opck := TOpChangeKey.Create(acc.account,acc.n_operation+1,_RPCServer.FWalletKeys.Key[i].PrivateKey,new_pub_key,fee,f_raw);
+          try
+            operationsht.AddOperationToHashTree(opck);
+          finally
+            opck.free;
+          end;
+        end; // For
+        // Ready to execute...
+        i := TNode.Node.AddOperations(Nil,operationsht,errors);
+        if (i<0) then begin
+          ErrorNum:=CT_RPC_ErrNum_InternalError;
+          ErrorDesc:=errors;
+          exit;
+        end;
+        GetResultObject.GetAsVariant('accounts_total').Value := operationsht.OperationsCount;
+        GetResultObject.GetAsVariant('accounts_ok').Value := i;
+        GetResultObject.GetAsVariant('accounts_error').Value := operationsht.OperationsCount - i;
+        GetResultObject.GetAsVariant('errors').Value := errors;
+        Result := true;
+      finally
+        operationsht.Free;
+      end;
+    finally
+      accountsnumber.Free;
+    end;
+  end;
+
   Procedure FillAccountObject(Const account : TAccount; jsonObj : TPCJSONObject);
   Begin
     jsonObj.GetAsVariant('account').Value:=account.account;
@@ -611,6 +749,15 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     jsonObj.GetAsVariant('updated_b').Value:=account.updated_block;
   end;
 
+  Procedure FillPublicKeyObject(const PubKey : TAccountKey; jsonObj : TPCJSONObject);
+  Begin
+    jsonObj.GetAsVariant('ec_nid').Value := PubKey.EC_OpenSSL_NID;
+    jsonObj.GetAsVariant('x').Value := TCrypto.ToHexaString(PubKey.x);
+    jsonObj.GetAsVariant('y').Value := TCrypto.ToHexaString(PubKey.y);
+    jsonObj.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(PubKey));
+    jsonObj.GetAsVariant('b58_pubkey').Value := TAccountComp.AccountPublicKeyExport(PubKey);
+  End;
+
   Function DoEncrypt(RawPayload : TRawBytes; pub_key : TAccountKey; Const Payload_method, EncodePwd : AnsiString) : Boolean;
   Var f_raw : TRawBytes;
   begin
@@ -677,8 +824,39 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     Result := true;
   End;
 
+  Function CapturePubKey(const prefix : String; var pubkey : TAccountKey; var errortxt : String) : Boolean;
+  var ansistr : AnsiString;
+    auxpubkey : TAccountKey;
+  begin
+    pubkey := CT_Account_NUL.accountkey;
+    errortxt := '';
+    Result := false;
+    if (params.IndexOfName(prefix+'b58_pubkey')>=0) then begin
+      If Not TAccountComp.AccountPublicKeyImport(params.AsString(prefix+'b58_pubkey',''),pubkey,ansistr) then begin
+        errortxt:= 'Invalid value of param "'+prefix+'b58_pubkey": '+ansistr;
+        exit;
+      end;
+      if (params.IndexOfName(prefix+'enc_pubkey')>=0) then begin
+        auxpubkey := TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(params.AsString(prefix+'enc_pubkey','')));
+        if (Not TAccountComp.Equal(auxpubkey,pubkey)) then begin
+          errortxt := 'Params "'+prefix+'b58_pubkey" and "'+prefix+'enc_pubkey" public keys are not the same public key';
+          exit;
+        end;
+      end;
+    end else begin
+      if (params.IndexOfName(prefix+'enc_pubkey')<0) then begin
+        errortxt := 'Need param "'+prefix+'enc_pubkey" or "'+prefix+'b58_pubkey"';
+        exit;
+      end;
+      pubkey := TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(params.AsString(prefix+'enc_pubkey','')));
+    end;
+    If Not TAccountComp.IsValidAccountKey(pubkey,ansistr) then begin
+      errortxt := 'Invalid public key: '+ansistr;
+    end else Result := true;
+  end;
+
 Var c,c2 : Cardinal;
-  i,j : Integer;
+  i,j,k,l : Integer;
   account : TAccount;
   ansistr : AnsiString;
   nsaarr : TNodeServerAddressArray;
@@ -720,12 +898,9 @@ begin
   end else if (method='getwalletaccounts') then begin
     // Returns JSON array with accounts in Wallet
     jsonarr := jsonresponse.GetAsArray('result');
-    if (params.IndexOfName('enc_pubkey')>=0) then begin
-      r := TCrypto.HexaToRaw(params.AsString('enc_pubkey',''));
-      opr.newKey := TAccountComp.RawString2Accountkey(r);
-      if Not TAccountComp.IsValidAccountKey(opr.newKey,ansistr) then begin
+    if (params.IndexOfName('enc_pubkey')>=0) Or (params.IndexOfName('b58_pubkey')>=0) then begin
+      if Not (CapturePubKey('',opr.newKey,ErrorDesc)) then begin
         ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
-        ErrorDesc := 'Invalid public key in param enc_pubkey: '+ansistr;
         exit;
       end;
       i := _RPCServer.WalletKeys.AccountsKeyList.IndexOfAccountKey(opr.newKey);
@@ -735,30 +910,40 @@ begin
         exit;
       end;
       ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
+      k := params.AsInteger('max',100);
+      l := params.AsInteger('start',0);
       for j := 0 to ocl.Count - 1 do begin
-        account := TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j));
-        FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+        if (j>=l) then begin
+          account := TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j));
+          FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+        end;
+        if (k>0) And ((j+1)>=(k+l)) then break;
       end;
       Result := true;
     end else begin
+      k := params.AsInteger('max',100);
+      l := params.AsInteger('start',0);
+      c := 0;
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
         ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
         for j := 0 to ocl.Count - 1 do begin
-          account := TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j));
-          FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+          if (c>=l) then begin
+            account := TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j));
+            FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+          end;
+          inc(c);
+          if (k>0) And (c>=(k+l)) then break;
         end;
+        if (k>0) And (c>=(k+l)) then break;
       end;
       Result := true;
     end;
   end else if (method='getwalletaccountscount') then begin
     // New Build 1.1.1
     // Returns a number with count value
-    if (params.IndexOfName('enc_pubkey')>=0) then begin
-      r := TCrypto.HexaToRaw(params.AsString('enc_pubkey',''));
-      opr.newKey := TAccountComp.RawString2Accountkey(r);
-      if Not TAccountComp.IsValidAccountKey(opr.newKey,ansistr) then begin
+    if (params.IndexOfName('enc_pubkey')>=0) Or (params.IndexOfName('b58_pubkey')>=0) then begin
+      if Not (CapturePubKey('',opr.newKey,ErrorDesc)) then begin
         ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
-        ErrorDesc := 'Invalid public key in param enc_pubkey: '+ansistr;
         exit;
       end;
       i := _RPCServer.WalletKeys.AccountsKeyList.IndexOfAccountKey(opr.newKey);
@@ -771,6 +956,7 @@ begin
       jsonresponse.GetAsVariant('result').value := ocl.count;
       Result := true;
     end else begin
+      ErrorDesc := '';
       c :=0;
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
         ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
@@ -780,12 +966,9 @@ begin
       Result := true;
     end;
   end else if (method='getwalletcoins') then begin
-    if (params.IndexOfName('enc_pubkey')>=0) then begin
-      r := TCrypto.HexaToRaw(params.AsString('enc_pubkey',''));
-      opr.newKey := TAccountComp.RawString2Accountkey(r);
-      if Not TAccountComp.IsValidAccountKey(opr.newKey,ansistr) then begin
+    if (params.IndexOfName('enc_pubkey')>=0) Or (params.IndexOfName('b58_pubkey')>=0) then begin
+      if Not (CapturePubKey('',opr.newKey,ErrorDesc)) then begin
         ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
-        ErrorDesc := 'Invalid public key in param enc_pubkey: '+ansistr;
         exit;
       end;
       i := _RPCServer.WalletKeys.AccountsKeyList.IndexOfAccountKey(opr.newKey);
@@ -802,6 +985,7 @@ begin
       jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
       Result := true;
     end else begin
+      ErrorDesc := '';
       c :=0;
       account.balance := 0;
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
@@ -815,13 +999,32 @@ begin
     end;
   end else if (method='getwalletpubkeys') then begin
     // Returns JSON array with pubkeys in wallet
+    k := params.AsInteger('max',100);
+    j := params.AsInteger('start',0);
     jsonarr := jsonresponse.GetAsArray('result');
     for i:=0 to _RPCServer.WalletKeys.Count-1 do begin
-      jsonarr.GetAsObject(i).GetAsVariant('name').Value := _RPCServer.WalletKeys.Key[i].Name;
-      jsonarr.GetAsObject(i).GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(_RPCServer.WalletKeys.Key[i].AccountKey));
-      jsonarr.GetAsObject(i).GetAsVariant('can_use').Value := (_RPCServer.WalletKeys.Key[i].CryptedKey<>'');
+      if (i>=j) then begin
+        jso := jsonarr.GetAsObject(jsonarr.count);
+        jso.GetAsVariant('name').Value := _RPCServer.WalletKeys.Key[i].Name;
+        jso.GetAsVariant('can_use').Value := (_RPCServer.WalletKeys.Key[i].CryptedKey<>'');
+        FillPublicKeyObject(_RPCServer.WalletKeys.Key[i].AccountKey,jso);
+      end;
+      if (k>0) And ((i+1)>=(j+k)) then break;
     end;
     Result := true;
+  end else if (method='getwalletpubkey') then begin
+    if Not (CapturePubKey('',opr.newKey,ErrorDesc)) then begin
+      ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+      exit;
+    end;
+    i := _RPCServer.WalletKeys.AccountsKeyList.IndexOfAccountKey(opr.newKey);
+    if (i<0) then begin
+      ErrorNum := CT_RPC_ErrNum_NotFound;
+      ErrorDesc := 'Public key not found in wallet';
+      exit;
+    end;
+    FillPublicKeyObject(_RPCServer.WalletKeys.AccountsKeyList.AccountKey[i],GetResultObject);
+    Result := true;
   end else if (method='getblock') then begin
     // Param "block" contains block number (0..getblockcount-1)
     // Returns JSON object with block information
@@ -911,14 +1114,19 @@ begin
           ErrorDesc := 'Cannot load Block: '+IntToStr(c);
           Exit;
         end;
-        GetResultArray;
-        for i := pcops.Count - 1 downto 0 do begin
-          If TPCOperation.OperationToOperationResume(c,pcops.Operation[i],pcops.Operation[i].SenderAccount,opr) then begin
-            opr.NOpInsideBlock:=i;
-            opr.time:=pcops.OperationBlock.timestamp;
-            opr.Balance := -1; // Don't include!
-            FillOperationResumeToJSONObject(opr,GetResultArray.GetAsObject(pcops.Count - 1 - i));
+        jsonarr := GetResultArray;
+        k := params.AsInteger('max',100);
+        j := params.AsInteger('start',0);
+        for i := 0 to pcops.Count - 1 do begin
+          if (i>=j) then begin
+            If TPCOperation.OperationToOperationResume(c,pcops.Operation[i],pcops.Operation[i].SenderAccount,opr) then begin
+              opr.NOpInsideBlock:=i;
+              opr.time:=pcops.OperationBlock.timestamp;
+              opr.Balance := -1; // Don't include!
+              FillOperationResumeToJSONObject(opr,jsonarr.GetAsObject(jsonarr.Count));
+            end;
           end;
+          if (k>0) And ((i+1)>=(j+k)) then break;
         end;
         Result := True;
       finally
@@ -933,9 +1141,10 @@ begin
     // Returns all the operations affecting an account in "Operation resume format" as an array
     // Param "account" contains account number
     // Param "deep" (optional) contains max blocks deep to search (Default: 100)
+    // Param "start" and "max" contains starting index and max operations respectively
     c := params.GetAsVariant('account').AsCardinal(CT_MaxAccount);
     if ((c>=0) And (c<TNode.Node.Bank.AccountsCount)) then begin
-      Result := GetAccountOperations(c,GetResultArray,params.AsInteger('deep',100));
+      Result := GetAccountOperations(c,GetResultArray,params.AsInteger('deep',100),params.AsInteger('start',0),params.AsInteger('max',100));
     end else begin
       ErrorNum := CT_RPC_ErrNum_InvalidAccount;
       If (c=CT_MaxAccount) then ErrorDesc := 'Need account param'
@@ -1000,7 +1209,7 @@ begin
        TCrypto.HexaToRaw(params.AsString('payload','')),
        params.AsString('payload_method','dest'),params.AsString('pwd',''));
   end else if (method='changekey') then begin
-    // Change key of "account" to "new_enc_pubkey" (encoded public key format) with "fee"
+    // Change key of "account" to "new_enc_pubkey" or "new_b58_pubkey" (encoded public key format) with "fee"
     // If "payload" is present, it will be encoded using "payload_method"
     // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
     // Returns a JSON "Operation Resume format" object when successfull
@@ -1010,8 +1219,42 @@ begin
       ErrorDesc := 'Wallet is password protected. Unlock first';
       exit;
     end;
+    if params.IndexOfName('account')<0 then begin
+      ErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      ErrorDesc := 'Need "account" param';
+      exit;
+    end;
+    If Not CapturePubKey('new_',account.accountkey,ErrorDesc) then begin
+      ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+      exit;
+    end;
     Result := ChangeAccountKey(params.AsCardinal('account',CT_MaxAccount),
-       TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(params.AsString('new_enc_pubkey',''))),
+       account.accountkey,
+       ToPascalCoins(params.AsDouble('fee',0)),
+       TCrypto.HexaToRaw(params.AsString('payload','')),
+       params.AsString('payload_method','dest'),params.AsString('pwd',''));
+  end else if (method='changekeys') then begin
+    // Allows a massive change key operation
+    // Change key of "accounts" to "new_enc_pubkey" or "new_b58_pubkey" (encoded public key format) with "fee"
+    // If "payload" is present, it will be encoded using "payload_method"
+    // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+    // Returns a JSON object with result information
+    If Not _RPCServer.WalletKeys.IsValidPassword then begin
+      ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+      ErrorDesc := 'Wallet is password protected. Unlock first';
+      exit;
+    end;
+    if params.IndexOfName('accounts')<0 then begin
+      ErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      ErrorDesc := 'Need "accounts" param';
+      exit;
+    end;
+    If Not CapturePubKey('new_',account.accountkey,ErrorDesc) then begin
+      ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+      exit;
+    end;
+    Result := ChangeAccountsKey(params.AsString('accounts',''),
+       account.accountkey,
        ToPascalCoins(params.AsDouble('fee',0)),
        TCrypto.HexaToRaw(params.AsString('payload','')),
        params.AsString('payload_method','dest'),params.AsString('pwd',''));
@@ -1084,18 +1327,16 @@ begin
     end;
   end else if (method='decodepubkey') then begin
     // Returns "ec_nid", "x" and "y" of an encoded public key (x and y in hexadecimal)
-    // Param "enc_pubkey" is an hexadecimal encoded address (see 'encodepubkey')
-    if (params.AsString('enc_pubkey','')='') then begin
-      ErrorDesc:= 'Need param "enc_pubkey"';
-      ErrorNum:= CT_RPC_ErrNum_InvalidPubKey;
+    // Must provide:
+    // - Param "enc_pubkey" is an hexadecimal encoded public key (see 'encodepubkey')
+    // or
+    // - Param "b58_pubkey" is a Base58 encoded public key
+    If Not CapturePubKey('',account.accountkey,ErrorDesc) then begin
+      ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
       exit;
     end;
-    account.accountkey := CT_Account_NUL.accountkey;
-    account.accountkey := TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(params.AsString('enc_pubkey','')));
     if (TAccountComp.IsValidAccountKey(account.accountkey,ansistr)) then begin
-      GetResultObject.GetAsVariant('ec_nid').Value := account.accountkey.EC_OpenSSL_NID;
-      GetResultObject.GetAsVariant('x').Value := TCrypto.ToHexaString(account.accountkey.x);
-      GetResultObject.GetAsVariant('y').Value := TCrypto.ToHexaString(account.accountkey.y);
+      FillPublicKeyObject(account.accountkey,GetResultObject);
       Result := True;
     end else begin
       ErrorDesc:= ansistr;
@@ -1103,7 +1344,7 @@ begin
     end;
   end else if (method='payloadencrypt') then begin
     // Encrypts a "payload" using "payload_method"
-    // "payload_method" types: "none","pubkey"(must provide "enc_pubkey"),"aes"(must provide "pwd" param)
+    // "payload_method" types: "none","pubkey"(must provide "enc_pubkey" or "b58_pubkey"),"aes"(must provide "pwd" param)
     // If payload is "pubkey"
     // Returns an hexa string with encrypted payload
     if (params.AsString('payload','')='') then begin
@@ -1111,8 +1352,15 @@ begin
       ErrorDesc := 'Need param "payload"';
       exit;
     end;
+    opr.newKey := CT_TWalletKey_NUL.AccountKey;
+    if (params.IndexOfName('enc_pubkey')>=0) Or (params.IndexOfName('b58_pubkey')>=0) then begin
+      if Not (CapturePubKey('',opr.newKey,ErrorDesc)) then begin
+        ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+        exit;
+      end;
+    end;
     Result := DoEncrypt(TCrypto.HexaToRaw(params.AsString('payload','')),
-       TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(params.AsString('enc_pubkey',''))),
+       opr.newKey,
        params.AsString('payload_method',''),params.AsString('pwd',''));
   end else if (method='payloaddecrypt') then begin
     // Decrypts a "payload" searching for wallet private keys and for array of strings in "pwds" param
@@ -1133,7 +1381,7 @@ begin
     GetConnections;
     Result := true;
   end else if (method='addnewkey') then begin
-    // Creates a new private key and stores it on the wallet, returning encoded value
+    // Creates a new private key and stores it on the wallet, returning Public key JSON object
     // Param "ec_nid" can be 714=secp256k1 715=secp384r1 729=secp283k1 716=secp521r1. (Default = CT_Default_EC_OpenSSL_NID)
     // Param "name" is name for this address
     If Not _RPCServer.WalletKeys.IsValidPassword then begin
@@ -1145,15 +1393,18 @@ begin
     try
       ecpkey.GenerateRandomPrivateKey(params.AsInteger('ec_nid',CT_Default_EC_OpenSSL_NID));
       _RPCServer.FWalletKeys.AddPrivateKey(params.AsString('name',DateTimeToStr(now)),ecpkey);
-      jsonresponse.GetAsVariant('result').Value:=TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(ecpkey.PublicKey));
+      FillPublicKeyObject(ecpkey.PublicKey,GetResultObject);
       Result := true;
     finally
       ecpkey.Free;
     end;
+  end else if (method='lock') then begin
+    jsonresponse.GetAsVariant('result').Value := _RPCServer.WalletKeys.LockWallet;
+    Result := true;
   end else if (method='unlock') then begin
     // Unlocks the Wallet with "pwd" password
     // Returns Boolean if wallet is unlocked
-    if (params.AsString('pwd','')='') then begin
+    if (params.IndexOfName('pwd')<0) then begin
       ErrorNum:= CT_RPC_ErrNum_InvalidData;
       ErrorDesc := 'Need param "pwd"';
       exit;

+ 8 - 0
Units/PascalCoin/UThread.pas

@@ -62,6 +62,7 @@ Type
     procedure Clear;
     procedure Remove(Item: Pointer); inline;
     function LockList: TList;
+    function TryLockList(MaxWaitMilliseconds : Cardinal; var lockedList : TList) : Boolean;
     procedure UnlockList; inline;
   end;
 
@@ -287,6 +288,13 @@ begin
   end;
 end;
 
+function TPCThreadList.TryLockList(MaxWaitMilliseconds: Cardinal;
+  var lockedList: TList): Boolean;
+begin
+  lockedList := FList;
+  Result := TPCThread.TryProtectEnterCriticalSection(Self,MaxWaitMilliseconds,FLock);
+end;
+
 procedure TPCThreadList.UnlockList;
 begin
   FLock.Release;

+ 11 - 0
Units/PascalCoin/UWalletKeys.pas

@@ -63,6 +63,7 @@ Type
     Property WalletFileName : AnsiString read FWalletFileName write SetWalletFileName;
     Property OnChanged : TNotifyEvent read FOnChanged write FOnChanged;
     Procedure SetName(index : Integer; Const newName : AnsiString);
+    Function LockWallet : Boolean;
   End;
 
   TWalletKeysExt = Class(TWalletKeys)
@@ -301,6 +302,15 @@ begin
   if Assigned(FOnChanged) then FOnChanged(Self);
 end;
 
+function TWalletKeys.LockWallet: Boolean;
+begin
+  // Return true when wallet has a password, locking it. False if there password is empty string
+  FWalletPassword := '';
+  GeneratePrivateKeysFromPassword;
+  Result := Not IsValidPassword;
+  if Assigned(FOnChanged) then FOnChanged(Self);
+end;
+
 procedure TWalletKeys.SaveToStream(Stream: TStream);
 var i : Integer;
   P : PWalletKey;
@@ -368,6 +378,7 @@ begin
   // Try if password is Ok
   GeneratePrivateKeysFromPassword;
   if FIsValidPassword then SaveToStream(FWalletFileStream);
+  if Assigned(FOnChanged) then FOnChanged(Self);
 end;
 
 { TWalletKeysExt }

+ 9 - 5
Units/PascalCoin/upcdaemon.pas

@@ -191,9 +191,11 @@ constructor TPCDaemonMapper.Create(AOwner: TComponent);
 Var D : TDaemonDef;
 begin
   inherited Create(AOwner);
-  FLog := TLog.Create(Nil);
-  FLog.SaveTypes:=CT_TLogTypes_ALL;
-  FLog.FileName:=TFolderHelper.GetPascalCoinDataFolder+PathDelim+'pascalcoin_'+FormatDateTime('yyyymmddhhnn',Now)+'.log';
+  if (Application.HasOption('l','log')) then begin
+    FLog := TLog.Create(Nil);
+    FLog.SaveTypes:=CT_TLogTypes_ALL;
+    FLog.FileName:=TFolderHelper.GetPascalCoinDataFolder+PathDelim+'pascalcoin_'+FormatDateTime('yyyymmddhhnn',Now)+'.log';
+  end;
   D:=DaemonDefs.Add as TDaemonDef;
   D.DisplayName:='Pascal Coin Daemon';
   D.Name:='PascalCoinDaemon';
@@ -203,8 +205,10 @@ end;
 
 destructor TPCDaemonMapper.Destroy;
 begin
-  FLog.OnInThreadNewLog:=Nil;
-  FreeAndNil(FLog);
+  If Assigned(FLog) then begin
+    FLog.OnInThreadNewLog:=Nil;
+    FreeAndNil(FLog);
+  end;
   inherited Destroy;
 end;
 

+ 0 - 2
Units/Utils/UFolderHelper.pas

@@ -91,8 +91,6 @@ var
   FolderPath: array[0 .. MAX_PATH] of Char;
 begin
   Result := '';
-  //SetLastError(ERROR_SUCCESS);
-
   if SHGetFolderPath(0, aCSIDL, 0, 0, @FolderPath) = S_OK then
     Result := FolderPath;
 end;

+ 15 - 2
Units/Utils/UGridUtils.pas

@@ -82,6 +82,7 @@ Type
     FPendingOperations: Boolean;
     FBlockStart: Int64;
     FBlockEnd: Int64;
+    FMustShowAlwaysAnAccount: Boolean;
     Procedure OnNodeNewOperation(Sender : TObject);
     Procedure OnNodeNewAccount(Sender : TObject);
     Procedure InitGrid;
@@ -93,7 +94,8 @@ Type
     procedure SetPendingOperations(const Value: Boolean);
 
     procedure SetBlockEnd(const Value: Int64);
-    procedure SetBlockStart(const Value: Int64);protected
+    procedure SetBlockStart(const Value: Int64);
+    procedure SetMustShowAlwaysAnAccount(const Value: Boolean);
   protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
   public
@@ -102,6 +104,7 @@ Type
     Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
     Property PendingOperations : Boolean read FPendingOperations write SetPendingOperations;
     Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
+    Property MustShowAlwaysAnAccount : Boolean read FMustShowAlwaysAnAccount write SetMustShowAlwaysAnAccount;
     Property Node : TNode read GetNode write SetNode;
     Procedure UpdateAccountOperations; virtual;
     Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
@@ -532,6 +535,7 @@ constructor TOperationsGrid.Create(AOwner: TComponent);
 begin
   FAccountNumber := 0;
   FDrawGrid := Nil;
+  MustShowAlwaysAnAccount := false;
   FOperationsResume := TOperationsResumeList.Create;
   FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
   FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
@@ -745,6 +749,13 @@ begin
   end;
 end;
 
+procedure TOperationsGrid.SetMustShowAlwaysAnAccount(const Value: Boolean);
+begin
+  if FMustShowAlwaysAnAccount=Value then exit;
+  FMustShowAlwaysAnAccount := Value;
+  UpdateAccountOperations;
+end;
+
 procedure TOperationsGrid.SetNode(const Value: TNode);
 begin
   if GetNode=Value then exit;
@@ -787,6 +798,8 @@ begin
   FOperationsResume.Clear;
   Try
     if Not Assigned(Node) then exit;
+    if (MustShowAlwaysAnAccount) And (AccountNumber<0) then exit;
+
     if FPendingOperations then begin
       for i := Node.Operations.Count - 1 downto 0 do begin
         Op := Node.Operations.OperationsHashTree.GetOperation(i);
@@ -858,7 +871,7 @@ begin
         Finally
           list.Free;
         End;
-        Node.GetStoredOperationsFromAccount(FOperationsResume,AccountNumber,100);
+        Node.GetStoredOperationsFromAccount(FOperationsResume,AccountNumber,100,5000);
       end;
     end;
   Finally