Browse Source

Build 1.5.0

Build 1.5.0
PascalCoin 8 years ago
parent
commit
f0f367554b

BIN
PascalCoinWallet.res


+ 7 - 0
README.md

@@ -34,6 +34,13 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.5.0.0 - 2017-02-15
+
+- Net protocol upgrade to 4-5
+- Introducing "more work" with high priority than "more high". Work is calculated based on target. Higher target (more work) is more important than higher length
+- Solved locking/crash bug on high connections (caused by bad thread locking)
+- Improved network connection
+
 ### Build 1.4.3.0 - 2017-02-02
 
 - Adding "maturation" param to "JSON Operation object", return null when operation is not included on a blockchain yet, 0 means that is included in highest block and so on...

+ 7 - 0
README.txt

@@ -34,6 +34,13 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.5.0.0 - 2017-02-15
+
+- Net protocol upgrade to 4-5
+- Introducing "more work" with high priority than "more high". Work is calculated based on target. Higher target (more work) is more important than higher length
+- Solved locking/crash bug on high connections (caused by bad thread locking)
+- Improved network connection
+
 ### Build 1.4.3.0 - 2017-02-02
 
 - Adding "maturation" param to "JSON Operation object", return null when operation is not included on a blockchain yet, 0 means that is included in highest block and so on...

+ 1 - 1
Units/Forms/UFRMNodesIp.pas

@@ -112,7 +112,7 @@ begin
     TNode.DecodeIpStringToNodeServerAddressArray(ips,nsarr);
   end else begin
     cbTryOnlyWithThisServers.Checked := false;
-    nsarr := TNetData.NetData.GetValidNodeServers(false);
+    nsarr := TNetData.NetData.GetValidNodeServers(false,0);
   end;
   for i := low(nsarr) to high(nsarr) do begin
     aux := nsarr[i].ip;

+ 67 - 30
Units/Forms/UFRMPascalCoinWalletConfig.dfm

@@ -4,7 +4,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
   Caption = 'Options'
-  ClientHeight = 476
+  ClientHeight = 519
   ClientWidth = 374
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
@@ -19,7 +19,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   TextHeight = 13
   object Label1: TLabel
     Left = 30
-    Top = 335
+    Top = 390
     Width = 120
     Height = 13
     Caption = 'Default fee for operation'
@@ -47,7 +47,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   end
   object Label4: TLabel
     Left = 90
-    Top = 90
+    Top = 91
     Width = 259
     Height = 13
     Caption = 'This name will be included in each new block you mine!'
@@ -60,72 +60,92 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   end
   object Label5: TLabel
     Left = 30
-    Top = 176
+    Top = 231
     Width = 73
     Height = 13
     Caption = 'JSON-RPC Port'
   end
   object lblDefaultJSONRPCMinerServerPort: TLabel
     Left = 248
-    Top = 176
+    Top = 231
     Width = 70
     Height = 13
     Caption = '(Default XXXX)'
   end
+  object Label6: TLabel
+    Left = 24
+    Top = 162
+    Width = 57
+    Height = 13
+    Caption = 'Allowed IP'#39's'
+  end
+  object Label7: TLabel
+    Left = 92
+    Top = 182
+    Width = 209
+    Height = 13
+    Caption = 'Ip'#39's separated by semicolon or empty for all'
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clGray
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = []
+    ParentFont = False
+  end
   object cbJSONRPCMinerServerActive: TCheckBox
     Left = 15
-    Top = 150
+    Top = 205
     Width = 261
     Height = 17
     Caption = 'JSON-RPC Server Miner (TCP/IP, no HTTP)'
-    TabOrder = 4
+    TabOrder = 6
   end
   object ebDefaultFee: TEdit
     Left = 170
-    Top = 332
+    Top = 387
     Width = 56
     Height = 21
     Alignment = taRightJustify
-    TabOrder = 8
+    TabOrder = 10
     Text = '0'
   end
   object cbSaveLogFiles: TCheckBox
     Left = 15
-    Top = 359
+    Top = 414
     Width = 97
     Height = 17
     Caption = 'Save log file'
-    TabOrder = 9
+    TabOrder = 11
     OnClick = cbSaveLogFilesClick
   end
   object cbShowLogs: TCheckBox
     Left = 15
-    Top = 397
+    Top = 452
     Width = 97
     Height = 17
     Caption = 'Show logs'
-    TabOrder = 11
+    TabOrder = 13
   end
   object bbOk: TBitBtn
     Left = 176
-    Top = 420
+    Top = 475
     Width = 75
     Height = 25
     DoubleBuffered = True
     Kind = bkOK
     ParentDoubleBuffered = False
-    TabOrder = 14
+    TabOrder = 16
     OnClick = bbOkClick
   end
   object bbCancel: TBitBtn
     Left = 266
-    Top = 420
+    Top = 475
     Width = 75
     Height = 25
     DoubleBuffered = True
     Kind = bkCancel
     ParentDoubleBuffered = False
-    TabOrder = 15
+    TabOrder = 17
   end
   object udInternetServerPort: TUpDown
     Left = 226
@@ -228,40 +248,40 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   end
   object cbShowModalMessages: TCheckBox
     Left = 170
-    Top = 359
+    Top = 414
     Width = 171
     Height = 17
     Caption = 'Show modal messages'
-    TabOrder = 12
+    TabOrder = 14
   end
   object udJSONRPCMinerServerPort: TUpDown
     Left = 226
-    Top = 173
+    Top = 228
     Width = 16
     Height = 21
     Associate = ebJSONRPCMinerServerPort
     Min = 1
     Max = 40000
     Position = 1
-    TabOrder = 6
+    TabOrder = 8
     Thousands = False
   end
   object ebJSONRPCMinerServerPort: TEdit
     Left = 170
-    Top = 173
+    Top = 228
     Width = 56
     Height = 21
     Alignment = taRightJustify
-    TabOrder = 5
+    TabOrder = 7
     Text = '1'
   end
   object gbMinerPrivateKey: TGroupBox
-    Left = 8
-    Top = 200
+    Left = 15
+    Top = 255
     Width = 334
     Height = 121
     Caption = ' Miner Server Private Key: '
-    TabOrder = 7
+    TabOrder = 9
     object rbGenerateANewPrivateKeyEachBlock: TRadioButton
       Left = 20
       Top = 20
@@ -297,15 +317,15 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   end
   object cbSaveDebugLogs: TCheckBox
     Left = 31
-    Top = 377
+    Top = 432
     Width = 97
     Height = 17
     Caption = 'Save debug logs too'
-    TabOrder = 10
+    TabOrder = 12
   end
   object bbOpenDataFolder: TBitBtn
     Left = 15
-    Top = 420
+    Top = 475
     Width = 120
     Height = 25
     Caption = 'Open Data folder'
@@ -338,7 +358,24 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
       FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
       00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
     ParentDoubleBuffered = False
-    TabOrder = 13
+    TabOrder = 15
     OnClick = bbOpenDataFolderClick
   end
+  object cbJSONRPCPortEnabled: TCheckBox
+    Left = 15
+    Top = 139
+    Width = 261
+    Height = 17
+    Caption = 'JSON-RPC Server port enabled (HTTP)'
+    TabOrder = 4
+    OnClick = cbJSONRPCPortEnabledClick
+  end
+  object ebJSONRPCAllowedIPs: TEdit
+    Left = 90
+    Top = 158
+    Width = 261
+    Height = 21
+    TabOrder = 5
+    Text = 'ebJSONRPCAllowedIPs'
+  end
 end

+ 73 - 30
Units/Forms/UFRMPascalCoinWalletConfig.lfm

@@ -1,12 +1,12 @@
 object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   Left = 462
-  Height = 479
+  Height = 524
   Top = 234
   Width = 374
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
   Caption = 'Options'
-  ClientHeight = 479
+  ClientHeight = 524
   ClientWidth = 374
   Color = clBtnFace
   Font.Color = clWindowText
@@ -18,7 +18,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   object Label1: TLabel
     Left = 30
     Height = 13
-    Top = 335
+    Top = 385
     Width = 120
     Caption = 'Default fee for operation'
     ParentColor = False
@@ -53,16 +53,19 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Top = 90
     Width = 259
     Caption = 'This name will be included in each new block you mine!'
+    Font.CharSet = ANSI_CHARSET
     Font.Color = clGray
     Font.Height = -11
     Font.Name = 'Tahoma'
+    Font.Pitch = fpVariable
+    Font.Quality = fqDraft
     ParentColor = False
     ParentFont = False
   end
   object Label5: TLabel
     Left = 30
     Height = 13
-    Top = 176
+    Top = 226
     Width = 73
     Caption = 'JSON-RPC Port'
     ParentColor = False
@@ -70,7 +73,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   object lblDefaultJSONRPCMinerServerPort: TLabel
     Left = 248
     Height = 13
-    Top = 176
+    Top = 226
     Width = 70
     Caption = '(Default XXXX)'
     ParentColor = False
@@ -78,55 +81,55 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   object cbJSONRPCMinerServerActive: TCheckBox
     Left = 15
     Height = 19
-    Top = 150
+    Top = 200
     Width = 225
     Caption = 'JSON-RPC Server Miner (TCP/IP, no HTTP)'
-    TabOrder = 4
+    TabOrder = 6
   end
   object ebDefaultFee: TEdit
     Left = 170
     Height = 21
-    Top = 332
+    Top = 382
     Width = 56
     Alignment = taRightJustify
-    TabOrder = 8
+    TabOrder = 10
     Text = '0'
   end
   object cbSaveLogFiles: TCheckBox
     Left = 15
     Height = 19
-    Top = 359
+    Top = 409
     Width = 78
     Caption = 'Save log file'
     OnClick = cbSaveLogFilesClick
-    TabOrder = 9
+    TabOrder = 11
   end
   object cbShowLogs: TCheckBox
     Left = 15
     Height = 19
-    Top = 397
+    Top = 447
     Width = 68
     Caption = 'Show logs'
-    TabOrder = 11
+    TabOrder = 13
   end
   object bbOk: TBitBtn
     Left = 184
     Height = 30
-    Top = 432
+    Top = 482
     Width = 75
     Kind = bkOK
     OnClick = bbOkClick
-    TabOrder = 14
+    TabOrder = 16
   end
   object bbCancel: TBitBtn
     Left = 274
     Height = 30
-    Top = 432
+    Top = 482
     Width = 75
     Cancel = True
     Kind = bkCancel
     ModalResult = 2
-    TabOrder = 15
+    TabOrder = 17
   end
   object udInternetServerPort: TUpDown
     Left = 226
@@ -154,7 +157,7 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
     Left = 15
     Height = 38
     Top = 14
-    Width = 336
+    Width = 337
     Caption = 'Wallet Password'
     Font.Color = clWindowText
     Font.Height = -13
@@ -229,42 +232,42 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   object cbShowModalMessages: TCheckBox
     Left = 170
     Height = 19
-    Top = 359
+    Top = 409
     Width = 127
     Caption = 'Show modal messages'
-    TabOrder = 12
+    TabOrder = 14
   end
   object udJSONRPCMinerServerPort: TUpDown
     Left = 226
     Height = 21
-    Top = 173
+    Top = 223
     Width = 16
     Associate = ebJSONRPCMinerServerPort
     Max = 25000
     Min = 1
     Position = 4009
-    TabOrder = 6
+    TabOrder = 8
     Thousands = False
     Wrap = False
   end
   object ebJSONRPCMinerServerPort: TEdit
     Left = 170
     Height = 21
-    Top = 173
+    Top = 223
     Width = 56
     Alignment = taRightJustify
-    TabOrder = 5
+    TabOrder = 7
     Text = '4009'
   end
   object gbMinerPrivateKey: TGroupBox
     Left = 8
     Height = 121
-    Top = 200
+    Top = 250
     Width = 334
     Caption = ' Miner Server Private Key: '
     ClientHeight = 103
     ClientWidth = 330
-    TabOrder = 7
+    TabOrder = 9
     object rbGenerateANewPrivateKeyEachBlock: TRadioButton
       Left = 18
       Height = 19
@@ -302,15 +305,15 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
   object cbSaveDebugLogs: TCheckBox
     Left = 31
     Height = 19
-    Top = 377
+    Top = 427
     Width = 118
     Caption = 'Save debug logs too'
-    TabOrder = 10
+    TabOrder = 12
   end
   object bbOpenDataFolder: TBitBtn
     Left = 16
     Height = 30
-    Top = 432
+    Top = 482
     Width = 131
     Caption = 'Open Data Folder'
     Glyph.Data = {
@@ -350,6 +353,46 @@ object FRMPascalCoinWalletConfig: TFRMPascalCoinWalletConfig
       FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00
     }
     OnClick = bbOpenDataFolderClick
-    TabOrder = 13
+    TabOrder = 15
+  end
+  object cbJSONRPCPortEnabled: TCheckBox
+    Left = 15
+    Height = 19
+    Top = 136
+    Width = 205
+    Caption = 'JSON-RPC Server port enabled (HTTP)'
+    OnClick = cbJSONRPCPortEnabledClick
+    TabOrder = 4
+  end
+  object Label6: TLabel
+    Left = 24
+    Height = 13
+    Top = 162
+    Width = 57
+    Caption = 'Allowed IP''s'
+    ParentColor = False
+  end
+  object ebJSONRPCAllowedIPs: TEdit
+    Left = 90
+    Height = 21
+    Top = 159
+    Width = 261
+    TabOrder = 5
+    Text = 'ebJSONRPCAllowedIPs'
+  end
+  object Label7: TLabel
+    Left = 90
+    Height = 13
+    Top = 183
+    Width = 209
+    Caption = 'Ip''s separated by semicolon or empty for all'
+    Font.CharSet = ANSI_CHARSET
+    Font.Color = clGray
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Pitch = fpVariable
+    Font.Quality = fqDraft
+    ParentColor = False
+    ParentFont = False
   end
 end

+ 16 - 0
Units/Forms/UFRMPascalCoinWalletConfig.pas

@@ -63,11 +63,16 @@ type
     cbPrivateKeyToMine: TComboBox;
     cbSaveDebugLogs: TCheckBox;
     bbOpenDataFolder: TBitBtn;
+    cbJSONRPCPortEnabled: TCheckBox;
+    ebJSONRPCAllowedIPs: TEdit;
+    Label6: TLabel;
+    Label7: TLabel;
     procedure FormCreate(Sender: TObject);
     procedure bbOkClick(Sender: TObject);
     procedure bbUpdatePasswordClick(Sender: TObject);
     procedure cbSaveLogFilesClick(Sender: TObject);
     procedure bbOpenDataFolderClick(Sender: TObject);
+    procedure cbJSONRPCPortEnabledClick(Sender: TObject);
   private
     FAppParams: TAppParams;
     FWalletKeys: TWalletKeys;
@@ -123,6 +128,9 @@ begin
   AppParams.ParamByName[CT_PARAM_MinerName].SetAsString(ebMinerName.Text);
   AppParams.ParamByName[CT_PARAM_ShowModalMessages].SetAsBoolean(cbShowModalMessages.Checked);
   AppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].SetAsInteger(udJSONRPCMinerServerPort.Position);
+  AppParams.ParamByName[CT_PARAM_JSONRPCEnabled].SetAsBoolean(cbJSONRPCPortEnabled.Checked);
+  AppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].SetAsString(ebJSONRPCAllowedIPs.Text);
+
   ModalResult := MrOk;
 end;
 
@@ -163,6 +171,11 @@ begin
   UpdateWalletConfig;
 end;
 
+procedure TFRMPascalCoinWalletConfig.cbJSONRPCPortEnabledClick(Sender: TObject);
+begin
+  ebJSONRPCAllowedIPs.Enabled := cbJSONRPCPortEnabled.Checked;
+end;
+
 procedure TFRMPascalCoinWalletConfig.cbSaveLogFilesClick(Sender: TObject);
 begin
   cbSaveDebugLogs.Enabled := cbSaveLogFiles.Checked;
@@ -201,12 +214,15 @@ begin
     ebMinerName.Text := AppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
     cbShowModalMessages.Checked := AppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false);
     udJSONRPCMinerServerPort.Position := AppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port);
+    cbJSONRPCPortEnabled.Checked := AppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
+    ebJSONRPCAllowedIPs.Text := AppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1;');
   Except
     On E:Exception do begin
       TLog.NewLog(lterror,ClassName,'Exception at SetAppParams: '+E.Message);
     end;
   End;
   cbSaveLogFilesClick(nil);
+  cbJSONRPCPortEnabledClick(nil);
 end;
 
 procedure TFRMPascalCoinWalletConfig.SetWalletKeys(const Value: TWalletKeys);

+ 9 - 0
Units/Forms/UFRMPayloadDecoder.dfm

@@ -255,6 +255,15 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
         TabOrder = 1
         OnKeyDown = memoDecodedKeyDown
       end
+      object cbShowAsHexadecimal: TCheckBox
+        Left = 115
+        Top = 93
+        Width = 136
+        Height = 17
+        Caption = 'Show as hexadecimal'
+        TabOrder = 2
+        OnClick = cbShowAsHexadecimalClick
+      end
     end
     object tsDecodeMethods: TTabSheet
       Caption = 'Decode methods'

+ 9 - 0
Units/Forms/UFRMPayloadDecoder.lfm

@@ -266,6 +266,15 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
         TabOrder = 1
         TabStop = False
       end
+      object cbShowAsHexadecimal: TCheckBox
+        Left = 112
+        Height = 19
+        Top = 91
+        Width = 122
+        Caption = 'Show as hexadecimal'
+        OnClick = cbShowAsHexadecimalClick
+        TabOrder = 2
+      end
     end
     object tsDecodeMethods: TTabSheet
       Caption = 'Decode methods'

+ 15 - 3
Units/Forms/UFRMPayloadDecoder.pas

@@ -67,6 +67,7 @@ type
     lblReceiverCaption: TLabel;
     lblReceiver: TLabel;
     lblReceiverInfo: TLabel;
+    cbShowAsHexadecimal: TCheckBox;
     procedure FormCreate(Sender: TObject);
     procedure PageControlChanging(Sender: TObject; var AllowChange: Boolean);
     procedure cbMethodPublicPayloadClick(Sender: TObject);
@@ -76,6 +77,7 @@ type
     procedure bbFindClick(Sender: TObject);
     procedure ebOphashExit(Sender: TObject);
     procedure ebOphashKeyPress(Sender: TObject; var Key: Char);
+    procedure cbShowAsHexadecimalClick(Sender: TObject);
   private
     FOpResume : TOperationResume;
     FWalletKeys : TWalletKeys;
@@ -126,6 +128,11 @@ begin
   lblPasswordsInfo.Caption := Format('Possible passwords: %d',[memoPasswords.Lines.Count]);
 end;
 
+procedure TFRMPayloadDecoder.cbShowAsHexadecimalClick(Sender: TObject);
+begin
+  TryToDecode;
+end;
+
 procedure TFRMPayloadDecoder.DoFind(Const OpHash : String);
 Var
   r : TRawBytes;
@@ -238,6 +245,7 @@ begin
   FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].SetAsBoolean(cbUsingPrivateKeys.Checked);
   FAppParams.ParamByName['PayloadDecoder.usingpasswords'].SetAsBoolean(cbUsingPasswords.Checked);
   FAppParams.ParamByName['PayloadDecoder.passwords'].SetAsString(memoPasswords.Lines.Text);
+  FAppParams.ParamByName['PayloadDecoder.showashexadecimal'].SetAsBoolean(cbShowAsHexadecimal.Checked);
   FSavedDecodeMethods := true;
 end;
 
@@ -305,6 +313,7 @@ begin
       cbUsingPrivateKeys.Checked := FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].GetAsBoolean(true);
       cbUsingPasswords.Checked := FAppParams.ParamByName['PayloadDecoder.usingpasswords'].GetAsBoolean(true);
       memoPasswords.Lines.Text := FAppParams.ParamByName['PayloadDecoder.passwords'].GetAsString('');
+      cbShowAsHexadecimal.Checked := FAppParams.ParamByName['PayloadDecoder.showashexadecimal'].GetAsBoolean(false);
     end else begin
       cbMethodPublicPayload.Checked := true;
       cbUsingPrivateKeys.Checked := true;
@@ -365,13 +374,16 @@ begin
     if raw<>'' then begin
       // First try to a human readable...
       if (cbMethodPublicPayload.Checked) and (TCrypto.IsHumanReadable(raw)) then begin
-        memoDecoded.Lines.Text := raw;
+        if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(raw)
+        else memoDecoded.Lines.Text := raw;
         lblDecodedMethod.Caption := 'Not encrypted payload';
       end else if (cbUsingPrivateKeys.Checked) And (UseWallet(raw,Decrypted,WalletKey)) then begin
-        memoDecoded.Lines.Text := Decrypted;
+        if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(Decrypted)
+        else memoDecoded.Lines.Text := Decrypted;
         lblDecodedMethod.Caption := 'Encrypted with EC '+TAccountComp.GetECInfoTxt(WalletKey.PrivateKey.EC_OpenSSL_NID);
       end else if (cbUsingPasswords.Checked) And (UsePassword(raw,Decrypted,PasswordUsed)) then begin
-        memoDecoded.Lines.Text := Decrypted;
+        if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(Decrypted)
+        else memoDecoded.Lines.Text := Decrypted;
         lblDecodedMethod.Caption := 'Encrypted with pwd:"'+PasswordUsed+'"';
       end else begin
         memoDecoded.Lines.Text := 'CANNOT DECRYPT';

+ 37 - 1
Units/Forms/UFRMWallet.dfm

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

+ 67 - 47
Units/Forms/UFRMWallet.pas

@@ -339,7 +339,8 @@ begin
     // Create RPC server
     FRPCServer := TRPCServer.Create;
     FRPCServer.WalletKeys := WalletKeys;
-    FRPCServer.Active := true;
+    FRPCServer.Active := FAppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
+    FRPCServer.ValidIPs := FAppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1');
     WalletKeys.SafeBox := FNode.Bank.SafeBox;
     // Check Database
     FNode.Bank.StorageClass := TFileStorage;
@@ -361,7 +362,7 @@ begin
     TNetData.NetData.OnNodeServersUpdated := OnNetNodeServersUpdated;
     TNetData.NetData.OnBlackListUpdated := OnNetBlackListUpdated;
     //
-    TimerUpdateStatus.Interval := 5000;
+    TimerUpdateStatus.Interval := 1000;
     TimerUpdateStatus.Enabled := true;
     UpdateConfigChanged;
   Except
@@ -513,8 +514,9 @@ Const CT_BooleanToString : Array[Boolean] of String = ('False','True');
 Var i : integer;
  NC : TNetConnection;
  l : TList;
- sClientApp : String;
+ sClientApp, sLastConnTime : String;
  strings, sNSC, sRS, sDisc : TStrings;
+ hh,nn,ss,ms : Word;
 begin
   Try
     if Not TNetData.NetData.NetConnections.TryLockList(100,l) then exit;
@@ -534,15 +536,25 @@ begin
           end;
 
           if NC.Connected then begin
+            if NC.Client.LastCommunicationTime>1000 then begin
+              DecodeTime(now - NC.Client.LastCommunicationTime,hh,nn,ss,ms);
+              if (hh=0) and (nn=0) And (ss<10) then begin
+                sLastConnTime := ' - Last comunication <10 sec.';
+              end else begin
+                sLastConnTime := Format(' - Last comunication %.2dm%.2ds',[(hh*60)+nn,ss]);
+              end;
+            end else begin
+              sLastConnTime := '';
+            end;
             if NC is TNetServerClient then begin
-              sNSC.Add(Format('Client: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
+              sNSC.Add(Format('Client: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]));
             end else begin
-              if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]))
+              if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]))
               else begin
-                sRS.Add(Format('Remote Server: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
+                sRS.Add(Format('Remote Server: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]));
               end;
             end;
           end else begin
@@ -805,6 +817,8 @@ begin
   FMustProcessWalletChanged := false;
   FMustProcessNetConnectionUpdated := false;
   FRPCServer := Nil;
+  FNode := Nil;
+  FPoolMiningServer := Nil;
   FMinAccountBalance := 0;
   FMaxAccountBalance := CT_MaxWalletAmount;
   FMessagesUnreadCount := 0;
@@ -814,7 +828,6 @@ begin
   memoNetBlackLists.Lines.Clear;
   memoMessages.Lines.Clear;
   memoMessageToSend.Lines.Clear;
-  FNode := Nil;
   FUpdating := false;
   FOrderedAccountsKeyList := Nil;
   TimerUpdateStatus.Enabled := false;
@@ -869,7 +882,6 @@ begin
   TrayIcon.BalloonFlags := bfInfo;
   MinersBlocksFound := 0;
   lblBuild.Caption := 'Build: '+CT_ClientAppVersion;
-  FPoolMiningServer := Nil;
 end;
 
 procedure TFRMWallet.FormDestroy(Sender: TObject);
@@ -1180,35 +1192,38 @@ end;
 
 procedure TFRMWallet.OnNetBlackListUpdated(Sender: TObject);
 Const CT_TRUE_FALSE : Array[Boolean] Of AnsiString = ('FALSE','TRUE');
-Var i,j : integer;
+Var i,j,n : integer;
  P : PNodeServerAddress;
  l : TList;
  strings : TStrings;
 begin
-  l := TNetData.NetData.BlackList.LockList;
+  l := TNetData.NetData.NodeServersAddresses.LockList;
   try
     strings := memoNetBlackLists.Lines;
     strings.BeginUpdate;
     Try
       strings.Clear;
       strings.Add('BlackList Updated: '+DateTimeToStr(now)+' by TID:'+IntToHex(TThread.CurrentThread.ThreadID,8));
-      j := 0;
+      j := 0; n:=0;
       for i := 0 to l.Count - 1 do begin
         P := l[i];
-        if Not P^.its_myself then begin
-          inc(j);
-          strings.Add(Format('Blacklist IP:%s:%d LastConnection:%s Reason: %s',
-            [
-             P^.ip,P^.port,
-             DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection))),P^.BlackListText]));
+        if (P^.is_blacklisted) then begin
+          inc(n);
+          if Not P^.its_myself then begin
+            inc(j);
+            strings.Add(Format('Blacklist IP:%s:%d LastConnection:%s Reason: %s',
+              [
+               P^.ip,P^.port,
+               DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection))),P^.BlackListText]));
+          end;
         end;
       end;
-      Strings.Add(Format('Total Blacklisted IPs: %d (Total %d)',[j,l.Count]));
+      Strings.Add(Format('Total Blacklisted IPs: %d (Total %d)',[j,n]));
     Finally
       strings.EndUpdate;
     End;
   finally
-    TNetData.NetData.BlackList.UnlockList;
+    TNetData.NetData.NodeServersAddresses.UnlockList;
   end;
 end;
 
@@ -1226,7 +1241,7 @@ Var i : integer;
  strings : TStrings;
  s : String;
 begin
-  l := TNetData.NetData.NodeServers.LockList;
+  l := TNetData.NetData.NodeServersAddresses.LockList;
   try
     strings := memoNetServers.Lines;
     strings.BeginUpdate;
@@ -1235,34 +1250,36 @@ begin
       strings.Add('NodeServers Updated: '+DateTimeToStr(now) +' Count: '+inttostr(l.Count));
       for i := 0 to l.Count - 1 do begin
         P := l[i];
-        s := Format('Server IP:%s:%d',[P^.ip,P^.port]);
-        if Assigned(P.netConnection) then begin
-          If P.last_connection>0 then  s := s+ ' ** ACTIVE **'
-          else s := s+' ** TRYING TO CONNECT **';
-        end;
-        if P.its_myself then begin
-          s := s+' ** NOT VALID ** '+P.BlackListText;
-        end;
-        if P.last_connection>0 then begin
-          s := s + ' Last connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection)));
-        end;
-        if P.last_connection_by_server>0 then begin
-          s := s + ' Last server connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection_by_server)));
-        end;
-        if (P.last_attempt_to_connect>0) then begin
-          s := s + ' Last attempt to connect: '+DateTimeToStr(P^.last_attempt_to_connect);
-        end;
-        if (P.total_failed_attemps_to_connect>0) then begin
-          s := s + ' (Attempts: '+inttostr(P^.total_failed_attemps_to_connect)+')';
-        end;
+        if Not (P^.is_blacklisted) then begin
+          s := Format('Server IP:%s:%d',[P^.ip,P^.port]);
+          if Assigned(P.netConnection) then begin
+            If P.last_connection>0 then  s := s+ ' ** ACTIVE **'
+            else s := s+' ** TRYING TO CONNECT **';
+          end;
+          if P.its_myself then begin
+            s := s+' ** NOT VALID ** '+P.BlackListText;
+          end;
+          if P.last_connection>0 then begin
+            s := s + ' Last connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection)));
+          end;
+          if P.last_connection_by_server>0 then begin
+            s := s + ' Last server connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection_by_server)));
+          end;
+          if (P.last_attempt_to_connect>0) then begin
+            s := s + ' Last attempt to connect: '+DateTimeToStr(P^.last_attempt_to_connect);
+          end;
+          if (P.total_failed_attemps_to_connect>0) then begin
+            s := s + ' (Attempts: '+inttostr(P^.total_failed_attemps_to_connect)+')';
+          end;
 
-        strings.Add(s);
+          strings.Add(s);
+        end;
       end;
     Finally
       strings.EndUpdate;
     End;
   finally
-    TNetData.NetData.NodeServers.UnlockList;
+    TNetData.NetData.NodeServersAddresses.UnlockList;
   end;
 end;
 
@@ -1348,7 +1365,7 @@ Var nsarr : TNodeServerAddressArray;
 begin
   //CheckMining;
   // Update node servers Peer Cache
-  nsarr := TNetData.NetData.GetValidNodeServers(true);
+  nsarr := TNetData.NetData.GetValidNodeServers(true,0);
   s := '';
   for i := low(nsarr) to High(nsarr) do begin
     if (s<>'') then s := s+';';
@@ -1703,7 +1720,10 @@ begin
     FPoolMiningServer.Active :=FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerActive].GetAsBoolean(true);
     FPoolMiningServer.UpdateAccountAndPayload(GetAccountKeyForMiner,FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString(''));
   end;
-
+  if Assigned(FRPCServer) then begin
+    FRPCServer.Active := FAppParams.ParamByName[CT_PARAM_JSONRPCEnabled].GetAsBoolean(false);
+    FRPCServer.ValidIPs := FAppParams.ParamByName[CT_PARAM_JSONRPCAllowedIPs].GetAsString('127.0.0.1');
+  end;
   i := FAppParams.ParamByName[CT_PARAM_MinerPrivateKeyType].GetAsInteger(Integer(mpk_Random));
   if (i>=Integer(Low(TMinerPrivatekey))) And (i<=Integer(High(TMinerPrivatekey))) then FMinerPrivateKeyType := TMinerPrivateKey(i)
   else FMinerPrivateKeyType := mpk_Random;

+ 1 - 1
Units/Forms/UFRMWalletKeys.pas

@@ -294,7 +294,7 @@ begin
                 i := WalletKeys.IndexOfAccountKey(EC.PublicKey);
                 if (i>=0) then begin
                   wk := WalletKeys.Key[i];
-                  if Assigned(wk.PrivateKey) And (Assigned(wk.PrivateKey.PrivateKey)) then raise Exception.Create('This key is allready in your wallet!');
+                  if Assigned(wk.PrivateKey) And (Assigned(wk.PrivateKey.PrivateKey)) then raise Exception.Create('This key is already in your wallet!');
                 end;
                 s := 'Imported '+DateTimeToStr(now);
                 s := InputBox('Set a name','Name for this private key:',s);

+ 25 - 18
Units/PascalCoin/UAccounts.pas

@@ -20,7 +20,7 @@ unit UAccounts;
 interface
 
 uses
-  Classes, UConst, UCrypto, SyncObjs;
+  Classes, UConst, UCrypto, SyncObjs, UThread;
 
 Type
   TAccountKey = TECDSA_Public;
@@ -66,6 +66,8 @@ Type
     block_hash: AnsiString;   // Calculated on every block change (on create and on accounts updated)
     // New Build 1.0.8 "target" stored in TBlockAccount to increase performance calculating network hash rate.
     target: Cardinal;         // FIXED: Same value that stored in BlockChain. ** NOT USED TO CALC BLOCK HASHING **
+    // New Build 1.5
+    AccumulatedWork : UInt64; // FIXED: Accumulated work (previous + target) ** NOT USED TO CALC BLOCK HASHING AND NOT STORED **
   end;
   PBlockAccount = ^TBlockAccount;
 
@@ -115,8 +117,8 @@ Type
     Destructor Destroy; override;
     Procedure AddAccountKey(Const AccountKey : TAccountKey);
     Procedure RemoveAccountKey(Const AccountKey : TAccountKey);
-    Procedure AddAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
-    Procedure RemoveAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
+    Procedure AddAccounts(Const AccountKey : TAccountKey; const accounts : Array of Cardinal);
+    Procedure RemoveAccounts(Const AccountKey : TAccountKey; const accounts : Array of Cardinal);
     Function IndexOfAccountKey(Const AccountKey : TAccountKey) : Integer;
     Property AccountKeyList[index : Integer] : TOrderedCardinalList read GetAccountKeyList;
     Property AccountKey[index : Integer] : TAccountKey read GetAccountKey;
@@ -140,11 +142,12 @@ Type
     FTotalBalance: Int64;
     FTotalFee: Int64;
     FSafeBoxHash : TRawBytes;
-    FLock: TCriticalSection; // Thread safe
+    FLock: TPCCriticalSection; // Thread safe
     FPreviousBlockSafeBoxHash : TRawBytes;
+    FWorkSum : UInt64;
     Procedure SetAccount(account_number : Cardinal; newAccountkey: TAccountKey; newBalance: UInt64; newN_operation: Cardinal);
-    Procedure AccountKeyListAddAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
-    Procedure AccountKeyListRemoveAccount(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
+    Procedure AccountKeyListAddAccounts(Const AccountKey : TAccountKey; const accounts : Array of Cardinal);
+    Procedure AccountKeyListRemoveAccount(Const AccountKey : TAccountKey; const accounts : Array of Cardinal);
   protected
     Function AddNew(Const accountkey: TAccountKey; reward: UInt64; timestamp: Cardinal; compact_target: Cardinal; Const proof_of_work: AnsiString) : TBlockAccount;
   public
@@ -168,6 +171,7 @@ Type
     Procedure EndThreadSave;
     Property SafeBoxHash : TRawBytes read FSafeBoxHash;
     Property PreviousBlockSafeBoxHash : TRawBytes read FPreviousBlockSafeBoxHash;
+    Property WorkSum : UInt64 read FWorkSum; // New Build 1.5
   End;
 
 
@@ -231,12 +235,13 @@ Const
     );
     timestamp:0;
     block_hash:'';
-    target:0;);
+    target:0;
+    AccumulatedWork:0);
 
 implementation
 
 uses
-  SysUtils, ULog, UOpenSSLdef, UOpenSSL, UThread;
+  SysUtils, ULog, UOpenSSLdef, UOpenSSL;
 
 { TStreamOp }
 
@@ -383,8 +388,6 @@ Var an : int64;
 begin
   an := account_number;
   an := ((an * 101) MOD 89)+10;
-  //BUILD 1.1.1 change cheksum calculation
-  //Prior was: an := ((((((an * 3) MOD 97) * 7) MOD 101) * 5) MOD 89)+10;
   Result := IntToStr(account_number)+'-'+Inttostr(an);
 end;
 
@@ -493,8 +496,6 @@ begin
   if (account_txt_number[i] in ['-','.',' ']) then inc(i);
   if length(account_txt_number)-1<>i then exit;
   rn := StrToIntDef(copy(account_txt_number,i,length(account_txt_number)),0);
-  //BUILD 1.1.1 change cheksum calculation
-  //Prior was: anaux := (((((((an * 3) MOD 97) * 7) MOD 101) * 5) MOD 89)+10);
   anaux := ((an * 101) MOD 89)+10;
   Result := rn = anaux;
 end;
@@ -645,6 +646,9 @@ begin
   Result.timestamp := timestamp;
   Result.block_hash := CalcBlockHash(Result);
   Result.target := compact_target;
+  Inc(FWorkSum,Result.target);
+  Result.AccumulatedWork := FWorkSum;
+
   New(P);
   P^ := Result;
   FBlockAccountsList.Add(P);
@@ -657,7 +661,7 @@ begin
   FSafeBoxHash := CalcSafeBoxHash;
 end;
 
-procedure TPCSafeBox.AccountKeyListAddAccounts(const AccountKey: TAccountKey; accounts: array of Cardinal);
+procedure TPCSafeBox.AccountKeyListAddAccounts(const AccountKey: TAccountKey; const accounts: array of Cardinal);
 Var i : Integer;
 begin
   for i := 0 to FListOfOrderedAccountKeysList.count-1 do begin
@@ -665,7 +669,7 @@ begin
   end;
 end;
 
-procedure TPCSafeBox.AccountKeyListRemoveAccount(const AccountKey: TAccountKey; accounts: array of Cardinal);
+procedure TPCSafeBox.AccountKeyListRemoveAccount(const AccountKey: TAccountKey; const accounts: array of Cardinal);
 Var i : Integer;
 begin
   for i := 0 to FListOfOrderedAccountKeysList.count-1 do begin
@@ -790,6 +794,7 @@ begin
     FTotalFee := 0;
     FSafeBoxHash := CalcSafeBoxHash;
     FPreviousBlockSafeBoxHash := '';
+    FWorkSum := 0;
   Finally
     EndThreadSave;
   end;
@@ -817,12 +822,12 @@ begin
           end;
         end;
       end;
-
       FTotalBalance := accounts.TotalBalance;
       FTotalFee := accounts.FTotalFee;
       FBufferBlocksHash := accounts.FBufferBlocksHash;
       FSafeBoxHash := accounts.FSafeBoxHash;
       FPreviousBlockSafeBoxHash := accounts.FPreviousBlockSafeBoxHash;
+      FWorkSum := accounts.FWorkSum;
     finally
       accounts.EndThreadSave;
     end;
@@ -833,7 +838,7 @@ end;
 
 constructor TPCSafeBox.Create;
 begin
-  FLock := TCriticalSection.Create;
+  FLock := TPCCriticalSection.Create('TPCSafeBox_Lock');
   FBlockAccountsList := TList.Create;
   FListOfOrderedAccountKeysList := TList.Create;
   Clear;
@@ -920,6 +925,8 @@ begin
         if safeBoxBankVersion>=2 then begin
           if Stream.Read(block.target,4)<4 then exit;
         end;
+        Inc(FWorkSum,block.target);
+        block.AccumulatedWork := FWorkSum;
         // Add
         New(P);
         P^ := block;
@@ -1348,7 +1355,7 @@ begin
   end;
 end;
 
-procedure TOrderedAccountKeysList.AddAccounts(const AccountKey: TAccountKey; accounts: array of Cardinal);
+procedure TOrderedAccountKeysList.AddAccounts(const AccountKey: TAccountKey; const accounts: array of Cardinal);
 Var P : POrderedAccountKeyList;
   i,i2 : Integer;
 begin
@@ -1463,7 +1470,7 @@ begin
   If Not Find(AccountKey,Result) then Result := -1;
 end;
 
-procedure TOrderedAccountKeysList.RemoveAccounts(const AccountKey: TAccountKey; accounts: array of Cardinal);
+procedure TOrderedAccountKeysList.RemoveAccounts(const AccountKey: TAccountKey; const accounts: array of Cardinal);
 Var P : POrderedAccountKeyList;
   i,j : Integer;
 begin

+ 65 - 67
Units/PascalCoin/UBlockChain.pas

@@ -217,6 +217,7 @@ Type
     Property TotalFee : Int64 read FTotalFee;
     function SaveOperationsHashTreeToStream(Stream: TStream; SaveToStorage : Boolean): Boolean;
     function LoadOperationsHashTreeFromStream(Stream: TStream; LoadingFromStorage : Boolean; var errors : AnsiString): Boolean;
+    function IndexOfOperation(op : TPCOperation) : Integer;
   End;
 
   { TPCOperationsComp }
@@ -233,7 +234,7 @@ Type
     FIsOnlyOperationBlock: Boolean;
     FStreamPoW : TMemoryStream;
     FDisableds : Integer;
-    FOperationsLock : TCriticalSection;
+    FOperationsLock : TPCCriticalSection;
     function GetOperation(index: Integer): TPCOperation;
     procedure SetBank(const value: TPCBank);
     procedure SetnOnce(const value: Cardinal);
@@ -254,7 +255,6 @@ Type
     Constructor Create(AOwner: TComponent); Override;
     Destructor Destroy; Override;
     Procedure CopyFromExceptAddressKey(Operations : TPCOperationsComp);
-    Function CopyFromAndValidate(Operations : TPCOperationsComp; var errors : AnsiString) : Boolean;
     Procedure CopyFrom(Operations : TPCOperationsComp);
     Function AddOperation(Execute : Boolean; op: TPCOperation; var errors: AnsiString): Boolean;
     Function AddOperations(operations: TOperationsHashTree; var errors: AnsiString): Integer;
@@ -365,7 +365,7 @@ Type
     FActualTargetHash: TRawBytes;
     FIsRestoringFromFile: Boolean;
     FOnLog: TPCBankLog;
-    FBankLock: TCriticalSection;
+    FBankLock: TPCCriticalSection;
     FNotifyList : TList;
     FStorageClass: TStorageClass;
     function GetStorage: TStorage;
@@ -486,6 +486,9 @@ begin
           ' Calculated:'+TCrypto.ToHexaString(SafeBox.CalcSafeBoxHash);
         exit;
       end;
+      if (Operations.OperationBlock.protocol_version<>CT_BlockChain_Protocol_Version) then begin
+        errors := 'Invalid PascalCoin protocol version: '+IntToStr( Operations.OperationBlock.protocol_version );
+      end;
 
       // Ok, include!
       // WINNER !!!
@@ -574,7 +577,7 @@ begin
   inherited;
   FStorage := Nil;
   FStorageClass := Nil;
-  FBankLock := TCriticalSection.Create;
+  FBankLock := TPCCriticalSection.Create('TPCBank_BANKLOCK');
   FIsRestoringFromFile := False;
   FOnLog := Nil;
   FSafeBox := TPCSafeBox.Create;
@@ -1144,38 +1147,6 @@ begin
   end;
 end;
 
-function TPCOperationsComp.CopyFromAndValidate(Operations: TPCOperationsComp; var errors: AnsiString): Boolean;
-Var i : Integer;
-  e : AnsiString;
-  op : TPCOperation;
-begin
-  Lock;
-  Try
-    errors := '';
-    if Self=Operations then begin
-      result := true;
-      exit;
-    end else Result := false;
-    Clear(true);
-    if Operations.IsOnlyOperationBlock then begin
-      errors := 'Operations is only an operation block';
-      exit;
-    end;
-    FOperationBlock := Operations.OperationBlock;
-    for i := 0 to Operations.OperationsHashTree.OperationsCount-1 do begin
-      op := Operations.OperationsHashTree.GetOperation(i);
-      if Not op.DoOperation(SafeBoxTransaction,e) then begin
-        errors := 'Error executing operation '+inttostr(i+1)+'/'+Inttostr(Operations.OperationsHashTree.OperationsCount)+':'+e;
-        exit;
-      end;
-      FOperationsHashTree.AddOperationToHashTree(op);
-    end;
-    Result := ValidateOperationBlock(errors);
-  finally
-    Unlock;
-  end;
-end;
-
 procedure TPCOperationsComp.CopyFromExceptAddressKey(Operations: TPCOperationsComp);
 var lastopb : TOperationBlock;
 begin
@@ -1207,7 +1178,7 @@ end;
 constructor TPCOperationsComp.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
-  FOperationsLock := TCriticalSection.Create;
+  FOperationsLock := TPCCriticalSection.Create('TPCOperationsComp_OPERATIONSLOCK');
   FDisableds := 0;
   FStreamPoW := TMemoryStream.Create;
   FStreamPoW.Position := 0;
@@ -1341,8 +1312,7 @@ begin
   Result := LoadBlockFromStreamExt(Stream,false,errors);
 end;
 
-function TPCOperationsComp.LoadBlockFromStreamExt(Stream: TStream;
-  LoadingFromStorage: Boolean; var errors: AnsiString): Boolean;
+function TPCOperationsComp.LoadBlockFromStreamExt(Stream: TStream; LoadingFromStorage: Boolean; var errors: AnsiString): Boolean;
 Var i: Cardinal;
   lastfee : UInt64;
   soob : Byte;
@@ -1363,14 +1333,14 @@ begin
     // - Value 0 and 2 means that contains also operations
     // - Value 1 and 3 means that only contains operationblock info
     // - Value 2 and 3 means that contains protocol info prior to block number
-    if (soob=0) or (soob=2) then FIsOnlyOperationBlock:=false
-    else if (soob=1) or (soob=3) then FIsOnlyOperationBlock:=true
+    if (soob in [0,2]) then FIsOnlyOperationBlock:=false
+    else if (soob in [1,3]) then FIsOnlyOperationBlock:=true
     else begin
       errors := 'Invalid value in protocol header! Found:'+inttostr(soob)+' - Check if your application version is Ok';
       exit;
     end;
 
-    if (soob=2) or (soob=3) then begin
+    if (soob in [2,3]) then begin
       Stream.Read(FOperationBlock.protocol_version, Sizeof(FOperationBlock.protocol_version));
       Stream.Read(FOperationBlock.protocol_available, Sizeof(FOperationBlock.protocol_available));
     end else begin
@@ -1435,8 +1405,8 @@ end;
 
 class function TPCOperationsComp.OperationBlockToText(OperationBlock: TOperationBlock): AnsiString;
 begin
-  Result := Format('Block:%d Timestamp:%d Reward:%d Fee:%d PoW:%s',[operationBlock.block,
-    operationblock.timestamp,operationblock.reward,operationblock.fee, TCrypto.ToHexaString(operationblock.proof_of_work)]);
+  Result := Format('Block:%d Timestamp:%d Reward:%d Fee:%d Target:%d PoW:%s',[operationBlock.block,
+    operationblock.timestamp,operationblock.reward,operationblock.fee, OperationBlock.compact_target, TCrypto.ToHexaString(operationblock.proof_of_work)]);
 end;
 
 class function TPCOperationsComp.RegisterOperationClass(OpClass: TPCOperationClass): Boolean;
@@ -1522,19 +1492,21 @@ begin
   Result := SaveBlockToStreamExt(save_only_OperationBlock,Stream,false);
 end;
 
-function TPCOperationsComp.SaveBlockToStreamExt(save_only_OperationBlock: Boolean;
-  Stream: TStream; SaveToStorage: Boolean): Boolean;
+function TPCOperationsComp.SaveBlockToStreamExt(save_only_OperationBlock: Boolean; Stream: TStream; SaveToStorage: Boolean): Boolean;
 Var soob : Byte;
 begin
   Lock;
   Try
-    //
     if save_only_OperationBlock then begin
+      {Old versions:
       if (FOperationBlock.protocol_version=1) And (FOperationBlock.protocol_available=0) then soob := 1
-      else soob := 3;
+      else soob := 3;}
+      soob := 3;
     end else begin
+      {Old versions:
       if (FOperationBlock.protocol_version=1) And (FOperationBlock.protocol_available=0) then soob := 0
-      else soob := 2;
+      else soob := 2;}
+      soob := 2;
     end;
     Stream.Write(soob,1);
     if (soob>=2) then begin
@@ -1758,6 +1730,12 @@ end;
 
 { TOperationsHashTree }
 
+Type TOperationHashTreeReg = Record
+       Hash : TRawBytes;
+       Op : TPCOperation;
+     end;
+     POperationHashTreeReg = ^TOperationHashTreeReg;
+
 procedure TOperationsHashTree.AddOperationToHashTree(op: TPCOperation);
 Var l : TList;
 begin
@@ -1770,9 +1748,9 @@ begin
 end;
 
 procedure TOperationsHashTree.ClearHastThree;
-var op : TPCOperation;
-  l : TList;
+var l : TList;
   i : Integer;
+  P : POperationHashTreeReg;
 begin
   l := FHashTreeOperations.LockList;
   try
@@ -1780,8 +1758,9 @@ begin
     FTotalFee := 0;
     Try
       for i := 0 to l.Count - 1 do begin
-        op := l[i];
-        op.Free;
+        P := l[i];
+        P^.Op.Free;
+        Dispose(P);
       end;
     Finally
       l.Clear;
@@ -1795,7 +1774,7 @@ end;
 procedure TOperationsHashTree.CopyFromHashTree(Sender: TOperationsHashTree);
 Var i : Integer;
   lme, lsender : TList;
-  opsender : TPCOperation;
+  PSender : POperationHashTreeReg;
 begin
   if (Sender = Self) then begin
     exit;
@@ -1806,8 +1785,8 @@ begin
     lsender := Sender.FHashTreeOperations.LockList;
     try
       for i := 0 to lsender.Count - 1 do begin
-        opsender := lsender[i];
-        InternalAddOperationToHashTree(lme,opsender);
+        PSender := lsender[i];
+        InternalAddOperationToHashTree(lme,PSender^.Op);
       end;
     finally
       Sender.FHashTreeOperations.UnlockList;
@@ -1822,7 +1801,7 @@ begin
   FTotalAmount := 0;
   FTotalFee := 0;
   FHashTree := TCrypto.DoSha256('');
-  FHashTreeOperations := TPCThreadList.Create;
+  FHashTreeOperations := TPCThreadList.Create('TOperationsHashTree_HashTreeOperations');
 end;
 
 destructor TOperationsHashTree.Destroy;
@@ -1838,7 +1817,7 @@ Var l : TList;
 begin
   l := FHashTreeOperations.LockList;
   try
-    Result := TPCOperation(l[index]);
+    Result := POperationHashTreeReg(l[index])^.Op;
   finally
     FHashTreeOperations.UnlockList;
   end;
@@ -1856,7 +1835,7 @@ begin
     try
       for i := 0 to l.Count - 1 do begin
         intl.Clear;
-        TPCOperation(l[i]).AffectedAccounts(intl);
+        POperationHashTreeReg(l[i])^.Op.AffectedAccounts(intl);
         if intl.IndexOf(TObject(account_number))>=0 then List.Add(TObject(i));
       end;
     finally
@@ -1868,22 +1847,41 @@ begin
   end;
 end;
 
+function TOperationsHashTree.IndexOfOperation(op: TPCOperation): Integer;
+Var
+  l : TList;
+  hash : TRawBytes;
+begin
+  hash := TCrypto.DoSha256(op.GetOperationBufferToHash);
+  l := FHashTreeOperations.LockList;
+  Try
+    for Result := 0 to l.Count - 1 do begin
+      if POperationHashTreeReg(l[Result])^.Hash=hash then exit;
+    end;
+    Result := -1;
+  Finally
+    FHashTreeOperations.UnlockList;
+  End;
+end;
+
 procedure TOperationsHashTree.InternalAddOperationToHashTree(list: TList; op: TPCOperation);
 Var ms : TMemoryStream;
   h : TRawBytes;
-  newOp : TPCOperation;
+  P : POperationHashTreeReg;
 begin
   ms := TMemoryStream.Create;
   try
-    newOp := TPCOperation( op.NewInstance );
+    New(P);
+    P^.Op := TPCOperation( op.NewInstance );
     op.SaveToStream(ms);
     ms.Position := 0;
-    newOp.LoadFromStream(ms);
-    newOp.FPrevious_Sender_updated_block := op.Previous_Sender_updated_block;
-    newOp.FPrevious_Destination_updated_block := op.FPrevious_Destination_updated_block;
+    P^.Op.LoadFromStream(ms);
+    P^.Op.FPrevious_Sender_updated_block := op.Previous_Sender_updated_block;
+    P^.Op.FPrevious_Destination_updated_block := op.FPrevious_Destination_updated_block;
     h := TCrypto.DoSha256(ms.Memory,ms.Size);
-    newOp.tag := list.Count;
-    list.Add(newOp);
+    P^.Op.tag := list.Count;
+    P^.Hash := TCrypto.DoSha256(op.GetOperationBufferToHash);
+    list.Add(P);
   finally
     ms.Free;
   end;
@@ -2218,7 +2216,7 @@ end;
 
 constructor TOperationsResumeList.Create;
 begin
-  FList := TPCThreadList.Create;
+  FList := TPCThreadList.Create('TOperationsResumeList_List');
 end;
 
 procedure TOperationsResumeList.Delete(index: Integer);

+ 6 - 4
Units/PascalCoin/UConst.pas

@@ -76,7 +76,7 @@ Const
 
   CT_MaxClientsConnected = 500;
 
-  CT_BankToDiskEveryNBlocks = 500; // Build 1.3.0 Changed from 1000 to 500
+  CT_BankToDiskEveryNBlocks = 100; // Build 1.5 changed from 500 to 100; // Build 1.3.0 Changed from 1000 to 500
 
   CT_Default_EC_OpenSSL_NID = NID_secp256k1;
 
@@ -86,10 +86,10 @@ Const
   CT_MagicNetIdentification = $0A043580; // Unix timestamp 168048000 ... It's Albert birthdate!
 
   // Build 1.0.4 - introducing NetProtocol versioning:
-  CT_NetProtocol_Version: Word = $0003;
+  CT_NetProtocol_Version: Word = $0004;
   // IMPORTANT NOTE!!!
   // NetProtocol_Available MUST BE always >= NetProtocol_version
-  CT_NetProtocol_Available: Word = $0004;  // Remember, >= NetProtocol_version !!!
+  CT_NetProtocol_Available: Word = $0005;  // Remember, >= NetProtocol_version !!!
 
   CT_SafeBoxBankVersion : Word = 2;
 
@@ -100,7 +100,7 @@ Const
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
 
-  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.4.3'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.5.0'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
 
@@ -125,6 +125,8 @@ Const
   CT_PARAM_TryToConnectOnlyWithThisFixedServers = 'TryToConnectOnlyWithFixedServers';
   CT_PARAM_JSONRPCMinerServerPort = 'JSONRPCMinerServerPort';
   CT_PARAM_JSONRPCMinerServerActive = 'JSONRPCMinerServerActive';
+  CT_PARAM_JSONRPCEnabled = 'JSONRPCEnabled';
+  CT_PARAM_JSONRPCAllowedIPs = 'JSONRPCAllowedIPs';
 
 
 

+ 4 - 4
Units/PascalCoin/UFileStorage.pas

@@ -20,7 +20,7 @@ unit UFileStorage;
 interface
 
 uses
-  Classes, UBlockChain, SyncObjs;
+  Classes, UBlockChain, SyncObjs, UThread;
 {$I config.inc}
 
 Type
@@ -36,7 +36,7 @@ Type
 
   TFileStorage = Class(TStorage)
   private
-    FStorageLock : TCriticalSection;
+    FStorageLock : TPCCriticalSection;
     FBlockChainStream : TFileStream;
     FStreamFirstBlockNumber : Int64;
     FStreamLastBlockNumber : Int64;
@@ -78,7 +78,7 @@ Type
 
 implementation
 
-Uses ULog, SysUtils, UThread, UConst;
+Uses ULog, SysUtils, UConst;
 
 { TFileStorage }
 
@@ -158,7 +158,7 @@ begin
   SetLength(FBlockHeadersFirstBytePosition,0);
   FStreamFirstBlockNumber := 0;
   FStreamLastBlockNumber := -1;
-  FStorageLock := TCriticalSection.Create;
+  FStorageLock := TPCCriticalSection.Create('TFileStorage_StorageLock');
 end;
 
 destructor TFileStorage.Destroy;

+ 188 - 112
Units/PascalCoin/UNetProtocol.pas

@@ -94,6 +94,7 @@ Type
     its_myself : Boolean;
     last_attempt_to_connect : TDateTime;
     total_failed_attemps_to_connect : Integer;
+    is_blacklisted : Boolean; // Build 1.4.4
     BlackListText : String;
   end;
   TNodeServerAddressArray = Array of TNodeServerAddress;
@@ -168,8 +169,7 @@ Type
     FNetDataNotifyEventsThread : TNetDataNotifyEventsThread;
     FNodePrivateKey : TECPrivateKey;
     FNetConnections : TPCThreadList;
-    FNodeServers : TPCThreadList;
-    FBlackList : TPCThreadList;
+    FNodeServersAddresses : TPCThreadList;
     FLastRequestId : Cardinal;
     FRegisteredRequests : TPCThreadList;
     FIsDiscoveringServers : Boolean;
@@ -224,16 +224,15 @@ Type
     Function FindConnectionByClientRandomValue(Sender : TNetConnection) : TNetConnection;
     Procedure DiscoverServers;
     Procedure DisconnectClients;
-    Procedure GetNewBlockChainFromClient(Connection : TNetConnection);
-    Property BlackList : TPCThreadList read FBlackList;
-    Property NodeServers : TPCThreadList read FNodeServers;
+    Procedure GetNewBlockChainFromClient(Connection : TNetConnection; const why : String);
+    Property NodeServersAddresses : TPCThreadList read FNodeServersAddresses;
     Property NetConnections : TPCThreadList read FNetConnections;
     Property NetStatistics : TNetStatistics read FNetStatistics;
     Property IsDiscoveringServers : Boolean read FIsDiscoveringServers;
     Property IsGettingNewBlockChainFromClient : Boolean read FIsGettingNewBlockChainFromClient;
     Property MaxRemoteOperationBlock : TOperationBlock read FMaxRemoteOperationBlock;
     Property NodePrivateKey : TECPrivateKey read FNodePrivateKey;
-    Function GetValidNodeServers(OnlyWhereIConnected : Boolean): TNodeServerAddressArray;
+    Function GetValidNodeServers(OnlyWhereIConnected : Boolean; Max : Integer): TNodeServerAddressArray;
     Property OnNetConnectionsUpdated : TNotifyEvent read FOnNetConnectionsUpdated write FOnNetConnectionsUpdated;
     Property OnNodeServersUpdated : TNotifyEvent read FOnNodeServersUpdated write FOnNodeServersUpdated;
     Property OnBlackListUpdated : TNotifyEvent read FOnBlackListUpdated write FOnBlackListUpdated;
@@ -251,10 +250,11 @@ Type
   private
     FTcpIpClient : TNetTcpIpClient;
     FRemoteOperationBlock : TOperationBlock;
+    FRemoteAccumulatedWork : UInt64;
     FLastDataReceivedTS : Cardinal;
     FLastDataSendedTS : Cardinal;
     FClientBufferRead : TStream;
-    FNetLock : TCriticalSection;
+    FNetLock : TPCCriticalSection;
     FIsWaitingForResponse : Boolean;
     FLastKnownTimestampDiff : Int64;
     FIsMyselfServer : Boolean;
@@ -354,7 +354,7 @@ Type
 
 
 Const
-  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_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;is_blacklisted:false;BlackListText:'');
   CT_TNetStatistics_NUL : TNetStatistics = (ActiveConnections:0;ClientsConnections:0;ServersConnections:0;ServersConnectionsWithResponse:0;TotalConnections:0;TotalClientsConnections:0;TotalServersConnections:0;BytesReceived:0;BytesSend:0);
 
 implementation
@@ -386,7 +386,8 @@ Var P : PNodeServerAddress;
   i : Integer;
   l : TList;
 begin
-  l := FNodeServers.LockList;
+  if trim(NodeServerAddress.ip)='' then exit;
+  l := FNodeServersAddresses.LockList;
   try
     i := IndexOfNetClient(l,NodeServerAddress.ip,NodeServerAddress.port);
     if i>=0 then begin
@@ -402,7 +403,7 @@ begin
     l.Sort(SortNodeServerAddress);
     TLog.NewLog(ltdebug,Classname,'Adding new server: '+NodeServerAddress.ip+':'+Inttostr(NodeServerAddress.port));
   finally
-    FNodeServers.UnlockList;
+    FNodeServersAddresses.UnlockList;
   end;
   NotifyNodeServersUpdated;
 end;
@@ -419,31 +420,19 @@ Var P,Pns : PNodeServerAddress;
 begin
   // This procedure cleans old blacklisted IPs
   n := 0;
-  l := FBlackList.LockList;
+  l := FNodeServersAddresses.LockList;
   Try
     for i := l.Count - 1 downto 0 do begin
       P := l[i];
       // Is an old blacklisted IP? (More than 1 hour)
-      If ((P^.last_connection+(60*60)) < (UnivDateTimeToUnix(DateTime2UnivDateTime(now)))) then begin
-        // Clean from FNodeServers
-        lns := FNodeServers.LockList;
-        Try
-          j := IndexOfNetClient(lns,P^.ip,P^.port);
-          if (j>=0) then begin
-            Pns := lns[j];
-            Pns^.its_myself := false;
-            Pns^.BlackListText := '';
-          end;
-        Finally
-          FNodeServers.UnlockList;
-        End;
+      If (P^.is_blacklisted) AND ((P^.last_connection+(60*60)) < (UnivDateTimeToUnix(DateTime2UnivDateTime(now)))) then begin
         l.Delete(i);
         Dispose(P);
         inc(n);
       end;
     end;
   Finally
-    FBlackList.UnlockList;
+    FNodeServersAddresses.UnlockList;
   End;
   if (n>0) then NotifyBlackListUpdated;
 end;
@@ -570,11 +559,10 @@ begin
   FOnBlackListUpdated := Nil;
   FOnReceivedHelloMessage := Nil;
   FIsDiscoveringServers := false;
-  FNodeServers := TPCThreadList.Create;
-  FRegisteredRequests := TPCThreadList.Create;
+  FRegisteredRequests := TPCThreadList.Create('TNetData_RegisteredRequests');
+  FNodeServersAddresses := TPCThreadList.Create('TNetData_NodeServersAddresses');
   FLastRequestId := 0;
-  FNetConnections := TPCThreadList.Create;
-  FBlackList := TPCThreadList.Create;
+  FNetConnections := TPCThreadList.Create('TNetData_NetConnections');
   FIsGettingNewBlockChainFromClient := false;
   FNodePrivateKey := TECPrivateKey.Create;
   FNodePrivateKey.GenerateRandomPrivateKey(CT_Default_EC_OpenSSL_NID);
@@ -638,19 +626,12 @@ begin
   FreeAndNil(FNetClientsDestroyThread);
 
   CleanBlackList;
-  l := FNodeServers.LockList;
-  try
-    while (l.Count>0) do DeleteNetClient(l,l.Count-1);
-  finally
-    FNodeServers.UnlockList;
-    FreeAndNil(FNodeServers);
-  end;
-  l := FBlackList.LockList;
+  l := FNodeServersAddresses.LockList;
   try
     while (l.Count>0) do DeleteNetClient(l,l.Count-1);
   finally
-    FBlackList.UnlockList;
-    FreeAndNil(FBlackList);
+    FNodeServersAddresses.UnlockList;
+    FreeAndNil(FNodeServersAddresses);
   end;
   FreeAndNil(FNetConnections);
   FreeAndNil(FNodePrivateKey);
@@ -685,7 +666,7 @@ procedure TNetData.DiscoverFixedServersOnly(const FixedServers: TNodeServerAddre
 Var i : Integer;
   l : TList;
 begin
-  l := FNodeServers.LockList;
+  l := FNodeServersAddresses.LockList;
   try
     SetLength(FFixedServers,length(FixedServers));
     for i := low(FixedServers) to high(FixedServers) do begin
@@ -695,7 +676,7 @@ begin
       AddServer(FixedServers[i]);
     end;
   finally
-    FNodeServers.UnlockList;
+    FNodeServersAddresses.UnlockList;
   end;
 end;
 
@@ -719,7 +700,7 @@ Var P : PNodeServerAddress;
 begin
   if Not FNetConnectionsActive then exit;
   if TPCThread.ThreadClassFound(TThreadDiscoverConnection,nil)>=0 then begin
-    TLog.NewLog(ltInfo,ClassName,'Allready discovering servers...');
+    TLog.NewLog(ltInfo,ClassName,'Already discovering servers...');
     exit;
   end;
   CleanBlackList;
@@ -729,10 +710,11 @@ begin
     j := CT_MaxServersConnected - NetStatistics.ServersConnectionsWithResponse;
   end;
   if j<=0 then exit;
+  TLog.NewLog(ltDebug,Classname,'Discover servers start process searching up to '+inttostr(j)+' servers');
   // can discover up to j servers
   l := TList.Create;
   try
-    lns := FNodeServers.LockList;
+    lns := FNodeServersAddresses.LockList;
     try
       for i:=0 to lns.Count-1 do begin
         P := lns[i];
@@ -764,7 +746,7 @@ begin
         tdc := TThreadDiscoverConnection.Create(P^,DiscoverServersTerminated);
       end;
     Finally
-      FNodeServers.UnlockList;
+      FNodeServersAddresses.UnlockList;
     end;
   finally
     l.Free;
@@ -857,7 +839,7 @@ begin
   Result := Nil;
 end;
 
-procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection);
+procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; const Why : String);
 Const CT_LogSender = 'GetNewBlockChainFromClient';
 
   function Do_GetOperationsBlock(AssignToBank : TPCBank; block_start,block_end, MaxWaitMilliseconds : Cardinal; OnlyOperationBlock : Boolean; BlocksList : TList) : Boolean;
@@ -992,7 +974,9 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
     finished : Boolean;
     Bank : TPCBank;
     ms : TMemoryStream;
+    IsAScam : Boolean;
   Begin
+    IsAScam := false;
     TLog.NewLog(ltdebug,CT_LogSender,Format('GetNewBank(new_start_block:%d)',[start_block]));
     Bank := TPCBank.Create(Nil);
     try
@@ -1032,6 +1016,7 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
                 // Add to blacklist !
                 Connection.DisconnectInvalidClient(false,'Invalid BlockChain on Block '+TPCOperationsComp.OperationBlockToText(OpExecute.OperationBlock)+' with errors:'+errors);
                 finished := true;
+                IsAScam := true;
                 break;
               end;
             finally
@@ -1045,18 +1030,30 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
         end;
         start := Bank.BlocksCount;
       until (Bank.BlocksCount=Connection.FRemoteOperationBlock.block+1) Or (finished);
-      if Bank.BlocksCount>TNode.Node.Bank.BlocksCount then begin
+      // New Build 1.5 more work vs more high
+      // work = SUM(target) of all previous blocks (Int64)
+      // -----------------------------
+      // Before of version 1.5 was: "if Bank.BlocksCount>TNode.Node.Bank.BlocksCount then ..."
+      // Starting on version 1.5 is: "if Bank.WORK > MyBank.WORK then ..."
+      if Bank.SafeBox.WorkSum > TNode.Node.Bank.SafeBox.WorkSum then begin
         TNode.Node.DisableNewBlocks;
         Try
           // I'm an orphan blockchain...
-          TLog.NewLog(ltinfo,CT_LogSender,'New valid blockchain found. My block count='+inttostr(TNode.Node.Bank.BlocksCount)+
-            ' found='+inttostr(Bank.BlocksCount)+' starting at block '+inttostr(start_block));
+          TLog.NewLog(ltinfo,CT_LogSender,'New valid blockchain found. My block count='+inttostr(TNode.Node.Bank.BlocksCount)+' work: '+IntToStr(TNode.Node.Bank.SafeBox.WorkSum)+
+            ' found count='+inttostr(Bank.BlocksCount)+' work: '+IntToStr(Bank.SafeBox.WorkSum)+' starting at block '+inttostr(start_block));
           TNode.Node.Bank.Storage.MoveBlockChainBlocks(start_block,Inttostr(start_block)+'_'+FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now)),Nil);
           Bank.Storage.MoveBlockChainBlocks(start_block,TNode.Node.Bank.Storage.Orphan,TNode.Node.Bank.Storage);
           TNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
         Finally
           TNode.Node.EnableNewBlocks;
         End;
+      end else begin
+        if (Not IsAScam) And (Connection.FRemoteAccumulatedWork > TNode.Node.Bank.SafeBox.WorkSum) then begin
+          // Possible scammer!
+          Connection.DisconnectInvalidClient(false,Format('Possible scammer! Says blocks:%d Work:% - Obtained blocks:%d work:%d',
+            [Connection.FRemoteOperationBlock.block+1,Connection.FRemoteAccumulatedWork,
+             Bank.BlocksCount,Bank.SafeBox.WorkSum]));
+        end;
       end;
     finally
       Bank.Free;
@@ -1077,7 +1074,7 @@ begin
   If FIsGettingNewBlockChainFromClient then begin
     TLog.NewLog(ltdebug,CT_LogSender,'Is getting new blockchain from client...');
     exit;
-  end else TLog.NewLog(ltdebug,CT_LogSender,'Starting receiving');
+  end else TLog.NewLog(ltdebug,CT_LogSender,'Starting receiving: '+why);
   Try
     FIsGettingNewBlockChainFromClient := true;
     FMaxRemoteOperationBlock := Connection.FRemoteOperationBlock;
@@ -1098,7 +1095,7 @@ begin
     end;
 
     if (NOT TPCOperationsComp.EqualsOperationBlock(my_op,client_op)) then begin
-      TLog.NewLog(ltinfo,CT_LogSender,'My blockchain is incorrect... received: '+TPCOperationsComp.OperationBlockToText(client_op)+' My: '+TPCOperationsComp.OperationBlockToText(my_op));
+      TLog.NewLog(ltinfo,CT_LogSender,'My blockchain is not equal... received: '+TPCOperationsComp.OperationBlockToText(client_op)+' My: '+TPCOperationsComp.OperationBlockToText(my_op));
       if Not FindLastSameBlockByOperationsBlock(0,client_op.block,client_op) then begin
         TLog.NewLog(ltinfo,CT_LogSender,'No found base block to start process... Receiving ALL');
         GetNewBank(-1);
@@ -1118,16 +1115,18 @@ begin
   end;
 end;
 
-function TNetData.GetValidNodeServers(OnlyWhereIConnected : Boolean): TNodeServerAddressArray;
-var i : Integer;
+function TNetData.GetValidNodeServers(OnlyWhereIConnected : Boolean; Max : Integer): TNodeServerAddressArray;
+var i,j : Integer;
   nsa : TNodeServerAddress;
   currunixtimestamp : Cardinal;
   l : TList;
+  Aux : TNodeServerAddressArray;
 begin
   SetLength(Result,0);
+  SetLength(Aux,0);
   currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
   // Save other node servers
-  l := FNodeServers.LockList;
+  l := FNodeServersAddresses.LockList;
   try
     for i := 0 to l.Count - 1 do begin
       nsa := PNodeServerAddress( l[i] )^;
@@ -1151,12 +1150,24 @@ begin
           (nsa.last_connection>0)
         )
         then begin
-        SetLength(Result,length(Result)+1);
-        Result[high(Result)] := nsa;
+        SetLength(Aux,length(Aux)+1);
+        Aux[high(Aux)] := nsa;
       end;
     end;
   finally
-    FNodeServers.UnlockList;
+    FNodeServersAddresses.UnlockList;
+  end;
+  if (Max<=0) Or (length(Aux)<Max) then begin
+    Result := Aux;
+  end else begin
+    for i := 1 to Max do begin
+      j := Random(length(Aux));
+      if Aux[j].ip<>'' then begin
+        SetLength(Result,length(Result)+1);
+        Result[high(Result)] := Aux[j];
+        Aux[j].ip := '';
+      end;
+    end;
   end;
 end;
 
@@ -1174,7 +1185,7 @@ procedure TNetData.IncStatistics(incActiveConnections, incClientsConnections,
   incServersConnections,incServersConnectionsWithResponse: Integer; incBytesReceived, incBytesSend: Int64);
 begin
   // Multithread prevention
-  FNodeServers.LockList;
+  FNodeServersAddresses.LockList;
   Try
     FNetStatistics.ActiveConnections := FNetStatistics.ActiveConnections + incActiveConnections;
     FNetStatistics.ClientsConnections := FNetStatistics.ClientsConnections + incClientsConnections;
@@ -1186,7 +1197,7 @@ begin
     FNetStatistics.BytesReceived := FNetStatistics.BytesReceived + incBytesReceived;
     FNetStatistics.BytesSend := FNetStatistics.BytesSend + incBytesSend;
   Finally
-    FNodeServers.UnlockList;
+    FNodeServersAddresses.UnlockList;
   End;
   NotifyStatisticsChanged;
   if (incBytesReceived<>0) Or (incBytesSend<>0) then begin
@@ -1210,17 +1221,19 @@ Var l : TList;
   i : Integer;
 begin
   Result := false;
-  l := FBlackList.LockList;
+  l := FNodeServersAddresses.LockList;
   Try
     i := -1;
     repeat
       i := IndexOfNetClient(l,ip,port,i+1);
       if (i>=0) then begin
-        Result := Not PNodeServerAddress(l[i])^.its_myself;
+        if (PNodeServerAddress(l[i])^.is_blacklisted) then begin
+          Result := Not PNodeServerAddress(l[i])^.its_myself;
+        end;
       end;
     until (i<0) Or (Result);
   Finally
-    FBlackList.UnlockList;
+    FNodeServersAddresses.UnlockList;
   End;
 end;
 
@@ -1466,14 +1479,14 @@ Var Pnsa : PNodeServerAddress;
   i : Integer;
 begin
   if Client.Connected then Client.Disconnect;
-  lns := TNetData.NetData.FNodeServers.LockList;
+  lns := TNetData.NetData.NodeServersAddresses.LockList;
   try
     i := TNetData.NetData.IndexOfNetClient(lns,ServerIp,ServerPort);
     if (i>=0) then Pnsa := lns[i]
     else Pnsa := Nil;
     if Assigned(Pnsa) then Pnsa^.netConnection := Self;
   finally
-    TNetData.NetData.FNodeServers.UnlockList;
+    TNetData.NetData.NodeServersAddresses.UnlockList;
   end;
 
   TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
@@ -1511,12 +1524,13 @@ begin
   FLastKnownTimestampDiff := 0;
   FIsWaitingForResponse := false;
   FClientBufferRead := TMemoryStream.Create;
-  FNetLock := TCriticalSection.Create;
+  FNetLock := TPCCriticalSection.Create('TNetConnection_NetLock');
   FLastDataReceivedTS := 0;
   FLastDataSendedTS := 0;
   FRandomWaitSecondsSendHello := 90 + Random(60);
   FTcpIpClient := Nil;
   FRemoteOperationBlock := CT_OperationBlock_NUL;
+  FRemoteAccumulatedWork := 0;
   SetClient( TBufferedNetTcpIpClient.Create(Self) );
   TNetData.NetData.FNetConnections.Add(Self);
   TNetData.NetData.NotifyNetConnectionUpdated;
@@ -1531,7 +1545,7 @@ begin
 
   Connected := false;
 
-  lns := TNetData.NetData.FNodeServers.LockList;
+  lns := TNetData.NetData.NodeServersAddresses.LockList;
   try
     for i := lns.Count - 1 downto 0 do begin
       Pnsa := lns[i];
@@ -1540,7 +1554,7 @@ begin
       End;
     end;
   finally
-    TNetData.NetData.FNodeServers.UnlockList;
+    TNetData.NetData.NodeServersAddresses.UnlockList;
   end;
   TNetData.NetData.FNetConnections.Remove(Self);
   TNetData.NetData.UnRegisterRequest(Self,0,0);
@@ -1571,7 +1585,7 @@ begin
     And (Not SameText('192.168.',Copy(Client.RemoteHost,1,8)))
     And (Not SameText('10.',Copy(Client.RemoteHost,1,3)));
   if include_in_list then begin
-    l := TNetData.NetData.FBlackList.LockList;
+    l := TNetData.NetData.NodeServersAddresses.LockList;
     try
       i := TNetData.NetData.IndexOfNetClient(l,Client.RemoteHost,Client.RemotePort);
       if i<0 then begin
@@ -1584,12 +1598,12 @@ begin
       P^.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
       P^.its_myself := ItsMyself;
       P^.BlackListText := Why;
+      P^.is_blacklisted := true;
     finally
-      TNetData.NetData.FBlackList.UnlockList;
+      TNetData.NetData.NodeServersAddresses.UnlockList;
     end;
-  end;
-  if ItsMyself then begin
-    l := TNetData.NetData.FNodeServers.LockList;
+  end else if ItsMyself then begin
+    l := TNetData.NetData.NodeServersAddresses.LockList;
     try
       i := TNetData.NetData.IndexOfNetClient(l,Client.RemoteHost,Client.RemotePort);
       if i>=0 then begin
@@ -1597,7 +1611,7 @@ begin
         P^.its_myself := ItsMyself;
       end;
     finally
-      TNetData.NetData.FNodeServers.UnlockList;
+      TNetData.NetData.NodeServersAddresses.UnlockList;
     end;
   end;
   Connected := False;
@@ -1980,6 +1994,7 @@ var op, myLastOp : TPCOperationsComp;
    RawAccountKey : TRawBytes;
    other_version : AnsiString;
 Begin
+  FRemoteAccumulatedWork := 0;
   op := TPCOperationsComp.Create(Nil);
   try
     DataBuffer.Position:=0;
@@ -2019,12 +2034,6 @@ Begin
 
     if op.LoadBlockFromStream(DataBuffer,errors) then begin
       FRemoteOperationBlock := op.OperationBlock;
-      If (TNetData.NetData.FMaxRemoteOperationBlock.block<FRemoteOperationBlock.block) then begin
-        TNetData.NetData.FMaxRemoteOperationBlock := FRemoteOperationBlock;
-        if TPCThread.ThreadClassFound(TThreadGetNewBlockChainFromClient,nil)<0 then begin
-          TThreadGetNewBlockChainFromClient.Create(false).FreeOnTerminate := true;
-        end;
-      end;
       if (DataBuffer.Size-DataBuffer.Position>=4) then begin
         DataBuffer.Read(c,4);
         for i := 1 to c do begin
@@ -2037,8 +2046,21 @@ Begin
         if TStreamOp.ReadAnsiString(DataBuffer,other_version)>=0 then begin
           // Captures version
           ClientAppVersion := other_version;
+          if (DataBuffer.Size-DataBuffer.Position>=SizeOf(FRemoteAccumulatedWork)) then begin
+            DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
+            TLog.NewLog(ltdebug,ClassName,'Received HELLO with Accumulated work '+IntToStr(FRemoteAccumulatedWork));
+          end;
+        end;
+        //
+        if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) Or
+          ((FRemoteAccumulatedWork=0) And (TNetData.NetData.FMaxRemoteOperationBlock.block<FRemoteOperationBlock.block)) then begin
+          TNetData.NetData.FMaxRemoteOperationBlock := FRemoteOperationBlock;
+          if TPCThread.ThreadClassFound(TThreadGetNewBlockChainFromClient,nil)<0 then begin
+            TThreadGetNewBlockChainFromClient.Create(false).FreeOnTerminate := true;
+          end;
         end;
       end;
+
       TLog.NewLog(ltdebug,Classname,'Hello received: '+TPCOperationsComp.OperationBlockToText(FRemoteOperationBlock));
       if (HeaderData.header_type in [ntp_request,ntp_response]) then begin
         // Response:
@@ -2054,7 +2076,6 @@ Begin
           DisconnectInvalidClient(true,'Duplicate connection with '+Duplicate.ClientRemoteAddr);
           exit;
         end;
-
         TNetData.NetData.NotifyReceivedHelloMessage;
       end else begin
         DisconnectInvalidClient(false,'Invalid header type > '+TNetData.HeaderDataToText(HeaderData));
@@ -2129,15 +2150,35 @@ begin
         exit;
       end else begin
         DoDisconnect := false;
+        if DataBuffer.Size - DataBuffer.Position >= SizeOf(FRemoteAccumulatedWork) then begin
+          DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
+          TLog.NewLog(ltdebug,ClassName,'Received NEW BLOCK with Accumulated work '+IntToStr(FRemoteAccumulatedWork));
+        end else FRemoteAccumulatedWork := 0;
         FRemoteOperationBlock := op.OperationBlock;
         //
-        if (op.OperationBlock.block>TNode.Node.Bank.BlocksCount) then begin
-          TNetData.NetData.GetNewBlockChainFromClient(Self);
-        end else if (op.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
-          // New block candidate:
-          If Not TNode.Node.AddNewBlockChain(Self,op,bacc,errors) then begin
-            // Received a new invalid block... perhaps I'm an orphan blockchain
-            TNetData.NetData.GetNewBlockChainFromClient(Self);
+        if FRemoteAccumulatedWork=0 then begin
+          // Old version. No data
+          if (op.OperationBlock.block>TNode.Node.Bank.BlocksCount) then begin
+            TNetData.NetData.GetNewBlockChainFromClient(Self,Format('BlocksCount:%d > my BlocksCount:%d',[op.OperationBlock.block+1,TNode.Node.Bank.BlocksCount]));
+          end else if (op.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
+            // New block candidate:
+            If Not TNode.Node.AddNewBlockChain(Self,op,bacc,errors) then begin
+              // Received a new invalid block... perhaps I'm an orphan blockchain
+              TNetData.NetData.GetNewBlockChainFromClient(Self,'Has a distinct block. '+errors);
+            end;
+          end;
+        end else begin
+          if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
+            if (op.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
+              // New block candidate:
+              If Not TNode.Node.AddNewBlockChain(Self,op,bacc,errors) then begin
+                // Received a new invalid block... perhaps I'm an orphan blockchain
+                TNetData.NetData.GetNewBlockChainFromClient(Self,'Higher Work with same block height. I''m a orphan blockchain candidate');
+              end;
+            end else begin
+              // Received a new higher work
+              TNetData.NetData.GetNewBlockChainFromClient(Self,Format('Higher Work and distinct blocks count. Need to download BlocksCount:%d  my BlocksCount:%d',[op.OperationBlock.block+1,TNode.Node.Bank.BlocksCount]));
+            end;
           end;
         end;
       end;
@@ -2178,7 +2219,7 @@ begin
       tc := GetTickCount;
       Repeat
         if (ReadTcpClientBuffer(MaxWaitTime,HeaderData,ReceiveDataBuffer)) then begin
-          l := TNetData.NetData.NodeServers.LockList;
+          l := TNetData.NetData.NodeServersAddresses.LockList;
           try
             for i := 0 to l.Count - 1 do begin
               If PNodeServerAddress( l[i] )^.netConnection=Self then begin
@@ -2187,7 +2228,7 @@ begin
               end;
             end;
           finally
-            TNetData.netData.NodeServers.UnlockList;
+            TNetData.netData.NodeServersAddresses.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) );
           if (RequestId=HeaderData.request_id) And (HeaderData.header_type=ntp_response) then begin
@@ -2262,7 +2303,7 @@ begin
 end;
 
 function TNetConnection.ReadTcpClientBuffer(MaxWaitMiliseconds: Cardinal; var HeaderData: TNetHeaderData; BufferData: TStream): Boolean;
-var buffer : Array[1..4096] of byte;
+var
   auxstream : TMemoryStream;
   tc : Cardinal;
   last_bytes_read, t_bytes_read : Int64;
@@ -2558,20 +2599,22 @@ begin
     try
       if (TNode.Node.Bank.BlocksCount>0) then TNode.Node.Bank.LoadOperations(op,TNode.Node.Bank.BlocksCount-1);
       op.SaveBlockToStream(true,data);
-      nsarr := TNetData.NetData.GetValidNodeServers(true);
-      i := length(nsarr);
-      data.Write(i,4);
-      for i := 0 to High(nsarr) do begin
-        nsa := nsarr[i];
-        TStreamOp.WriteAnsiString(data, nsa.ip);
-        data.Write(nsa.port,2);
-        data.Write(nsa.last_connection,4);
-      end;
-      // Send client version
-      TStreamOp.WriteAnsiString(data,CT_ClientAppVersion{$IFDEF LINUX}+'l'{$ELSE}+'w'{$ENDIF}{$IFDEF FPC}{$IFDEF LCL}+'L'{$ELSE}+'F'{$ENDIF}{$ENDIF});
     finally
       op.free;
     end;
+    nsarr := TNetData.NetData.GetValidNodeServers(true,20);
+    i := length(nsarr);
+    data.Write(i,4);
+    for i := 0 to High(nsarr) do begin
+      nsa := nsarr[i];
+      TStreamOp.WriteAnsiString(data, nsa.ip);
+      data.Write(nsa.port,2);
+      data.Write(nsa.last_connection,4);
+    end;
+    // Send client version
+    TStreamOp.WriteAnsiString(data,CT_ClientAppVersion{$IFDEF LINUX}+'l'{$ELSE}+'w'{$ENDIF}{$IFDEF FPC}{$IFDEF LCL}+'L'{$ELSE}+'F'{$ENDIF}{$ENDIF});
+    // Build 1.5 send accumulated work
+    data.Write(TNode.Node.Bank.SafeBox.WorkSum,SizeOf(TNode.Node.Bank.SafeBox.WorkSum));
     //
     Send(NetTranferType,CT_NetOp_Hello,0,request_id,data);
     Result := Client.Connected;
@@ -2620,6 +2663,8 @@ begin
           exit;
         end;
         op.SaveBlockToStream(false,data);
+        // Build 1.5 sending Accumulated work
+        data.Write(op.bank.SafeBox.WorkSum,SizeOf(op.bank.SafeBox.WorkSum));
         Send(ntp_autosend,CT_NetOp_NewBlock,0,request_id,data);
       finally
         op.free;
@@ -2745,7 +2790,7 @@ begin
   Pnsa := Nil;
   DebugStep := 'Locking list';
   // Register attempt
-  lns := TNetData.NetData.FNodeServers.LockList;
+  lns := TNetData.NetData.NodeServersAddresses.LockList;
   try
     DebugStep := 'Searching net client';
     i := TNetData.NetData.IndexOfNetClient(lns,FNodeServerAddress.ip,FNodeServerAddress.port);
@@ -2756,7 +2801,7 @@ begin
       Inc(Pnsa.total_failed_attemps_to_connect);
     end;
   finally
-    TNetData.NetData.FNodeServers.UnlockList;
+    TNetData.NetData.NodeServersAddresses.UnlockList;
   end;
   DebugStep := 'Synchronizing notify';
   if Terminated then exit;
@@ -2888,7 +2933,8 @@ end;
 { TThreadGetNewBlockChainFromClient }
 
 procedure TThreadGetNewBlockChainFromClient.BCExecute;
-Var i : Integer;
+Var i, iMax : Integer;
+  maxWork : UInt64;
   nsa : TNodeServerAddress;
   candidates : TList;
   lop : TOperationBlock;
@@ -2901,27 +2947,57 @@ begin
     lop := CT_OperationBlock_NUL;
     netConnectionsList := TNetData.NetData.ConnectionsLock;
     Try
+      TNetData.NetData.FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
+      // First round: Find by most work
+      iMax := 0;
+      maxWork := 0;
       for i := 0 to netConnectionsList.Count - 1 do begin
-        TNetData.NetData.FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
         nc := TNetConnection(netConnectionsList[i]);
-        if (nc.FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount) And
-           (nc.FRemoteOperationBlock.block>=lop.block)
-           then begin
-           candidates.Add(nc);
-           lop := TNetConnection(netConnectionsList[i]).FRemoteOperationBlock;
+        if (nc.FRemoteAccumulatedWork>maxWork) And (nc.FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
+          maxWork := nc.FRemoteAccumulatedWork;
+          iMax := i;
         end;
-        //
+        // Preventing downloading
         if nc.FIsDownloadingBlocks then exit;
         //
       end;
+      if (maxWork>0) then begin
+        for i := 0 to netConnectionsList.Count - 1 do begin
+          nc := TNetConnection(netConnectionsList[i]);
+          if (nc.FRemoteAccumulatedWork>=maxWork) then begin
+            candidates.Add(nc);
+            lop := nc.FRemoteOperationBlock;
+          end;
+        end;
+      end;
+      // Second round: Find by most height
+      if candidates.Count=0 then begin
+        for i := 0 to netConnectionsList.Count - 1 do begin
+          nc := TNetConnection(netConnectionsList[i]);
+          if (nc.FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount) And
+             (nc.FRemoteOperationBlock.block>=lop.block) then begin
+             lop := nc.FRemoteOperationBlock;
+          end;
+        end;
+        if (lop.block>0) then begin
+          for i := 0 to netConnectionsList.Count - 1 do begin
+            nc := TNetConnection(netConnectionsList[i]);
+            if (nc.FRemoteOperationBlock.block>=lop.block) then begin
+               candidates.Add(nc);
+            end;
+          end;
+        end;
+      end;
     Finally
       TNetData.NetData.ConnectionsUnlock;
     End;
     TNetData.NetData.FMaxRemoteOperationBlock := lop;
     if (candidates.Count>0) then begin
       // Random a candidate
-      i := Random(candidates.Count); // i = 0..count-1
-      TNetData.NetData.GetNewBlockChainFromClient(TNetConnection(candidates[i]));
+      i := 0;
+      if (candidates.Count>1) then i := Random(candidates.Count); // i = 0..count-1
+      nc := TNetConnection(candidates[i]);
+      TNetData.NetData.GetNewBlockChainFromClient(nc,Format('Candidate block: %d sum: %d',[nc.FRemoteOperationBlock.block,nc.FRemoteAccumulatedWork]));
     end;
   finally
     candidates.Free;

+ 60 - 51
Units/PascalCoin/UNode.pas

@@ -39,7 +39,7 @@ Type
   TNode = Class(TComponent)
   private
     FNodeLog : TLog;
-    FLockNodeOperations : TCriticalSection;
+    FLockNodeOperations : TPCCriticalSection;
     FNotifyList : TList;
     FBank : TPCBank;
     FOperations : TPCOperationsComp;
@@ -159,9 +159,11 @@ begin
     Inttohex(PtrInt(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock)]));
     exit;
   end;
+  If NewBlockOperations.OperationBlock.block<>Bank.BlocksCount then exit;
   TLog.NewLog(ltdebug,Classname,Format('AddNewBlockChain Connection:%s NewBlock:%s',[
     Inttohex(PtrInt(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock)]));
   If Not TPCThread.TryProtectEnterCriticalSection(Self,2000,FLockNodeOperations) then begin
+    If NewBlockOperations.OperationBlock.block<>Bank.BlocksCount then exit;
     s := 'Cannot AddNewBlockChain due blocking lock operations node';
     TLog.NewLog(lterror,Classname,s);
     if TThread.CurrentThread.ThreadID=MainThreadID then raise Exception.Create(s) else exit;
@@ -249,65 +251,72 @@ begin
     TLog.NewLog(ltinfo,Classname,errors);
     exit;
   end;
-  TLog.NewLog(ltdebug,Classname,Format('AddOperations Connection:%s Operations:%d',[
-    Inttohex(PtrInt(SenderConnection),8),Operations.OperationsCount]));
-  if Not TPCThread.TryProtectEnterCriticalSection(Self,4000,FLockNodeOperations) then begin
-    s := 'Cannot AddOperations due blocking lock operations node';
-    TLog.NewLog(lterror,Classname,s);
-    if TThread.CurrentThread.ThreadID=MainThreadID then raise Exception.Create(s) else exit;
-  end;
+  Result := 0;
+  errors := '';
+  valids_operations := TOperationsHashTree.Create;
   try
-    Result := 0;
-    errors := '';
-    valids_operations := TOperationsHashTree.Create;
+    TLog.NewLog(ltdebug,Classname,Format('AddOperations Connection:%s Operations:%d',[
+      Inttohex(PtrInt(SenderConnection),8),Operations.OperationsCount]));
+    if Not TPCThread.TryProtectEnterCriticalSection(Self,4000,FLockNodeOperations) then begin
+      s := 'Cannot AddOperations due blocking lock operations node';
+      TLog.NewLog(lterror,Classname,s);
+      if TThread.CurrentThread.ThreadID=MainThreadID then raise Exception.Create(s) else exit;
+    end;
     try
       for j := 0 to Operations.OperationsCount-1 do begin
         ActOp := Operations.GetOperation(j);
-        if (FOperations.AddOperation(true,ActOp,e)) then begin
-          inc(Result);
-          valids_operations.AddOperationToHashTree(ActOp);
-          TLog.NewLog(ltdebug,Classname,Format('AddOperation %d/%d: %s',[(j+1),Operations.OperationsCount,ActOp.ToString]));
-          if Assigned(OperationsResult) then begin
-            TPCOperation.OperationToOperationResume(0,ActOp,ActOp.SenderAccount,OPR);
-            OPR.NOpInsideBlock:=FOperations.Count-1;
-            OPR.Balance := FOperations.SafeBoxTransaction.Account(ActOp.SenderAccount).balance;
-            OperationsResult.Add(OPR);
+        If FOperations.OperationsHashTree.IndexOfOperation(ActOp)<0 then begin
+          if (FOperations.AddOperation(true,ActOp,e)) then begin
+            inc(Result);
+            valids_operations.AddOperationToHashTree(ActOp);
+            TLog.NewLog(ltdebug,Classname,Format('AddOperation %d/%d: %s',[(j+1),Operations.OperationsCount,ActOp.ToString]));
+            if Assigned(OperationsResult) then begin
+              TPCOperation.OperationToOperationResume(0,ActOp,ActOp.SenderAccount,OPR);
+              OPR.NOpInsideBlock:=FOperations.Count-1;
+              OPR.Balance := FOperations.SafeBoxTransaction.Account(ActOp.SenderAccount).balance;
+              OperationsResult.Add(OPR);
+            end;
+          end else begin
+            if (errors<>'') then errors := errors+' ';
+            errors := errors+'Op '+IntToStr(j+1)+'/'+IntToStr(Operations.OperationsCount)+':'+e;
+            TLog.NewLog(ltdebug,Classname,Format('AddOperation invalid/duplicated %d/%d: %s  - Error:%s',
+              [(j+1),Operations.OperationsCount,ActOp.ToString,e]));
+            if Assigned(OperationsResult) then begin
+              TPCOperation.OperationToOperationResume(0,ActOp,ActOp.SenderAccount,OPR);
+              OPR.valid := false;
+              OPR.NOpInsideBlock:=-1;
+              OPR.OperationHash := '';
+              OPR.errors := e;
+              OperationsResult.Add(OPR);
+            end;
           end;
         end else begin
-          if (errors<>'') then errors := errors+' ';
-          errors := errors+'Op '+IntToStr(j+1)+'/'+IntToStr(Operations.OperationsCount)+':'+e;
-          TLog.NewLog(ltdebug,Classname,Format('AddOperation failed %d/%d: %s  - Error:%s',
-            [(j+1),Operations.OperationsCount,ActOp.ToString,e]));
-          if Assigned(OperationsResult) then begin
-            TPCOperation.OperationToOperationResume(0,ActOp,ActOp.SenderAccount,OPR);
-            OPR.valid := false;
-            OPR.NOpInsideBlock:=-1;
-            OPR.OperationHash := '';
-            OPR.errors := e;
-            OperationsResult.Add(OPR);
-          end;
+          // XXXXX DEBUG ONLY
+          // TLog.NewLog(ltdebug,Classname,Format('AddOperation made before %d/%d: %s',[(j+1),Operations.OperationsCount,ActOp.ToString]));
         end;
       end;
-      if Result=0 then exit;
-      // Send to other nodes
-      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;
-      Finally
-        TNetData.NetData.ConnectionsUnlock;
-      End;
     finally
-      valids_operations.Free;
+      FLockNodeOperations.Release;
+      if Result<>0 then begin
+        TLog.NewLog(ltdebug,Classname,Format('Finalizing AddOperations Connection:%s Operations:%d valids:%d',[
+          Inttohex(PtrInt(SenderConnection),8),Operations.OperationsCount,Result ]));
+      end;
     end;
+    if Result=0 then exit;
+    // Send to other nodes
+    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;
+    Finally
+      TNetData.NetData.ConnectionsUnlock;
+    End;
   finally
-    FLockNodeOperations.Release;
-    TLog.NewLog(ltdebug,Classname,Format('Finalizing AddOperations Connection:%s Operations:%d',[
-      Inttohex(PtrInt(SenderConnection),8),Operations.OperationsCount ]));
+    valids_operations.Free;
   end;
   // Notify it!
   for i := 0 to FNotifyList.Count-1 do begin
@@ -337,7 +346,7 @@ begin
   TLog.NewLog(ltInfo,ClassName,'TNode.Create');
   inherited;
   FDisabledsNewBlocksCount := 0;
-  FLockNodeOperations := TCriticalSection.Create;
+  FLockNodeOperations := TPCCriticalSection.Create('TNode_LockNodeOperations');
   FBank := TPCBank.Create(Self);
   FBCBankNotify := TPCBankNotify.Create(Self);
   FBCBankNotify.Bank := FBank;
@@ -728,7 +737,7 @@ begin
   FOnBlocksChanged := Nil;
   FOnNodeMessageEvent := Nil;
   FMessages := TStringList.Create;
-  FPendingNotificationsList := TPCThreadList.Create;
+  FPendingNotificationsList := TPCThreadList.Create('TNodeNotifyEvents_PendingNotificationsList');
   FThreadSafeNodeNotifyEvent := TThreadSafeNodeNotifyEvent.Create(Self);
   FThreadSafeNodeNotifyEvent.FreeOnTerminate := true; // This is to prevent locking when freeing component
   Node := _Node;

+ 5 - 5
Units/PascalCoin/UPoolMining.pas

@@ -57,9 +57,9 @@ Type
   TJSONRPCTcpIpClient = Class(TBufferedNetTcpIpClient)
   private
     FLastId : Cardinal;
-    FLockProcessBuffer : TCriticalSection;
+    FLockProcessBuffer : TPCCriticalSection;
     FReceivedBuffer : TBytes;
-    FLockReceivedBuffer : TCriticalSection;
+    FLockReceivedBuffer : TPCCriticalSection;
     FPendingResponseMessages : TPCThreadList;
   protected
   public
@@ -168,9 +168,9 @@ begin
   inherited;
   FLastId := 1;
   SetLength(FReceivedBuffer,0);
-  FLockProcessBuffer := TCriticalSection.Create;
-  FLockReceivedBuffer := TCriticalSection.Create;
-  FPendingResponseMessages := TPCThreadList.Create;
+  FLockProcessBuffer := TPCCriticalSection.Create('TJSONRPCTcpIpClient_LockProcessBuffer');
+  FLockReceivedBuffer := TPCCriticalSection.Create('TJSONRPCTcpIpClient_LockReceivedBuffer');
+  FPendingResponseMessages := TPCThreadList.Create('TJSONRPCTcpIpClient_PendingResponseMessages');
 end;
 
 destructor TJSONRPCTcpIpClient.Destroy;

+ 19 - 6
Units/PascalCoin/URPC.pas

@@ -51,11 +51,12 @@ Type
     FIniFile : TIniFile;
     FRPCLog : TLog;
     FCallsCounter : Int64;
+    FValidIPs: AnsiString;
     procedure SetActive(AValue: Boolean);
     procedure SetIniFileName(const Value: AnsiString);
     procedure SetLogFileName(const Value: AnsiString);
     Function GetLogFileName : AnsiString;
-  protected
+    procedure SetValidIPs(const Value: AnsiString);  protected
     Function IsValidClientIP(Const clientIp : String; clientPort : Word) : Boolean;
     Procedure AddRPCLog(Const Sender : String; Const Message : String);
     Function GetNewCallCounter : Int64;
@@ -69,6 +70,7 @@ Type
     Property JSON20Strict : Boolean read FJSON20Strict write FJSON20Strict;
     Property IniFileName : AnsiString read FIniFileName write SetIniFileName;
     Property LogFileName : AnsiString read GetLogFileName write SetLogFileName;
+    Property ValidIPs : AnsiString read FValidIPs write SetValidIPs;
   end;
 
   { TRPCServerThread }
@@ -136,6 +138,7 @@ begin
     FRPCServerThread.WaitFor;
     FreeAndNil(FRPCServerThread);
   end;
+  TLog.NewLog(ltupdate,Classname,'Updated RPC Server to Active='+CT_TRUE_FALSE[FActive]);
 end;
 
 procedure TRPCServer.SetIniFileName(const Value: AnsiString);
@@ -148,7 +151,6 @@ begin
   end;
   if Assigned(FIniFile) then begin
     FJSON20Strict := FIniFile.ReadBool('general','json20strict',true)
-    // TODO
   end;
 end;
 
@@ -164,15 +166,25 @@ begin
   end else FreeAndNil(FRPCLog);
 end;
 
+procedure TRPCServer.SetValidIPs(const Value: AnsiString);
+begin
+  if FValidIPs=Value then exit;
+  FValidIPs := Value;
+  if FValidIPs='' then TLog.NewLog(ltupdate,Classname,'Updated RPC Server valid IPs to ALL')
+  else TLog.NewLog(ltupdate,Classname,'Updated RPC Server valid IPs to: '+FValidIPs)
+end;
+
 function TRPCServer.IsValidClientIP(const clientIp: String; clientPort: Word): Boolean;
 begin
-  Result := true;
-  // TODO: Allow only specific IP's listed in IniFile
-  // Result := (clientIp='127.0.0.1');
+  if FValidIPs='' then Result := true
+  else begin
+    Result := pos(clientIP,FValidIPs) > 0;
+  end;
 end;
 
 constructor TRPCServer.Create;
 begin
+  FActive := false;
   FRPCLog := Nil;
   FIniFile := Nil;
   FIniFileName := '';
@@ -181,6 +193,7 @@ begin
   FRPCServerThread := Nil;
   FPort := CT_JSONRPC_Port;
   FCallsCounter := 0;
+  FValidIPs := '127.0.0.1;localhost'; // New Build 1.5 - By default, only localhost can access to RPC
   If Not assigned(_RPCServer) then _RPCServer := Self;
 end;
 
@@ -1630,7 +1643,7 @@ begin
     GetResultObject.GetAsObject('netstats').GetAsVariant('tservers').Value:=TNetData.NetData.NetStatistics.TotalServersConnections;
     GetResultObject.GetAsObject('netstats').GetAsVariant('breceived').Value:=TNetData.NetData.NetStatistics.BytesReceived;
     GetResultObject.GetAsObject('netstats').GetAsVariant('bsend').Value:=TNetData.NetData.NetStatistics.BytesSend;
-    nsaarr := TNetData.NetData.GetValidNodeServers(true);
+    nsaarr := TNetData.NetData.GetValidNodeServers(true,20);
     for i := low(nsaarr) to High(nsaarr) do begin
       jso := GetResultObject.GetAsArray('nodeservers').GetAsObject(i);
       jso.GetAsVariant('ip').Value := nsaarr[i].ip;

+ 106 - 67
Units/PascalCoin/UTCPIP.pas

@@ -55,11 +55,12 @@ type
     FRemoteHost : AnsiString;
     FRemotePort : Word;
     FBytesReceived, FBytesSent : Int64;
-    FLock : TCriticalSection;
+    FLock : TPCCriticalSection;
     {$ENDIF}
     FOnConnect: TNotifyEvent;
     FOnDisconnect: TNotifyEvent;
     FSocketError: Integer;
+    FLastCommunicationTime : TDateTime;
     function GetConnected: Boolean;
     function GetRemoteHost: AnsiString;
     function GetRemotePort: Word;
@@ -93,6 +94,7 @@ type
     Function BytesReceived : Int64;
     Function BytesSent : Int64;
     Property SocketError : Integer read FSocketError write SetSocketError;
+    Property LastCommunicationTime : TDateTime read FLastCommunicationTime;
   End;
 
   TNetTcpIpClientClass = Class of TNetTcpIpClient;
@@ -111,7 +113,7 @@ type
   private
     FSendBuffer : TMemoryStream;
     FReadBuffer : TMemoryStream;
-    FCritical : TCriticalSection;
+    FCritical : TPCCriticalSection;
     FLastReadTC : Cardinal;
     FBufferedNetTcpIpClientThread : TBufferedNetTcpIpClientThread;
   protected
@@ -227,9 +229,7 @@ begin
     Result := FTcpBlockSocket.RemoteHost+':'+FTcpBlockSocket.RemotePort;
     {$ENDIF}
     {$IFDEF Synapse}
-    if FConnected then
-      Result := FTcpBlockSocket.GetRemoteSinIP+':'+IntToStr(FTcpBlockSocket.GetRemoteSinPort)
-    else Result := FRemoteHost+':'+inttostr(FRemotePort);
+    Result := FRemoteHost+':'+inttostr(FRemotePort);
     {$ENDIF}
   end else Result := 'NIL';
 end;
@@ -241,18 +241,26 @@ begin
   Result := FTcpBlockSocket.Connect;
   {$ENDIF}
   {$IFDEF Synapse}
-  Try
-    FTcpBlockSocket.Connect(FRemoteHost,IntToStr(FRemotePort));
-    FConnected := FTcpBlockSocket.LastError=0;
-    if (FConnected) then DoOnConnect
-    else TLog.NewLog(ltdebug,Classname,'Cannot connect to a server at: '+ClientRemoteAddr+' Reason: '+FTcpBlockSocket.GetErrorDescEx);
-  Except
-    On E:Exception do begin
-      FSocketError := FTcpBlockSocket.LastError;
-      TLog.NewLog(lterror,ClassName,'Error Connecting to '+ClientRemoteAddr+': '+FTcpBlockSocket.GetErrorDescEx);
-      Disconnect;
-    end;
-  End;
+  FLock.Acquire;
+  try
+    Try
+      FTcpBlockSocket.Connect(FRemoteHost,IntToStr(FRemotePort));
+      FConnected := FTcpBlockSocket.LastError=0;
+      if (FConnected) then begin
+        FRemoteHost := FTcpBlockSocket.GetRemoteSinIP;
+        FRemotePort := FTcpBlockSocket.GetRemoteSinPort;
+        DoOnConnect;
+      end else TLog.NewLog(ltdebug,Classname,'Cannot connect to a server at: '+ClientRemoteAddr+' Reason: '+FTcpBlockSocket.GetErrorDescEx);
+    Except
+      On E:Exception do begin
+        SocketError := FTcpBlockSocket.LastError;
+        TLog.NewLog(lterror,ClassName,'Error Connecting to '+ClientRemoteAddr+': '+FTcpBlockSocket.GetErrorDescEx);
+        Disconnect;
+      end;
+    End;
+  finally
+    FLock.Release;
+  end;
   Result := FConnected;
   {$ENDIF}
 end;
@@ -262,6 +270,7 @@ begin
   inherited;
   FTcpBlockSocket := Nil;
   FSocketError := 0;
+  FLastCommunicationTime := 0;
   {$IFDEF DelphiSockets}
   FTcpBlockSocket := TTcpClient.Create(Nil);
   FTcpBlockSocket.OnConnect := OnConnect;
@@ -269,7 +278,7 @@ begin
   FTcpBlockSocket.OnError := TCustomIpClient_OnError;
   {$ENDIF}
   {$IFDEF Synapse}
-  FLock := TCriticalSection.Create;
+  FLock := TPCCriticalSection.Create('TNetTcpIpClient_Lock');
   FTcpBlockSocket := TTCPBlockSocket.Create;
   FTcpBlockSocket.OnAfterConnect := OnConnect;
   FTcpBlockSocket.SocksTimeout := 10000;
@@ -284,7 +293,9 @@ end;
 destructor TNetTcpIpClient.Destroy;
 begin
   Disconnect;
+  {$IFDEF DelphiSockets}
   FreeAndNil(FLock);
+  {$ENDIF}
   inherited;
   FreeAndNil(FTcpBlockSocket);
   TLog.NewLog(ltdebug,ClassName,'Destroying Socket end');
@@ -301,10 +312,10 @@ begin
     if Not FConnected then exit;
     FConnected := false;
     FTcpBlockSocket.CloseSocket;
-    if Assigned(FOnDisconnect) then FOnDisconnect(Self);
   Finally
     FLock.Release;
   End;
+  if Assigned(FOnDisconnect) then FOnDisconnect(Self);
   {$ENDIF}
 end;
 
@@ -320,14 +331,19 @@ Begin
   HasData := FTcpBlockSocket.WaitForData(WaitMilliseconds);
   {$ENDIF}
   {$IFDEF Synapse}
+  FLock.Acquire;
   Try
-    HasData := FTcpBlockSocket.CanRead(WaitMilliseconds);
-  Except
-    On E:Exception do begin
-      FSocketError := FTcpBlockSocket.LastError;
-      TLog.NewLog(lterror,ClassName,'Error WaitingForData from '+ClientRemoteAddr+': '+FTcpBlockSocket.GetErrorDescEx);
-      Disconnect;
-    end;
+    Try
+      HasData := FTcpBlockSocket.CanRead(WaitMilliseconds);
+    Except
+      On E:Exception do begin
+        SocketError := FTcpBlockSocket.LastError;
+        TLog.NewLog(lterror,ClassName,'Error WaitingForData from '+ClientRemoteAddr+': '+FTcpBlockSocket.GetErrorDescEx);
+        Disconnect;
+      end;
+    End;
+  Finally
+    FLock.Release;
   End;
   {$ENDIF}
 end;
@@ -348,8 +364,7 @@ begin
   Result := FTcpBlockSocket.RemoteHost;
   {$ENDIF}
   {$IFDEF Synapse}
-  if FConnected then Result := FTcpBlockSocket.GetRemoteSinIP
-  else Result := FRemoteHost;
+  Result := FRemoteHost;
   {$ENDIF}
 end;
 
@@ -359,8 +374,7 @@ begin
   Result := StrToIntDef(FTcpBlockSocket.RemotePort,0);
   {$ENDIF}
   {$IFDEF Synapse}
-  if FConnected then Result := FTcpBlockSocket.GetRemoteSinPort
-  else Result := FRemotePort;
+  Result := FRemotePort;
   {$ENDIF}
 end;
 
@@ -371,20 +385,26 @@ begin
   Result := FTcpBlockSocket.ReceiveBuf(Buf,BufSize);
   {$ENDIF}
   {$IFDEF Synapse}
+  FLock.Acquire;
   Try
-    Result := FTcpBlockSocket.RecvBuffer(@Buf,BufSize);
-    if (Result<0) Or (FTcpBlockSocket.LastError<>0) then begin
-      TLog.NewLog(ltInfo,ClassName,'Closing connection from '+ClientRemoteAddr+' (Receiving error): '+Inttostr(FTcpBlockSocket.LastError)+' '+FTcpBlockSocket.GetErrorDescEx);
-      Disconnect;
-    end else if Result>0 then inc(FBytesReceived,Result);
-  Except
-    On E:Exception do begin
-      FSocketError := FTcpBlockSocket.LastError;
-      TLog.NewLog(lterror,ClassName,'Exception receiving buffer from '+ClientRemoteAddr+': '+FTcpBlockSocket.GetErrorDescEx);
-      Disconnect;
-    end;
+    Try
+      Result := FTcpBlockSocket.RecvBuffer(@Buf,BufSize);
+      if (Result<0) Or (FTcpBlockSocket.LastError<>0) then begin
+        TLog.NewLog(ltInfo,ClassName,'Closing connection from '+ClientRemoteAddr+' (Receiving error): '+Inttostr(FTcpBlockSocket.LastError)+' '+FTcpBlockSocket.GetErrorDescEx);
+        Disconnect;
+      end else if Result>0 then inc(FBytesReceived,Result);
+    Except
+      On E:Exception do begin
+        SocketError := FTcpBlockSocket.LastError;
+        TLog.NewLog(lterror,ClassName,'Exception receiving buffer from '+ClientRemoteAddr+' '+FTcpBlockSocket.GetErrorDescEx);
+        Disconnect;
+      end;
+    End;
+  Finally
+    FLock.Release;
   End;
   {$ENDIF}
+  if Result>0 then FLastCommunicationTime := Now;
 end;
 
 function TNetTcpIpClient.SendStream(Stream: TStream): Int64;
@@ -397,24 +417,30 @@ begin
   Result := Stream.Position - sp;
   {$ENDIF}
   {$IFDEF Synapse}
+  FLock.Acquire;
   Try
-    FTcpBlockSocket.SendStreamRaw(Stream);
-    if FTcpBlockSocket.LastError<>0 then begin
-      TLog.NewLog(ltInfo,ClassName,'Closing connection from '+ClientRemoteAddr+' (Sending error): '+Inttostr(FTcpBlockSocket.LastError)+' '+FTcpBlockSocket.GetErrorDescEx);
-      Result := -1;
-      Disconnect;
-    end else begin
-      Result := Stream.Position - sp;
-      inc(FBytesSent,Result);
-    end;
-  Except
-    On E:Exception do begin
-      FSocketError := FTcpBlockSocket.LastError;
-      TLog.NewLog(lterror,ClassName,'Exception sending stream to '+ClientRemoteAddr+': '+FTcpBlockSocket.GetErrorDescEx);
-      Disconnect;
-    end;
+    Try
+      FTcpBlockSocket.SendStreamRaw(Stream);
+      if FTcpBlockSocket.LastError<>0 then begin
+        TLog.NewLog(ltInfo,ClassName,'Closing connection from '+ClientRemoteAddr+' (Sending error): '+Inttostr(FTcpBlockSocket.LastError)+' '+FTcpBlockSocket.GetErrorDescEx);
+        Result := -1;
+        Disconnect;
+      end else begin
+        Result := Stream.Position - sp;
+        inc(FBytesSent,Result);
+      end;
+    Except
+      On E:Exception do begin
+        SocketError := FTcpBlockSocket.LastError;
+        TLog.NewLog(lterror,ClassName,'Exception sending stream to '+ClientRemoteAddr+': '+FTcpBlockSocket.GetErrorDescEx);
+        Disconnect;
+      end;
+    End;
+  Finally
+    FLock.Release;
   End;
   {$ENDIF}
+  if Result>0 then FLastCommunicationTime := Now;
 end;
 
 procedure TNetTcpIpClient.SetOnConnect(const Value: TNotifyEvent);
@@ -480,9 +506,11 @@ var SendBuffStream : TStream;
   ReceiveBuffer : Array[0..4095] of byte;
   Procedure DoReceiveBuf;
   var last_bytes_read : Integer;
+    total_read, total_size : Int64;
     ms : TMemoryStream;
     lastpos : Int64;
   begin
+    total_read := 0; total_size := 0;
     If FBufferedNetTcpIpClient.DoWaitForDataInherited(10) then begin
       last_bytes_read := 0;
       repeat
@@ -503,12 +531,14 @@ var SendBuffStream : TStream;
             ms.Position := ms.Size;
             ms.Write(ReceiveBuffer,last_bytes_read);
             ms.Position := lastpos;
-            TLog.NewLog(ltdebug,ClassName,Format('Received %d bytes. Buffer length: %d bytes',[last_bytes_read,ms.Size]));
+            inc(total_read,last_bytes_read);
+            total_size := ms.Size;
           Finally
             FBufferedNetTcpIpClient.ReadBufferUnlock;
           End;
         end;
-      until (last_bytes_read<sizeof(ReceiveBuffer));
+      until (last_bytes_read<sizeof(ReceiveBuffer)) Or (Terminated) Or (Not FBufferedNetTcpIpClient.Connected);
+      If total_read>0 then TLog.NewLog(ltdebug,ClassName,Format('Received %d bytes. Buffer length: %d bytes',[total_read,total_size]));
     end else begin
       if FBufferedNetTcpIpClient.SocketError<>0 then FBufferedNetTcpIpClient.Disconnect;
     end;
@@ -539,9 +569,9 @@ begin
       while (Not Terminated) And (Not FBufferedNetTcpIpClient.Connected) do sleep(100);
       if (FBufferedNetTcpIpClient.Connected) then begin
         // Receive data
-        DoReceiveBuf;
+        If (Not Terminated) And (FBufferedNetTcpIpClient.Connected) then DoReceiveBuf;
         // Send Data
-        DoSendBuf;
+        If (Not Terminated) And (FBufferedNetTcpIpClient.Connected) then DoSendBuf;
       end else FBufferedNetTcpIpClient.FLastReadTC := GetTickCount;
       // Sleep
       Sleep(10); // Slepp 10 is better than sleep 1
@@ -564,7 +594,7 @@ constructor TBufferedNetTcpIpClient.Create(AOwner: TComponent);
 begin
   inherited;
   FLastReadTC := GetTickCount;
-  FCritical := SyncObjs.TCriticalSection.Create;
+  FCritical := TPCCriticalSection.Create('TBufferedNetTcpIpClient_Critical');
   FSendBuffer := TMemoryStream.Create;
   FReadBuffer := TMemoryStream.Create;
   FBufferedNetTcpIpClientThread := TBufferedNetTcpIpClientThread.Create(Self);
@@ -640,7 +670,7 @@ begin
   {$ELSE}
   FActive := false;
   {$ENDIF}
-  FNetClients := TPCThreadList.Create;
+  FNetClients := TPCThreadList.Create('TNetTcpIpServer_NetClients');
 end;
 
 destructor TNetTcpIpServer.Destroy;
@@ -697,12 +727,21 @@ begin
 
   n := FNetTcpIpClientClass.Create(Nil);
   Try
-    oldSocket := n.FTcpBlockSocket;
-    n.FTcpBlockSocket := ClientSocket;
     {$IFDEF Synapse}
-    n.FConnected := True;
-    n.RemoteHost := ClientSocket.GetRemoteSinIP;
-    n.RemotePort := ClientSocket.GetRemoteSinPort;
+    n.FLock.Acquire;
+    try
+    {$ENDIF}
+      oldSocket := n.FTcpBlockSocket;
+      n.FTcpBlockSocket := ClientSocket;
+      {$IFDEF Synapse}
+      n.FConnected := True;
+      n.RemoteHost := ClientSocket.GetRemoteSinIP;
+      n.RemotePort := ClientSocket.GetRemoteSinPort;
+      {$ENDIF}
+    {$IFDEF Synapse}
+    finally
+      n.FLock.Release;
+    end;
     {$ENDIF}
     FNetClients.Add(n);
     try

+ 145 - 15
Units/PascalCoin/UThread.pas

@@ -28,6 +28,25 @@ uses
   Classes, SyncObjs;
 
 Type
+  TPCCriticalSection = Class(TCriticalSection)
+  private
+    FCounterLock : TCriticalSection;
+    FWaitingForCounter : Integer;
+    FCurrentThread : Cardinal;
+    FStartedTimestamp : Cardinal;
+    FName : String;
+  public
+    Constructor Create(const AName : String);
+    Destructor Destroy; override;
+    procedure Acquire; override;
+    procedure Release; override;
+    function TryEnter: Boolean;
+    Property CurrentThread : Cardinal read FCurrentThread;
+    Property WaitingForCounter : Integer read FWaitingForCounter;
+    Property StartedTimestamp : Cardinal read FStartedTimestamp;
+    Property Name : String read FName;
+  end;
+
   TPCThread = Class;
   TPCThreadClass = Class of TPCThread;
   TPCThread = Class(TThread)
@@ -44,9 +63,11 @@ Type
     Class function GetThread(index : Integer) : TPCThread;
     Class function GetThreadByClass(tclass : TPCThreadClass; Exclude : TObject) : TPCThread;
     Class function TerminateAllThreads(tclass: TPCThreadClass) : Integer;
-    Class Procedure ProtectEnterCriticalSection(Const Sender : TObject; var Lock : TCriticalSection);
-    Class Function TryProtectEnterCriticalSection(Const Sender : TObject; MaxWaitMilliseconds : Cardinal; var Lock : TCriticalSection) : Boolean;
+    Class Procedure ProtectEnterCriticalSection(Const Sender : TObject; var Lock : TPCCriticalSection);
+    Class Function TryProtectEnterCriticalSection(Const Sender : TObject; MaxWaitMilliseconds : Cardinal; var Lock : TPCCriticalSection) : Boolean;
     Class Procedure ThreadsListInfo(list: TStrings);
+    constructor Create(CreateSuspended: Boolean);
+    destructor Destroy; override;
     Property DebugStep : String read FDebugStep write FDebugStep;
     property Terminated;
   End;
@@ -54,9 +75,9 @@ Type
   TPCThreadList = class
   private
     FList: TList;
-    FLock: TCriticalSection;
+    FLock: TPCCriticalSection;
   public
-    constructor Create;
+    constructor Create(const AName : String);
     destructor Destroy; override;
     function Add(Item: Pointer) : Integer;
     procedure Clear;
@@ -70,12 +91,23 @@ Type
 implementation
 
 uses
-  SysUtils, ULog;
+  SysUtils, ULog, UConst;
 
 { TPCThread }
 
 Var _threads : TPCThreadList;
 
+constructor TPCThread.Create(CreateSuspended: Boolean);
+begin
+  inherited Create(CreateSuspended);
+  TLog.NewLog(ltdebug,Classname,'Created Thread '+IntToHex(PtrInt(Self),8));
+end;
+
+destructor TPCThread.Destroy;
+begin
+  inherited;
+end;
+
 procedure TPCThread.DoTerminate;
 begin
   inherited;
@@ -89,7 +121,7 @@ begin
   FDebugStep := '';
   i := _threads.Add(Self);
   try
-    TLog.NewLog(ltdebug,Classname,'Starting Thread in pos '+inttostr(i+1));
+    TLog.NewLog(ltdebug,Classname,'Starting Thread '+IntToHex(PtrInt(Self),8)+' in pos '+inttostr(i+1));
     Try
       Try
         BCExecute;
@@ -146,7 +178,7 @@ begin
   end;
 end;
 
-class procedure TPCThread.ProtectEnterCriticalSection(Const Sender : TObject; var Lock: TCriticalSection);
+class procedure TPCThread.ProtectEnterCriticalSection(Const Sender : TObject; var Lock: TPCCriticalSection);
 begin
   if Not Lock.TryEnter then begin
 //    TLog.NewLog(ltdebug,Sender.Classname,Format('Locked critical section (WAIT): LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
@@ -207,19 +239,31 @@ begin
 end;
 
 class function TPCThread.TryProtectEnterCriticalSection(const Sender: TObject;
-  MaxWaitMilliseconds: Cardinal; var Lock: TCriticalSection): Boolean;
-Var tc : Cardinal;
+  MaxWaitMilliseconds: Cardinal; var Lock: TPCCriticalSection): Boolean;
+Var tc,tc2,tc3,lockCurrThread,lockWatingForCounter,lockStartedTimestamp : Cardinal;
   s : String;
 begin
-  if MaxWaitMilliseconds>60000 then MaxWaitMilliseconds := 60000;
   tc := GetTickCount;
+  if MaxWaitMilliseconds>60000 then MaxWaitMilliseconds := 60000;
+  lockWatingForCounter := Lock.WaitingForCounter;
+  lockStartedTimestamp := Lock.StartedTimestamp;
+  lockCurrThread := Lock.CurrentThread;
   Repeat
     Result := Lock.TryEnter;
     if Not Result then sleep(1);
   Until (Result) Or (GetTickCount > (tc + MaxWaitMilliseconds));
   if Not Result then begin
-    s := Format('Cannot Protect a critical section by %s after %d milis',
-      [Sender.ClassName,MaxWaitMilliseconds]);
+    tc2 := GetTickCount;
+    if lockStartedTimestamp=0 then lockStartedTimestamp := Lock.StartedTimestamp;
+    if lockStartedTimestamp=0 then tc3 := 0
+    else tc3 := tc2-lockStartedTimestamp;
+    s := Format('Cannot Protect a critical section %s %s class %s after %d milis locked by %s waiting %d-%d elapsed milis: %d',
+      [IntToHex(PtrInt(Lock),8),Lock.Name,
+      Sender.ClassName,tc2-tc,
+      IntToHex(lockCurrThread,8)+'-'+IntToHex(Lock.CurrentThread,8),
+      lockWatingForCounter,Lock.WaitingForCounter,
+      tc3
+      ]);
     TLog.NewLog(ltdebug,Classname,s);
   end;
 end;
@@ -246,9 +290,9 @@ begin
   End;
 end;
 
-constructor TPCThreadList.Create;
+constructor TPCThreadList.Create(const AName : String);
 begin
-  FLock := TCriticalSection.Create;
+  FLock := TPCCriticalSection.Create(AName);
   FList := TList.Create;
 end;
 
@@ -292,8 +336,94 @@ begin
   FLock.Release;
 end;
 
+{ TPCCriticalSection }
+
+procedure TPCCriticalSection.Acquire;
+Var continue, logged : Boolean;
+  startTC : Cardinal;
+begin
+  startTC := GetTickCount;
+  FCounterLock.Acquire;
+  try
+    FWaitingForCounter := FWaitingForCounter + 1;
+  finally
+    FCounterLock.Release;
+  end;
+  logged := false;
+  Repeat
+    continue := inherited TryEnter;
+    if (Not continue) then begin
+      If (not logged) And ((FStartedTimestamp>0) And ((FStartedTimestamp+1000)<GetTickCount)) then begin
+        logged := true;
+        TLog.NewLog(ltdebug,ClassName,'ALERT Critical section '+IntToHex(PtrInt(Self),8)+' '+Name+
+          ' locked by '+IntToHex(FCurrentThread,8)+' waiting '+
+          IntToStr(FWaitingForCounter)+' elapsed milis: '+IntToStr(GetTickCount-FStartedTimestamp) );
+        continue := true;
+        inherited;
+      end else sleep(1);
+    end;
+  Until continue;
+  if (logged) then begin
+    TLog.NewLog(ltdebug,Classname,'ENTER Critical section '+IntToHex(PtrInt(Self),8)+' '+Name+' elapsed milis: '+IntToStr(GetTickCount - startTC) );
+  end;
+  FCounterLock.Acquire;
+  try
+    FWaitingForCounter := FWaitingForCounter - 1;
+  finally
+    FCounterLock.Release;
+  end;
+  FCurrentThread := TThread.CurrentThread.ThreadID;
+  FStartedTimestamp := GetTickCount;
+end;
+
+constructor TPCCriticalSection.Create(const AName : String);
+begin
+  FCounterLock := TCriticalSection.Create;
+  FWaitingForCounter := 0;
+  FCurrentThread := 0;
+  FStartedTimestamp := 0;
+  FName := AName;
+  inherited Create;
+  // XXXXX DEBUG ONLY
+  // TLog.NewLog(ltDebug,ClassName,'Created critical section '+IntToHex(PtrInt(Self),8)+' '+AName );
+end;
+
+destructor TPCCriticalSection.Destroy;
+begin
+  FCounterLock.Free;
+  inherited;
+end;
+
+procedure TPCCriticalSection.Release;
+begin
+  FCurrentThread := 0;
+  FStartedTimestamp := 0;
+  inherited;
+end;
+
+function TPCCriticalSection.TryEnter: Boolean;
+begin
+  FCounterLock.Acquire;
+  try
+    FWaitingForCounter := FWaitingForCounter + 1;
+  finally
+    FCounterLock.Release;
+  end;
+  If inherited TryEnter then begin
+    FCurrentThread := TThread.CurrentThread.ThreadID;
+    FStartedTimestamp := GetTickCount;
+    Result := true;
+  end else Result := false;
+  FCounterLock.Acquire;
+  try
+    FWaitingForCounter := FWaitingForCounter - 1;
+  finally
+    FCounterLock.Release;
+  end;
+end;
+
 initialization
-  _threads := TPCThreadList.Create;
+  _threads := TPCThreadList.Create('GLOBAL_THREADS');
 finalization
   {$IFnDEF FPC}
   FreeAndNil(_threads);

+ 2 - 0
Units/PascalCoin/upcdaemon.pas

@@ -27,6 +27,7 @@ Const
   CT_INI_SECTION_GLOBAL = 'GLOBAL';
   CT_INI_IDENT_SAVELOGS = 'SAVELOGS';
   CT_INI_IDENT_RPC_PORT = 'RPC_PORT';
+  CT_INI_IDENT_RPC_WHITELIST = 'RPC_WHITELIST';
   CT_INI_IDENT_RPC_SAVELOGS = 'RPC_SAVELOGS';
   CT_INI_IDENT_RPC_SERVERMINER_PORT = 'RPC_SERVERMINER_PORT';
   CT_INI_IDENT_MINER_B58_PUBLICKEY = 'RPC_SERVERMINER_B58_PUBKEY';
@@ -102,6 +103,7 @@ var
     FRPC.WalletKeys := FWalletKeys;
     FRPC.Port:=port;
     FRPC.Active:=true;
+    FRPC.ValidIPs:=FIniFile.ReadString(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_WHITELIST,'127.0.0.1;');
     TLog.NewLog(ltInfo,ClassName,'RPC server is active on port '+IntToStr(port));
     If FIniFile.ReadBool(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_SAVELOGS,true) then begin
       FIniFile.WriteBool(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_RPC_SAVELOGS,true);

+ 15 - 2
Units/Utils/UGridUtils.pas

@@ -126,6 +126,7 @@ Type
     MinerPayload : TRawBytes;
     PoW : TRawBytes;
     SafeBoxHash : TRawBytes;
+    AccumulatedWork : UInt64;
   End;
   TBlockChainDataArray = Array of TBlockChainData;
 
@@ -164,7 +165,7 @@ Type
   End;
 
 Const
-  CT_TBlockChainData_NUL : TBlockChainData = (Block:0;Timestamp:0;BlockProtocolVersion:0;BlockProtocolAvailable:0;OperationsCount:0;Volume:0;Reward:0;Fee:0;Target:0;HashRateKhs:0;MinerPayload:'';PoW:'';SafeBoxHash:'');
+  CT_TBlockChainData_NUL : TBlockChainData = (Block:0;Timestamp:0;BlockProtocolVersion:0;BlockProtocolAvailable:0;OperationsCount:0;Volume:0;Reward:0;Fee:0;Target:0;HashRateKhs:0;MinerPayload:'';PoW:'';SafeBoxHash:'';AccumulatedWork:0);
 
 
 implementation
@@ -917,7 +918,7 @@ begin
   DrawGrid.FixedRows := 1;
   DrawGrid.DefaultDrawing := true;
   DrawGrid.FixedCols := 0;
-  DrawGrid.ColCount := 12;
+  DrawGrid.ColCount := 13;
   DrawGrid.ColWidths[0] := 50; // Block
   DrawGrid.ColWidths[1] := 110; // Time
   DrawGrid.ColWidths[2] := 30; // Ops
@@ -930,6 +931,7 @@ begin
   DrawGrid.ColWidths[9] := 190; // PoW
   DrawGrid.ColWidths[10] := 190; // SafeBox Hash
   DrawGrid.ColWidths[11] := 50; // Protocol
+  DrawGrid.ColWidths[12] := 120; // Accumulated work
   FDrawGrid.DefaultRowHeight := 18;
   FDrawGrid.Invalidate;
   DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
@@ -974,6 +976,7 @@ begin
       9 : s := 'Proof of Work';
       10 : s := 'SafeBox Hash';
       11 : s := 'Protocol';
+      12 : s := 'Acc.Work';
     else s:= '';
     end;
     Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter]);
@@ -1030,6 +1033,15 @@ begin
       end else if ACol=11 then begin
         s := Inttostr(bcd.BlockProtocolVersion)+'-'+IntToStr(bcd.BlockProtocolAvailable);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
+      end else if ACol=12 then begin
+        if bcd.AccumulatedWork>0 then begin
+          s := Inttostr(bcd.AccumulatedWork);
+          Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter]);
+        end else begin
+          DrawGrid.Canvas.Font.Color := clGrayText;
+          s := '(no data)';
+          Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
+        end;
       end;
     end;
   end;
@@ -1155,6 +1167,7 @@ begin
           bcd.MinerPayload := opc.OperationBlock.block_payload;
           bcd.PoW := opc.OperationBlock.proof_of_work;
           bcd.SafeBoxHash := opc.OperationBlock.initial_safe_box_hash;
+          bcd.AccumulatedWork := Node.Bank.SafeBox.Block(bcd.Block).AccumulatedWork;
         end;
         FBlockChainDataArray[i] := bcd;
         if (nend>0) then dec(nend) else break;

+ 2 - 0
pascalcoin_daemon.ini

@@ -5,6 +5,8 @@ SAVELOGS=0
 ;RPC_PORT : Integer (Default 4003)
 ;Port to use by TCP/IP JSON-RPC commands
 RPC_PORT=4003
+;RPC_WHITELIST : String containing allowed IP's that can use port 4003. Empty=ALL
+RPC_WHITELIST=127.0.0.1 192.168.0.1
 ;RPC_SAVELOGS : Boolean
 ;Save RPC commands log file $HOME/PascalCoin
 RPC_SAVELOGS=1