Browse Source

Build 1.0.2

See README.txt to know Build 1.0.2 changes
PascalCoin 9 years ago
parent
commit
749a7114a9

BIN
Instaler/PascalCoinWalletB1.0.1.0.exe


BIN
Instaler/PascalCoinWalletB1.0.2.0.exe


BIN
PascalCoinWallet.res


+ 9 - 0
README.md

@@ -38,6 +38,15 @@ If you like it, consider a donation using BitCoin:
 
 
 History:
 History:
 
 
+Build 1.0.2.0 - 2016-08-31
+--------------------------
+- Improved hashing speed
+- Allow mining without opening external ports
+- Choose how many CPU's want to mine
+- Show real-time pending operations waiting to be included in the block
+- More stable
+- Some miner modifications
+
 Build 1.0.1.0 - 2016-08-12
 Build 1.0.1.0 - 2016-08-12
 --------------------------
 --------------------------
 - Included an option to Import/Export Wallet keys file
 - Included an option to Import/Export Wallet keys file

+ 9 - 0
README.txt

@@ -38,6 +38,15 @@ If you like it, consider a donation using BitCoin:
 
 
 History:
 History:
 
 
+Build 1.0.2.0 - 2016-08-31
+--------------------------
+- Improved hashing speed
+- Allow mining without opening external ports
+- Choose how many CPU's want to mine
+- Show real-time pending operations waiting to be included in the block
+- More stable
+- Some miner modifications
+
 Build 1.0.1.0 - 2016-08-12
 Build 1.0.1.0 - 2016-08-12
 --------------------------
 --------------------------
 - Included an option to Import/Export Wallet keys file
 - Included an option to Import/Export Wallet keys file

+ 61 - 8
Units/Forms/UFRMAbout.dfm

@@ -5,7 +5,7 @@ object FRMAbout: TFRMAbout
   BorderIcons = [biSystemMenu]
   BorderIcons = [biSystemMenu]
   BorderStyle = bsDialog
   BorderStyle = bsDialog
   Caption = 'About...'
   Caption = 'About...'
-  ClientHeight = 341
+  ClientHeight = 415
   ClientWidth = 522
   ClientWidth = 522
   Color = clBtnFace
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
   Font.Charset = DEFAULT_CHARSET
@@ -165,8 +165,8 @@ object FRMAbout: TFRMAbout
     ParentFont = False
     ParentFont = False
   end
   end
   object lblBuild: TLabel
   object lblBuild: TLabel
-    Left = 8
-    Top = 280
+    Left = 15
+    Top = 356
     Width = 30
     Width = 30
     Height = 13
     Height = 13
     Caption = 'Build:'
     Caption = 'Build:'
@@ -178,8 +178,8 @@ object FRMAbout: TFRMAbout
     ParentFont = False
     ParentFont = False
   end
   end
   object lblProtocolVersion: TLabel
   object lblProtocolVersion: TLabel
-    Left = 8
-    Top = 299
+    Left = 15
+    Top = 375
     Width = 50
     Width = 50
     Height = 13
     Height = 13
     Caption = 'Protocol:'
     Caption = 'Protocol:'
@@ -190,11 +190,61 @@ object FRMAbout: TFRMAbout
     Font.Style = [fsBold]
     Font.Style = [fsBold]
     ParentFont = False
     ParentFont = False
   end
   end
+  object Label2: TLabel
+    Left = 90
+    Top = 320
+    Width = 65
+    Height = 13
+    Caption = 'Source Code:'
+  end
+  object Label3: TLabel
+    Left = 90
+    Top = 339
+    Width = 135
+    Height = 13
+    Caption = 'Check For New Versions:'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object Label4: TLabel
+    Left = 170
+    Top = 320
+    Width = 240
+    Height = 13
+    Cursor = crHandPoint
+    Caption = 'https://github.com/PascalCoin/PascalCoin'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlue
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+    OnClick = Label4Click
+  end
+  object Label5: TLabel
+    Left = 237
+    Top = 339
+    Width = 253
+    Height = 13
+    Cursor = crHandPoint
+    Caption = 'https://sourceforge.net/projects/pascalcoin'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clBlue
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = [fsBold]
+    ParentFont = False
+    OnClick = Label5Click
+  end
   object Memo1: TMemo
   object Memo1: TMemo
     Left = 90
     Left = 90
     Top = 46
     Top = 46
     Width = 401
     Width = 401
-    Height = 229
+    Height = 275
     BevelInner = bvNone
     BevelInner = bvNone
     BevelOuter = bvNone
     BevelOuter = bvNone
     BorderStyle = bsNone
     BorderStyle = bsNone
@@ -229,7 +279,10 @@ object FRMAbout: TFRMAbout
         'functions inspirated in code written by Ladar Levison and Marco ' +
         'functions inspirated in code written by Ladar Levison and Marco ' +
         'Ferrante. Original '
         'Ferrante. Original '
       'source code is written in Pascal Language and is available at '
       'source code is written in Pascal Language and is available at '
-      'https://github.com/PascalCoin/PascalCoin')
+      'https://github.com/PascalCoin/PascalCoin'
+      ''
+      'If you like it, consider a donation using BitCoin:'
+      '16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk')
     ParentColor = True
     ParentColor = True
     ParentCtl3D = False
     ParentCtl3D = False
     ReadOnly = True
     ReadOnly = True
@@ -237,7 +290,7 @@ object FRMAbout: TFRMAbout
   end
   end
   object bbClose: TBitBtn
   object bbClose: TBitBtn
     Left = 380
     Left = 380
-    Top = 281
+    Top = 358
     Width = 111
     Width = 111
     Height = 31
     Height = 31
     Caption = 'Close'
     Caption = 'Close'

+ 23 - 1
Units/Forms/UFRMAbout.pas

@@ -27,16 +27,23 @@ type
     bbClose: TBitBtn;
     bbClose: TBitBtn;
     lblBuild: TLabel;
     lblBuild: TLabel;
     lblProtocolVersion: TLabel;
     lblProtocolVersion: TLabel;
+    Label2: TLabel;
+    Label3: TLabel;
+    Label4: TLabel;
+    Label5: TLabel;
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
+    procedure Label4Click(Sender: TObject);
+    procedure Label5Click(Sender: TObject);
   private
   private
     { Private declarations }
     { Private declarations }
+    Procedure OpenURL(Url : String);
   public
   public
     { Public declarations }
     { Public declarations }
   end;
   end;
 
 
 implementation
 implementation
 
 
-uses UFolderHelper, UConst;
+uses UFolderHelper, UConst, ShellApi;
 
 
 {$R *.dfm}
 {$R *.dfm}
 
 
@@ -52,4 +59,19 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TFRMAbout.Label4Click(Sender: TObject);
+begin
+  OpenURL(TLabel(Sender).Caption);
+end;
+
+procedure TFRMAbout.Label5Click(Sender: TObject);
+begin
+  OpenURL(TLabel(Sender).Caption);
+end;
+
+procedure TFRMAbout.OpenURL(Url: String);
+begin
+  shellexecute(0, 'open', pchar(URL), nil, nil, SW_SHOW)
+end;
+
 end.
 end.

+ 86 - 30
Units/Forms/UFRMPascalCoinWalletConfig.dfm

@@ -4,7 +4,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   BorderIcons = [biSystemMenu]
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
   BorderStyle = bsSingle
   Caption = 'Options'
   Caption = 'Options'
-  ClientHeight = 311
+  ClientHeight = 460
   ClientWidth = 374
   ClientWidth = 374
   Color = clBtnFace
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
   Font.Charset = DEFAULT_CHARSET
@@ -19,7 +19,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   TextHeight = 13
   TextHeight = 13
   object Label1: TLabel
   object Label1: TLabel
     Left = 30
     Left = 30
-    Top = 201
+    Top = 335
     Width = 120
     Width = 120
     Height = 13
     Height = 13
     Caption = 'Default fee for operation'
     Caption = 'Default fee for operation'
@@ -58,6 +58,20 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Font.Style = []
     Font.Style = []
     ParentFont = False
     ParentFont = False
   end
   end
+  object Label5: TLabel
+    Left = 30
+    Top = 176
+    Width = 60
+    Height = 13
+    Caption = 'CPU'#39's to use'
+  end
+  object lblMaxCPUS: TLabel
+    Left = 248
+    Top = 176
+    Width = 70
+    Height = 13
+    Caption = '(Default XXXX)'
+  end
   object cbAutomaticMiningWhenConnectedToNodes: TCheckBox
   object cbAutomaticMiningWhenConnectedToNodes: TCheckBox
     Left = 15
     Left = 15
     Top = 150
     Top = 150
@@ -66,37 +80,18 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Caption = 'Allow automatic mining when connected to nodes'
     Caption = 'Allow automatic mining when connected to nodes'
     TabOrder = 4
     TabOrder = 4
   end
   end
-  object cbGenerateANewPrivateKeyForEachNewGeneratedBlock: TCheckBox
-    Left = 15
-    Top = 173
-    Width = 326
-    Height = 17
-    Caption = 'Generate a new Private key for each new generated block'
-    TabOrder = 5
-  end
-  object udDefaultFee: TUpDown
-    Left = 226
-    Top = 198
-    Width = 17
-    Height = 21
-    Max = 5000000
-    Increment = 5
-    TabOrder = 7
-    Thousands = False
-    OnChangingEx = udDefaultFeeChangingEx
-  end
   object ebDefaultFee: TEdit
   object ebDefaultFee: TEdit
     Left = 170
     Left = 170
-    Top = 198
+    Top = 332
     Width = 56
     Width = 56
     Height = 21
     Height = 21
     Alignment = taRightJustify
     Alignment = taRightJustify
-    TabOrder = 6
+    TabOrder = 7
     Text = '0'
     Text = '0'
   end
   end
   object cbSaveLogFiles: TCheckBox
   object cbSaveLogFiles: TCheckBox
     Left = 15
     Left = 15
-    Top = 225
+    Top = 359
     Width = 97
     Width = 97
     Height = 17
     Height = 17
     Caption = 'Save log file'
     Caption = 'Save log file'
@@ -104,15 +99,15 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   end
   end
   object cbShowLogs: TCheckBox
   object cbShowLogs: TCheckBox
     Left = 15
     Left = 15
-    Top = 248
+    Top = 382
     Width = 97
     Width = 97
     Height = 17
     Height = 17
     Caption = 'Show logs'
     Caption = 'Show logs'
     TabOrder = 9
     TabOrder = 9
   end
   end
   object bbOk: TBitBtn
   object bbOk: TBitBtn
-    Left = 186
-    Top = 270
+    Left = 171
+    Top = 410
     Width = 75
     Width = 75
     Height = 25
     Height = 25
     DoubleBuffered = True
     DoubleBuffered = True
@@ -122,8 +117,8 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     OnClick = bbOkClick
     OnClick = bbOkClick
   end
   end
   object bbCancel: TBitBtn
   object bbCancel: TBitBtn
-    Left = 276
-    Top = 270
+    Left = 261
+    Top = 410
     Width = 75
     Width = 75
     Height = 25
     Height = 25
     DoubleBuffered = True
     DoubleBuffered = True
@@ -232,10 +227,71 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   end
   end
   object cbShowModalMessages: TCheckBox
   object cbShowModalMessages: TCheckBox
     Left = 170
     Left = 170
-    Top = 225
+    Top = 359
     Width = 171
     Width = 171
     Height = 17
     Height = 17
     Caption = 'Show Modal Messages'
     Caption = 'Show Modal Messages'
     TabOrder = 12
     TabOrder = 12
   end
   end
+  object udCPUs: TUpDown
+    Left = 226
+    Top = 173
+    Width = 16
+    Height = 21
+    Associate = ebCPUs
+    Min = 1
+    Max = 6
+    Position = 1
+    TabOrder = 6
+    Thousands = False
+  end
+  object ebCPUs: TEdit
+    Left = 170
+    Top = 173
+    Width = 56
+    Height = 21
+    Alignment = taRightJustify
+    TabOrder = 5
+    Text = '1'
+  end
+  object gbMinerPrivateKey: TGroupBox
+    Left = 8
+    Top = 200
+    Width = 334
+    Height = 121
+    Caption = ' Miner Private Key: '
+    TabOrder = 13
+    object rbGenerateANewPrivateKeyEachBlock: TRadioButton
+      Left = 20
+      Top = 20
+      Width = 301
+      Height = 17
+      Caption = 'Generate a new Private Key for each new generated block'
+      TabOrder = 0
+    end
+    object rbUseARandomKey: TRadioButton
+      Left = 20
+      Top = 40
+      Width = 216
+      Height = 17
+      Caption = 'Use a random existing Key'
+      TabOrder = 1
+    end
+    object rbMineAllwaysWithThisKey: TRadioButton
+      Left = 20
+      Top = 61
+      Width = 216
+      Height = 17
+      Caption = 'Mine allways with this Key:'
+      TabOrder = 2
+    end
+    object cbPrivateKeyToMine: TComboBox
+      Left = 45
+      Top = 85
+      Width = 266
+      Height = 21
+      Style = csDropDownList
+      TabOrder = 3
+    end
+  end
 end
 end

+ 80 - 23
Units/Forms/UFRMPascalCoinWalletConfig.pas

@@ -22,8 +22,6 @@ uses
 type
 type
   TFRMPascalCoinWalletConfig = class(TForm)
   TFRMPascalCoinWalletConfig = class(TForm)
     cbAutomaticMiningWhenConnectedToNodes: TCheckBox;
     cbAutomaticMiningWhenConnectedToNodes: TCheckBox;
-    cbGenerateANewPrivateKeyForEachNewGeneratedBlock: TCheckBox;
-    udDefaultFee: TUpDown;
     ebDefaultFee: TEdit;
     ebDefaultFee: TEdit;
     Label1: TLabel;
     Label1: TLabel;
     cbSaveLogFiles: TCheckBox;
     cbSaveLogFiles: TCheckBox;
@@ -39,10 +37,17 @@ type
     ebMinerName: TEdit;
     ebMinerName: TEdit;
     Label4: TLabel;
     Label4: TLabel;
     cbShowModalMessages: TCheckBox;
     cbShowModalMessages: TCheckBox;
+    Label5: TLabel;
+    udCPUs: TUpDown;
+    ebCPUs: TEdit;
+    lblMaxCPUS: TLabel;
+    gbMinerPrivateKey: TGroupBox;
+    rbGenerateANewPrivateKeyEachBlock: TRadioButton;
+    rbUseARandomKey: TRadioButton;
+    rbMineAllwaysWithThisKey: TRadioButton;
+    cbPrivateKeyToMine: TComboBox;
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure bbOkClick(Sender: TObject);
     procedure bbOkClick(Sender: TObject);
-    procedure udDefaultFeeChangingEx(Sender: TObject; var AllowChange: Boolean;
-      NewValue: SmallInt; Direction: TUpDownDirection);
     procedure bbUpdatePasswordClick(Sender: TObject);
     procedure bbUpdatePasswordClick(Sender: TObject);
   private
   private
     FAppParams: TAppParams;
     FAppParams: TAppParams;
@@ -59,20 +64,38 @@ type
 
 
 implementation
 implementation
 
 
-uses UConst, UAccounts, UFRMWallet;
+uses UConst, UAccounts, UFRMWallet, ULog, UCrypto;
 
 
 {$R *.dfm}
 {$R *.dfm}
 
 
 procedure TFRMPascalCoinWalletConfig.bbOkClick(Sender: TObject);
 procedure TFRMPascalCoinWalletConfig.bbOkClick(Sender: TObject);
+Var df : Int64;
+  mpk : TMinerPrivateKey;
+  i : Integer;
 begin
 begin
-  AppParams.ParamByName[CT_PARAM_DefaultFee].SetAsInt64(udDefaultFee.Position );
+  if TAccountComp.TxtToMoney(ebDefaultFee.Text,df) then begin
+    AppParams.ParamByName[CT_PARAM_DefaultFee].SetAsInt64(df);
+  end else begin
+    ebDefaultFee.Text := TAccountComp.FormatMoney(AppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInteger(0));
+    raise Exception.Create('Invalid Fee value');
+  end;
   AppParams.ParamByName[CT_PARAM_InternetServerPort].SetAsInteger(udInternetServerPort.Position );
   AppParams.ParamByName[CT_PARAM_InternetServerPort].SetAsInteger(udInternetServerPort.Position );
-  AppParams.ParamByName[CT_PARAM_NewPrivateKeyForEachGeneratedBlock].SetAsBoolean(cbGenerateANewPrivateKeyForEachNewGeneratedBlock.Checked );
+  if rbGenerateANewPrivateKeyEachBlock.Checked then mpk := mpk_NewEachTime
+  else if rbUseARandomKey.Checked then mpk := mpk_Random
+  else if rbMineAllwaysWithThisKey.Checked then begin
+    mpk := mpk_Selected;
+    if cbPrivateKeyToMine.ItemIndex<0 then raise Exception.Create('Must select a private key');
+    i := Integer(cbPrivateKeyToMine.Items.Objects[cbPrivateKeyToMine.ItemIndex]);
+    if (i<0) Or (i>=FWalletKeys.Count) then raise Exception.Create('Invalid private key');
+    AppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].SetAsString( TAccountComp.AccountKey2RawString( FWalletKeys.Key[i].AccountKey ) );
+  end else mpk := mpk_Random;
+  AppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].SetAsInteger(integer(mpk));
   AppParams.ParamByName[CT_PARAM_AutomaticMineWhenConnectedToNodes].SetAsBoolean(cbAutomaticMiningWhenConnectedToNodes.Checked );
   AppParams.ParamByName[CT_PARAM_AutomaticMineWhenConnectedToNodes].SetAsBoolean(cbAutomaticMiningWhenConnectedToNodes.Checked );
   AppParams.ParamByName[CT_PARAM_SaveLogFiles].SetAsBoolean(cbSaveLogFiles.Checked );
   AppParams.ParamByName[CT_PARAM_SaveLogFiles].SetAsBoolean(cbSaveLogFiles.Checked );
   AppParams.ParamByName[CT_PARAM_ShowLogs].SetAsBoolean(cbShowLogs.Checked );
   AppParams.ParamByName[CT_PARAM_ShowLogs].SetAsBoolean(cbShowLogs.Checked );
   AppParams.ParamByName[CT_PARAM_MinerName].SetAsString(ebMinerName.Text);
   AppParams.ParamByName[CT_PARAM_MinerName].SetAsString(ebMinerName.Text);
   AppParams.ParamByName[CT_PARAM_ShowModalMessages].SetAsBoolean(cbShowModalMessages.Checked);
   AppParams.ParamByName[CT_PARAM_ShowModalMessages].SetAsBoolean(cbShowModalMessages.Checked);
+  AppParams.ParamByName[CT_PARAM_MaxCPUs].SetAsInteger(udCPUs.Position);
 end;
 end;
 
 
 procedure TFRMPascalCoinWalletConfig.bbUpdatePasswordClick(Sender: TObject);
 procedure TFRMPascalCoinWalletConfig.bbUpdatePasswordClick(Sender: TObject);
@@ -107,26 +130,40 @@ procedure TFRMPascalCoinWalletConfig.FormCreate(Sender: TObject);
 begin
 begin
   lblDefaultInternetServerPort.Caption := Format('(Default %d)',[CT_NetServer_Port]);
   lblDefaultInternetServerPort.Caption := Format('(Default %d)',[CT_NetServer_Port]);
   udInternetServerPort.Position := CT_NetServer_Port;
   udInternetServerPort.Position := CT_NetServer_Port;
-  udDefaultFee.Position := 0;
   ebDefaultFee.Text := TAccountComp.FormatMoney(0);
   ebDefaultFee.Text := TAccountComp.FormatMoney(0);
   ebMinerName.Text := '';
   ebMinerName.Text := '';
   bbUpdatePassword.Enabled := false;
   bbUpdatePassword.Enabled := false;
   UpdateWalletConfig;
   UpdateWalletConfig;
+  udCPUs.Max := CPUCount;
+  lblMaxCPUS.Caption := '(Avail. '+inttostr(CPUCount)+' cpu''s)';
 end;
 end;
 
 
 procedure TFRMPascalCoinWalletConfig.SetAppParams(const Value: TAppParams);
 procedure TFRMPascalCoinWalletConfig.SetAppParams(const Value: TAppParams);
+Var i : Integer;
 begin
 begin
   FAppParams := Value;
   FAppParams := Value;
   if Not Assigned(Value) then exit;
   if Not Assigned(Value) then exit;
-  udInternetServerPort.Position := AppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
-  udDefaultFee.Position := AppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInt64(0);
-  ebDefaultFee.Text := TAccountComp.FormatMoney(udDefaultFee.Position);
-  cbAutomaticMiningWhenConnectedToNodes.Checked := AppParams.ParamByName[CT_PARAM_AutomaticMineWhenConnectedToNodes].GetAsBoolean(true);
-  cbGenerateANewPrivateKeyForEachNewGeneratedBlock.Checked := AppParams.ParamByName[CT_PARAM_NewPrivateKeyForEachGeneratedBlock].GetAsBoolean(false);
-  cbSaveLogFiles.Checked := AppParams.ParamByName[CT_PARAM_SaveLogFiles].GetAsBoolean(false);
-  cbShowLogs.Checked := AppParams.ParamByName[CT_PARAM_ShowLogs].GetAsBoolean(false);
-  ebMinerName.Text := AppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
-  cbShowModalMessages.Checked := AppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false);
+  Try
+    udInternetServerPort.Position := AppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
+    ebDefaultFee.Text := TAccountComp.FormatMoney(AppParams.ParamByName[CT_PARAM_DefaultFee].GetAsInt64(0));
+    cbAutomaticMiningWhenConnectedToNodes.Checked := AppParams.ParamByName[CT_PARAM_AutomaticMineWhenConnectedToNodes].GetAsBoolean(true);
+    case TMinerPrivateKey(AppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random))) of
+      mpk_NewEachTime : rbGenerateANewPrivateKeyEachBlock.Checked := true;
+      mpk_Random : rbUseARandomKey.Checked := true;
+      mpk_Selected : rbMineAllwaysWithThisKey.Checked := true;
+    else rbUseARandomKey.Checked := true;
+    end;
+    UpdateWalletConfig;
+    cbSaveLogFiles.Checked := AppParams.ParamByName[CT_PARAM_SaveLogFiles].GetAsBoolean(false);
+    cbShowLogs.Checked := AppParams.ParamByName[CT_PARAM_ShowLogs].GetAsBoolean(false);
+    ebMinerName.Text := AppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
+    cbShowModalMessages.Checked := AppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false);
+    udCPUs.Position := AppParams.ParamByName[CT_PARAM_MaxCPUs].GetAsInteger(1);
+  Except
+    On E:Exception do begin
+      TLog.NewLog(lterror,ClassName,'Exception at SetAppParams: '+E.Message);
+    end;
+  End;
 end;
 end;
 
 
 procedure TFRMPascalCoinWalletConfig.SetWalletKeys(const Value: TWalletKeys);
 procedure TFRMPascalCoinWalletConfig.SetWalletKeys(const Value: TWalletKeys);
@@ -135,14 +172,11 @@ begin
   UpdateWalletConfig;
   UpdateWalletConfig;
 end;
 end;
 
 
-procedure TFRMPascalCoinWalletConfig.udDefaultFeeChangingEx(Sender: TObject;
-  var AllowChange: Boolean; NewValue: SmallInt; Direction: TUpDownDirection);
-begin
-  AllowChange := true;
-  ebDefaultFee.Text := TAccountComp.FormatMoney(NewValue);
-end;
 
 
 procedure TFRMPascalCoinWalletConfig.UpdateWalletConfig;
 procedure TFRMPascalCoinWalletConfig.UpdateWalletConfig;
+Var i, iselected : Integer;
+  s : String;
+  wk : TWalletKey;
 begin
 begin
   if Assigned(FWalletKeys) then begin
   if Assigned(FWalletKeys) then begin
     if FWalletKeys.IsValidPassword then begin
     if FWalletKeys.IsValidPassword then begin
@@ -154,6 +188,29 @@ begin
     end else begin
     end else begin
         bbUpdatePassword.Caption := 'Wallet with password, change it!';
         bbUpdatePassword.Caption := 'Wallet with password, change it!';
     end;
     end;
+    cbPrivateKeyToMine.Items.Clear;
+    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 wk.CryptedKey<>'' then begin
+        cbPrivateKeyToMine.Items.AddObject(s,TObject(i));
+      end;
+    end;
+    cbPrivateKeyToMine.Sorted := true;
+    if Assigned(FAppParams) then begin
+      s := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].GetAsString('');
+      iselected := FWalletKeys.IndexOfAccountKey(TAccountComp.RawString2Accountkey(s));
+      if iselected>=0 then begin
+        iselected :=  cbPrivateKeyToMine.Items.IndexOfObject(TObject(iselected));
+        cbPrivateKeyToMine.ItemIndex := iselected;
+      end;
+
+    end;
+
   end else bbUpdatePassword.Caption := '(Wallet password)';
   end else bbUpdatePassword.Caption := '(Wallet password)';
   bbUpdatePassword.Enabled := Assigned(FWAlletKeys);
   bbUpdatePassword.Enabled := Assigned(FWAlletKeys);
 end;
 end;

+ 138 - 26
Units/Forms/UFRMWallet.dfm

@@ -12,6 +12,7 @@ object FRMWallet: TFRMWallet
   Font.Style = []
   Font.Style = []
   Menu = MainMenu
   Menu = MainMenu
   OldCreateOrder = False
   OldCreateOrder = False
+  Position = poOwnerFormCenter
   OnCreate = FormCreate
   OnCreate = FormCreate
   OnDestroy = FormDestroy
   OnDestroy = FormDestroy
   PixelsPerInch = 96
   PixelsPerInch = 96
@@ -282,6 +283,63 @@ object FRMWallet: TFRMWallet
       Font.Style = []
       Font.Style = []
       ParentFont = False
       ParentFont = False
     end
     end
+    object Label16: TLabel
+      Left = 360
+      Top = 56
+      Width = 74
+      Height = 13
+      Caption = 'Blocks found:'
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = [fsBold]
+      ParentFont = False
+    end
+    object lblBlocksFound: TLabel
+      Left = 440
+      Top = 56
+      Width = 21
+      Height = 13
+      Hint = 'Blocks found while Miner is running...'
+      Caption = '000'
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = [fsBold]
+      ParentFont = False
+      ParentShowHint = False
+      ShowHint = True
+    end
+    object lblReceivedMessages: TLabel
+      Left = 360
+      Top = 66
+      Width = 185
+      Height = 23
+      Cursor = crHandPoint
+      Caption = 'Received messages'
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clRed
+      Font.Height = -19
+      Font.Name = 'Tahoma'
+      Font.Style = [fsBold]
+      ParentFont = False
+      OnClick = lblReceivedMessagesClick
+    end
+    object Label15: TLabel
+      Left = 721
+      Top = 6
+      Width = 112
+      Height = 23
+      Caption = 'TEST MODE'
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -19
+      Font.Name = 'Tahoma'
+      Font.Style = [fsBold]
+      ParentFont = False
+    end
     object cbAllowMining: TCheckBox
     object cbAllowMining: TCheckBox
       Left = 620
       Left = 620
       Top = 10
       Top = 10
@@ -317,16 +375,12 @@ object FRMWallet: TFRMWallet
     Top = 91
     Top = 91
     Width = 899
     Width = 899
     Height = 448
     Height = 448
-    ActivePage = tsMessages
+    ActivePage = tsAccountsExplorer
     Align = alClient
     Align = alClient
     TabOrder = 2
     TabOrder = 2
     OnChange = PageControlChange
     OnChange = PageControlChange
     object tsAccountsExplorer: TTabSheet
     object tsAccountsExplorer: TTabSheet
       Caption = 'Accounts Explorer'
       Caption = 'Accounts Explorer'
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object Splitter1: TSplitter
       object Splitter1: TSplitter
         Left = 380
         Left = 380
         Top = 41
         Top = 41
@@ -361,32 +415,78 @@ object FRMWallet: TFRMWallet
           OnClick = cbExploreMyAccountsClick
           OnClick = cbExploreMyAccountsClick
         end
         end
       end
       end
-      object dgAccounts: TDrawGrid
-        Left = 0
-        Top = 41
-        Width = 380
-        Height = 379
-        Align = alLeft
-        TabOrder = 1
-        OnClick = dgAccountsClick
-        OnColumnMoved = dgAccountsColumnMoved
-        OnFixedCellClick = dgAccountsFixedCellClick
-        ColWidths = (
-          64
-          64
-          64
-          64
-          64)
-      end
       object dgAccountOperations: TDrawGrid
       object dgAccountOperations: TDrawGrid
         Left = 383
         Left = 383
         Top = 41
         Top = 41
         Width = 508
         Width = 508
         Height = 379
         Height = 379
         Align = alClient
         Align = alClient
-        TabOrder = 2
+        TabOrder = 1
         OnDblClick = MiDecodePayloadClick
         OnDblClick = MiDecodePayloadClick
       end
       end
+      object pnlAccounts: TPanel
+        Left = 0
+        Top = 41
+        Width = 380
+        Height = 379
+        Align = alLeft
+        BevelOuter = bvNone
+        TabOrder = 2
+        object dgAccounts: TDrawGrid
+          Left = 0
+          Top = 0
+          Width = 380
+          Height = 345
+          Align = alLeft
+          TabOrder = 0
+          OnClick = dgAccountsClick
+          OnColumnMoved = dgAccountsColumnMoved
+          OnFixedCellClick = dgAccountsFixedCellClick
+          ColWidths = (
+            64
+            64
+            64
+            64
+            64)
+        end
+        object pnlAccountsInfo: TPanel
+          Left = 0
+          Top = 345
+          Width = 380
+          Height = 34
+          Align = alBottom
+          BevelOuter = bvNone
+          TabOrder = 1
+          object Label17: TLabel
+            Left = 5
+            Top = 10
+            Width = 48
+            Height = 13
+            Caption = 'Accounts:'
+          end
+          object Label19: TLabel
+            Left = 120
+            Top = 10
+            Width = 88
+            Height = 13
+            Caption = 'Accounts Balance:'
+          end
+          object lblAccountsCount: TLabel
+            Left = 60
+            Top = 10
+            Width = 18
+            Height = 13
+            Caption = '000'
+          end
+          object lblAccountsBalance: TLabel
+            Left = 214
+            Top = 10
+            Width = 18
+            Height = 13
+            Caption = '000'
+          end
+        end
+      end
     end
     end
     object tsPendingOperations: TTabSheet
     object tsPendingOperations: TTabSheet
       Caption = 'Pending Operations'
       Caption = 'Pending Operations'
@@ -697,7 +797,7 @@ object FRMWallet: TFRMWallet
       object memoNetConnections: TMemo
       object memoNetConnections: TMemo
         Left = 15
         Left = 15
         Top = 34
         Top = 34
-        Width = 571
+        Width = 860
         Height = 92
         Height = 92
         ReadOnly = True
         ReadOnly = True
         ScrollBars = ssVertical
         ScrollBars = ssVertical
@@ -727,6 +827,10 @@ object FRMWallet: TFRMWallet
     object tsMessages: TTabSheet
     object tsMessages: TTabSheet
       Caption = 'Messages'
       Caption = 'Messages'
       ImageIndex = 6
       ImageIndex = 6
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       DesignSize = (
       DesignSize = (
         891
         891
         420)
         420)
@@ -790,6 +894,15 @@ object FRMWallet: TFRMWallet
         Width = 860
         Width = 860
         Height = 231
         Height = 231
         Anchors = [akLeft, akTop, akRight, akBottom]
         Anchors = [akLeft, akTop, akRight, akBottom]
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -16
+        Font.Name = 'Tahoma'
+        Font.Style = []
+        Lines.Strings = (
+          'dsfa '#241'ldsaf '#241'lk dasf'
+          'dsfklda'#241'fs '#241'l')
+        ParentFont = False
         ReadOnly = True
         ReadOnly = True
         ScrollBars = ssBoth
         ScrollBars = ssBoth
         TabOrder = 2
         TabOrder = 2
@@ -803,7 +916,6 @@ object FRMWallet: TFRMWallet
           'memoMessageToSend')
           'memoMessageToSend')
         TabOrder = 3
         TabOrder = 3
         WantReturns = False
         WantReturns = False
-        WordWrap = False
       end
       end
     end
     end
   end
   end
@@ -905,7 +1017,7 @@ object FRMWallet: TFRMWallet
     Left = 90
     Left = 90
     Top = 155
     Top = 155
     Bitmap = {
     Bitmap = {
-      494C010102000800600010003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C0101020008009C0010003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 229 - 118
Units/Forms/UFRMWallet.pas

@@ -29,18 +29,22 @@ Const
   CT_PARAM_DefaultFee = 'DefaultFee';
   CT_PARAM_DefaultFee = 'DefaultFee';
   CT_PARAM_InternetServerPort = 'InternetServerPort';
   CT_PARAM_InternetServerPort = 'InternetServerPort';
   CT_PARAM_AutomaticMineWhenConnectedToNodes = 'AutomaticMineWhenConnectedToNodes';
   CT_PARAM_AutomaticMineWhenConnectedToNodes = 'AutomaticMineWhenConnectedToNodes';
-  CT_PARAM_NewPrivateKeyForEachGeneratedBlock = 'NewPrivateKeyForEachGeneratedBlock';
+  CT_PARAM_MinerPrivateKeyType = 'MinerPrivateKeyType';
+  CT_PARAM_MinerPrivateKeySelectedPublicKey = 'MinerPrivateKeySelectedPublicKey';
   CT_PARAM_SaveLogFiles = 'SaveLogFiles';
   CT_PARAM_SaveLogFiles = 'SaveLogFiles';
   CT_PARAM_ShowLogs = 'ShowLogs';
   CT_PARAM_ShowLogs = 'ShowLogs';
   CT_PARAM_MinerName = 'MinerName';
   CT_PARAM_MinerName = 'MinerName';
   CT_PARAM_FirstTime = 'FirstTime';
   CT_PARAM_FirstTime = 'FirstTime';
   CT_PARAM_ShowModalMessages = 'ShowModalMessages';
   CT_PARAM_ShowModalMessages = 'ShowModalMessages';
+  CT_PARAM_MaxCPUs = 'MaxCPUs';
 
 
 type
 type
   TStringListAux = Class(TStringList)
   TStringListAux = Class(TStringList)
 
 
   End;
   End;
 
 
+  TMinerPrivateKey = (mpk_NewEachTime, mpk_Random, mpk_Selected);
+
   TFRMWallet = class(TForm)
   TFRMWallet = class(TForm)
     pnlTop: TPanel;
     pnlTop: TPanel;
     Image1: TImage;
     Image1: TImage;
@@ -130,6 +134,16 @@ type
     Label12: TLabel;
     Label12: TLabel;
     Label13: TLabel;
     Label13: TLabel;
     Label14: TLabel;
     Label14: TLabel;
+    Label16: TLabel;
+    lblBlocksFound: TLabel;
+    pnlAccounts: TPanel;
+    pnlAccountsInfo: TPanel;
+    Label17: TLabel;
+    Label19: TLabel;
+    lblAccountsCount: TLabel;
+    lblAccountsBalance: TLabel;
+    lblReceivedMessages: TLabel;
+    Label15: TLabel;
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure TimerUpdateStatusTimer(Sender: TObject);
     procedure TimerUpdateStatusTimer(Sender: TObject);
@@ -156,13 +170,18 @@ type
     procedure TrayIconDblClick(Sender: TObject);
     procedure TrayIconDblClick(Sender: TObject);
     procedure ApplicationEventsMinimize(Sender: TObject);
     procedure ApplicationEventsMinimize(Sender: TObject);
     procedure bbSendAMessageClick(Sender: TObject);
     procedure bbSendAMessageClick(Sender: TObject);
+    procedure lblReceivedMessagesClick(Sender: TObject);
   private
   private
+    FMinersBlocksFound: Integer;
+    procedure SetMinersBlocksFound(const Value: Integer);
+    Procedure CheckIsReady;
   protected
   protected
     { Private declarations }
     { Private declarations }
     FNode : TNode;
     FNode : TNode;
     FIsActivated : Boolean;
     FIsActivated : Boolean;
     FWalletKeys : TWalletKeys;
     FWalletKeys : TWalletKeys;
     FLog : TLog;
     FLog : TLog;
+    FMaxCPUs : Integer;
     FAppParams : TAppParams;
     FAppParams : TAppParams;
     FNodeNotifyEvents : TNodeNotifyEvents;
     FNodeNotifyEvents : TNodeNotifyEvents;
     FAccountsGrid : TAccountsGrid;
     FAccountsGrid : TAccountsGrid;
@@ -171,12 +190,12 @@ type
     FOrderedAccountsKeyList : TOrderedAccountKeysList;
     FOrderedAccountsKeyList : TOrderedAccountKeysList;
     FOperationsDBGrid : TOperationsDBGrid;
     FOperationsDBGrid : TOperationsDBGrid;
     FBlockChainDBGrid : TBlockChainDBGrid;
     FBlockChainDBGrid : TBlockChainDBGrid;
-
+    FMinerPrivateKeyType : TMinerPrivateKey;
     FMemoNetConnections : TStringListAux;
     FMemoNetConnections : TStringListAux;
     FMemoBlackListNodes : TStringListAux;
     FMemoBlackListNodes : TStringListAux;
     FMemoAvailableNodeServers : TStringListAux;
     FMemoAvailableNodeServers : TStringListAux;
-
     FUpdating : Boolean;
     FUpdating : Boolean;
+    FMessagesUnreadCount : Integer;
     Procedure CheckMining;
     Procedure CheckMining;
     Procedure OnNewAccount(Sender : TObject);
     Procedure OnNewAccount(Sender : TObject);
     Procedure OnReceivedHelloResponse(Sender : TObject);
     Procedure OnReceivedHelloResponse(Sender : TObject);
@@ -200,9 +219,11 @@ type
     Procedure UpdateAvailableConnections;
     Procedure UpdateAvailableConnections;
     procedure Activate; override;
     procedure Activate; override;
     Function ForceMining : Boolean; virtual;
     Function ForceMining : Boolean; virtual;
+    Function GetAccountKeyForMiner : TAccountKey;
   public
   public
     { Public declarations }
     { Public declarations }
     Property WalletKeys : TWalletKeys read FWalletKeys;
     Property WalletKeys : TWalletKeys read FWalletKeys;
+    Property MinersBlocksFound : Integer read FMinersBlocksFound write SetMinersBlocksFound;
   end;
   end;
 
 
 var
 var
@@ -309,25 +330,33 @@ begin
 end;
 end;
 
 
 procedure TFRMWallet.bbSendAMessageClick(Sender: TObject);
 procedure TFRMWallet.bbSendAMessageClick(Sender: TObject);
-Var m : String;
+Var basem,m : String;
   them, errors : AnsiString;
   them, errors : AnsiString;
-  i : Integer;
+  i,n : Integer;
   nc : TNetConnection;
   nc : TNetConnection;
 begin
 begin
+  CheckIsReady;
   if (lbNetConnections.SelCount<=0) Or (lbNetConnections.ItemIndex<0) then raise Exception.Create('Select at least 1 connection');
   if (lbNetConnections.SelCount<=0) Or (lbNetConnections.ItemIndex<0) then raise Exception.Create('Select at least 1 connection');
-  if lbNetConnections.SelCount<=0 then i := 1
-  else i := lbNetConnections.SelCount;
+  if lbNetConnections.SelCount<=0 then n := 1
+  else n := lbNetConnections.SelCount;
+
+  basem := memoMessageToSend.Lines.Text;
+  m := '';
+  // Clear non valid characters:
+  for i := 1 to length(basem) do begin
+    if basem[i] in [#32..#127] then m := m + basem[i]
+    else m:=m+'.';
+  end;
 
 
-  m := memoMessageToSend.Lines.Text;
   if trim(m)='' then raise Exception.Create('No message');
   if trim(m)='' then raise Exception.Create('No message');
 
 
-  if Application.MessageBox(PChaR('Send this message to '+inttostr(i)+' nodes?'+#10+
+  if Application.MessageBox(PChaR('Send this message to '+inttostr(n)+' nodes?'+#10+
     'ALERT: Sending unauthorized messages will be considered spam and you will be banned'+#10+
     'ALERT: Sending unauthorized messages will be considered spam and you will be banned'+#10+
     #10+
     #10+
     'Message: '+#10+
     'Message: '+#10+
     m),PChar(Application.Title),MB_ICONQUESTION+MB_YESNO+MB_DEFBUTTON1)<>IdYes then exit;
     m),PChar(Application.Title),MB_ICONQUESTION+MB_YESNO+MB_DEFBUTTON1)<>IdYes then exit;
   them := m;
   them := m;
-  if i>1 then begin
+  if n>1 then begin
     for i := 0 to lbNetConnections.Items.Count - 1 do begin
     for i := 0 to lbNetConnections.Items.Count - 1 do begin
       if lbNetConnections.Selected[i] then begin
       if lbNetConnections.Selected[i] then begin
         nc := TNetConnection(lbNetconnections.Items.Objects[i]);
         nc := TNetConnection(lbNetconnections.Items.Objects[i]);
@@ -345,7 +374,7 @@ begin
     end;
     end;
   end;
   end;
 
 
-  Application.MessageBox(PChaR('Message sent to '+inttostr(i)+' nodes'+#10+
+  Application.MessageBox(PChaR('Message sent to '+inttostr(n)+' nodes'+#10+
     'Message: '+#10+m),PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
     'Message: '+#10+m),PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
 end;
 end;
 
 
@@ -354,11 +383,14 @@ begin
   if Not Assigned(FNode) then exit;
   if Not Assigned(FNode) then exit;
   if cbAllowMining.Checked then begin
   if cbAllowMining.Checked then begin
     if (TNetData.NetData.NetStatistics.ClientsConnections<=0) then begin
     if (TNetData.NetData.NetStatistics.ClientsConnections<=0) then begin
-      Application.MessageBox(PChar(Format('In order to Mine is necessary that you open your external port %d from the Internet to allow other nodes of Pascal Coin to connect to you.'+#10+
+      Application.MessageBox(PChar(Format(
+        'In order to Mine is necessary that you open your external port %d from the Internet to allow other nodes of Pascal Coin to connect to you.'+#10+
+        '(Note: This is not mandatory... but will work better with open ports)'+#10+
         #10+
         #10+
         'To do this you must configure your Router/Firewall and enable NAT to your local machine at port: %d'+#10+#10+
         'To do this you must configure your Router/Firewall and enable NAT to your local machine at port: %d'+#10+#10+
         'After allowing incoming connections... you must wait until other nodes connects to you to mine'+#10+
         'After allowing incoming connections... you must wait until other nodes connects to you to mine'+#10+
-        'Please... be patient'+#10+#10+
+        #10+
+        'PLEASE... BE PATIENT !!!'+#10+#10+
         'Help mining Pascal Coin and win Pascal Coins!',[FNode.NetServer.Port,FNode.NetServer.Port])),
         'Help mining Pascal Coin and win Pascal Coins!',[FNode.NetServer.Port,FNode.NetServer.Port])),
         PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
         PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
     end;
     end;
@@ -375,8 +407,7 @@ end;
 procedure TFRMWallet.cbExploreMyAccountsClick(Sender: TObject);
 procedure TFRMWallet.cbExploreMyAccountsClick(Sender: TObject);
 begin
 begin
   cbMyPrivateKeys.Enabled := cbExploreMyAccounts.Checked;
   cbMyPrivateKeys.Enabled := cbExploreMyAccounts.Checked;
-  if cbExploreMyAccounts.Checked then UpdateAccounts;
-  FAccountsGrid.ShowAllAccounts := Not cbExploreMyAccounts.Checked;
+  UpdateAccounts;
   UpdateOperations;
   UpdateOperations;
 end;
 end;
 
 
@@ -392,6 +423,16 @@ begin
   UpdateAccounts;
   UpdateAccounts;
 end;
 end;
 
 
+procedure TFRMWallet.CheckIsReady;
+Var isready : AnsiString;
+begin
+  if Not Assigned(FNode) then Abort;
+
+  if Not FNode.Node.IsReady(isready) then begin
+    Raise Exception.Create('You cannot do this operation now:'+#10+#10+isready);
+  end;
+end;
+
 procedure TFRMWallet.CheckMining;
 procedure TFRMWallet.CheckMining;
   Procedure Stop;
   Procedure Stop;
   var i : Integer;
   var i : Integer;
@@ -399,7 +440,7 @@ procedure TFRMWallet.CheckMining;
   begin
   begin
     if ForceMining then exit;
     if ForceMining then exit;
     // Stop mining
     // Stop mining
-    mtl := FNode.MinerThreads.LockList;
+    mtl := FNode.MinerThreads.LockList('TFRMWallet.CheckMining stop');
     try
     try
       for i:=mtl.Count-1 downto 0 do begin
       for i:=mtl.Count-1 downto 0 do begin
         TMinerThread(mtl[i]).Paused := true;
         TMinerThread(mtl[i]).Paused := true;
@@ -410,36 +451,32 @@ procedure TFRMWallet.CheckMining;
   end;
   end;
 Var i, n : Integer;
 Var i, n : Integer;
   MT : TMinerThread;
   MT : TMinerThread;
-  wk : TWalletKey;
-  EC : TECPrivateKey;
   mtl : TList;
   mtl : TList;
 begin
 begin
   if Not Assigned(FNode) then exit;
   if Not Assigned(FNode) then exit;
   if (ForceMining) Or
   if (ForceMining) Or
-    ((TNetData.NetData.NetStatistics.TotalClientsConnections>0) And (TNetData.NetData.NetStatistics.ActiveConnections>0) And
-    (TNetData.NetData.MaxRemoteOperationBlock.block<=FNode.Operations.OperationBlock.block)) then begin
+    (
+      (TNetData.NetData.NetStatistics.ActiveConnections>0) And
+      // Build 1.0.2 allows mine if there was at least 1 client connection (working as a server)
+      // or (new) there are 2 active connections to a servers (allowing non servers to mine too)
+      ( (TNetData.NetData.NetStatistics.TotalClientsConnections>0)
+        Or (TNetData.NetData.NetStatistics.ServersConnections>=2) ) And
+      (TNetData.NetData.MaxRemoteOperationBlock.block<=FNode.Operations.OperationBlock.block)
+    ) then begin
     if (cbAllowMining.checked) Or (ForceMining) then begin
     if (cbAllowMining.checked) Or (ForceMining) then begin
       n := 0;
       n := 0;
-      mtl := FNode.MinerThreads.LockList;
+      mtl := FNode.MinerThreads.LockList('TFRMWallet.CheckMining base');
       try
       try
         for i:=mtl.Count-1 downto 0 do begin
         for i:=mtl.Count-1 downto 0 do begin
           if TMinerThread(mtl[i]).Paused then TMinerThread(mtl[i]).Paused := false;
           if TMinerThread(mtl[i]).Paused then TMinerThread(mtl[i]).Paused := false;
           inc(n);
           inc(n);
         end;
         end;
-        if n=0 then begin
-          wk := CT_TWalletKey_NUL;
-          If FWalletKeys.Count>0 then begin
-            wk := FWalletKeys.Key[Random(FWalletKeys.Count)];
-          end;
-          if wk.CryptedKey='' then begin
-            EC := TECPrivateKey.Create;
-            EC.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
-            wk := FWalletKeys.Key[FWalletKeys.AddPrivateKey('New key '+DateTimeToStr(Now),EC)];
-          end;
-          if mtl.Count<=0 then MT := FNode.AddMiner(wk.AccountKey)
-          else MT := TMinerThread(mtl[0]);
+        if n<FMaxCPUs then begin
+          MT := FNode.AddMiner(GetAccountKeyForMiner);
           MT.OnNewAccountFound := OnMinerNewBlockFound;
           MT.OnNewAccountFound := OnMinerNewBlockFound;
           MT.Paused := false;
           MT.Paused := false;
+        end else begin
+          while (mtl.Count>FMaxCPUs) do FNode.DeleteMiner(mtl.Count-1);
         end;
         end;
       Finally
       Finally
         FNode.MinerThreads.UnlockList;
         FNode.MinerThreads.UnlockList;
@@ -557,6 +594,10 @@ end;
 procedure TFRMWallet.FormCreate(Sender: TObject);
 procedure TFRMWallet.FormCreate(Sender: TObject);
 Var i : Integer;
 Var i : Integer;
 begin
 begin
+  if CPUCount>1 then FMaxCPUs := CPUCount-1
+  else FMaxCPUs := 1;
+  FMessagesUnreadCount := 0;
+  lblReceivedMessages.Visible := false;
   FMemoNetConnections := TStringListAux.Create;
   FMemoNetConnections := TStringListAux.Create;
   FMemoBlackListNodes := TStringListAux.Create;
   FMemoBlackListNodes := TStringListAux.Create;
   FMemoAvailableNodeServers := TStringListAux.Create;
   FMemoAvailableNodeServers := TStringListAux.Create;
@@ -590,6 +631,7 @@ begin
   FPendingOperationsGrid := TOperationsGrid.Create(Self);
   FPendingOperationsGrid := TOperationsGrid.Create(Self);
   FPendingOperationsGrid.DrawGrid := dgPendingOperations;
   FPendingOperationsGrid.DrawGrid := dgPendingOperations;
   FPendingOperationsGrid.AccountNumber := -1; // all
   FPendingOperationsGrid.AccountNumber := -1; // all
+  FPendingOperationsGrid.PendingOperations := true;
   FWalletKeys.OnChanged := OnWalletChanged;
   FWalletKeys.OnChanged := OnWalletChanged;
   FOperationsDBGrid := TOperationsDBGrid.Create(Self);
   FOperationsDBGrid := TOperationsDBGrid.Create(Self);
   FBlockChainDBGrid := TBlockChainDBGrid.Create(Self);
   FBlockChainDBGrid := TBlockChainDBGrid.Create(Self);
@@ -614,6 +656,7 @@ begin
   TrayIcon.BalloonHint :=
   TrayIcon.BalloonHint :=
     'Double click the system tray icon to restore Pascal Coin';
     'Double click the system tray icon to restore Pascal Coin';
   TrayIcon.BalloonFlags := bfInfo;
   TrayIcon.BalloonFlags := bfInfo;
+  MinersBlocksFound := 0;
 end;
 end;
 
 
 procedure TFRMWallet.FormDestroy(Sender: TObject);
 procedure TFRMWallet.FormDestroy(Sender: TObject);
@@ -691,6 +734,46 @@ begin
   TLog.NewLog(ltinfo,Classname,'Destroying form - END');
   TLog.NewLog(ltinfo,Classname,'Destroying form - END');
 end;
 end;
 
 
+function TFRMWallet.GetAccountKeyForMiner: TAccountKey;
+Var PK : TECPrivateKey;
+  i : Integer;
+  PublicK : TECDSA_Public;
+begin
+  Result := CT_TECDSA_Public_Nul;
+  if Not Assigned(FWalletKeys) then exit;
+  if Not Assigned(FAppParams) then exit;
+  case FMinerPrivateKeyType of
+    mpk_NewEachTime: PublicK := CT_TECDSA_Public_Nul;
+    mpk_Selected: begin
+      PublicK := TAccountComp.RawString2Accountkey(FAppParams.ParamByName[CT_PARAM_MinerPrivateKeySelectedPublicKey].GetAsString(''));
+    end;
+  else
+    // Random
+    PublicK := CT_TECDSA_Public_Nul;
+    if FWalletKeys.Count>0 then PublicK := FWalletKeys.Key[Random(FWalletKeys.Count)].AccountKey;
+  end;
+  i := FWalletKeys.IndexOfAccountKey(PublicK);
+  if i>=0 then begin
+    if (FWalletKeys.Key[i].CryptedKey='') then i:=-1;
+  end;
+  if i<0 then begin
+    PK := TECPrivateKey.Create;
+    try
+      PK.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
+      FWalletKeys.AddPrivateKey('New for miner '+DateTimeToStr(Now), PK);
+      PublicK := PK.PublicKey;
+    finally
+      PK.Free;
+    end;
+  end;
+  Result := PublicK;
+end;
+
+procedure TFRMWallet.lblReceivedMessagesClick(Sender: TObject);
+begin
+  PageControl.ActivePage := tsMessages;
+end;
+
 procedure TFRMWallet.LoadAppParams;
 procedure TFRMWallet.LoadAppParams;
 Var ms : TMemoryStream;
 Var ms : TMemoryStream;
   s : AnsiString;
   s : AnsiString;
@@ -742,6 +825,7 @@ end;
 
 
 procedure TFRMWallet.miNewOperationClick(Sender: TObject);
 procedure TFRMWallet.miNewOperationClick(Sender: TObject);
 begin
 begin
+  CheckIsReady;
   With TFRMOperation.Create(Self) do
   With TFRMOperation.Create(Self) do
   Try
   Try
     SenderAccount := FAccountsGrid.AccountNumber(dgAccounts.Row);
     SenderAccount := FAccountsGrid.AccountNumber(dgAccounts.Row);
@@ -782,24 +866,9 @@ begin
 end;
 end;
 
 
 procedure TFRMWallet.OnMinerNewBlockFound(sender: TMinerThread; Operations: TPCOperationsComp);
 procedure TFRMWallet.OnMinerNewBlockFound(sender: TMinerThread; Operations: TPCOperationsComp);
-Var PK : TECPrivateKey;
-  i : Integer;
 begin
 begin
-  if FAppParams.ParamByName[CT_PARAM_NewPrivateKeyForEachGeneratedBlock].GetAsBoolean(false) then begin
-    PK := TECPrivateKey.Create;
-    try
-      PK.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
-      FWalletKeys.AddPrivateKey('New for miner '+DateTimeToStr(Now), PK);
-      sender.AccountKey := PK.PublicKey;
-    finally
-      PK.Free;
-    end;
-  end else begin
-    If (FWalletKeys.Count>1) then begin
-      i := Random(FWalletKeys.Count);
-      if Assigned(FWalletKeys.Key[i].PrivateKey) then sender.AccountKey := FWalletKeys.Key[i].AccountKey;
-    end;
-  end;
+  MinersBlocksFound := MinersBlocksFound+1;
+  Sender.AccountKey := GetAccountKeyForMiner;
 end;
 end;
 
 
 procedure TFRMWallet.OnNetBlackListUpdated(Sender: TObject);
 procedure TFRMWallet.OnNetBlackListUpdated(Sender: TObject);
@@ -809,7 +878,7 @@ Var i,j : integer;
  l : TList;
  l : TList;
  strings : TStrings;
  strings : TStrings;
 begin
 begin
-  l := TNetData.NetData.BlackList.LockList;
+  l := TNetData.NetData.BlackList.LockList('TFRMWallet.OnNetBlackListUpdated');
   try
   try
     strings := FMemoBlackListNodes;
     strings := FMemoBlackListNodes;
     strings.BeginUpdate;
     strings.BeginUpdate;
@@ -843,7 +912,7 @@ Var i : integer;
  l : TList;
  l : TList;
  strings, sNSC, sRS, sDisc : TStrings;
  strings, sNSC, sRS, sDisc : TStrings;
 begin
 begin
-  l := TNetData.NetData.NetConnections.LockList;
+  l := TNetData.NetData.NetConnections.LockList('TFRMWallet.OnNetConnectionsUpdated');
   try
   try
     strings := FMemoNetConnections;
     strings := FMemoNetConnections;
     sNSC := TStringList.Create;
     sNSC := TStringList.Create;
@@ -855,14 +924,14 @@ begin
         NC := l[i];
         NC := l[i];
         if NC.Connected then begin
         if NC.Connected then begin
           if NC is TNetServerClient then begin
           if NC is TNetServerClient then begin
-            sNSC.Add(Format('Client: IP:%s:%s Sent/Received:%d/%d Bytes',
-              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived]));
+            sNSC.Add(Format('Client: IP:%s:%s Sent/Received:%d/%d Bytes - Active since %s',
+              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived,DateTimeElapsedTime(NC.CreatedTime)]));
           end else begin
           end else begin
-            if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s:%s Sent/Received:%d/%d Bytes',
-              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived]))
+            if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s:%s Sent/Received:%d/%d Bytes - Active since %s',
+              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived,DateTimeElapsedTime(NC.CreatedTime)]))
             else begin
             else begin
-              sRS.Add(Format('Remote Server: IP:%s:%s Sent/Received:%d/%d Bytes',
-              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived]));
+              sRS.Add(Format('Remote Server: IP:%s:%s Sent/Received:%d/%d Bytes - Active since %s',
+              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived,DateTimeElapsedTime(NC.CreatedTime)]));
             end;
             end;
           end;
           end;
         end else begin
         end else begin
@@ -877,8 +946,8 @@ begin
       end;
       end;
       strings.Clear;
       strings.Clear;
       strings.Add(Format('Connections Updated %s Clients:%d Servers:%d',[DateTimeToStr(now),sNSC.Count,sRS.Count]));
       strings.Add(Format('Connections Updated %s Clients:%d Servers:%d',[DateTimeToStr(now),sNSC.Count,sRS.Count]));
-      strings.AddStrings(sNSC);
       strings.AddStrings(sRS);
       strings.AddStrings(sRS);
+      strings.AddStrings(sNSC);
       if sDisc.Count>0 then begin
       if sDisc.Count>0 then begin
         strings.Add('');
         strings.Add('');
         strings.Add('Disconnected connections: '+Inttostr(sDisc.Count));
         strings.Add('Disconnected connections: '+Inttostr(sDisc.Count));
@@ -903,27 +972,28 @@ Var i : integer;
  strings : TStrings;
  strings : TStrings;
  s : String;
  s : String;
 begin
 begin
-  l := TNetData.NetData.NodeServers.LockList;
+  l := TNetData.NetData.NodeServers.LockList('TFRMWallet.OnNetNodeServersUpdated');
   try
   try
     strings := FMemoAvailableNodeServers;
     strings := FMemoAvailableNodeServers;
     strings.BeginUpdate;
     strings.BeginUpdate;
     Try
     Try
       strings.Clear;
       strings.Clear;
-      strings.Add('NodeServers Updated: '+DateTimeToStr(now));
+      strings.Add('NodeServers Updated: '+DateTimeToStr(now) +' Count: '+inttostr(l.Count));
       for i := 0 to l.Count - 1 do begin
       for i := 0 to l.Count - 1 do begin
         P := l[i];
         P := l[i];
         s := Format('Server IP:%s:%d',[P^.ip,P^.port]);
         s := Format('Server IP:%s:%d',[P^.ip,P^.port]);
         if Assigned(P.netConnection) then begin
         if Assigned(P.netConnection) then begin
-          s := s+ ' ** ACTIVE **';
+          If P.last_connection>0 then  s := s+ ' ** ACTIVE **'
+          else s := s+' ** TRYING TO CONNECT **';
         end;
         end;
         if P.its_myself then begin
         if P.its_myself then begin
-          s := s+' ** DUPLICATE **';
+          s := s+' ** NOT VALID ** '+P.BlackListText;
         end;
         end;
         if P.last_connection>0 then begin
         if P.last_connection>0 then begin
           s := s + ' Last Connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection)));
           s := s + ' Last Connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection)));
         end;
         end;
-        if (Not Assigned(P.netConnection)) AND (P.last_attempt_to_connect>0) then begin
-          s := s + ' Attempting to connect: '+DateTimeToStr(P^.last_attempt_to_connect)+' (Attempts: '+inttostr(P^.total_failed_attemps_to_connect)+')';
+        if (P.last_attempt_to_connect>0) then begin
+          s := s + ' Last Attempt to connect: '+DateTimeToStr(P^.last_attempt_to_connect)+' (Attempts: '+inttostr(P^.total_failed_attemps_to_connect)+')';
         end;
         end;
         strings.Add(s);
         strings.Add(s);
       end;
       end;
@@ -979,9 +1049,10 @@ end;
 procedure TFRMWallet.OnNodeMessageEvent(NetConnection: TNetConnection; MessageData: TRawBytes);
 procedure TFRMWallet.OnNodeMessageEvent(NetConnection: TNetConnection; MessageData: TRawBytes);
 Var s : String;
 Var s : String;
 begin
 begin
-  s := DateTimeToStr(now)+' Received from '+NetConnection.Client.RemoteHost+':'+NetConnection.Client.RemotePort+' < ';
-  s := s + MessageData + ' (Hexadecimal: '+TCrypto.ToHexaString(MessageData)+') Length '+inttostr(Length(MessageData))+' bytes';
-  memoMessages.Lines.Add(s);
+  inc(FMessagesUnreadCount);
+  s := DateTimeToStr(now)+' Message received from '+NetConnection.Client.RemoteHost+':'+NetConnection.Client.RemotePort;
+  memoMessages.Lines.Add(DateTimeToStr(now)+' Message received from '+NetConnection.Client.RemoteHost+':'+NetConnection.Client.RemotePort+' Length '+inttostr(Length(MessageData))+' bytes');
+  memoMessages.Lines.Add('RECEIVED> '+MessageData);
   if FAppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false) then begin
   if FAppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false) then begin
     s := DateTimeToStr(now)+' Message from '+NetConnection.Client.RemoteHost+':'+NetConnection.Client.RemotePort+#10+
     s := DateTimeToStr(now)+' Message from '+NetConnection.Client.RemoteHost+':'+NetConnection.Client.RemotePort+#10+
        'Length '+inttostr(length(MessageData))+' bytes'+#10+#10;
        'Length '+inttostr(length(MessageData))+' bytes'+#10+#10;
@@ -993,6 +1064,9 @@ begin
     end;
     end;
     Application.MessageBox(PChar(s),PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
     Application.MessageBox(PChar(s),PChar(Application.Title),MB_ICONINFORMATION+MB_OK);
   end;
   end;
+  if FMessagesUnreadCount>1 then lblReceivedMessages.Caption := Format('You have received %d messages',[FMessagesUnreadCount])
+  else lblReceivedMessages.Caption := 'You have received 1 message';
+  lblReceivedMessages.Visible := true;
 end;
 end;
 
 
 procedure TFRMWallet.OnReceivedHelloResponse(Sender: TObject);
 procedure TFRMWallet.OnReceivedHelloResponse(Sender: TObject);
@@ -1008,22 +1082,24 @@ end;
 procedure TFRMWallet.PageControlChange(Sender: TObject);
 procedure TFRMWallet.PageControlChange(Sender: TObject);
 begin
 begin
   MiDecodePayload.Enabled := false;
   MiDecodePayload.Enabled := false;
-  if PageControl.ActivePage=tsOperations then begin
-    FOperationsDBGrid.Node := FNode;
+  if PageControl.ActivePage=tsAccountsExplorer then begin
+    FAccountsGrid.Node := FNode;
     MiDecodePayload.Enabled := true;
     MiDecodePayload.Enabled := true;
-  end else FOperationsDBGrid.Node := Nil;
-  if PageControl.ActivePage=tsBlockChain then FBlockChainDBGrid.Node := FNode
-  else FBlockChainDBGrid.Node := Nil;
+  end else FAccountsGrid.Node := Nil;
   if PageControl.ActivePage=tsPendingOperations then begin
   if PageControl.ActivePage=tsPendingOperations then begin
     FPendingOperationsGrid.Node := FNode;
     FPendingOperationsGrid.Node := FNode;
     MiDecodePayload.Enabled := true;
     MiDecodePayload.Enabled := true;
   end else FPendingOperationsGrid.Node := Nil;
   end else FPendingOperationsGrid.Node := Nil;
-  if PageControl.ActivePage=tsAccountsExplorer then begin
-    FAccountsGrid.Node := FNode;
+  if PageControl.ActivePage=tsBlockChain then FBlockChainDBGrid.Node := FNode
+  else FBlockChainDBGrid.Node := Nil;
+  if PageControl.ActivePage=tsOperations then begin
+    FOperationsDBGrid.Node := FNode;
     MiDecodePayload.Enabled := true;
     MiDecodePayload.Enabled := true;
-  end else FAccountsGrid.Node := Nil;
+  end else FOperationsDBGrid.Node := Nil;
   if PageControl.ActivePage=tsMessages then begin
   if PageControl.ActivePage=tsMessages then begin
     UpdateAvailableConnections;
     UpdateAvailableConnections;
+    FMessagesUnreadCount := 0;
+    lblReceivedMessages.Visible := false;
   end;
   end;
 end;
 end;
 
 
@@ -1043,23 +1119,38 @@ begin
   End;
   End;
 end;
 end;
 
 
+procedure TFRMWallet.SetMinersBlocksFound(const Value: Integer);
+begin
+  FMinersBlocksFound := Value;
+  lblBlocksFound.Caption := Inttostr(Value);
+  if Value>0 then lblBlocksFound.Font.Color := clGreen
+  else lblBlocksFound.Font.Color := clDkGray;
+end;
+
 procedure TFRMWallet.TimerUpdateStatusTimer(Sender: TObject);
 procedure TFRMWallet.TimerUpdateStatusTimer(Sender: TObject);
 begin
 begin
-  UpdateConnectionStatus;
-  UpdateBlockChainState;
-  UpdateNodeStatus;
-  If (FMemoNetConnections.UpdateCount=0) And (FMemoNetConnections.Count>0) then begin
-    memoNetConnections.Lines.Assign(FMemoNetConnections);
-    FMemoNetConnections.Clear;
-  end;
-  If (FMemoAvailableNodeServers.UpdateCount=0) And (FMemoAvailableNodeServers.Count>0) then begin
-    memoNetServers.Lines.Assign(FMemoAvailableNodeServers);
-    FMemoAvailableNodeServers.Clear;
-  end;
-  If (FMemoBlackListNodes.UpdateCount=0) And (FMemoBlackListNodes.Count>0) then begin
-    memoNetBlackLists.Lines.Assign(FMemoBlackListNodes);
-    FMemoBlackListNodes.Clear;
-  end;
+  Try
+    UpdateConnectionStatus;
+    UpdateBlockChainState;
+    UpdateNodeStatus;
+    If (FMemoNetConnections.UpdateCount=0) And (FMemoNetConnections.Count>0) then begin
+      memoNetConnections.Lines.Assign(FMemoNetConnections);
+      FMemoNetConnections.Clear;
+    end;
+    If (FMemoAvailableNodeServers.UpdateCount=0) And (FMemoAvailableNodeServers.Count>0) then begin
+      memoNetServers.Lines.Assign(FMemoAvailableNodeServers);
+      FMemoAvailableNodeServers.Clear;
+    end;
+    If (FMemoBlackListNodes.UpdateCount=0) And (FMemoBlackListNodes.Count>0) then begin
+      memoNetBlackLists.Lines.Assign(FMemoBlackListNodes);
+      FMemoBlackListNodes.Clear;
+    end;
+  Except
+    On E:Exception do begin
+      E.Message := 'Exception at TimerUpdate '+E.ClassName+': '+E.Message;
+      TLog.NewLog(lterror,ClassName,E.Message);
+    end;
+  End;
 end;
 end;
 
 
 procedure TFRMWallet.TrayIconDblClick(Sender: TObject);
 procedure TFRMWallet.TrayIconDblClick(Sender: TObject);
@@ -1076,13 +1167,25 @@ Var accl : TOrderedCardinalList;
   i,j,k : Integer;
   i,j,k : Integer;
 begin
 begin
   If Not Assigned(FOrderedAccountsKeyList) Then exit;
   If Not Assigned(FOrderedAccountsKeyList) Then exit;
-  accl := FAccountsGrid.LockAccountsList;
-  Try
-    accl.Clear;
-    if cbMyPrivateKeys.ItemIndex<0 then exit;
-    if cbMyPrivateKeys.ItemIndex=0 then begin
-      // All keys in the wallet
-      for i := 0 to FWalletKeys.Count - 1 do begin
+  FAccountsGrid.ShowAllAccounts := Not cbExploreMyAccounts.Checked;
+  if cbExploreMyAccounts.Checked then begin
+    accl := FAccountsGrid.LockAccountsList;
+    Try
+      accl.Clear;
+      if cbMyPrivateKeys.ItemIndex<0 then exit;
+      if cbMyPrivateKeys.ItemIndex=0 then begin
+        // All keys in the wallet
+        for i := 0 to FWalletKeys.Count - 1 do begin
+          j := FOrderedAccountsKeyList.IndexOfAccountKey(FWalletKeys[i].AccountKey);
+          if (j>=0) then begin
+            l := FOrderedAccountsKeyList.AccountKeyList[j];
+            for k := 0 to l.Count - 1 do begin
+              accl.Add(Cardinal(l[k]));
+            end;
+          end;
+        end;
+      end else begin
+        i := cbMyPrivateKeys.ItemIndex-1;
         j := FOrderedAccountsKeyList.IndexOfAccountKey(FWalletKeys[i].AccountKey);
         j := FOrderedAccountsKeyList.IndexOfAccountKey(FWalletKeys[i].AccountKey);
         if (j>=0) then begin
         if (j>=0) then begin
           l := FOrderedAccountsKeyList.AccountKeyList[j];
           l := FOrderedAccountsKeyList.AccountKeyList[j];
@@ -1091,19 +1194,15 @@ begin
           end;
           end;
         end;
         end;
       end;
       end;
-    end else begin
-      i := cbMyPrivateKeys.ItemIndex-1;
-      j := FOrderedAccountsKeyList.IndexOfAccountKey(FWalletKeys[i].AccountKey);
-      if (j>=0) then begin
-        l := FOrderedAccountsKeyList.AccountKeyList[j];
-        for k := 0 to l.Count - 1 do begin
-          accl.Add(Cardinal(l[k]));
-        end;
-      end;
-    end;
-  Finally
-    FAccountsGrid.UnlockAccountsList;
-  End;
+    Finally
+      FAccountsGrid.UnlockAccountsList;
+    End;
+    lblAccountsCount.Caption := inttostr(accl.Count);
+  end else begin
+    lblAccountsCount.Caption := inttostr(FNode.Bank.AccountsCount);
+  end;
+  // Show Totals:
+  lblAccountsBalance.Caption := TAccountComp.FormatMoney(FAccountsGrid.AccountsBalance);
   UpdateOperations;
   UpdateOperations;
 end;
 end;
 
 
@@ -1112,7 +1211,7 @@ Var i : integer;
  NC : TNetConnection;
  NC : TNetConnection;
  l : TList;
  l : TList;
 begin
 begin
-  l := TNetData.NetData.NetConnections.LockList;
+  l := TNetData.NetData.NetConnections.LockList('TFRMWallet.UpdateAvailableConnections');
   try
   try
     lbNetConnections.Items.BeginUpdate;
     lbNetConnections.Items.BeginUpdate;
     Try
     Try
@@ -1142,8 +1241,7 @@ end;
 procedure TFRMWallet.UpdateBlockChainState;
 procedure TFRMWallet.UpdateBlockChainState;
 Var isMining : boolean;
 Var isMining : boolean;
   hr : Int64;
   hr : Int64;
-  pc : Int64;
-  mc : Integer;
+  i,mc : Integer;
   s : String;
   s : String;
   mtl : TList;
   mtl : TList;
   f, favg : real;
   f, favg : real;
@@ -1169,13 +1267,15 @@ begin
         CT_CalcNewTargetBlocksAverage * 2 ,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage * 2)),
         CT_CalcNewTargetBlocksAverage * 2 ,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage * 2)),
         CT_CalcNewTargetBlocksAverage DIV 2,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage DIV 2)),
         CT_CalcNewTargetBlocksAverage DIV 2,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage DIV 2)),
         CT_CalcNewTargetBlocksAverage DIV 4,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage DIV 4))]);
         CT_CalcNewTargetBlocksAverage DIV 4,FormatFloat('0.0',FNode.Bank.GetActualTargetSecondsAverage(CT_CalcNewTargetBlocksAverage DIV 4))]);
-    mtl := FNode.MinerThreads.LockList;
+    mtl := FNode.MinerThreads.LockList('TFRMWallet.UpdateBlockChainState');
     try
     try
       mc := mtl.Count;
       mc := mtl.Count;
       If mc>0 then begin
       If mc>0 then begin
         isMining := Not TMinerThread(mtl[0]).Paused;
         isMining := Not TMinerThread(mtl[0]).Paused;
-        hr := TMinerThread(mtl[0]).HashRate;
-        pc := TMinerThread(mtl[0]).PlayCount;
+        hr := 0;
+        for i := 0 to mtl.Count - 1 do begin
+          hr := hr + TMinerThread(mtl[i]).HashRate;
+        end;
       end else isMining :=false;
       end else isMining :=false;
     finally
     finally
       FNode.MinerThreads.UnlockList;
       FNode.MinerThreads.UnlockList;
@@ -1193,7 +1293,7 @@ begin
   if isMining then begin
   if isMining then begin
     if mc>1 then s := inttostr(mc)+' Miners at '
     if mc>1 then s := inttostr(mc)+' Miners at '
     else s := 'Mining at ';
     else s := 'Mining at ';
-    lblMiningStatus.Caption := s +FormatFloat('0.0',hr / 1024)+' Kh/s Rounds: '+FormatFloat('0.0',pc / 1000000)+' G';
+    lblMiningStatus.Caption := s +FormatFloat('0.0',hr / 1024)+' Kh/s (R: '+FormatFloat('0.0',TMinerThread.AllMinersPlayCount / 1000000)+'G)';
     lblMiningStatus.Font.Color := clNavy
     lblMiningStatus.Font.Color := clNavy
   end else begin
   end else begin
     lblMiningStatus.Caption := 'Not mining';
     lblMiningStatus.Caption := 'Not mining';
@@ -1204,6 +1304,7 @@ end;
 
 
 procedure TFRMWallet.UpdateConfigChanged;
 procedure TFRMWallet.UpdateConfigChanged;
 Var wa : Boolean;
 Var wa : Boolean;
+  i : Integer;
 begin
 begin
   tsLogs.TabVisible := FAppParams.ParamByName[CT_PARAM_ShowLogs].GetAsBoolean(false);
   tsLogs.TabVisible := FAppParams.ParamByName[CT_PARAM_ShowLogs].GetAsBoolean(false);
   if (Not tsLogs.TabVisible) then begin
   if (Not tsLogs.TabVisible) then begin
@@ -1223,6 +1324,14 @@ begin
     FNode.NetServer.Active := wa;
     FNode.NetServer.Active := wa;
     FNode.Operations.BlockPayload := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
     FNode.Operations.BlockPayload := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
   end;
   end;
+  FMaxCPUs := FAppParams.ParamByName[CT_PARAM_MaxCPUs].GetAsInteger(1);
+  if FMaxCPUs>CPUCount then FMaxCPUs := CPUCount;
+  if FMaxCPUs<0 then FMaxCPUs := 0;
+
+  i := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random));
+  if (i>=Integer(Low(TMinerPrivatekey))) And (i<=Integer(High(TMinerPrivatekey))) then FMinerPrivateKeyType := TMinerPrivateKey(i)
+  else FMinerPrivateKeyType := mpk_Random;
+
   cbAllowMining.Checked :=  (FAppParams.ParamByName[CT_PARAM_AutomaticMineWhenConnectedToNodes].GetAsBoolean(true));
   cbAllowMining.Checked :=  (FAppParams.ParamByName[CT_PARAM_AutomaticMineWhenConnectedToNodes].GetAsBoolean(true));
 end;
 end;
 
 
@@ -1318,4 +1427,6 @@ begin
   else if cbMyPrivateKeys.Items.Count>=0 then cbMyPrivateKeys.ItemIndex := 0;
   else if cbMyPrivateKeys.Items.Count>=0 then cbMyPrivateKeys.ItemIndex := 0;
 end;
 end;
 
 
+initialization
+  FRMWallet := Nil;
 end.
 end.

+ 1 - 1
Units/PascalCoin/UAccounts.pas

@@ -851,7 +851,7 @@ begin
     TLog.NewLog(lterror,Classname,'IS LOCKED !!!');
     TLog.NewLog(lterror,Classname,'IS LOCKED !!!');
     raise Exception.Create('IS LOCKED !!!');
     raise Exception.Create('IS LOCKED !!!');
   end;
   end;
-  TPCThread.ProtectEnterCriticalSection(Self,FLock);
+  TPCThread.ProtectEnterCriticalSection(Self,'StartThreadSafe',FLock);
   FIsLocked := true;
   FIsLocked := true;
 end;
 end;
 
 

+ 37 - 35
Units/PascalCoin/UBlockChain.pas

@@ -16,7 +16,7 @@
 interface
 interface
 
 
 uses
 uses
-  Classes, UCrypto, UAccounts, Windows, ULog;
+  Classes, UCrypto, UAccounts, Windows, ULog, UThread;
 
 
 
 
 Type
 Type
@@ -147,7 +147,7 @@ Type
 
 
   TOperationsHashTree = Class
   TOperationsHashTree = Class
   private
   private
-    FHashTreeOperations : TThreadList;
+    FHashTreeOperations : TPCThreadList;
     FHashTree: TRawBytes;
     FHashTree: TRawBytes;
     Procedure InternalAddOperationToHashTree(list : TList; op : TPCOperation);
     Procedure InternalAddOperationToHashTree(list : TList; op : TPCOperation);
   public
   public
@@ -171,6 +171,7 @@ Type
     FDigest_Basic : TRawBytes;
     FDigest_Basic : TRawBytes;
     FDigest_Operations : TRawBytes;
     FDigest_Operations : TRawBytes;
     FIsOnlyOperationBlock: Boolean;
     FIsOnlyOperationBlock: Boolean;
+    FStreamPoW : TMemoryStream;
     function GetOperation(index: Integer): TPCOperation;
     function GetOperation(index: Integer): TPCOperation;
     procedure SetBank(const value: TPCBank);
     procedure SetBank(const value: TPCBank);
     procedure SetnOnce(const value: Cardinal);
     procedure SetnOnce(const value: Cardinal);
@@ -181,7 +182,7 @@ Type
     function GetAccountKey: TAccountKey;
     function GetAccountKey: TAccountKey;
     Procedure Calc_Digest_Basic;
     Procedure Calc_Digest_Basic;
     Procedure Calc_Digest_Operations;
     Procedure Calc_Digest_Operations;
-    Function CalcProofOfWork(fullcalculation : Boolean): TRawBytes;
+    Procedure CalcProofOfWork(fullcalculation : Boolean; var PoW: TRawBytes);
     function GetBlockPayload: TRawBytes;
     function GetBlockPayload: TRawBytes;
     procedure SetBlockPayload(const Value: TRawBytes);
     procedure SetBlockPayload(const Value: TRawBytes);
   protected
   protected
@@ -323,7 +324,7 @@ implementation
 uses
 uses
   Messages, SysUtils, Variants, Graphics, Controls, Forms,
   Messages, SysUtils, Variants, Graphics, Controls, Forms,
   Dialogs, StdCtrls,
   Dialogs, StdCtrls,
-  UTime, UConst, UThread;
+  UTime, UConst;
 
 
 { TPCBank }
 { TPCBank }
 
 
@@ -337,7 +338,7 @@ Var
   buffer, pow: AnsiString;
   buffer, pow: AnsiString;
   i : Integer;
   i : Integer;
 begin
 begin
-  TPCThread.ProtectEnterCriticalSection(Self,FBankLock);
+  TPCThread.ProtectEnterCriticalSection(Self,'AddNewBlockChainBlock',FBankLock);
   Try
   Try
     Result := False;
     Result := False;
     errors := '';
     errors := '';
@@ -516,7 +517,7 @@ begin
     TLog.NewLog(lterror,Classname,'Is Restoring!!!');
     TLog.NewLog(lterror,Classname,'Is Restoring!!!');
     raise Exception.Create('Is restoring!');
     raise Exception.Create('Is restoring!');
   end;
   end;
-  TPCThread.ProtectEnterCriticalSection(Self,FBankLock);
+  TPCThread.ProtectEnterCriticalSection(Self,'DiskRestoreFromOperations',FBankLock);
   try
   try
     FIsRestoringFromFile := true;
     FIsRestoringFromFile := true;
     try
     try
@@ -705,7 +706,7 @@ begin
   Clear;
   Clear;
   Result := SafeBox.LoadFromStream(Stream,LastReadBlock,errors);
   Result := SafeBox.LoadFromStream(Stream,LastReadBlock,errors);
   if Result then begin
   if Result then begin
-    TPCThread.ProtectEnterCriticalSection(Self,FBankLock);
+    TPCThread.ProtectEnterCriticalSection(Self,'LoadFromStream',FBankLock);
     try
     try
       op := TPCOperationsComp.Create(Self);
       op := TPCOperationsComp.Create(Self);
       try
       try
@@ -735,7 +736,7 @@ end;
 
 
 function TPCBank.LoadOperations(Operations: TPCOperationsComp; Block: Cardinal): Boolean;
 function TPCBank.LoadOperations(Operations: TPCOperationsComp; Block: Cardinal): Boolean;
 begin
 begin
-  TPCThread.ProtectEnterCriticalSection(Self,FBankLock);
+  TPCThread.ProtectEnterCriticalSection(Self,'LoadOperations',FBankLock);
   try
   try
     Result := Storage.LoadBlockChainBlock(Operations,Block);
     Result := Storage.LoadBlockChainBlock(Operations,Block);
   finally
   finally
@@ -899,23 +900,19 @@ begin
   end;
   end;
 end;
 end;
 
 
-function TPCOperationsComp.CalcProofOfWork(fullcalculation : Boolean): TRawBytes;
-Var ms : TMemoryStream;
+Procedure TPCOperationsComp.CalcProofOfWork(fullcalculation : Boolean; var PoW: TRawBytes);
 begin
 begin
   if fullcalculation then begin
   if fullcalculation then begin
     Calc_Digest_Basic;
     Calc_Digest_Basic;
     Calc_Digest_Operations;
     Calc_Digest_Operations;
   end;
   end;
-  ms := TMemoryStream.Create;
-  try
-    ms.WriteBuffer(FDigest_Basic[1],length(FDigest_Basic));
-    ms.WriteBuffer(FDigest_Operations[1],length(FDigest_Operations));
-    ms.Write(FOperationBlock.timestamp,4);
-    ms.Write(FOperationBlock.nonce,4);
-    Result := TCrypto.DoDoubleSha256(ms.Memory,ms.Size);
-  finally
-    ms.Free;
-  end;
+  // New at Build 1.0.2 to increase Hashing Speed instead of creating TMemoryStream due Delphi memory creation is slowly...
+  FStreamPoW.Position := 0;
+  FStreamPoW.WriteBuffer(FDigest_Basic[1],length(FDigest_Basic));
+  FStreamPoW.WriteBuffer(FDigest_Operations[1],length(FDigest_Operations));
+  FStreamPoW.Write(FOperationBlock.timestamp,4);
+  FStreamPoW.Write(FOperationBlock.nonce,4);
+  TCrypto.DoDoubleSha256(FStreamPoW.Memory,length(FDigest_Basic)+length(FDigest_Operations)+8,PoW);
 end;
 end;
 
 
 procedure TPCOperationsComp.Calc_Digest_Basic;
 procedure TPCOperationsComp.Calc_Digest_Basic;
@@ -989,7 +986,7 @@ begin
     FOperationBlock.protocol_available := CT_Protocol_Available;
     FOperationBlock.protocol_available := CT_Protocol_Available;
     FIsOnlyOperationBlock := false;
     FIsOnlyOperationBlock := false;
   Finally
   Finally
-    FOperationBlock.proof_of_work := CalcProofOfWork(true);
+    CalcProofOfWork(true,FOperationBlock.proof_of_work);
   End;
   End;
 end;
 end;
 
 
@@ -1033,7 +1030,7 @@ begin
   FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
   FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
   FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
   FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
   // Recalc all
   // Recalc all
-  FOperationBlock.proof_of_work := CalcProofOfWork(true);
+  CalcProofOfWork(true,FOperationBlock.proof_of_work);
 end;
 end;
 
 
 function TPCOperationsComp.Count: Integer;
 function TPCOperationsComp.Count: Integer;
@@ -1044,6 +1041,10 @@ end;
 constructor TPCOperationsComp.Create(AOwner: TComponent);
 constructor TPCOperationsComp.Create(AOwner: TComponent);
 begin
 begin
   inherited;
   inherited;
+  // New at Build 1.0.2
+  FStreamPoW := TMemoryStream.Create;
+  FStreamPoW.Position := 0;
+
   FOperationsHashTree := TOperationsHashTree.Create;
   FOperationsHashTree := TOperationsHashTree.Create;
   FBank := Nil;
   FBank := Nil;
   FOperationBlock := GetFirstBlock;
   FOperationBlock := GetFirstBlock;
@@ -1058,6 +1059,7 @@ begin
   Clear(true);
   Clear(true);
   FOperationsHashTree.Free;
   FOperationsHashTree.Free;
   FSafeBoxTransaction.Free;
   FSafeBoxTransaction.Free;
+  FStreamPoW.Free;
   inherited;
   inherited;
 end;
 end;
 
 
@@ -1315,7 +1317,7 @@ begin
       FOperationsHashTree := aux;
       FOperationsHashTree := aux;
     End;
     End;
   Finally
   Finally
-    FOperationBlock.proof_of_work := CalcProofOfWork(true);
+    CalcProofOfWork(true,FOperationBlock.proof_of_work);
   End;
   End;
   if (n>0) then begin
   if (n>0) then begin
     TLog.NewLog(ltdebug,Classname,Format('Sanitize operations (before %d - after %d)',[lastn,n]));
     TLog.NewLog(ltdebug,Classname,Format('Sanitize operations (before %d - after %d)',[lastn,n]));
@@ -1393,20 +1395,20 @@ begin
   if Value=FOperationBlock.block_payload then exit;
   if Value=FOperationBlock.block_payload then exit;
   if Length(Value)>CT_MaxPayloadSize then Exit;
   if Length(Value)>CT_MaxPayloadSize then Exit;
   FOperationBlock.block_payload := Value;
   FOperationBlock.block_payload := Value;
-  FOperationBlock.proof_of_work := CalcProofOfWork(true);
+  CalcProofOfWork(true,FOperationBlock.proof_of_work);
 end;
 end;
 
 
 procedure TPCOperationsComp.SetnOnce(const value: Cardinal);
 procedure TPCOperationsComp.SetnOnce(const value: Cardinal);
 begin
 begin
   FOperationBlock.nonce := value;
   FOperationBlock.nonce := value;
-  FOperationBlock.proof_of_work := CalcProofOfWork(false);
+  CalcProofOfWork(false,FOperationBlock.proof_of_work);
 end;
 end;
 
 
 procedure TPCOperationsComp.Settimestamp(const value: Cardinal);
 procedure TPCOperationsComp.Settimestamp(const value: Cardinal);
 begin
 begin
   if FOperationBlock.timestamp=Value then exit; // No change, nothing to do
   if FOperationBlock.timestamp=Value then exit; // No change, nothing to do
   FOperationBlock.timestamp := value;
   FOperationBlock.timestamp := value;
-  FOperationBlock.proof_of_work := CalcProofOfWork(false);
+  CalcProofOfWork(false,FOperationBlock.proof_of_work);
 end;
 end;
 
 
 procedure TPCOperationsComp.UpdateTimestamp;
 procedure TPCOperationsComp.UpdateTimestamp;
@@ -1433,7 +1435,7 @@ begin
       exit;
       exit;
     end;
     end;
   end;
   end;
-  FOperationBlock.proof_of_work := CalcProofOfWork(true);
+  CalcProofOfWork(true,FOperationBlock.proof_of_work);
   if Not AnsiSameStr(OperationBlock.proof_of_work,lastpow) then begin
   if Not AnsiSameStr(OperationBlock.proof_of_work,lastpow) then begin
     errors := 'Invalid Proof of work calculation';
     errors := 'Invalid Proof of work calculation';
     exit;
     exit;
@@ -1507,7 +1509,7 @@ end;
 procedure TOperationsHashTree.AddOperationToHashTree(op: TPCOperation);
 procedure TOperationsHashTree.AddOperationToHashTree(op: TPCOperation);
 Var l : TList;
 Var l : TList;
 begin
 begin
-  l := FHashTreeOperations.LockList;
+  l := FHashTreeOperations.LockList('TOperationsHashTree.AddOperationToHashTree');
   try
   try
     InternalAddOperationToHashTree(l,op);
     InternalAddOperationToHashTree(l,op);
   finally
   finally
@@ -1520,7 +1522,7 @@ var op : TPCOperation;
   l : TList;
   l : TList;
   i : Integer;
   i : Integer;
 begin
 begin
-  l := FHashTreeOperations.LockList;
+  l := FHashTreeOperations.LockList('TOperationsHashTree.ClearHastThree');
   try
   try
     Try
     Try
       for i := 0 to l.Count - 1 do begin
       for i := 0 to l.Count - 1 do begin
@@ -1547,8 +1549,8 @@ begin
   end;
   end;
 
 
   ClearHastThree;
   ClearHastThree;
-  lme := FHashTreeOperations.LockList;
-  lsender := Sender.FHashTreeOperations.LockList;
+  lme := FHashTreeOperations.LockList('TOperationsHashTree.CopyFromHashTree me');
+  lsender := Sender.FHashTreeOperations.LockList('TOperationsHashTree.CopyFromHashTree sender');
   try
   try
     ms := TMemoryStream.Create;
     ms := TMemoryStream.Create;
     Try
     Try
@@ -1573,7 +1575,7 @@ end;
 constructor TOperationsHashTree.Create;
 constructor TOperationsHashTree.Create;
 begin
 begin
   FHashTree := TCrypto.DoSha256('');
   FHashTree := TCrypto.DoSha256('');
-  FHashTreeOperations := TThreadList.Create;
+  FHashTreeOperations := TPCThreadList.Create;
 end;
 end;
 
 
 destructor TOperationsHashTree.Destroy;
 destructor TOperationsHashTree.Destroy;
@@ -1586,7 +1588,7 @@ end;
 function TOperationsHashTree.GetOperation(index: Integer): TPCOperation;
 function TOperationsHashTree.GetOperation(index: Integer): TPCOperation;
 Var l : TList;
 Var l : TList;
 begin
 begin
-  l := FHashTreeOperations.LockList;
+  l := FHashTreeOperations.LockList('TOperationsHashTree.GetOperation');
   try
   try
     Result := TPCOperation(l[index]);
     Result := TPCOperation(l[index]);
   finally
   finally
@@ -1600,7 +1602,7 @@ Var l,intl : TList;
   i,j : Integer;
   i,j : Integer;
 begin
 begin
   List.Clear;
   List.Clear;
-  l := FHashTreeOperations.LockList;
+  l := FHashTreeOperations.LockList('TOperationsHashTree.GetOperationsAffectingAccount');
   try
   try
     intl := TList.Create;
     intl := TList.Create;
     try
     try
@@ -1641,7 +1643,7 @@ end;
 function TOperationsHashTree.OperationsCount: Integer;
 function TOperationsHashTree.OperationsCount: Integer;
 Var l : TList;
 Var l : TList;
 begin
 begin
-  l := FHashTreeOperations.LockList;
+  l := FHashTreeOperations.LockList('TOperationsHashTree.OperationsCount');
   try
   try
     Result := l.Count;
     Result := l.Count;
   finally
   finally

+ 15 - 0
Units/PascalCoin/UCrypto.pas

@@ -66,6 +66,7 @@ Type
     Class function DoSha256(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
     Class function DoSha256(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
     Class function DoSha256(const TheMessage : AnsiString) : TRawBytes; overload;
     Class function DoSha256(const TheMessage : AnsiString) : TRawBytes; overload;
     Class function DoDoubleSha256(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
     Class function DoDoubleSha256(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
+    Class procedure DoDoubleSha256(p : PAnsiChar; plength : Cardinal; Var ResultSha256 : TRawBytes); overload;
     Class function DoDoubleSha256(const TheMessage : AnsiString) : TRawBytes; overload;
     Class function DoDoubleSha256(const TheMessage : AnsiString) : TRawBytes; overload;
     Class function DoRipeMD160(const TheMessage : AnsiString) : TRawBytes;
     Class function DoRipeMD160(const TheMessage : AnsiString) : TRawBytes;
     Class function PrivateKey2Hexa(Key : PEC_KEY) : AnsiString;
     Class function PrivateKey2Hexa(Key : PEC_KEY) : AnsiString;
@@ -331,6 +332,20 @@ begin
   FreeMem(PS1,32);
   FreeMem(PS1,32);
 end;
 end;
 
 
+{ New at Build 1.0.2
+  Note: Delphi is slowly when working with Strings (allowing space)... so to
+  increase speed we use a String as a pointer, and only increase speed if
+  needed. Also the same with functions "GetMem" and "FreeMem" }
+class procedure TCrypto.DoDoubleSha256(p: PAnsiChar; plength: Cardinal; var ResultSha256: TRawBytes);
+Var PS : PAnsiChar;
+  PC : PAnsiChar;
+begin
+  If length(ResultSha256)<>32 then SetLength(ResultSha256,32);
+  PS := @ResultSha256[1];
+  SHA256(p,plength,PS);
+  SHA256(PS,32,PS);
+end;
+
 class function TCrypto.DoRipeMD160(const TheMessage: AnsiString): TRawBytes;
 class function TCrypto.DoRipeMD160(const TheMessage: AnsiString): TRawBytes;
 Var PS : PAnsiChar;
 Var PS : PAnsiChar;
   PC : PAnsiChar;
   PC : PAnsiChar;

+ 8 - 9
Units/PascalCoin/UDBStorage.pas

@@ -37,7 +37,7 @@ interface
 
 
 uses
 uses
   UBlockChain, Classes, db, ADODB, SysUtils, UAccounts, ULog, Variants, UCrypto,
   UBlockChain, Classes, db, ADODB, SysUtils, UAccounts, ULog, Variants, UCrypto,
-  UConst, UOpTransaction;
+  UConst, UOpTransaction, UThread;
 
 
 Const
 Const
   CT_TblName_BlockChain = 'tblockchain';
   CT_TblName_BlockChain = 'tblockchain';
@@ -75,7 +75,6 @@ Const
   CT_TblFld_Operations_fee = 'fee';
   CT_TblFld_Operations_fee = 'fee';
   CT_TblFld_Operations_balance = 'balance';
   CT_TblFld_Operations_balance = 'balance';
   CT_TblFld_Operations_rawpayload = 'payload';
   CT_TblFld_Operations_rawpayload = 'payload';
-//  CT_TblFld_Operations_payload_stream = 'payload_stream';
   CT_TblFld_Operations_newaccountkey = 'newaccountkey';
   CT_TblFld_Operations_newaccountkey = 'newaccountkey';
   CT_TblFld_Operations_orphan = 'orphan';
   CT_TblFld_Operations_orphan = 'orphan';
 
 
@@ -104,7 +103,7 @@ Type
 
 
   TOperationsResumeList = Class
   TOperationsResumeList = Class
   private
   private
-    FList : TThreadList;
+    FList : TPCThreadList;
     function GetOperationResume(index: Integer): TOperationResume;
     function GetOperationResume(index: Integer): TOperationResume;
   public
   public
     Constructor Create;
     Constructor Create;
@@ -934,7 +933,7 @@ Var P : POperationResume;
 begin
 begin
   New(P);
   New(P);
   P^ := OperationResume;
   P^ := OperationResume;
-  FList.Add(P);
+  FList.Add(P,'TOperationsResumeList.Add');
 end;
 end;
 
 
 procedure TOperationsResumeList.Clear;
 procedure TOperationsResumeList.Clear;
@@ -942,7 +941,7 @@ Var P : POperationResume;
   i : Integer;
   i : Integer;
   l : TList;
   l : TList;
 begin
 begin
-  l := FList.LockList;
+  l := FList.LockList('TOperationsResumeList.Clear');
   try
   try
     for i := 0 to l.Count - 1 do begin
     for i := 0 to l.Count - 1 do begin
       P := l[i];
       P := l[i];
@@ -957,7 +956,7 @@ end;
 function TOperationsResumeList.Count: Integer;
 function TOperationsResumeList.Count: Integer;
 Var l : TList;
 Var l : TList;
 begin
 begin
-  l := FList.LockList;
+  l := FList.LockList('TOperationsResumeList.Count');
   Try
   Try
     Result := l.Count;
     Result := l.Count;
   Finally
   Finally
@@ -967,14 +966,14 @@ end;
 
 
 constructor TOperationsResumeList.Create;
 constructor TOperationsResumeList.Create;
 begin
 begin
-  FList := TThreadList.Create;
+  FList := TPCThreadList.Create;
 end;
 end;
 
 
 procedure TOperationsResumeList.Delete(index: Integer);
 procedure TOperationsResumeList.Delete(index: Integer);
 Var P : POperationResume;
 Var P : POperationResume;
   l : TList;
   l : TList;
 begin
 begin
-  l := FList.LockList;
+  l := FList.LockList('TOperationsResumeList.Delete');
   Try
   Try
     P := l[index];
     P := l[index];
     l.Delete(index);
     l.Delete(index);
@@ -994,7 +993,7 @@ end;
 function TOperationsResumeList.GetOperationResume(index: Integer): TOperationResume;
 function TOperationsResumeList.GetOperationResume(index: Integer): TOperationResume;
 Var l : TList;
 Var l : TList;
 begin
 begin
-  l := FList.LockList;
+  l := FList.LockList('TOperationsResumeList.GetOperationResume');
   try
   try
     if index<l.Count then Result := POperationResume(l[index])^
     if index<l.Count then Result := POperationResume(l[index])^
     else Result := CT_TOperationResume_NUL;
     else Result := CT_TOperationResume_NUL;

+ 20 - 4
Units/PascalCoin/UMiner.pas

@@ -53,14 +53,17 @@ Type
     Property AccountKey : TAccountKey read FAccountKey write SetAccountKey;
     Property AccountKey : TAccountKey read FAccountKey write SetAccountKey;
     Property Paused : Boolean read FPaused Write FPaused;
     Property Paused : Boolean read FPaused Write FPaused;
     Function HashRate : Int64;
     Function HashRate : Int64;
+    Class function AllMinersPlayCount : Int64;
   End;
   End;
 
 
 implementation
 implementation
 
 
-uses UNode, ULog, SysUtils, UConst, UOpTransaction;
+uses UNode, ULog, SysUtils, UConst, UOpTransaction, UCrypto;
 
 
 { TMinerThread }
 { TMinerThread }
 
 
+var _all_miners_play_count : Int64;
+
 procedure TMinerThread.CheckIfCanRecoverBlocks;
 procedure TMinerThread.CheckIfCanRecoverBlocks;
 Var n_account : Cardinal;
 Var n_account : Cardinal;
   recover_block : Cardinal;
   recover_block : Cardinal;
@@ -103,9 +106,15 @@ begin
   FOperations.AccountKey := AccountKey;
   FOperations.AccountKey := AccountKey;
   FOnNewAccountFound := AOnNewAccountFound;
   FOnNewAccountFound := AOnNewAccountFound;
   FOnErrorFound := AOnErrorFound;
   FOnErrorFound := AOnErrorFound;
+  Priority := tpLower;
   Suspended := false;
   Suspended := false;
 end;
 end;
 
 
+class function TMinerThread.AllMinersPlayCount: Int64;
+begin
+  Result := _all_miners_play_count;
+end;
+
 procedure TMinerThread.BCExecute;
 procedure TMinerThread.BCExecute;
 Var i : Integer;
 Var i : Integer;
   winner : Boolean;
   winner : Boolean;
@@ -120,16 +129,20 @@ begin
     Try
     Try
       if Terminated then exit;
       if Terminated then exit;
       winner := false;
       winner := false;
-      TPCThread.ProtectEnterCriticalSection(Self,FLock);
+      TPCThread.ProtectEnterCriticalSection(Self,'Mining process',FLock);
       try
       try
         FOperations.UpdateTimestamp;
         FOperations.UpdateTimestamp;
         FOperations.AccountKey := FAccountKey;
         FOperations.AccountKey := FAccountKey;
-        for I := 0 to 50000 do begin
+        for i := 0 to 100000 do begin
           inc(FPlayCount);
           inc(FPlayCount);
+          inc(_all_miners_play_count);
+          if Terminated then exit;
+
           if FOperations.IncrementNOnce then begin
           if FOperations.IncrementNOnce then begin
             winner := true;
             winner := true;
             break;
             break;
           end;
           end;
+
         end;
         end;
       finally
       finally
         LeaveCriticalSection(FLock);
         LeaveCriticalSection(FLock);
@@ -174,7 +187,7 @@ end;
 
 
 function TMinerThread.MinerLockOperations: TPCOperationsComp;
 function TMinerThread.MinerLockOperations: TPCOperationsComp;
 begin
 begin
-  TPCThread.ProtectEnterCriticalSection(Self,FLock);
+  TPCThread.ProtectEnterCriticalSection(Self,'MinerLockOperations',FLock);
   Result := FOperations;
   Result := FOperations;
 end;
 end;
 
 
@@ -199,4 +212,7 @@ begin
   if assigned(FOnNewAccountFound) then FOnNewAccountFound(self,FOperations);
   if assigned(FOnNewAccountFound) then FOnNewAccountFound(self,FOperations);
 end;
 end;
 
 
+initialization
+  _all_miners_play_count := 0;
+finalization
 end.
 end.

+ 153 - 90
Units/PascalCoin/UNetProtocol.pas

@@ -80,6 +80,7 @@ Type
     ip : AnsiString;
     ip : AnsiString;
     port : Word;
     port : Word;
     last_connection : Cardinal;
     last_connection : Cardinal;
+    last_connection_by_server : Cardinal;
     //
     //
     netConnection : TNetConnection;
     netConnection : TNetConnection;
     its_myself : Boolean;
     its_myself : Boolean;
@@ -123,11 +124,11 @@ Type
   TNetData = Class(TComponent)
   TNetData = Class(TComponent)
   private
   private
     FNodePrivateKey : TECPrivateKey;
     FNodePrivateKey : TECPrivateKey;
-    FNetConnections : TThreadList;
-    FNodeServers : TThreadList;
-    FBlackList : TThreadList;
+    FNetConnections : TPCThreadList;
+    FNodeServers : TPCThreadList;
+    FBlackList : TPCThreadList;
     FLastRequestId : Cardinal;
     FLastRequestId : Cardinal;
-    FRegisteredRequests : TThreadList;
+    FRegisteredRequests : TPCThreadList;
     FIsDiscoveringServers : Boolean;
     FIsDiscoveringServers : Boolean;
     FIsGettingNewBlockChainFromClient : Boolean;
     FIsGettingNewBlockChainFromClient : Boolean;
     FOnNetConnectionsUpdated: TNotifyEvent;
     FOnNetConnectionsUpdated: TNotifyEvent;
@@ -165,6 +166,8 @@ Type
     Function ConnectionsCount(CountOnlyNetClients : Boolean) : Integer;
     Function ConnectionsCount(CountOnlyNetClients : Boolean) : Integer;
     Function Connection(index : Integer) : TNetConnection;
     Function Connection(index : Integer) : TNetConnection;
     Function ConnectionExists(ObjectPointer : TObject) : Boolean;
     Function ConnectionExists(ObjectPointer : TObject) : Boolean;
+    Function ConnectionsLock : TList;
+    Procedure ConnectionsUnlock;
     Function FindConnectionByClientRandomValue(Sender : TNetConnection) : TNetConnection;
     Function FindConnectionByClientRandomValue(Sender : TNetConnection) : TNetConnection;
     Procedure DiscoverServers;
     Procedure DiscoverServers;
     Procedure DisconnectClients;
     Procedure DisconnectClients;
@@ -172,9 +175,9 @@ Type
     Property OnNetConnectionsUpdated : TNotifyEvent read FOnNetConnectionsUpdated write FOnNetConnectionsUpdated;
     Property OnNetConnectionsUpdated : TNotifyEvent read FOnNetConnectionsUpdated write FOnNetConnectionsUpdated;
     Property OnNodeServersUpdated : TNotifyEvent read FOnNodeServersUpdated write FOnNodeServersUpdated;
     Property OnNodeServersUpdated : TNotifyEvent read FOnNodeServersUpdated write FOnNodeServersUpdated;
     Property OnBlackListUpdated : TNotifyEvent read FOnBlackListUpdated write FOnBlackListUpdated;
     Property OnBlackListUpdated : TNotifyEvent read FOnBlackListUpdated write FOnBlackListUpdated;
-    Property BlackList : TThreadList read FBlackList;
-    Property NodeServers : TThreadList read FNodeServers;
-    Property NetConnections : TThreadList read FNetConnections;
+    Property BlackList : TPCThreadList read FBlackList;
+    Property NodeServers : TPCThreadList read FNodeServers;
+    Property NetConnections : TPCThreadList read FNetConnections;
     Property OnReceivedHelloResponse : TNotifyEvent read FOnReceivedHelloResponse write FOnReceivedHelloResponse;
     Property OnReceivedHelloResponse : TNotifyEvent read FOnReceivedHelloResponse write FOnReceivedHelloResponse;
     Property NetStatistics : TNetStatistics read FNetStatistics;
     Property NetStatistics : TNetStatistics read FNetStatistics;
     Property OnStatisticsChanged : TNotifyEvent read FOnStatisticsChanged write FOnStatisticsChanged;
     Property OnStatisticsChanged : TNotifyEvent read FOnStatisticsChanged write FOnStatisticsChanged;
@@ -197,6 +200,7 @@ Type
     FLastKnownTimestampDiff : Int64;
     FLastKnownTimestampDiff : Int64;
     FIsMyselfServer : Boolean;
     FIsMyselfServer : Boolean;
     FClientPublicKey : TAccountKey;
     FClientPublicKey : TAccountKey;
+    FCreatedTime: TDateTime;
     function GetConnected: Boolean;
     function GetConnected: Boolean;
     procedure SetConnected(const Value: Boolean);
     procedure SetConnected(const Value: Boolean);
     procedure TcpClient_OnError(Sender: TObject; SocketError: Integer);
     procedure TcpClient_OnError(Sender: TObject; SocketError: Integer);
@@ -234,6 +238,7 @@ Type
     Function Send_Message(Const TheMessage : AnsiString) : Boolean;
     Function Send_Message(Const TheMessage : AnsiString) : Boolean;
     Property Client : TNetTcpIpClient read FClient;
     Property Client : TNetTcpIpClient read FClient;
     Property IsMyselfServer : Boolean read FIsMyselfServer;
     Property IsMyselfServer : Boolean read FIsMyselfServer;
+    Property CreatedTime : TDateTime read FCreatedTime;
   End;
   End;
 
 
   TNetClient = Class;
   TNetClient = Class;
@@ -295,7 +300,7 @@ Type
 
 
 
 
 Const
 Const
-  CT_TNodeServerAddress_NUL : TNodeServerAddress = (ip:'';port:0;last_connection:0; netConnection:nil;its_myself:false;last_attempt_to_connect:0;total_failed_attemps_to_connect:0;BlackListText:'');
+  CT_TNodeServerAddress_NUL : TNodeServerAddress = (ip:'';port:0;last_connection:0;last_connection_by_server:0; netConnection:nil;its_myself:false;last_attempt_to_connect:0;total_failed_attemps_to_connect:0;BlackListText:'');
   CT_TNetStatistics_NUL : TNetStatistics = (ActiveConnections:0;ClientsConnections:0;ServersConnections:0;TotalConnections:0;TotalClientsConnections:0;TotalServersConnections:0;BytesReceived:0;BytesSend:0);
   CT_TNetStatistics_NUL : TNetStatistics = (ActiveConnections:0;ClientsConnections:0;ServersConnections:0;TotalConnections:0;TotalClientsConnections:0;TotalServersConnections:0;BytesReceived:0;BytesSend:0);
 
 
 implementation
 implementation
@@ -313,18 +318,28 @@ Var _NetData : TNetData = nil;
 
 
 Type PNetRequestRegistered = ^TNetRequestRegistered;
 Type PNetRequestRegistered = ^TNetRequestRegistered;
 
 
+function SortNodeServerAddress(Item1, Item2: Pointer): Integer;
+Var P1,P2 : PNodeServerAddress;
+Begin
+  P1 := Item1;
+  P2 := Item2;
+  Result := AnsiCompareText(P1.ip,P2.ip);
+  if Result=0 then Result := P1.port - P2.port;
+End;
+
 procedure TNetData.AddServer(NodeServerAddress: TNodeServerAddress);
 procedure TNetData.AddServer(NodeServerAddress: TNodeServerAddress);
 Var P : PNodeServerAddress;
 Var P : PNodeServerAddress;
   i : Integer;
   i : Integer;
   l : TList;
   l : TList;
 begin
 begin
-  l := FNodeServers.LockList;
+  l := FNodeServers.LockList('TNetData.AddServer');
   try
   try
     i := IndexOfNetClient(l,NodeServerAddress.ip,NodeServerAddress.port);
     i := IndexOfNetClient(l,NodeServerAddress.ip,NodeServerAddress.port);
     if i>=0 then exit;
     if i>=0 then exit;
     New(P);
     New(P);
     P^ := NodeServerAddress;
     P^ := NodeServerAddress;
     l.Add(P);
     l.Add(P);
+    l.Sort(SortNodeServerAddress);
     TLog.NewLog(ltdebug,Classname,'Adding new server: '+NodeServerAddress.ip+':'+Inttostr(NodeServerAddress.port));
     TLog.NewLog(ltdebug,Classname,'Adding new server: '+NodeServerAddress.ip+':'+Inttostr(NodeServerAddress.port));
   finally
   finally
     FNodeServers.UnlockList;
     FNodeServers.UnlockList;
@@ -344,7 +359,7 @@ Var P : PNodeServerAddress;
 begin
 begin
   // This procedure cleans old blacklisted IPs
   // This procedure cleans old blacklisted IPs
   n := 0;
   n := 0;
-  l := FBlackList.LockList;
+  l := FBlackList.LockList('TNetData.CleanBlackList');
   Try
   Try
     for i := l.Count - 1 downto 0 do begin
     for i := l.Count - 1 downto 0 do begin
       P := l[i];
       P := l[i];
@@ -366,7 +381,7 @@ end;
 function TNetData.Connection(index: Integer): TNetConnection;
 function TNetData.Connection(index: Integer): TNetConnection;
 Var l : TList;
 Var l : TList;
 begin
 begin
-  l := FNetConnections.LockList;
+  l := FNetConnections.LockList('TNetData.Connection');
   try
   try
     Result := TNetConnection( l[index] );
     Result := TNetConnection( l[index] );
   finally
   finally
@@ -379,7 +394,7 @@ var i : Integer;
   l : TList;
   l : TList;
 begin
 begin
   Result := false;
   Result := false;
-  l := FNetConnections.LockList;
+  l := FNetConnections.LockList('TNetData.ConnectionExists');
   try
   try
     for i := 0 to l.Count - 1 do begin
     for i := 0 to l.Count - 1 do begin
       if TObject(l[i])=ObjectPointer then begin
       if TObject(l[i])=ObjectPointer then begin
@@ -396,7 +411,7 @@ function TNetData.ConnectionsCount(CountOnlyNetClients : Boolean): Integer;
 var i : Integer;
 var i : Integer;
   l : TList;
   l : TList;
 begin
 begin
-  l := FNetConnections.LockList;
+  l := FNetConnections.LockList('TNetData.ConnectionsCount');
   try
   try
     if CountOnlyNetClients then begin
     if CountOnlyNetClients then begin
       Result := 0;
       Result := 0;
@@ -409,6 +424,16 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TNetData.ConnectionsLock: TList;
+begin
+  Result := FNetConnections.LockList('TNetData.ConnectionsLock');
+end;
+
+procedure TNetData.ConnectionsUnlock;
+begin
+  FNetConnections.UnlockList;
+end;
+
 constructor TNetData.Create;
 constructor TNetData.Create;
 begin
 begin
   FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
   FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
@@ -418,11 +443,11 @@ begin
   FOnNodeServersUpdated := Nil;
   FOnNodeServersUpdated := Nil;
   FOnBlackListUpdated := Nil;
   FOnBlackListUpdated := Nil;
   FIsDiscoveringServers := false;
   FIsDiscoveringServers := false;
-  FNodeServers := TThreadList.Create;
-  FRegisteredRequests := TThreadList.Create;
+  FNodeServers := TPCThreadList.Create;
+  FRegisteredRequests := TPCThreadList.Create;
   FLastRequestId := 0;
   FLastRequestId := 0;
-  FNetConnections := TThreadList.Create;
-  FBlackList := TThreadList.Create;
+  FNetConnections := TPCThreadList.Create;
+  FBlackList := TPCThreadList.Create;
   FIsGettingNewBlockChainFromClient := false;
   FIsGettingNewBlockChainFromClient := false;
   FNodePrivateKey := TECPrivateKey.Create;
   FNodePrivateKey := TECPrivateKey.Create;
   FNodePrivateKey.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
   FNodePrivateKey.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
@@ -447,14 +472,14 @@ begin
   FThreadCheckConnections.Terminate;
   FThreadCheckConnections.Terminate;
   FThreadCheckConnections.WaitFor;
   FThreadCheckConnections.WaitFor;
   CleanBlackList;
   CleanBlackList;
-  l := FNodeServers.LockList;
+  l := FNodeServers.LockList('TNetData.Destroy NodeServers');
   try
   try
     while (l.Count>0) do DeleteNetClient(l,l.Count-1);
     while (l.Count>0) do DeleteNetClient(l,l.Count-1);
   finally
   finally
     FNodeServers.UnlockList;
     FNodeServers.UnlockList;
     FNodeServers.Free;
     FNodeServers.Free;
   end;
   end;
-  l := FBlackList.LockList;
+  l := FBlackList.LockList('TNetData.Destroy BlackList');
   try
   try
     while (l.Count>0) do DeleteNetClient(l,l.Count-1);
     while (l.Count>0) do DeleteNetClient(l,l.Count-1);
   finally
   finally
@@ -470,7 +495,7 @@ procedure TNetData.DisconnectClients;
 var i : Integer;
 var i : Integer;
   l : TList;
   l : TList;
 begin
 begin
-  l := FNetConnections.LockList;
+  l := FNetConnections.LockList('TNetData.DisconnectClients');
   Try
   Try
     for i := l.Count - 1 downto 0 do begin
     for i := l.Count - 1 downto 0 do begin
       if TObject(l[i]) is TNetClient then begin
       if TObject(l[i]) is TNetClient then begin
@@ -487,7 +512,7 @@ procedure TNetData.DiscoverServers;
   Var i,j,x,y : Integer;
   Var i,j,x,y : Integer;
   begin
   begin
     if l.Count<=1 then exit;
     if l.Count<=1 then exit;
-    j := Random(l.Count);
+    j := Random(l.Count)*3;
     for i := 0 to j do begin
     for i := 0 to j do begin
       x := Random(l.Count);
       x := Random(l.Count);
       y := Random(l.Count);
       y := Random(l.Count);
@@ -509,7 +534,7 @@ begin
   // can discover up to j servers
   // can discover up to j servers
   l := TList.Create;
   l := TList.Create;
   try
   try
-    lns := FNodeServers.LockList;
+    lns := FNodeServers.LockList('TNetData.DiscoverServers');
     try
     try
       for i:=0 to lns.Count-1 do begin
       for i:=0 to lns.Count-1 do begin
         P := lns[i];
         P := lns[i];
@@ -611,7 +636,7 @@ function TNetData.FindConnectionByClientRandomValue(Sender: TNetConnection): TNe
 Var l : TList;
 Var l : TList;
   i : Integer;
   i : Integer;
 begin
 begin
-  l := FNetConnections.LockList;
+  l := FNetConnections.LockList('TNetData.FindConnectionByClientRandomValue');
   try
   try
     for i := 0 to L.Count - 1 do begin
     for i := 0 to L.Count - 1 do begin
       Result := TNetConnection( l[i] );
       Result := TNetConnection( l[i] );
@@ -919,7 +944,7 @@ Var l : TList;
   i : Integer;
   i : Integer;
 begin
 begin
   Result := false;
   Result := false;
-  l := FBlackList.LockList;
+  l := FBlackList.LockList('TNetData.IsBlackListed');
   Try
   Try
     i := -1;
     i := -1;
     repeat
     repeat
@@ -953,7 +978,7 @@ begin
   inherited;
   inherited;
   if Operation=OpRemove then begin
   if Operation=OpRemove then begin
     if not (csDestroying in ComponentState) then begin
     if not (csDestroying in ComponentState) then begin
-      l := FNetConnections.LockList;
+      l := FNetConnections.LockList('TNetData.Notification');
       try
       try
         if l.Remove(AComponent)>=0 then begin
         if l.Remove(AComponent)>=0 then begin
           if Assigned(FOnNetConnectionsUpdated) then FOnNetConnectionsUpdated(Self);
           if Assigned(FOnNetConnectionsUpdated) then FOnNetConnectionsUpdated(Self);
@@ -985,7 +1010,7 @@ Var P : PNetRequestRegistered;
   l : TList;
   l : TList;
 begin
 begin
   requests_data := '';
   requests_data := '';
-  l := FRegisteredRequests.LockList;
+  l := FRegisteredRequests.LockList('TNetData.PendingRequest');
   Try
   Try
     if Assigned(Sender) then begin
     if Assigned(Sender) then begin
       Result := 0;
       Result := 0;
@@ -1005,7 +1030,7 @@ procedure TNetData.RegisterRequest(Sender: TNetConnection; operation: Word; requ
 Var P : PNetRequestRegistered;
 Var P : PNetRequestRegistered;
   l : TList;
   l : TList;
 begin
 begin
-  l := FRegisteredRequests.LockList;
+  l := FRegisteredRequests.LockList('TNetData.RegisterRequest');
   Try
   Try
     New(P);
     New(P);
     P^.NetClient := Sender;
     P^.NetClient := Sender;
@@ -1025,7 +1050,7 @@ Var P : PNetRequestRegistered;
   l : TList;
   l : TList;
 begin
 begin
   Result := false;
   Result := false;
-  l := FRegisteredRequests.LockList;
+  l := FRegisteredRequests.LockList('TNetData.UnRegisterRequest');
   try
   try
     for i := l.Count - 1 downto 0 do begin
     for i := l.Count - 1 downto 0 do begin
       P := l[i];
       P := l[i];
@@ -1168,15 +1193,15 @@ Var Pnsa : PNodeServerAddress;
   i : Integer;
   i : Integer;
 begin
 begin
   if FClient.Connected then FClient.Disconnect;
   if FClient.Connected then FClient.Disconnect;
-  lns := TNetData.NetData.FNodeServers.LockList;
+  lns := TNetData.NetData.FNodeServers.LockList('TNetConnection.ConnectTo');
   try
   try
     i := TNetData.NetData.IndexOfNetClient(lns,ServerIp,ServerPort);
     i := TNetData.NetData.IndexOfNetClient(lns,ServerIp,ServerPort);
     if (i>=0) then Pnsa := lns[i]
     if (i>=0) then Pnsa := lns[i]
     else Pnsa := Nil;
     else Pnsa := Nil;
+    if Assigned(Pnsa) then Pnsa^.netConnection := Self;
   finally
   finally
     TNetData.NetData.FNodeServers.UnlockList;
     TNetData.NetData.FNodeServers.UnlockList;
   end;
   end;
-  if Assigned(Pnsa) then Pnsa^.netConnection := Self;
 
 
   FClient.RemoteHost := ServerIP;
   FClient.RemoteHost := ServerIP;
   if ServerPort<=0 then ServerPort := CT_NetServer_Port;
   if ServerPort<=0 then ServerPort := CT_NetServer_Port;
@@ -1196,6 +1221,7 @@ constructor TNetConnection.Create(AOwner: TComponent);
 begin
 begin
   inherited;
   inherited;
   FClientPublicKey := CT_TECDSA_Public_Nul;
   FClientPublicKey := CT_TECDSA_Public_Nul;
+  FCreatedTime := Now;
   FIsMyselfServer := false;
   FIsMyselfServer := false;
   FLastKnownTimestampDiff := 0;
   FLastKnownTimestampDiff := 0;
   FIsWaitingForResponse := false;
   FIsWaitingForResponse := false;
@@ -1207,7 +1233,7 @@ begin
   SetClient( TTcpClient.Create(Self) );
   SetClient( TTcpClient.Create(Self) );
   FRemoteOperationBlock := CT_OperationBlock_NUL;
   FRemoteOperationBlock := CT_OperationBlock_NUL;
   FSocketError := 0;
   FSocketError := 0;
-  TNetData.NetData.FNetConnections.Add(Self);
+  TNetData.NetData.FNetConnections.Add(Self,'TNetConnection.Create');
   if Assigned(TNetData.NetData.FOnNetConnectionsUpdated) then TNetData.NetData.FOnNetConnectionsUpdated(Self);
   if Assigned(TNetData.NetData.FOnNetConnectionsUpdated) then TNetData.NetData.FOnNetConnectionsUpdated(Self);
 end;
 end;
 
 
@@ -1218,11 +1244,13 @@ Var Pnsa : PNodeServerAddress;
 begin
 begin
   Connected := false;
   Connected := false;
 
 
-  lns := TNetData.NetData.FNodeServers.LockList;
+  lns := TNetData.NetData.FNodeServers.LockList('TNetConnection.Destroy');
   try
   try
-    for i := 0 to lns.Count - 1 do begin
+    for i := lns.Count - 1 downto 0 do begin
       Pnsa := lns[i];
       Pnsa := lns[i];
-      if Pnsa^.netConnection=Self then Pnsa^.netConnection := Nil;
+      if Pnsa^.netConnection=Self then Begin
+        Pnsa^.netConnection := Nil;
+      End;
     end;
     end;
   finally
   finally
     TNetData.NetData.FNodeServers.UnlockList;
     TNetData.NetData.FNodeServers.UnlockList;
@@ -1241,6 +1269,7 @@ procedure TNetConnection.DisconnectInvalidClient(ItsMyself : Boolean; const why:
 Var P : PNodeServerAddress;
 Var P : PNodeServerAddress;
   l : TList;
   l : TList;
   i : Integer;
   i : Integer;
+  include_in_list : Boolean;
 begin
 begin
   if ItsMyself then begin
   if ItsMyself then begin
     TLog.NewLog(ltInfo,Classname,'Disconecting myself '+FClient.RemoteHost+':'+FClient.RemotePort+' > '+Why)
     TLog.NewLog(ltInfo,Classname,'Disconecting myself '+FClient.RemoteHost+':'+FClient.RemotePort+' > '+Why)
@@ -1248,24 +1277,27 @@ begin
     TLog.NewLog(lterror,Classname,'Disconecting '+FClient.RemoteHost+':'+FClient.RemotePort+' > '+Why);
     TLog.NewLog(lterror,Classname,'Disconecting '+FClient.RemoteHost+':'+FClient.RemotePort+' > '+Why);
   end;
   end;
   FIsMyselfServer := ItsMyself;
   FIsMyselfServer := ItsMyself;
-  l := TNetData.NetData.FBlackList.LockList;
-  try
-    i := TNetData.NetData.IndexOfNetClient(l,FClient.RemoteHost,StrToIntDef( FClient.RemotePort,CT_NetServer_Port));
-    if i<0 then begin
-      new(P);
-      P^ := CT_TNodeServerAddress_NUL;
-      TNetData.NetData.FBlackList.add(P);
-    end else P := l[i];
-    P^.ip := Fclient.RemoteHost;
-    P^.port := StrToIntDef( FClient.RemotePort,CT_NetServer_Port);
-    P^.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
-    P^.its_myself := ItsMyself;
-    P^.BlackListText := Why;
-  finally
-    TNetData.NetData.FBlackList.UnlockList;
+  include_in_list := (Not SameText(FClient.RemoteHost,'localhost')) And (Not SameText(FClient.RemoteHost,'127.0.0.1'))  And (Not SameText('192.168',Copy(FClient.RemoteHost,1,7)));
+  if include_in_list then begin
+    l := TNetData.NetData.FBlackList.LockList('TNetConnection.DisconnectInvalidClient include_in_list');
+    try
+      i := TNetData.NetData.IndexOfNetClient(l,FClient.RemoteHost,StrToIntDef( FClient.RemotePort,CT_NetServer_Port));
+      if i<0 then begin
+        new(P);
+        P^ := CT_TNodeServerAddress_NUL;
+        l.Add(P);
+      end else P := l[i];
+      P^.ip := Fclient.RemoteHost;
+      P^.port := StrToIntDef( FClient.RemotePort,CT_NetServer_Port);
+      P^.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+      P^.its_myself := ItsMyself;
+      P^.BlackListText := Why;
+    finally
+      TNetData.NetData.FBlackList.UnlockList;
+    end;
   end;
   end;
   if ItsMyself then begin
   if ItsMyself then begin
-    l := TNetData.NetData.FNodeServers.LockList;
+    l := TNetData.NetData.FNodeServers.LockList('TNetConnection.DisconnectInvalidClient MySelf');
     try
     try
       i := TNetData.NetData.IndexOfNetClient(l,FClient.RemoteHost,StrToIntDef( FClient.RemotePort,CT_NetServer_Port));
       i := TNetData.NetData.IndexOfNetClient(l,FClient.RemoteHost,StrToIntDef( FClient.RemotePort,CT_NetServer_Port));
       if i>=0 then begin
       if i>=0 then begin
@@ -1288,7 +1320,7 @@ Var HeaderData : TNetHeaderData;
 begin
 begin
   ms := TMemoryStream.Create;
   ms := TMemoryStream.Create;
   try
   try
-    TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
+    TPCThread.ProtectEnterCriticalSection(Self,'DoProcessBuffer',FNetLock);
     Try
     Try
       if Not FIsWaitingForResponse then begin
       if Not FIsWaitingForResponse then begin
         DoSendAndWaitForResponse(0,0,Nil,ms,0,HeaderData);
         DoSendAndWaitForResponse(0,0,Nil,ms,0,HeaderData);
@@ -1464,8 +1496,9 @@ begin
         end;
         end;
       end;
       end;
       if ((opcount>0) And (FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount)) then begin
       if ((opcount>0) And (FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount)) then begin
-        Send_GetBlocks(TNode.Node.Bank.BlocksCount,5,i);
+        Send_GetBlocks(TNode.Node.Bank.BlocksCount,50,i);
       end;
       end;
+      TNode.Node.NotifyBlocksChanged;
     Finally
     Finally
       op.Free;
       op.Free;
     End;
     End;
@@ -1588,7 +1621,7 @@ Begin
       nsa := CT_TNodeServerAddress_NUL;
       nsa := CT_TNodeServerAddress_NUL;
       nsa.ip := FClient.RemoteHost;
       nsa.ip := FClient.RemoteHost;
       nsa.port := connection_has_a_server;
       nsa.port := connection_has_a_server;
-      nsa.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+      nsa.last_connection_by_server := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
       TNetData.NetData.AddServer(nsa);
       TNetData.NetData.AddServer(nsa);
     end;
     end;
 
 
@@ -1607,10 +1640,14 @@ Begin
           nsa := CT_TNodeServerAddress_NUL;
           nsa := CT_TNodeServerAddress_NUL;
           TStreamOp.ReadAnsiString(DataBuffer,nsa.ip);
           TStreamOp.ReadAnsiString(DataBuffer,nsa.ip);
           DataBuffer.Read(nsa.port,2);
           DataBuffer.Read(nsa.port,2);
-          DataBuffer.Read(nsa.last_connection,4);
-          SetLength(messagehello.servers_address,length(messagehello.servers_address)+1);
-          messagehello.servers_address[high(messagehello.servers_address)] := nsa;
-          TNetData.NetData.AddServer(nsa);
+          // New in Build 1.0.2 saved at last_connection_by_server DataBuffer.Read(nsa.last_connection,4);
+          DataBuffer.Read(nsa.last_connection_by_server,4);
+          if ((nsa.last_connection_by_server + (60*60*24)) > UnivDateTimeToUnix(DateTime2UnivDateTime(now))) then begin
+            // New in Build 1.0.2: Only stores if connected 24 h before
+            SetLength(messagehello.servers_address,length(messagehello.servers_address)+1);
+            messagehello.servers_address[high(messagehello.servers_address)] := nsa;
+            TNetData.NetData.AddServer(nsa);
+          end;
         end;
         end;
       end;
       end;
       TLog.NewLog(ltdebug,Classname,'Hello received: '+TPCOperationsComp.OperationBlockToText(FRemoteOperationBlock));
       TLog.NewLog(ltdebug,Classname,'Hello received: '+TPCOperationsComp.OperationBlockToText(FRemoteOperationBlock));
@@ -1732,6 +1769,8 @@ function TNetConnection.DoSendAndWaitForResponse(operation: Word;
   MaxWaitTime: Cardinal; var HeaderData: TNetHeaderData): Boolean;
   MaxWaitTime: Cardinal; var HeaderData: TNetHeaderData): Boolean;
 var tc : Cardinal;
 var tc : Cardinal;
   was_waiting_for_response : Boolean;
   was_waiting_for_response : Boolean;
+  l : TList;
+  i : Integer;
 begin
 begin
   Result := false;
   Result := false;
   HeaderData := CT_NetHeaderData;
   HeaderData := CT_NetHeaderData;
@@ -1741,7 +1780,7 @@ begin
   end;
   end;
   If Not Assigned(FClient) then exit;
   If Not Assigned(FClient) then exit;
   if Not FClient.Active then exit;
   if Not FClient.Active then exit;
-  TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
+  TPCThread.ProtectEnterCriticalSection(Self,'DoSendAndWaitForResponse',FNetLock);
   Try
   Try
     was_waiting_for_response := RequestId>0;
     was_waiting_for_response := RequestId>0;
     try
     try
@@ -1767,6 +1806,17 @@ begin
           if (FClientBufferRead.Size=0) And (RequestId=0) then exit; // Nothing to read nor wait
           if (FClientBufferRead.Size=0) And (RequestId=0) then exit; // Nothing to read nor wait
         end;
         end;
         if (ReadTcpClientBuffer(MaxWaitTime,HeaderData,ReceiveDataBuffer)) then begin
         if (ReadTcpClientBuffer(MaxWaitTime,HeaderData,ReceiveDataBuffer)) then begin
+          l := TNetData.NetData.NodeServers.LockList('TNetConnection.DoSendAndWaitForResponse');
+          try
+            for i := 0 to l.Count - 1 do begin
+              If PNodeServerAddress( l[i] )^.netConnection=Self then begin
+                PNodeServerAddress( l[i] )^.last_connection := (UnivDateTimeToUnix(DateTime2UnivDateTime(now)));
+                PNodeServerAddress( l[i] )^.total_failed_attemps_to_connect := 0;
+              end;
+            end;
+          finally
+            TNetData.netData.NodeServers.UnlockList;
+          end;
           TLog.NewLog(ltDebug,Classname,'Received '+CT_NetTransferType[HeaderData.header_type]+' operation:'+TNetData.OperationToText(HeaderData.operation)+' id:'+Inttostr(HeaderData.request_id)+' Buffer size:'+Inttostr(HeaderData.buffer_data_length) );
           TLog.NewLog(ltDebug,Classname,'Received '+CT_NetTransferType[HeaderData.header_type]+' operation:'+TNetData.OperationToText(HeaderData.operation)+' id:'+Inttostr(HeaderData.request_id)+' Buffer size:'+Inttostr(HeaderData.buffer_data_length) );
           if (RequestId=HeaderData.request_id) And (HeaderData.header_type=ntp_response) then begin
           if (RequestId=HeaderData.request_id) And (HeaderData.header_type=ntp_response) then begin
             Result := true;
             Result := true;
@@ -1835,7 +1885,7 @@ begin
   Result := false;
   Result := false;
   HeaderData := CT_NetHeaderData;
   HeaderData := CT_NetHeaderData;
   BufferData.Size := 0;
   BufferData.Size := 0;
-  TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
+  TPCThread.ProtectEnterCriticalSection(Self,'ReadTcpClientBuffer',FNetLock);
   try
   try
     If not Connected then exit;
     If not Connected then exit;
     if Not FClient.Active then exit;
     if Not FClient.Active then exit;
@@ -1942,7 +1992,7 @@ begin
       s := '';
       s := '';
     end;
     end;
     Buffer.Position := 0;
     Buffer.Position := 0;
-    TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
+    TPCThread.ProtectEnterCriticalSection(Self,'Send',FNetLock);
     Try
     Try
       TLog.NewLog(ltDebug,Classname,'Sending: '+CT_NetTransferType[NetTranferType]+' operation:'+
       TLog.NewLog(ltDebug,Classname,'Sending: '+CT_NetTransferType[NetTranferType]+' operation:'+
         TNetData.OperationToText(operation)+' id:'+Inttostr(request_id)+' errorcode:'+InttoStr(errorcode)+
         TNetData.OperationToText(operation)+' id:'+Inttostr(request_id)+' errorcode:'+InttoStr(errorcode)+
@@ -2046,7 +2096,7 @@ var data : TStream;
   nsa : TNodeServerAddress;
   nsa : TNodeServerAddress;
   nsarr : Array of TNodeServerAddress;
   nsarr : Array of TNodeServerAddress;
   w : Word;
   w : Word;
-  c : Cardinal;
+  currunixtimestamp : Cardinal;
   l : TList;
   l : TList;
 begin
 begin
   Result := false;
   Result := false;
@@ -2065,8 +2115,8 @@ begin
     // Save a random value (4 bytes)
     // Save a random value (4 bytes)
     TStreamOp.WriteAnsiString(data,TAccountComp.AccountKey2RawString(TNetData.NetData.FNodePrivateKey.PublicKey));
     TStreamOp.WriteAnsiString(data,TAccountComp.AccountKey2RawString(TNetData.NetData.FNodePrivateKey.PublicKey));
     // Save my Unix timestamp (4 bytes)
     // Save my Unix timestamp (4 bytes)
-    c := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
-    data.Write(c,4);
+    currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+    data.Write(currunixtimestamp,4);
     // Save last operations block
     // Save last operations block
     op := TPCOperationsComp.Create(TNode.Node.Bank);
     op := TPCOperationsComp.Create(TNode.Node.Bank);
     try
     try
@@ -2074,13 +2124,17 @@ begin
       op.SaveToStream(false,true,data);
       op.SaveToStream(false,true,data);
       SetLength(nsarr,0);
       SetLength(nsarr,0);
       // Save other node servers
       // Save other node servers
-      l := TNetData.NetData.FNodeServers.LockList;
+      l := TNetData.NetData.FNodeServers.LockList('TNetConnection.Send_Hello');
       try
       try
         for i := 0 to l.Count - 1 do begin
         for i := 0 to l.Count - 1 do begin
           nsa := PNodeServerAddress( l[i] )^;
           nsa := PNodeServerAddress( l[i] )^;
           if (Not (nsa.its_myself)) And
           if (Not (nsa.its_myself)) And
             (nsa.BlackListText='') And
             (nsa.BlackListText='') And
-            (nsa.last_connection>0) then begin
+            (nsa.last_connection>0) And
+            // New on build 1.0.2
+            ((Assigned(nsa.netConnection)) Or
+             (nsa.last_connection + (60*60*24) > (currunixtimestamp))) // Only If connected 24h before...
+            then begin
             SetLength(nsarr,length(nsarr)+1);
             SetLength(nsarr,length(nsarr)+1);
             nsarr[high(nsarr)] := nsa;
             nsarr[high(nsarr)] := nsa;
           end;
           end;
@@ -2241,12 +2295,25 @@ end;
 { TNetClientThread }
 { TNetClientThread }
 
 
 procedure TNetClientThread.BCExecute;
 procedure TNetClientThread.BCExecute;
+Var debugstep : String;
 begin
 begin
-  while (Not Terminated) do begin
-    If FNetClient.Connected then
-      FNetClient.DoProcessBuffer;
-    Sleep(1);
-  end;
+  debugstep := 'Initiating...';
+  Try
+    while (Not Terminated) do begin
+      debugstep := 'Check connection';
+      If FNetClient.Connected then begin
+        debugstep := 'Processing Buffer';
+        FNetClient.DoProcessBuffer;
+      end;
+      Sleep(1);
+    end;
+    debugstep := 'Finalizing...';
+  Except
+    On E:Exception do begin
+      E.Message := E.Message+' Step:'+debugstep;
+      Raise;
+    end;
+  End;
 end;
 end;
 
 
 constructor TNetClientThread.Create(NetClient: TNetClient);
 constructor TNetClientThread.Create(NetClient: TNetClient);
@@ -2290,7 +2357,7 @@ Var NC : TNetClient;
 begin
 begin
   Pnsa := Nil;
   Pnsa := Nil;
   // Register attempt
   // Register attempt
-  lns := TNetData.NetData.FNodeServers.LockList;
+  lns := TNetData.NetData.FNodeServers.LockList('TThreadDiscoverConnection.BCExecute');
   try
   try
     i := TNetData.NetData.IndexOfNetClient(lns,FNodeServerAddress.ip,FNodeServerAddress.port);
     i := TNetData.NetData.IndexOfNetClient(lns,FNodeServerAddress.ip,FNodeServerAddress.port);
     if i>=0 then begin
     if i>=0 then begin
@@ -2309,16 +2376,6 @@ begin
     If NC.ConnectTo(FNodeServerAddress.ip,FNodeServerAddress.port) then begin
     If NC.ConnectTo(FNodeServerAddress.ip,FNodeServerAddress.port) then begin
       Sleep(500);
       Sleep(500);
       ok :=NC.Connected;
       ok :=NC.Connected;
-      lns := TNetData.NetData.FNodeServers.LockList;
-      try
-        i := TNetData.NetData.IndexOfNetClient(lns,FNodeServerAddress.ip,FNodeServerAddress.port);
-        if i>=0 then begin
-          PNodeServerAddress(lns[i])^.last_connection := (UnivDateTimeToUnix(DateTime2UnivDateTime(now)));
-          PNodeServerAddress(lns[i])^.total_failed_attemps_to_connect := 0; // Clean attemps counter
-        end;
-      finally
-        TNetData.NetData.FNodeServers.UnlockList;
-      end;
     end;
     end;
   Finally
   Finally
     if not ok then begin
     if not ok then begin
@@ -2354,7 +2411,7 @@ begin
       ndeleted := 0;
       ndeleted := 0;
       ntotal := 0;
       ntotal := 0;
       FLastCheckTS := GetTickCount;
       FLastCheckTS := GetTickCount;
-      l := TNetData.NetData.FNetConnections.LockList;
+      l := TNetData.NetData.FNetConnections.LockList('TThreadCheckConnections.BCExecute');
       try
       try
         ntotal := l.Count;
         ntotal := l.Count;
         for i := l.Count-1 downto 0 do begin
         for i := l.Count-1 downto 0 do begin
@@ -2385,20 +2442,26 @@ Var i : Integer;
   nsa : TNodeServerAddress;
   nsa : TNodeServerAddress;
   candidates : TList;
   candidates : TList;
   lop : TOperationBlock;
   lop : TOperationBlock;
+  netConnectionsList : TList;
 begin
 begin
   // Search better candidates:
   // Search better candidates:
   candidates := TList.Create;
   candidates := TList.Create;
   try
   try
     lop := CT_OperationBlock_NUL;
     lop := CT_OperationBlock_NUL;
-    for i := 0 to TNetData.NetData.ConnectionsCount(false) - 1 do begin
-      TNetData.NetData.FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
-      if (TNetData.NetData.Connection(i).FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount) And
-         (TNetData.NetData.Connection(i).FRemoteOperationBlock.block>=lop.block)
-         then begin
-         candidates.Add(TNetData.NetData.Connection(i));
-         lop := TNetData.NetData.Connection(i).FRemoteOperationBlock;
+    netConnectionsList := TNetData.NetData.ConnectionsLock;
+    Try
+      for i := 0 to netConnectionsList.Count - 1 do begin
+        TNetData.NetData.FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
+        if (TNetConnection(netConnectionsList[i]).FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount) And
+           (TNetConnection(netConnectionsList[i]).FRemoteOperationBlock.block>=lop.block)
+           then begin
+           candidates.Add(TNetConnection(netConnectionsList[i]));
+           lop := TNetConnection(netConnectionsList[i]).FRemoteOperationBlock;
+        end;
       end;
       end;
-    end;
+    Finally
+      TNetData.NetData.ConnectionsUnlock;
+    End;
     TNetData.NetData.FMaxRemoteOperationBlock := lop;
     TNetData.NetData.FMaxRemoteOperationBlock := lop;
     if (candidates.Count>0) then begin
     if (candidates.Count>0) then begin
       // Random a candidate
       // Random a candidate

+ 132 - 42
Units/PascalCoin/UNode.pas

@@ -36,7 +36,7 @@ Type
     FBank : TPCBank;
     FBank : TPCBank;
     FOperations : TPCOperationsComp;
     FOperations : TPCOperationsComp;
     FNetServer : TNetServer;
     FNetServer : TNetServer;
-    FMinerThreads : TThreadList;
+    FMinerThreads : TPCThreadList;
     FBCBankNotify : TPCBankNotify;
     FBCBankNotify : TPCBankNotify;
     Procedure OnBankNewBlock(Sender : TObject);
     Procedure OnBankNewBlock(Sender : TObject);
     Procedure StartLocking(MaxWaitMilliseconds : Cardinal);
     Procedure StartLocking(MaxWaitMilliseconds : Cardinal);
@@ -51,7 +51,7 @@ Type
     Property Bank : TPCBank read FBank;
     Property Bank : TPCBank read FBank;
     Function NetServer : TNetServer;
     Function NetServer : TNetServer;
     Function MinersCount : Integer;
     Function MinersCount : Integer;
-    Property MinerThreads : TThreadList read FMinerThreads;
+    Property MinerThreads : TPCThreadList read FMinerThreads;
     Function AddMiner(AccountKey : TAccountKey) : TMinerThread;
     Function AddMiner(AccountKey : TAccountKey) : TMinerThread;
     Procedure DeleteMiner(index : Integer);
     Procedure DeleteMiner(index : Integer);
     Procedure NotifyNetClientMessage(Sender : TNetConnection; Const TheMessage : AnsiString);
     Procedure NotifyNetClientMessage(Sender : TNetConnection; Const TheMessage : AnsiString);
@@ -62,7 +62,9 @@ Type
     Function AddOperations(SenderConnection : TNetConnection; Operations : TOperationsHashTree; var errors: AnsiString): Integer;
     Function AddOperations(SenderConnection : TNetConnection; Operations : TOperationsHashTree; var errors: AnsiString): Integer;
     Function AddOperation(SenderConnection : TNetConnection; Operation : TPCOperation; var errors: AnsiString): Boolean;
     Function AddOperation(SenderConnection : TNetConnection; Operation : TPCOperation; var errors: AnsiString): Boolean;
     Function SendNodeMessage(Target : TNetConnection; TheMessage : AnsiString; var errors : AnsiString) : Boolean;
     Function SendNodeMessage(Target : TNetConnection; TheMessage : AnsiString; var errors : AnsiString) : Boolean;
-
+    //
+    Procedure NotifyBlocksChanged;
+    //
     Procedure AutoDiscoverNodes(Const ips : AnsiString);
     Procedure AutoDiscoverNodes(Const ips : AnsiString);
     Function IsBlockChainValid(var WhyNot : AnsiString) : Boolean;
     Function IsBlockChainValid(var WhyNot : AnsiString) : Boolean;
     Function IsReady(Var CurrentProcess : AnsiString) : Boolean;
     Function IsReady(Var CurrentProcess : AnsiString) : Boolean;
@@ -84,7 +86,7 @@ Type
   TNodeNotifyEvents = Class(TComponent)
   TNodeNotifyEvents = Class(TComponent)
   private
   private
     FNode: TNode;
     FNode: TNode;
-    FPendingNotificationsList : TThreadList;
+    FPendingNotificationsList : TPCThreadList;
     FThreadSafeNodeNotifyEvent : TThreadSafeNodeNotifyEvent;
     FThreadSafeNodeNotifyEvent : TThreadSafeNodeNotifyEvent;
     FOnBlocksChanged: TNotifyEvent;
     FOnBlocksChanged: TNotifyEvent;
     FOnOperationsChanged: TNotifyEvent;
     FOnOperationsChanged: TNotifyEvent;
@@ -103,6 +105,22 @@ Type
     Property OnNodeMessageEvent : TNodeMessageEvent read FOnNodeMessageEvent write FOnNodeMessageEvent;
     Property OnNodeMessageEvent : TNodeMessageEvent read FOnNodeMessageEvent write FOnNodeMessageEvent;
   End;
   End;
 
 
+  TThreadNodeNotifyNewBlock = Class(TPCThread)
+    FNetConnection : TNetConnection;
+  protected
+    procedure BCExecute; override;
+    Constructor Create(NetConnection : TNetConnection);
+  End;
+
+  TThreadNodeNotifyOperations = Class(TPCThread)
+    FNetConnection : TNetConnection;
+    FOperationsHashTree : TOperationsHashTree;
+  protected
+    procedure BCExecute; override;
+    Constructor Create(NetConnection : TNetConnection; MakeACopyOfOperationsHashTree : TOperationsHashTree);
+    destructor Destroy; override;
+  End;
+
 implementation
 implementation
 
 
 Uses UOpTransaction, SysUtils, ULog, Forms, UConst, UTime;
 Uses UOpTransaction, SysUtils, ULog, Forms, UConst, UTime;
@@ -124,7 +142,7 @@ begin
   finally
   finally
     Result.MinerUnLockOperations(True);
     Result.MinerUnLockOperations(True);
   end;
   end;
-  FMinerThreads.Add(Result);
+  FMinerThreads.Add(Result,'TNode.AddMiner');
 end;
 end;
 
 
 function TNode.AddNewBlockChain(SenderMiner: TMinerThread; SenderConnection: TNetConnection; NewBlockOperations: TPCOperationsComp;
 function TNode.AddNewBlockChain(SenderMiner: TMinerThread; SenderConnection: TNetConnection; NewBlockOperations: TPCOperationsComp;
@@ -134,7 +152,9 @@ Var i : Integer;
   nc : TNetConnection;
   nc : TNetConnection;
   ms : TMemoryStream;
   ms : TMemoryStream;
   mtl : TList;
   mtl : TList;
+  netConnectionsList : TList;
 begin
 begin
+  Result := false;
   TLog.NewLog(ltdebug,Classname,Format('AddNewBlockChain Miner:%s Connection:%s NewBlock:%s',[Inttohex(Integer(SenderMiner),8),
   TLog.NewLog(ltdebug,Classname,Format('AddNewBlockChain Miner:%s Connection:%s NewBlock:%s',[Inttohex(Integer(SenderMiner),8),
     Inttohex(Integer(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock)]));
     Inttohex(Integer(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock)]));
   Try
   Try
@@ -161,10 +181,11 @@ begin
     if Result then begin
     if Result then begin
       FOperations.SanitizeOperations;
       FOperations.SanitizeOperations;
       // Notify to all clients and other miners
       // Notify to all clients and other miners
-      mtl := FMinerThreads.LockList;
+      mtl := FMinerThreads.LockList('TNode.AddNewBlockChain - Notify clients');
       try
       try
         for i := 0 to mtl.Count - 1 do begin
         for i := 0 to mtl.Count - 1 do begin
-          if (mtl[i]<>SenderMiner) OR (1=1) then begin
+          if (mtl[i]<>SenderMiner) then begin
+            TLog.NewLog(ltdebug,Classname,'Sending new Operations to miner '+inttostr(i+1)+'/'+inttostr(mtl.Count));
             operationscomp := TMinerThread(mtl[i]).MinerLockOperations;
             operationscomp := TMinerThread(mtl[i]).MinerLockOperations;
             try
             try
               operationscomp.CopyFromExceptAddressKey(FOperations);
               operationscomp.CopyFromExceptAddressKey(FOperations);
@@ -179,20 +200,17 @@ begin
         FMinerThreads.UnlockList;
         FMinerThreads.UnlockList;
       end;
       end;
       // Notify to clients
       // Notify to clients
-      for i:=0 to TNetData.NetData.ConnectionsCount(false)-1 do begin
-        nc := TNetData.NetData.Connection(i);
-        if (SenderConnection<>nc) then begin
-          nc.Send_NewBlockFound;
-        end;
-      end;
-      // Send sanitized operations to other nodes
-      if FOperations.OperationsHashTree.OperationsCount>0 then begin
-        TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(FOperations.OperationsHashTree.OperationsCount)+' sanitized operations to nodes');
-        for i:=0 to TNetData.NetData.ConnectionsCount(false)-1 do begin
-          nc := TNetData.NetData.Connection(i);
-          nc.Send_AddOperations(FOperations.OperationsHashTree);
+      netConnectionsList := TNetData.NetData.ConnectionsLock;
+      Try
+        for i:=0 to netConnectionsList.Count-1 do begin
+          nc := netConnectionsList[i];
+          if (SenderConnection<>nc) then begin
+            TThreadNodeNotifyNewBlock.Create(nc);
+          end;
         end;
         end;
-      end;
+      Finally
+        TNetData.NetData.ConnectionsUnlock;
+      End;
     end else begin
     end else begin
       // If error is on a SenderMiner its a hole
       // If error is on a SenderMiner its a hole
       FOperations.SanitizeOperations;
       FOperations.SanitizeOperations;
@@ -205,7 +223,7 @@ begin
           SenderMiner.MinerUnLockOperations(true);
           SenderMiner.MinerUnLockOperations(true);
         end;
         end;
         // Reset others:
         // Reset others:
-        mtl := FMinerThreads.LockList;
+        mtl := FMinerThreads.LockList('TNode.AddNewBlockChain - Reset others');
         try
         try
           for i := 0 to mtl.Count - 1 do begin
           for i := 0 to mtl.Count - 1 do begin
             if (TMinerThread(mtl[i])<>SenderMiner) then begin
             if (TMinerThread(mtl[i])<>SenderMiner) then begin
@@ -229,9 +247,7 @@ begin
   End;
   End;
   if Result then begin
   if Result then begin
     // Notify it!
     // Notify it!
-    for i := 0 to FNotifyList.Count-1 do begin
-      TNodeNotifyEvents( FNotifyList[i] ).NotifyBlocksChanged;
-    end;
+    NotifyBlocksChanged;
   end;
   end;
 end;
 end;
 
 
@@ -255,6 +271,7 @@ Var
   nc : TNetConnection;
   nc : TNetConnection;
   e : AnsiString;
   e : AnsiString;
   mtl : TList;
   mtl : TList;
+  netConnectionsList : TList;
 begin
 begin
   Result := -1;
   Result := -1;
   TLog.NewLog(ltdebug,Classname,Format('AddOperations Connection:%s Operations:%d',[
   TLog.NewLog(ltdebug,Classname,Format('AddOperations Connection:%s Operations:%d',[
@@ -284,7 +301,7 @@ begin
       end;
       end;
       if Result=0 then exit;
       if Result=0 then exit;
       // Send to miners
       // Send to miners
-      mtl := FMinerThreads.LockList;
+      mtl := FMinerThreads.LockList('TNode.AddOperations');
       Try
       Try
         for i := 0 to mtl.Count - 1 do begin
         for i := 0 to mtl.Count - 1 do begin
           operationscomp := TMinerThread(mtl[i]).MinerLockOperations;
           operationscomp := TMinerThread(mtl[i]).MinerLockOperations;
@@ -298,12 +315,17 @@ begin
         FMinerThreads.UnlockList;
         FMinerThreads.UnlockList;
       End;
       End;
       // Send to other nodes
       // Send to other nodes
-      for i:=0 to TNetData.NetData.ConnectionsCount(false)-1 do begin
-        nc := TNetData.NetData.Connection(i);
-        if (nc<>SenderConnection) then begin
-          nc.Send_AddOperations(valids_operations);
+      netConnectionsList := TNetData.NetData.ConnectionsLock;
+      Try
+        for i:=0 to netConnectionsList.Count-1 do begin
+          nc := netConnectionsList[i];
+          if (nc<>SenderConnection) then begin
+            TThreadNodeNotifyOperations.Create(nc,valids_operations);
+          end;
         end;
         end;
-      end;
+      Finally
+        TNetData.NetData.ConnectionsUnlock;
+      End;
     finally
     finally
       valids_operations.Free;
       valids_operations.Free;
     end;
     end;
@@ -378,7 +400,7 @@ begin
   FBCBankNotify.Bank := FBank;
   FBCBankNotify.Bank := FBank;
   FBCBankNotify.OnNewBlock := OnBankNewBlock;
   FBCBankNotify.OnNewBlock := OnBankNewBlock;
   FNetServer := TNetServer.Create(Self);
   FNetServer := TNetServer.Create(Self);
-  FMinerThreads := TThreadList.Create;
+  FMinerThreads := TPCThreadList.Create;
   FOperations := TPCOperationsComp.Create(Self);
   FOperations := TPCOperationsComp.Create(Self);
   FOperations.bank := FBank;
   FOperations.bank := FBank;
   FNotifyList := TList.Create;
   FNotifyList := TList.Create;
@@ -389,7 +411,7 @@ procedure TNode.DeleteMiner(index: Integer);
 Var m : TMinerThread;
 Var m : TMinerThread;
   mtl : TList;
   mtl : TList;
 begin
 begin
-  mtl := FMinerThreads.LockList;
+  mtl := FMinerThreads.LockList('TNode.DeleteMiner');
   Try
   Try
     m := TMinerThread(mtl[index]);
     m := TMinerThread(mtl[index]);
     m.Suspended := false;
     m.Suspended := false;
@@ -477,10 +499,14 @@ begin
   CurrentProcess := '';
   CurrentProcess := '';
   if FBank.IsReady(CurrentProcess) then begin
   if FBank.IsReady(CurrentProcess) then begin
     if FNetServer.Active then begin
     if FNetServer.Active then begin
-      if TNetData.NetData.MaxRemoteOperationBlock.block>FOperations.OperationBlock.block then begin
-        CurrentProcess := 'Found block '+inttostr(TNetData.NetData.MaxRemoteOperationBlock.block);
+      if TNetData.NetData.IsGettingNewBlockChainFromClient then begin
+        CurrentProcess := 'Obtaining valid BlockChain - Found block '+inttostr(TNetData.NetData.MaxRemoteOperationBlock.block);
       end else begin
       end else begin
-        Result := true;
+        if TNetData.NetData.MaxRemoteOperationBlock.block>FOperations.OperationBlock.block then begin
+          CurrentProcess := 'Found block '+inttostr(TNetData.NetData.MaxRemoteOperationBlock.block)+' (Wait until downloaded)';
+        end else begin
+          Result := true;
+        end;
       end;
       end;
     end else begin
     end else begin
       CurrentProcess := 'Server not active';
       CurrentProcess := 'Server not active';
@@ -491,7 +517,7 @@ end;
 function TNode.MinersCount : Integer;
 function TNode.MinersCount : Integer;
 Var mtl : TList;
 Var mtl : TList;
 begin
 begin
-  mtl := FMinerThreads.LockList;
+  mtl := FMinerThreads.LockList('TNode.MinersCount');
   Try
   Try
     Result := mtl.Count;
     Result := mtl.Count;
   Finally
   Finally
@@ -515,6 +541,14 @@ begin
   inherited;
   inherited;
 end;
 end;
 
 
+procedure TNode.NotifyBlocksChanged;
+Var i : Integer;
+begin
+  for i := 0 to FNotifyList.Count-1 do begin
+    TNodeNotifyEvents( FNotifyList[i] ).NotifyBlocksChanged;
+  end;
+end;
+
 procedure TNode.NotifyNetClientMessage(Sender: TNetConnection; const TheMessage: AnsiString);
 procedure TNode.NotifyNetClientMessage(Sender: TNetConnection; const TheMessage: AnsiString);
 Var i : Integer;
 Var i : Integer;
   s : AnsiString;
   s : AnsiString;
@@ -539,6 +573,7 @@ end;
 function TNode.SendNodeMessage(Target: TNetConnection; TheMessage: AnsiString; var errors: AnsiString): Boolean;
 function TNode.SendNodeMessage(Target: TNetConnection; TheMessage: AnsiString; var errors: AnsiString): Boolean;
 Var i : Integer;
 Var i : Integer;
   nc : TNetConnection;
   nc : TNetConnection;
+  netConnectionsList : TList;
 begin
 begin
   Try
   Try
     StartLocking(4000);
     StartLocking(4000);
@@ -551,13 +586,18 @@ begin
   try
   try
     Result := false;
     Result := false;
     errors := '';
     errors := '';
-    if assigned(Target) then begin 
+    if assigned(Target) then begin
       Target.Send_Message(TheMessage);
       Target.Send_Message(TheMessage);
     end else begin
     end else begin
-      for i:=0 to TNetData.NetData.ConnectionsCount(false)-1 do begin
-        nc := TNetData.NetData.Connection(i);
-        nc.Send_Message(TheMessage);
-      end;        
+      netConnectionsList := TNetData.NetData.ConnectionsLock;
+      Try
+        for i:=0 to netConnectionsList.Count-1 do begin
+          nc := netConnectionsList[i];
+          nc.Send_Message(TheMessage);
+        end;
+      Finally
+        TNetData.NetData.ConnectionsUnlock;
+      End;
     end;
     end;
     result := true;
     result := true;
   finally
   finally
@@ -593,7 +633,7 @@ begin
   FOnBlocksChanged := Nil;
   FOnBlocksChanged := Nil;
   FOnNodeMessageEvent := Nil;
   FOnNodeMessageEvent := Nil;
   FMessages := TStringList.Create;
   FMessages := TStringList.Create;
-  FPendingNotificationsList := TThreadList.Create;
+  FPendingNotificationsList := TPCThreadList.Create;
   FThreadSafeNodeNotifyEvent := TThreadSafeNodeNotifyEvent.Create(false);
   FThreadSafeNodeNotifyEvent := TThreadSafeNodeNotifyEvent.Create(false);
   FThreadSafeNodeNotifyEvent.FNodeNotifyEvents := Self;
   FThreadSafeNodeNotifyEvent.FNodeNotifyEvents := Self;
   FThreadSafeNodeNotifyEvent.FreeOnTerminate := true;
   FThreadSafeNodeNotifyEvent.FreeOnTerminate := true;
@@ -676,6 +716,56 @@ begin
   end;
   end;
 end;
 end;
 
 
+{ TThreadNodeNotifyNewBlock }
+
+procedure TThreadNodeNotifyNewBlock.BCExecute;
+begin
+  If Not TNetData.NetData.ConnectionExists(FNetConnection) then begin
+    TLog.NewLog(ltdebug,Classname,'Connection not exists');
+  end;
+  TLog.NewLog(ltdebug,ClassName,'Sending new block found to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
+  FNetConnection.Send_NewBlockFound;
+  if TNode.Node.Operations.OperationsHashTree.OperationsCount>0 then begin
+     TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(TNode.Node.Operations.OperationsHashTree.OperationsCount)+' sanitized operations to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
+     FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
+  end;
+end;
+
+constructor TThreadNodeNotifyNewBlock.Create(NetConnection: TNetConnection);
+begin
+  FNetConnection := NetConnection;
+  Inherited Create(false);
+  FreeOnTerminate := true;
+end;
+
+{ TThreadNodeNotifyOperations }
+
+procedure TThreadNodeNotifyOperations.BCExecute;
+begin
+  If Not TNetData.NetData.ConnectionExists(FNetConnection) then begin
+    TLog.NewLog(ltdebug,Classname,'Connection not exists');
+  end;
+  if FOperationsHashTree.OperationsCount<=0 then exit;
+  TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(FOperationsHashTree.OperationsCount)+' Operations to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
+  FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
+end;
+
+constructor TThreadNodeNotifyOperations.Create(NetConnection: TNetConnection;
+  MakeACopyOfOperationsHashTree: TOperationsHashTree);
+begin
+  FOperationsHashTree := TOperationsHashTree.Create;
+  FOperationsHashTree.CopyFromHashTree(MakeACopyOfOperationsHashTree);
+  FNetConnection := NetConnection;
+  Inherited Create(false);
+  FreeOnTerminate := true;
+end;
+
+destructor TThreadNodeNotifyOperations.Destroy;
+begin
+  FOperationsHashTree.Free;
+  inherited;
+end;
+
 initialization
 initialization
   _Node := Nil;
   _Node := Nil;
 finalization
 finalization

+ 89 - 11
Units/PascalCoin/UThread.pas

@@ -32,9 +32,24 @@ Type
     Class function ThreadCount : Integer;
     Class function ThreadCount : Integer;
     Class function GetThread(index : Integer) : TPCThread;
     Class function GetThread(index : Integer) : TPCThread;
     Class function TerminateAllThreads : Integer;
     Class function TerminateAllThreads : Integer;
-    Class Procedure ProtectEnterCriticalSection(Const Sender : TObject; var Lock : TRTLCriticalSection);
+    Class Procedure ProtectEnterCriticalSection(Const Sender : TObject; Const Subject : String; var Lock : TRTLCriticalSection);
   End;
   End;
 
 
+  TPCThreadList = class
+  private
+    FList: TList;
+    FLock: TRTLCriticalSection;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Add(Item: Pointer; Const Subject : String);
+    procedure Clear;
+    procedure Remove(Item: Pointer); inline;
+    function LockList(Const Subject : String): TList;
+    procedure UnlockList; inline;
+  end;
+
+
 implementation
 implementation
 
 
 uses
 uses
@@ -42,7 +57,7 @@ uses
 
 
 { TPCThread }
 { TPCThread }
 
 
-Var _threads,_aux : TThreadList;
+Var _threads,_aux : TPCThreadList;
 
 
 procedure TPCThread.DoTerminate;
 procedure TPCThread.DoTerminate;
 begin
 begin
@@ -52,7 +67,7 @@ end;
 procedure TPCThread.Execute;
 procedure TPCThread.Execute;
 Var l : TList;
 Var l : TList;
 begin
 begin
-  _threads.Add(Self);
+  _threads.Add(Self,'TPCThread.Execute');
   try
   try
     TLog.NewLog(ltdebug,Classname,'Starting Thread');
     TLog.NewLog(ltdebug,Classname,'Starting Thread');
     Try
     Try
@@ -69,7 +84,7 @@ begin
     End;
     End;
   finally
   finally
     if (Assigned(_threads)) then begin
     if (Assigned(_threads)) then begin
-      l := _threads.LockList;
+      l := _threads.LockList('TPCThread.Execute');
       Try
       Try
         l.Remove(Self);
         l.Remove(Self);
       Finally
       Finally
@@ -83,7 +98,7 @@ class function TPCThread.GetThread(index: Integer): TPCThread;
 Var l : TList;
 Var l : TList;
 begin
 begin
   Result := Nil;
   Result := Nil;
-  l := _threads.LockList;
+  l := _threads.LockList('TPCThread.GetThread');
   try
   try
     if (index<0) or (index>=l.Count) then exit;
     if (index<0) or (index>=l.Count) then exit;
     Result := TPCThread(l[index]);
     Result := TPCThread(l[index]);
@@ -92,12 +107,14 @@ begin
   end;
   end;
 end;
 end;
 
 
-class procedure TPCThread.ProtectEnterCriticalSection(Const Sender : TObject; var Lock: TRTLCriticalSection);
+class procedure TPCThread.ProtectEnterCriticalSection(Const Sender : TObject; Const Subject : String; var Lock: TRTLCriticalSection);
 begin
 begin
   if Not TryEnterCriticalSection(Lock) then begin
   if Not TryEnterCriticalSection(Lock) then begin
-    TLog.NewLog(ltdebug,Sender.Classname,Format('Entering to a Locked critical section. LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
+    TLog.NewLog(ltdebug,Sender.Classname,Format('Locked critical section (WAIT):'+Subject+' LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
       Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
       Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
     EnterCriticalSection(Lock);
     EnterCriticalSection(Lock);
+    TLog.NewLog(ltdebug,Sender.Classname,Format('UnLocked critical section (ENTER):'+Subject+' LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
+      Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
   end;
   end;
 end;
 end;
 
 
@@ -107,7 +124,7 @@ Var l : TList;
 begin
 begin
   Result := -1;
   Result := -1;
   if Not Assigned(_threads) then exit;
   if Not Assigned(_threads) then exit;
-  l := _threads.LockList;
+  l := _threads.LockList('TPCThread.TerminateAllThreads');
   try
   try
     for i :=l.Count - 1 downto 0 do begin
     for i :=l.Count - 1 downto 0 do begin
       TPCThread(l[i]).Terminate;
       TPCThread(l[i]).Terminate;
@@ -125,7 +142,7 @@ Var l : TList;
 begin
 begin
   Result := -1;
   Result := -1;
   if Not Assigned(_threads) then exit;
   if Not Assigned(_threads) then exit;
-  l := _threads.LockList;
+  l := _threads.LockList('TPCThread.ThreadClassFound');
   try
   try
     for Result := 0 to l.Count - 1 do begin
     for Result := 0 to l.Count - 1 do begin
       if (TPCThread(l[Result]) is tclass) And ((l[Result])<>Exclude) then exit;
       if (TPCThread(l[Result]) is tclass) And ((l[Result])<>Exclude) then exit;
@@ -139,7 +156,7 @@ end;
 class function TPCThread.ThreadCount: Integer;
 class function TPCThread.ThreadCount: Integer;
 Var l : TList;
 Var l : TList;
 begin
 begin
-  l := _threads.LockList;
+  l := _threads.LockList('TPCThread.ThreadCount');
   try
   try
     Result := l.Count;
     Result := l.Count;
   finally
   finally
@@ -147,8 +164,69 @@ begin
   end;
   end;
 end;
 end;
 
 
+{ TPCThreadList }
+
+procedure TPCThreadList.Add(Item: Pointer; Const Subject : String);
+begin
+  LockList('TPCThreadList.Add - '+Subject);
+  Try
+    FList.Add(Item);
+  Finally
+    UnlockList;
+  End;
+end;
+
+procedure TPCThreadList.Clear;
+begin
+  LockList('TPCThreadList.Clear');
+  Try
+    FList.Clear;
+  Finally
+    UnlockList;
+  End;
+end;
+
+constructor TPCThreadList.Create;
+begin
+  InitializeCriticalSection(FLock);
+  FList := TList.Create;
+end;
+
+destructor TPCThreadList.Destroy;
+begin
+  LockList('TPCThreadList.Destroy');
+  try
+    FList.Free;
+    inherited Destroy;
+  finally
+    UnlockList;
+    DeleteCriticalSection(FLock);
+  end;
+end;
+
+function TPCThreadList.LockList(Const Subject : String): TList;
+begin
+  TPCThread.ProtectEnterCriticalSection(Self,Subject,FLock);
+  Result := FList;
+end;
+
+procedure TPCThreadList.Remove(Item: Pointer);
+begin
+  LockList('TPCThreadList.Remove');
+  try
+    FList.Remove(Item);
+  finally
+    UnlockList;
+  end;
+end;
+
+procedure TPCThreadList.UnlockList;
+begin
+  LeaveCriticalSection(FLock);
+end;
+
 initialization
 initialization
-  _threads := TThreadList.Create;
+  _threads := TPCThreadList.Create;
 finalization
 finalization
   _aux := _threads;
   _aux := _threads;
   _threads := Nil;
   _threads := Nil;

+ 6 - 0
Units/PascalCoin/UTime.pas

@@ -27,6 +27,7 @@ function UnivDateTimeToUnix(dtDate: TDateTime): Longint;
 function UnixToUnivDateTime(USec: Longint): TDateTime;
 function UnixToUnivDateTime(USec: Longint): TDateTime;
 
 
 function UnixTimeToLocalElapsedTime(USec : Longint) : AnsiString;
 function UnixTimeToLocalElapsedTime(USec : Longint) : AnsiString;
+Function DateTimeElapsedTime(dtDate : TDateTime) : AnsiString;
 
 
 implementation
 implementation
 
 
@@ -51,6 +52,11 @@ Begin
   else Result := inttostr(diff DIV (60*60*24))+' days ago';
   else Result := inttostr(diff DIV (60*60*24))+' days ago';
 End;
 End;
 
 
+Function DateTimeElapsedTime(dtDate : TDateTime) : AnsiString;
+Begin
+  Result := UnixTimeToLocalElapsedTime( UnivDateTimeToUnix(DateTime2UnivDateTime(dtDate)) );
+End;
+
 Function DateTime2UnivDateTime(d:TDateTime):TDateTime;
 Function DateTime2UnivDateTime(d:TDateTime):TDateTime;
 var
 var
  TZI:TTimeZoneInformation;
  TZI:TTimeZoneInformation;

+ 1 - 1
Units/PascalCoin/UWalletKeys.pas

@@ -192,7 +192,7 @@ begin
           end;
           end;
         end;
         end;
       end;
       end;
-    end;// else isOk := false;
+    end;
   end;
   end;
   FIsValidPassword := isOk;
   FIsValidPassword := isOk;
 end;
 end;

+ 61 - 32
Units/Utils/UGridUtils.pas

@@ -44,6 +44,7 @@ Type
 
 
   TAccountsGrid = Class(TComponent)
   TAccountsGrid = Class(TComponent)
   private
   private
+    FAccountsBalance : Int64;
     FAccountsList : TOrderedCardinalList;
     FAccountsList : TOrderedCardinalList;
     FColumns : Array of TAccountColumn;
     FColumns : Array of TAccountColumn;
     FDrawGrid : TDrawGrid;
     FDrawGrid : TDrawGrid;
@@ -69,6 +70,7 @@ Type
     Procedure SaveToStream(Stream : TStream);
     Procedure SaveToStream(Stream : TStream);
     Procedure LoadFromStream(Stream : TStream);
     Procedure LoadFromStream(Stream : TStream);
     Property ShowAllAccounts : Boolean read FShowAllAccounts write SetShowAllAccounts;
     Property ShowAllAccounts : Boolean read FShowAllAccounts write SetShowAllAccounts;
+    Property AccountsBalance : Int64 read FAccountsBalance;
   End;
   End;
 
 
   TOperationsGrid = Class(TComponent)
   TOperationsGrid = Class(TComponent)
@@ -77,6 +79,7 @@ Type
     FAccountNumber: Int64;
     FAccountNumber: Int64;
     FOperationsResume : TOperationsResumeList;
     FOperationsResume : TOperationsResumeList;
     FNodeNotifyEvents : TNodeNotifyEvents;
     FNodeNotifyEvents : TNodeNotifyEvents;
+    FPendingOperations: Boolean;
     Procedure OnNodeNewOperation(Sender : TObject);
     Procedure OnNodeNewOperation(Sender : TObject);
     Procedure OnNodeNewAccount(Sender : TObject);
     Procedure OnNodeNewAccount(Sender : TObject);
     Procedure InitGrid;
     Procedure InitGrid;
@@ -85,12 +88,14 @@ Type
     procedure SetAccountNumber(const Value: Int64);
     procedure SetAccountNumber(const Value: Int64);
     procedure SetNode(const Value: TNode);
     procedure SetNode(const Value: TNode);
     function GetNode: TNode;
     function GetNode: TNode;
+    procedure SetPendingOperations(const Value: Boolean);
   protected
   protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
     procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
   public
   public
     Constructor Create(AOwner : TComponent); override;
     Constructor Create(AOwner : TComponent); override;
     Destructor Destroy; override;
     Destructor Destroy; override;
     Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
     Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
+    Property PendingOperations : Boolean read FPendingOperations write SetPendingOperations;
     Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
     Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
     Property Node : TNode read GetNode write SetNode;
     Property Node : TNode read GetNode write SetNode;
     Procedure UpdateAccountOperations;
     Procedure UpdateAccountOperations;
@@ -217,6 +222,7 @@ constructor TAccountsGrid.Create(AOwner: TComponent);
 Var i : Integer;
 Var i : Integer;
 begin
 begin
   inherited;
   inherited;
+  FAccountsBalance := 0;
   FShowAllAccounts := false;
   FShowAllAccounts := false;
   FAccountsList := TOrderedCardinalList.Create;
   FAccountsList := TOrderedCardinalList.Create;
   FDrawGrid := Nil;
   FDrawGrid := Nil;
@@ -247,16 +253,25 @@ end;
 
 
 procedure TAccountsGrid.InitGrid;
 procedure TAccountsGrid.InitGrid;
 Var i : Integer;
 Var i : Integer;
+  acc : TAccount;
 begin
 begin
+  FAccountsBalance := 0;
   if Not assigned(DrawGrid) then exit;
   if Not assigned(DrawGrid) then exit;
   if FShowAllAccounts then begin
   if FShowAllAccounts then begin
     if Assigned(Node) then begin
     if Assigned(Node) then begin
       if Node.Bank.AccountsCount<1 then DrawGrid.RowCount := 2
       if Node.Bank.AccountsCount<1 then DrawGrid.RowCount := 2
       else DrawGrid.RowCount := Node.Bank.AccountsCount+1;
       else DrawGrid.RowCount := Node.Bank.AccountsCount+1;
+      FAccountsBalance := Node.Bank.SafeBox.TotalBalance;
     end else DrawGrid.RowCount := 2;
     end else DrawGrid.RowCount := 2;
   end else begin
   end else begin
     if FAccountsList.Count<1 then DrawGrid.RowCount := 2
     if FAccountsList.Count<1 then DrawGrid.RowCount := 2
     else DrawGrid.RowCount := FAccountsList.Count+1;
     else DrawGrid.RowCount := FAccountsList.Count+1;
+    if Assigned(Node) then begin
+      for i := 0 to FAccountsList.Count - 1 do begin
+        acc := Node.Bank.SafeBox.Account( FAccountsList.Get(i) );
+        inc(FAccountsBalance, acc.balance);
+      end;
+    end;
   end;
   end;
   DrawGrid.FixedRows := 1;
   DrawGrid.FixedRows := 1;
   if Length(FColumns)=0 then DrawGrid.ColCount := 1
   if Length(FColumns)=0 then DrawGrid.ColCount := 1
@@ -532,6 +547,7 @@ end;
 
 
 constructor TOperationsGrid.Create(AOwner: TComponent);
 constructor TOperationsGrid.Create(AOwner: TComponent);
 begin
 begin
+  FAccountNumber := 0;
   FDrawGrid := Nil;
   FDrawGrid := Nil;
   FOperationsResume := TOperationsResumeList.Create;
   FOperationsResume := TOperationsResumeList.Create;
   FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
   FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
@@ -695,6 +711,7 @@ procedure TOperationsGrid.SetAccountNumber(const Value: Int64);
 begin
 begin
   if FAccountNumber=Value then exit;
   if FAccountNumber=Value then exit;
   FAccountNumber := Value;
   FAccountNumber := Value;
+  if FAccountNumber>=0 then FPendingOperations := false;
   UpdateAccountOperations;
   UpdateAccountOperations;
 end;
 end;
 
 
@@ -715,6 +732,13 @@ begin
   InitGrid;
   InitGrid;
 end;
 end;
 
 
+procedure TOperationsGrid.SetPendingOperations(const Value: Boolean);
+begin
+  FPendingOperations := Value;
+  if FPendingOperations then  FAccountNumber := -1;
+  UpdateAccountOperations;
+end;
+
 procedure TOperationsGrid.ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
 procedure TOperationsGrid.ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
 Var i : Integer;
 Var i : Integer;
   opr : TOperationResume;
   opr : TOperationResume;
@@ -736,46 +760,53 @@ procedure TOperationsGrid.UpdateAccountOperations;
 Var list : TList;
 Var list : TList;
   i,j : Integer;
   i,j : Integer;
   OPR : TOperationResume;
   OPR : TOperationResume;
-  bbalance : Int64;
   Op : TPCOperation;
   Op : TPCOperation;
 begin
 begin
   FOperationsResume.Clear;
   FOperationsResume.Clear;
   Try
   Try
     if Not Assigned(Node) then exit;
     if Not Assigned(Node) then exit;
-    if AccountNumber<0 then begin
-      list := TList.Create;
-      try
-        for i := 0 to Node.Operations.Count-1 do begin
-          Op := Node.Operations.Operation[i];
-          If TDBStorage.OperationToOperationResume(Op,Op.SenderAccount,OPR) then begin
-            OPR.Block := Node.Operations.OperationBlock.block;
-            OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
-            FOperationsResume.Add(OPR);
-          end;
+    if FPendingOperations then begin
+      for i := Node.Operations.Count - 1 downto 0 do begin
+        Op := Node.Operations.OperationsHashTree.GetOperation(i);
+        If TDBStorage.OperationToOperationResume(Op,Op.SenderAccount,OPR) then begin
+          OPR.Block := Node.Operations.OperationBlock.block;
+          OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
+          FOperationsResume.Add(OPR);
         end;
         end;
-      finally
-        list.Free;
       end;
       end;
     end else begin
     end else begin
-      list := TList.Create;
-      Try
-        Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
-//        bbalance := Node.Bank.SafeBox.Account(AccountNumber).balance;
-        for i := list.Count - 1 downto 0 do begin
-          Op := Node.Operations.OperationsHashTree.GetOperation(Integer(list[i]));
-          If TDBStorage.OperationToOperationResume(Op,AccountNumber,OPR) then begin
-            OPR.Block := Node.Operations.OperationBlock.block;
-//            bbalance := bbalance + OPR.Amount - OPR.Fee;
-//            OPR.Balance := bbalance;
-            OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
-            FOperationsResume.Add(OPR);
+      if AccountNumber<0 then begin
+        list := TList.Create;
+        try
+          for i := 0 to Node.Operations.Count-1 do begin
+            Op := Node.Operations.Operation[i];
+            If TDBStorage.OperationToOperationResume(Op,Op.SenderAccount,OPR) then begin
+              OPR.Block := Node.Operations.OperationBlock.block;
+              OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
+              FOperationsResume.Add(OPR);
+            end;
           end;
           end;
+        finally
+          list.Free;
+        end;
+      end else begin
+        list := TList.Create;
+        Try
+          Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
+          for i := list.Count - 1 downto 0 do begin
+            Op := Node.Operations.OperationsHashTree.GetOperation(Integer(list[i]));
+            If TDBStorage.OperationToOperationResume(Op,AccountNumber,OPR) then begin
+              OPR.Block := Node.Operations.OperationBlock.block;
+              OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
+              FOperationsResume.Add(OPR);
+            end;
+          end;
+        Finally
+          list.Free;
+        End;
+        if Node.Bank.Storage is TDBStorage then begin
+          TDBStorage(Node.Bank.Storage).GetOperationsFromAccount(FOperationsResume,AccountNumber,0,200);
         end;
         end;
-      Finally
-        list.Free;
-      End;
-      if Node.Bank.Storage is TDBStorage then begin
-        TDBStorage(Node.Bank.Storage).GetOperationsFromAccount(FOperationsResume,AccountNumber,0,20);
       end;
       end;
     end;
     end;
   Finally
   Finally
@@ -963,9 +994,7 @@ begin
   fld := DataSet.FieldByName('op_account');
   fld := DataSet.FieldByName('op_account');
   fld.AsString := TAccountComp.AccountNumberToAccountTxtNumber(DataSet.FieldByName(CT_TblFld_Operations_account).AsInteger);
   fld.AsString := TAccountComp.AccountNumberToAccountTxtNumber(DataSet.FieldByName(CT_TblFld_Operations_account).AsInteger);
   fld := DataSet.FieldByName('payload_txt');
   fld := DataSet.FieldByName('payload_txt');
-//  TDBStorage.BlobSaveToRaw(DataSet.FieldByName(CT_TblFld_Operations_payload_stream) as TBlobField,raw);
   TDBStorage.DBStringFieldToRaw(DataSet.FieldByName(CT_TblFld_Operations_rawpayload),raw);
   TDBStorage.DBStringFieldToRaw(DataSet.FieldByName(CT_TblFld_Operations_rawpayload),raw);
-//  raw := DataSet.FieldByName(CT_TblFld_Operations_payload).AsAnsiString;
   If TDBStorage.DBPayloadToReadableText(raw,s) then begin
   If TDBStorage.DBPayloadToReadableText(raw,s) then begin
     fld.AsString := s;
     fld.AsString := s;
   end else begin
   end else begin