Browse Source

Build 1.5.4

- Added Network Timestamp Adjustment (NAT) to calc valid timestamps
- Minimum 4 active connections to calc median used for NAT, otherwise
use local timestamp
- Based on IP's (to prevent a malicious IP timejacking, each IP is only
used once)
- Removed IP's and recalculated after disconnecting (to prevent
malicious node connecting/disconnecting for timejacking)
- New blocks will not be accepted if using future timestamp greater than
NAT timestamp + 15 seconds (also, mantaining current protocol rule >=
lastBlock.timestamp)
- Network protocol fixed to 5-5 (Nodes with version prior to 1.5 will
not be allowed)
- Added protection for non included operations on a block, to prevent
continuous sending. Only will resend operations once.
- Bug #27 fixed: Invalid timestamp on FPC
(https://github.com/PascalCoin/PascalCoin/issues/27)
- JSON-RPC
- Method "getconnections" added "timediff" to know timestamp diff of
node
- Method "payloaddecrypt" added "unenc_hexpayload" result value with
HEXASTRING of unencrypted payload
- Fixed some "Random Memory access violation errors" bugs found caused
by multithreading and disconnected nodes
PascalCoin 8 years ago
parent
commit
d288b9763c

BIN
PascalCoinWallet.res


+ 15 - 0
README.md

@@ -34,6 +34,21 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.5.4.0 - 2017-03-14
+
+- Added Network Timestamp Adjustment (NAT) to calc valid timestamps
+  - Minimum 4 active connections to calc median used for NAT, otherwise use local timestamp
+  - Based on IP's (to prevent a malicious IP timejacking, each IP is only used once)
+  - Removed IP's and recalculated after disconnecting (to prevent malicious node connecting/disconnecting for timejacking)
+- New blocks will not be accepted if using future timestamp greater than NAT timestamp + 15 seconds (also, mantaining current protocol rule >= lastBlock.timestamp)
+- Network protocol fixed to 5-5 (Nodes with version prior to 1.5 will not be allowed)
+- Added protection for non included operations on a block, to prevent continuous sending. Only will resend operations once.
+- Bug #27 fixed: Invalid timestamp on FPC (https://github.com/PascalCoin/PascalCoin/issues/27)
+- JSON-RPC
+  - Method "getconnections" added "timediff" to know timestamp diff of node
+  - Method "payloaddecrypt" added "unenc_hexpayload" result value with HEXASTRING of unencrypted payload
+- Fixed some "Random Memory access violation errors" bugs found caused by multithreading and disconnected nodes
+
 ### Build 1.5.3.0 - 2017-03-06
 
 - Fixed issue #23: RPC findoperation fails to find operation by opHash

+ 15 - 0
README.txt

@@ -34,6 +34,21 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.5.4.0 - 2017-03-14
+
+- Added Network Timestamp Adjustment (NAT) to calc valid timestamps
+  - Minimum 4 active connections to calc median used for NAT, otherwise use local timestamp
+  - Based on IP's (to prevent a malicious IP timejacking, each IP is only used once)
+  - Removed IP's and recalculated after disconnecting (to prevent malicious node connecting/disconnecting for timejacking)
+- New blocks will not be accepted if using future timestamp greater than NAT timestamp + 15 seconds (also, mantaining current protocol rule >= lastBlock.timestamp)
+- Network protocol fixed to 5-5 (Nodes with version prior to 1.5 will not be allowed)
+- Added protection for non included operations on a block, to prevent continuous sending. Only will resend operations once.
+- Bug #27 fixed: Invalid timestamp on FPC (https://github.com/PascalCoin/PascalCoin/issues/27)
+- JSON-RPC
+  - Method "getconnections" added "timediff" to know timestamp diff of node
+  - Method "payloaddecrypt" added "unenc_hexpayload" result value with HEXASTRING of unencrypted payload
+- Fixed some "Random Memory access violation errors" bugs found caused by multithreading and disconnected nodes
+
 ### Build 1.5.3.0 - 2017-03-06
 
 - Fixed issue #23: RPC findoperation fails to find operation by opHash

+ 10 - 41
Units/Forms/UFRMWallet.dfm

@@ -368,23 +368,16 @@ object FRMWallet: TFRMWallet
     Top = 91
     Width = 849
     Height = 432
-    ActivePage = tsNodeStats
+    ActivePage = tsMyAccounts
     Align = alClient
     TabOrder = 2
     OnChange = PageControlChange
     object tsMyAccounts: TTabSheet
       Caption = 'Accounts Explorer'
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object Splitter1: TSplitter
         Left = 380
         Top = 66
         Height = 338
-        ExplicitLeft = 390
-        ExplicitTop = 140
-        ExplicitHeight = 100
       end
       object pnlMyAccountsTop: TPanel
         Left = 0
@@ -481,7 +474,7 @@ object FRMWallet: TFRMWallet
           Top = 0
           Width = 380
           Height = 304
-          Align = alLeft
+          Align = alClient
           TabOrder = 0
           OnClick = dgAccountsClick
           OnColumnMoved = dgAccountsColumnMoved
@@ -583,10 +576,6 @@ 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
@@ -606,10 +595,6 @@ 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
@@ -799,10 +784,6 @@ 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
@@ -850,10 +831,6 @@ 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
@@ -899,10 +876,6 @@ 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
@@ -948,10 +921,6 @@ 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
@@ -1016,8 +985,9 @@ object FRMWallet: TFRMWallet
         Height = 106
         Anchors = [akLeft, akTop, akRight, akBottom]
         ReadOnly = True
-        ScrollBars = ssVertical
+        ScrollBars = ssBoth
         TabOrder = 0
+        WordWrap = False
       end
       object memoNetServers: TMemo
         Left = 15
@@ -1026,8 +996,9 @@ object FRMWallet: TFRMWallet
         Height = 116
         Anchors = [akLeft, akRight, akBottom]
         ReadOnly = True
-        ScrollBars = ssVertical
+        ScrollBars = ssBoth
         TabOrder = 1
+        WordWrap = False
       end
       object memoNetBlackLists: TMemo
         Left = 15
@@ -1036,17 +1007,14 @@ object FRMWallet: TFRMWallet
         Height = 79
         Anchors = [akLeft, akRight, akBottom]
         ReadOnly = True
-        ScrollBars = ssVertical
+        ScrollBars = ssBoth
         TabOrder = 2
+        WordWrap = False
       end
     end
     object tsMessages: TTabSheet
       Caption = 'Messages'
       ImageIndex = 6
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       DesignSize = (
         841
         404)
@@ -1122,6 +1090,7 @@ object FRMWallet: TFRMWallet
         ReadOnly = True
         ScrollBars = ssBoth
         TabOrder = 2
+        WordWrap = False
       end
       object memoMessageToSend: TMemo
         Left = 315
@@ -1280,7 +1249,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Top = 180
     Bitmap = {
-      494C010102000800E00110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000800E80110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 95 - 94
Units/Forms/UFRMWallet.lfm

@@ -4,7 +4,7 @@ object FRMWallet: TFRMWallet
   Top = 201
   Width = 865
   Caption = 'Pascal Coin Wallet, JSON-RPC Miner & Explorer'
-  ClientHeight = 580
+  ClientHeight = 600
   ClientWidth = 865
   Color = clBtnFace
   Constraints.MinHeight = 600
@@ -162,7 +162,7 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 11
-      Width = 60
+      Width = 70
       Caption = 'Total Blocks:'
       ParentColor = False
     end
@@ -170,7 +170,7 @@ object FRMWallet: TFRMWallet
       Left = 166
       Height = 13
       Top = 11
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -178,7 +178,7 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 26
-      Width = 89
+      Width = 106
       Caption = 'Current Block age:'
       ParentColor = False
     end
@@ -186,7 +186,7 @@ object FRMWallet: TFRMWallet
       Left = 198
       Height = 13
       Top = 26
-      Width = 81
+      Width = 96
       Caption = '000 seconds ago'
       ParentColor = False
     end
@@ -194,7 +194,7 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 41
-      Width = 98
+      Width = 115
       Caption = 'Pending Operations:'
       ParentColor = False
     end
@@ -202,7 +202,7 @@ object FRMWallet: TFRMWallet
       Left = 207
       Height = 13
       Top = 41
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -210,7 +210,7 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 56
-      Width = 68
+      Width = 81
       Caption = 'Miners clients:'
       ParentColor = False
     end
@@ -218,7 +218,7 @@ object FRMWallet: TFRMWallet
       Left = 177
       Height = 13
       Top = 56
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -226,7 +226,7 @@ object FRMWallet: TFRMWallet
       Left = 429
       Height = 13
       Top = 11
-      Width = 76
+      Width = 86
       Caption = 'Current Target:'
       ParentColor = False
     end
@@ -234,7 +234,7 @@ object FRMWallet: TFRMWallet
       Left = 518
       Height = 13
       Top = 11
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -242,7 +242,7 @@ object FRMWallet: TFRMWallet
       Left = 370
       Height = 13
       Top = 26
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -250,7 +250,7 @@ object FRMWallet: TFRMWallet
       Left = 285
       Height = 13
       Top = 26
-      Width = 69
+      Width = 83
       Caption = 'Time average:'
       ParentColor = False
     end
@@ -258,7 +258,7 @@ object FRMWallet: TFRMWallet
       Left = 90
       Height = 13
       Top = 70
-      Width = 63
+      Width = 72
       Caption = 'Node Status:'
       ParentColor = False
     end
@@ -266,7 +266,7 @@ object FRMWallet: TFRMWallet
       Left = 168
       Height = 13
       Top = 70
-      Width = 15
+      Width = 18
       Caption = '???'
       ParentColor = False
     end
@@ -274,7 +274,7 @@ object FRMWallet: TFRMWallet
       Left = 285
       Height = 13
       Top = 11
-      Width = 48
+      Width = 55
       Caption = 'Accounts:'
       ParentColor = False
     end
@@ -282,7 +282,7 @@ object FRMWallet: TFRMWallet
       Left = 344
       Height = 13
       Top = 11
-      Width = 18
+      Width = 21
       Caption = '000'
       ParentColor = False
     end
@@ -290,7 +290,7 @@ object FRMWallet: TFRMWallet
       Left = 370
       Height = 13
       Top = 41
-      Width = 18
+      Width = 21
       Caption = '000'
       Font.Color = clGray
       Font.Height = -11
@@ -302,7 +302,7 @@ object FRMWallet: TFRMWallet
       Left = 360
       Height = 13
       Top = 56
-      Width = 74
+      Width = 86
       Caption = 'Blocks found:'
       Font.Color = clWindowText
       Font.Height = -11
@@ -316,7 +316,7 @@ object FRMWallet: TFRMWallet
       Height = 13
       Hint = 'Blocks found while Miner is running...'
       Top = 56
-      Width = 21
+      Width = 24
       Caption = '000'
       Font.Color = clWindowText
       Font.Height = -11
@@ -330,9 +330,9 @@ object FRMWallet: TFRMWallet
     object lblReceivedMessages: TLabel
       Cursor = crHandPoint
       Left = 360
-      Height = 23
+      Height = 22
       Top = 66
-      Width = 185
+      Width = 211
       Caption = 'Received messages'
       Font.Color = clRed
       Font.Height = -19
@@ -344,9 +344,9 @@ object FRMWallet: TFRMWallet
     end
     object lblBuild: TLabel
       Left = 586
-      Height = 23
+      Height = 22
       Top = 3
-      Width = 49
+      Width = 56
       Caption = 'Build'
       Font.Color = clWindowText
       Font.Height = -19
@@ -358,8 +358,8 @@ object FRMWallet: TFRMWallet
   end
   object StatusBar: TStatusBar
     Left = 0
-    Height = 23
-    Top = 557
+    Height = 21
+    Top = 579
     Width = 865
     Panels = <    
       item
@@ -379,21 +379,21 @@ object FRMWallet: TFRMWallet
   end
   object PageControl: TPageControl
     Left = 0
-    Height = 466
+    Height = 488
     Top = 91
     Width = 865
-    ActivePage = tsLogs
+    ActivePage = tsMyAccounts
     Align = alClient
-    TabIndex = 4
+    TabIndex = 0
     TabOrder = 2
     OnChange = PageControlChange
     object tsMyAccounts: TTabSheet
       Caption = 'Accounts Explorer'
-      ClientHeight = 440
-      ClientWidth = 857
+      ClientHeight = 461
+      ClientWidth = 861
       object Splitter1: TSplitter
         Left = 380
-        Height = 374
+        Height = 395
         Top = 66
         Width = 5
       end
@@ -401,41 +401,41 @@ object FRMWallet: TFRMWallet
         Left = 0
         Height = 66
         Top = 0
-        Width = 857
+        Width = 861
         Align = alTop
         ClientHeight = 66
-        ClientWidth = 857
+        ClientWidth = 861
         TabOrder = 0
         object Label18: TLabel
           Left = 11
           Height = 13
           Top = 35
-          Width = 61
+          Width = 70
           Caption = 'Find account'
           ParentColor = False
         end
         object cbMyPrivateKeys: TComboBox
           Left = 260
-          Height = 21
+          Height = 31
           Top = 7
           Width = 411
-          ItemHeight = 13
+          ItemHeight = 0
           OnChange = cbMyPrivateKeysChange
           Style = csDropDownList
           TabOrder = 0
         end
         object cbExploreMyAccounts: TCheckBox
           Left = 11
-          Height = 19
+          Height = 24
           Top = 10
-          Width = 235
+          Width = 329
           Caption = 'Explore accounts with one of my Wallet Keys'
           OnClick = cbExploreMyAccountsClick
           TabOrder = 1
         end
         object ebFindAccountNumber: TEdit
           Left = 87
-          Height = 21
+          Height = 23
           Top = 33
           Width = 83
           OnChange = ebFindAccountNumberChange
@@ -453,16 +453,16 @@ object FRMWallet: TFRMWallet
         end
         object cbFilterAccounts: TCheckBox
           Left = 260
-          Height = 19
+          Height = 24
           Top = 35
-          Width = 145
+          Width = 202
           Caption = 'Filter accounts by balance'
           OnClick = cbFilterAccountsClick
           TabOrder = 4
         end
         object ebFilterAccountByBalanceMin: TEdit
           Left = 412
-          Height = 21
+          Height = 23
           Hint = 'Min balance'
           Top = 33
           Width = 83
@@ -472,7 +472,7 @@ object FRMWallet: TFRMWallet
         end
         object ebFilterAccountByBalanceMax: TEdit
           Left = 503
-          Height = 21
+          Height = 23
           Hint = 'Max balance'
           Top = 33
           Width = 83
@@ -483,20 +483,20 @@ object FRMWallet: TFRMWallet
       end
       object pnlAccounts: TPanel
         Left = 0
-        Height = 374
+        Height = 395
         Top = 66
         Width = 380
         Align = alLeft
         BevelOuter = bvNone
-        ClientHeight = 374
+        ClientHeight = 395
         ClientWidth = 380
         TabOrder = 1
         object dgAccounts: TDrawGrid
           Left = 0
-          Height = 340
+          Height = 361
           Top = 0
           Width = 380
-          Align = alLeft
+          Align = alClient
           ExtendedSelect = False
           TabOrder = 0
           TitleFont.Color = clWindowText
@@ -507,7 +507,7 @@ object FRMWallet: TFRMWallet
         object pnlAccountsInfo: TPanel
           Left = 0
           Height = 34
-          Top = 340
+          Top = 361
           Width = 380
           Align = alBottom
           BevelOuter = bvNone
@@ -518,7 +518,7 @@ object FRMWallet: TFRMWallet
             Left = 5
             Height = 13
             Top = 10
-            Width = 48
+            Width = 55
             Caption = 'Accounts:'
             ParentColor = False
           end
@@ -526,7 +526,7 @@ object FRMWallet: TFRMWallet
             Left = 136
             Height = 13
             Top = 10
-            Width = 41
+            Width = 49
             Caption = 'Balance:'
             ParentColor = False
           end
@@ -534,7 +534,7 @@ object FRMWallet: TFRMWallet
             Left = 60
             Height = 13
             Top = 10
-            Width = 18
+            Width = 21
             Caption = '000'
             ParentColor = False
           end
@@ -542,7 +542,7 @@ object FRMWallet: TFRMWallet
             Left = 200
             Height = 13
             Top = 10
-            Width = 18
+            Width = 21
             Caption = '000'
             ParentColor = False
           end
@@ -588,22 +588,22 @@ object FRMWallet: TFRMWallet
       end
       object pcAccountsOptions: TPageControl
         Left = 385
-        Height = 374
+        Height = 395
         Top = 66
-        Width = 472
+        Width = 476
         ActivePage = tsAccountOperations
         Align = alClient
         TabIndex = 0
         TabOrder = 2
         object tsAccountOperations: TTabSheet
           Caption = 'Operations of selected Account'
-          ClientHeight = 348
-          ClientWidth = 464
+          ClientHeight = 368
+          ClientWidth = 472
           object dgAccountOperations: TDrawGrid
             Left = 0
-            Height = 348
+            Height = 368
             Top = 0
-            Width = 464
+            Width = 472
             Align = alClient
             ExtendedSelect = False
             TabOrder = 0
@@ -859,8 +859,8 @@ object FRMWallet: TFRMWallet
     end
     object tsBlockChain: TTabSheet
       Caption = 'BlockChain Explorer'
-      ClientHeight = 440
-      ClientWidth = 857
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 1
       object Panel2: TPanel
         Left = 0
@@ -913,29 +913,29 @@ object FRMWallet: TFRMWallet
     end
     object tsOperations: TTabSheet
       Caption = 'Operations Explorer'
-      ClientHeight = 440
-      ClientWidth = 857
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 1
       object Panel1: TPanel
         Left = 0
         Height = 41
         Top = 0
-        Width = 857
+        Width = 861
         Align = alTop
         ClientHeight = 41
-        ClientWidth = 857
+        ClientWidth = 861
         TabOrder = 0
         object Label2: TLabel
           Left = 11
           Height = 13
           Top = 10
-          Width = 102
+          Width = 121
           Caption = 'Filter by blocks range'
           ParentColor = False
         end
         object ebFilterOperationsStartBlock: TEdit
           Left = 125
-          Height = 21
+          Height = 23
           Top = 7
           Width = 57
           OnExit = ebFilterOperationsAccountExit
@@ -944,7 +944,7 @@ object FRMWallet: TFRMWallet
         end
         object ebFilterOperationsEndBlock: TEdit
           Left = 185
-          Height = 21
+          Height = 23
           Top = 7
           Width = 57
           OnExit = ebFilterOperationsAccountExit
@@ -954,9 +954,9 @@ object FRMWallet: TFRMWallet
       end
       object dgOperationsExplorer: TDrawGrid
         Left = 0
-        Height = 399
+        Height = 420
         Top = 41
-        Width = 857
+        Width = 861
         Align = alClient
         ExtendedSelect = False
         TabOrder = 1
@@ -967,32 +967,32 @@ object FRMWallet: TFRMWallet
     end
     object tsLogs: TTabSheet
       Caption = 'Logs'
-      ClientHeight = 440
-      ClientWidth = 857
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 2
       object pnlTopLogs: TPanel
         Left = 0
         Height = 41
         Top = 0
-        Width = 857
+        Width = 861
         Align = alTop
         ClientHeight = 41
-        ClientWidth = 857
+        ClientWidth = 861
         TabOrder = 0
         object cbShowDebugLogs: TCheckBox
           Left = 15
-          Height = 19
+          Height = 24
           Top = 10
-          Width = 102
+          Width = 145
           Caption = 'Show Debug logs'
           TabOrder = 0
         end
       end
       object memoLogs: TMemo
         Left = 0
-        Height = 399
+        Height = 420
         Top = 41
-        Width = 857
+        Width = 861
         Align = alClient
         ScrollBars = ssBoth
         TabOrder = 1
@@ -1001,22 +1001,22 @@ object FRMWallet: TFRMWallet
     end
     object tsNodeStats: TTabSheet
       Caption = 'Node Stats'
-      ClientHeight = 440
-      ClientWidth = 857
+      ClientHeight = 461
+      ClientWidth = 861
       ImageIndex = 3
       object Label3: TLabel
         Left = 15
         Height = 13
         Top = 15
-        Width = 177
+        Width = 207
         Caption = 'Active Net Connections of this Node:'
         ParentColor = False
       end
       object Label6: TLabel
         Left = 15
         Height = 13
-        Top = 291
-        Width = 198
+        Top = 312
+        Width = 202
         Anchors = [akLeft, akRight, akBottom]
         Caption = 'Available or possible Node Servers:'
         ParentColor = False
@@ -1024,42 +1024,42 @@ object FRMWallet: TFRMWallet
       object Label7: TLabel
         Left = 15
         Height = 13
-        Top = 187
-        Width = 99
+        Top = 208
+        Width = 103
         Anchors = [akLeft, akRight, akBottom]
         Caption = 'BlackList of Nodes'
         ParentColor = False
       end
       object memoNetConnections: TMemo
         Left = 15
-        Height = 145
+        Height = 166
         Top = 34
-        Width = 830
+        Width = 834
         Anchors = [akTop, akLeft, akRight, akBottom]
         ReadOnly = True
-        ScrollBars = ssVertical
+        ScrollBars = ssBoth
         TabOrder = 0
         WordWrap = False
       end
       object memoNetServers: TMemo
         Left = 15
         Height = 116
-        Top = 310
-        Width = 830
+        Top = 331
+        Width = 834
         Anchors = [akLeft, akRight, akBottom]
         ReadOnly = True
-        ScrollBars = ssVertical
+        ScrollBars = ssBoth
         TabOrder = 1
         WordWrap = False
       end
       object memoNetBlackLists: TMemo
         Left = 16
         Height = 79
-        Top = 206
-        Width = 829
+        Top = 227
+        Width = 833
         Anchors = [akLeft, akRight, akBottom]
         ReadOnly = True
-        ScrollBars = ssVertical
+        ScrollBars = ssBoth
         TabOrder = 2
         WordWrap = False
       end
@@ -1114,6 +1114,7 @@ object FRMWallet: TFRMWallet
         MultiSelect = True
         ScrollWidth = 273
         TabOrder = 0
+        TopIndex = -1
       end
       object bbSendAMessage: TButton
         Left = 315

+ 6 - 6
Units/Forms/UFRMWallet.pas

@@ -547,14 +547,14 @@ begin
               sLastConnTime := '';
             end;
             if NC is TNetServerClient then begin
-              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]));
+              sNSC.Add(Format('Client: IP:%s Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,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 %s',
-                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]))
+              if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]))
               else begin
-                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]));
+                sRS.Add(Format('Remote Server: IP:%s Sent/Received:%d/%d Bytes - %s - Time offset %d - Active since %s %s',
+                [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,NC.TimestampDiff,DateTimeElapsedTime(NC.CreatedTime),sLastConnTime]));
               end;
             end;
           end else begin

+ 93 - 64
Units/PascalCoin/UAccounts.pas

@@ -190,17 +190,20 @@ Type
 
   // Maintains a TRawBytes (AnsiString) list ordered to quick search withoud duplicates
   TOrderedRawList = Class
-  private
+  private
     FList : TList;
     Function Find(const RawData: TRawBytes; var Index: Integer): Boolean;
   public
     Constructor Create;
     Destructor Destroy; Override;
     Procedure Clear;
-    Function Add(Const RawData : TRawBytes) : Integer;
+    Function Add(Const RawData : TRawBytes; tagValue : Integer = 0) : Integer;
     Function Count : Integer;
     Function Get(index : Integer) : TRawBytes;
     Procedure Delete(index : Integer);
+    procedure SetTag(Const RawData : TRawBytes; newTagValue : Integer);
+    function GetTag(Const RawData : TRawBytes) : Integer; overload;
+    function GetTag(index : Integer) : Integer; overload;
     Function IndexOf(Const RawData : TRawBytes) : Integer;
   End;
 
@@ -844,8 +847,8 @@ begin
       FSafeBoxHash := accounts.FSafeBoxHash;
       FPreviousBlockSafeBoxHash := accounts.FPreviousBlockSafeBoxHash;
       FWorkSum := accounts.FWorkSum;
-    finally
-      accounts.EndThreadSave;
+    finally
+      accounts.EndThreadSave;
     end;
   finally
     EndThreadSave;
@@ -1389,10 +1392,10 @@ begin
 end;
 
 procedure TOrderedAccountKeysList.Clear;
-begin
-  ClearAccounts(true);
-end;
-
+begin
+  ClearAccounts(true);
+end;
+
 procedure TOrderedAccountKeysList.ClearAccounts(RemoveAccountList : Boolean);
 Var P : POrderedAccountKeyList;
   i : Integer;
@@ -1628,60 +1631,67 @@ begin
 end;
 
 { TOrderedRawList }
-
-function TOrderedRawList.Add(const RawData: TRawBytes): Integer;
-Var P : PRawBytes;
-begin
-  if Find(RawData,Result) then exit
-  else begin
+
+
Type TRawListData = Record
+
    RawData : TRawBytes;
+    tag : Integer;
+  End;
+
  PRawListData = ^TRawListData;
+
+function TOrderedRawList.Add(const RawData: TRawBytes; tagValue : Integer = 0) : Integer;
+Var P : PRawListData;
+begin
+  if Find(RawData,Result) then begin
+    PRawListData(FList[Result])^.tag := tagValue;
+  end else begin
     New(P);
-    P^ := RawData;
+    P^.RawData := RawData;
+    P^.tag := tagValue;
     FList.Insert(Result,P);
   end;
 end;
-
+
 procedure TOrderedRawList.Clear;
-Var P : PRawBytes;
+Var P : PRawListData;
   i : Integer;
-begin
-  for i := FList.Count - 1 downto 0 do begin
-    P := FList[i];
-    Dispose(P);
-  end;
-  FList.Clear;
-end;
-
+begin
+  for i := FList.Count - 1 downto 0 do begin
+    P := FList[i];
+    Dispose(P);
+  end;
+  FList.Clear;
+end;
+
 function TOrderedRawList.Count: Integer;
-begin
-  Result := FList.Count;
-end;
-
+begin
+  Result := FList.Count;
+end;
+
 constructor TOrderedRawList.Create;
-begin
-  FList := TList.Create;
-end;
-
-
+begin
+  FList := TList.Create;
+end;
+
 procedure TOrderedRawList.Delete(index: Integer);
-Var P : PRawBytes;
-begin
-  P := PRawBytes(FList[index]);
-  FList.Delete(index);
-  Dispose(P);
-end;
-
+Var P : PRawListData;
+begin
+  P := PRawListData(FList[index]);
+  FList.Delete(index);
+  Dispose(P);
+end;
+
 destructor TOrderedRawList.Destroy;
-begin
-  Clear;
-  FreeAndNil(FList);
-  inherited;
-end;
-
+begin
+  Clear;
+  FreeAndNil(FList);
+  inherited;
+end;
+
 
 function TOrderedRawList.Find(const RawData: TRawBytes; var Index: Integer): Boolean;
-var L, H, I: Integer;
-  c : Integer;
-  PRawData : PAnsiChar;
+var L, H, I: Integer;
+  c : Integer;
+  PRawData : PAnsiChar;
 begin
   Result := False;
   L := 0;
@@ -1690,7 +1700,7 @@ begin
   while L <= H do
   begin
     I := (L + H) shr 1;
-    c := StrComp(PAnsiChar(PRawBytes(FList[i])^),PRawData);
+    c := StrComp(PAnsiChar(PRawListData(FList[i])^.RawData),PRawData);
     if C < 0 then L := I + 1 else
     begin
       H := I - 1;
@@ -1702,18 +1712,37 @@ begin
     end;
   end;
   Index := L;
-end;
-
-
+end;
+
 function TOrderedRawList.Get(index: Integer): TRawBytes;
-begin
-  Result := PRawBytes(FList[index])^;
-end;
-
-function TOrderedRawList.IndexOf(const RawData: TRawBytes): Integer;
-begin
-  if Not Find(RawData,Result) then Result := -1;
-end;
-
-end.
+begin
+  Result := PRawListData(FList[index])^.RawData;
+end;
+
+function TOrderedRawList.GetTag(index: Integer): Integer;
+begin
+  Result := PRawListData(FList[index])^.tag;
+end;
+
+function TOrderedRawList.GetTag(const RawData: TRawBytes): Integer;
+Var i : Integer;
+begin
+  if Not Find(RawData,i) then begin
+    Result := 0;
+  end else begin
+    Result := PRawListData(FList[i])^.tag;
+  end;
+end;
+
+function TOrderedRawList.IndexOf(const RawData: TRawBytes): Integer;
+begin
+  if Not Find(RawData,Result) then Result := -1;
+end;
+
+procedure TOrderedRawList.SetTag(const RawData: TRawBytes; newTagValue: Integer);
+begin
+  Add(RawData,newTagValue);
+end;
+
+end.
 

+ 6 - 7
Units/PascalCoin/UBlockChain.pas

@@ -393,7 +393,7 @@ Type
     Procedure Clear;
     Function LoadOperations(Operations : TPCOperationsComp; Block : Cardinal) : Boolean;
     Property SafeBox : TPCSafeBox read FSafeBox;
-    Function AddNewBlockChainBlock(Operations: TPCOperationsComp; var newBlock: TBlockAccount; var errors: AnsiString): Boolean;
+    Function AddNewBlockChainBlock(Operations: TPCOperationsComp; MaxAllowedTimestamp : Cardinal; var newBlock: TBlockAccount; var errors: AnsiString): Boolean;
     Procedure DiskRestoreFromOperations(max_block : Int64);
     Procedure NewLog(Operations: TPCOperationsComp; Logtype: TLogType; Logtxt: AnsiString);
     Property OnLog: TPCBankLog read FOnLog write FOnLog;
@@ -426,7 +426,7 @@ begin
   Result := FSafeBox.AccountsCount;
 end;
 
-function TPCBank.AddNewBlockChainBlock(Operations: TPCOperationsComp; var newBlock: TBlockAccount; var errors: AnsiString): Boolean;
+function TPCBank.AddNewBlockChainBlock(Operations: TPCOperationsComp; MaxAllowedTimestamp : Cardinal; var newBlock: TBlockAccount; var errors: AnsiString): Boolean;
 Var
   buffer, pow: AnsiString;
   i : Integer;
@@ -459,12 +459,11 @@ begin
       end;
       if (Operations.OperationBlock.block > 0) then begin
         if ((Operations.OperationBlock.timestamp) < (FLastOperationBlock.timestamp)) then begin
-          errors := 'Invalid timestamp (New timestamp:'+inttostr(Operations.OperationBlock.timestamp)+' last timestamp ('+Inttostr(SafeBox.BlocksCount-1)+'):'+Inttostr(FLastOperationBlock.timestamp)+')';
+          errors := 'Invalid timestamp (Back timestamp: New timestamp:'+inttostr(Operations.OperationBlock.timestamp)+' < last timestamp ('+Inttostr(SafeBox.BlocksCount-1)+'):'+Inttostr(FLastOperationBlock.timestamp)+')';
           exit;
         end;
-        if (Operations.OperationBlock.timestamp > (UnivDateTimeToUnix(DateTime2UnivDateTime(now))+CT_MaxSecondsDifferenceOfNetworkNodes)) then begin
-          errors := 'Invalid timestamp (Future time '+Inttostr(Operations.OperationBlock.timestamp)+'-'+inttostr(UnivDateTimeToUnix(DateTime2UnivDateTime(now)))+'='+
-             inttostr(Operations.OperationBlock.timestamp-UnivDateTimeToUnix(DateTime2UnivDateTime(now)))+' > '+inttostr(CT_MaxSecondsDifferenceOfNetworkNodes)+')';
+        if ((MaxAllowedTimestamp>0) And (Operations.OperationBlock.timestamp>MaxAllowedTimestamp)) then begin
+          errors := 'Invalid timestamp (Future time: New timestamp '+Inttostr(Operations.OperationBlock.timestamp)+' > max allowed '+inttostr(MaxAllowedTimestamp)+')';
           exit;
         end;
       end else begin
@@ -646,7 +645,7 @@ begin
         while ((BlocksCount<=max_block)) do begin
           if Storage.BlockExists(BlocksCount) then begin
             if Storage.LoadBlockChainBlock(Operations,BlocksCount) then begin
-              if Not AddNewBlockChainBlock(Operations,newBlock,errors) then begin
+              if Not AddNewBlockChainBlock(Operations,0,newBlock,errors) then begin
                 NewLog(Operations, lterror,'Error restoring block: ' + Inttostr(BlocksCount)+ ' Errors: ' + errors);
                 Storage.DeleteBlockChainBlocks(BlocksCount);
                 break;

+ 4 - 3
Units/PascalCoin/UConst.pas

@@ -69,7 +69,8 @@ Const
   CT_MaxBlock : Cardinal = $FFFFFFFF;
 
   CT_MaxPayloadSize = 255; // Max payload size in bytes
-  CT_MaxSecondsDifferenceOfNetworkNodes = 180; // 3 minutes. If a Node has a +- value difference, will be blacklisted
+  CT_MaxFutureBlockTimestampOffset = 15;
+  CT_MinNodesToCalcNAT = 4;
 
   CT_MinServersConnected = 3;
   CT_MaxServersConnected = 5;
@@ -85,7 +86,7 @@ Const
 
   CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}$0A04FFFF{$ENDIF}; // Unix timestamp 168048000 ... It's Albert birthdate!
 
-  CT_NetProtocol_Version: Word = $0004;
+  CT_NetProtocol_Version: Word = $0005; // Version 1.5.4 only allows net protocol version 5  (introduced on 1.5.0)
   // IMPORTANT NOTE!!!
   // NetProtocol_Available MUST BE always >= NetProtocol_version
   CT_NetProtocol_Available: Word = $0005;  // Remember, >= NetProtocol_version !!!
@@ -99,7 +100,7 @@ Const
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
 
-  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.5.3'{$ELSE}{$IFDEF TESTNET}'TESTNET 1.5.3'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.5.4'{$ELSE}{$IFDEF TESTNET}'TESTNET 1.5.4'{$ELSE}{$ENDIF}{$ENDIF};
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
 

+ 225 - 98
Units/PascalCoin/UNetProtocol.pas

@@ -164,6 +164,24 @@ Type
     Constructor Create(NetData : TNetData);
   End;
 
+  TNetworkAdjustedTime = Class
+  private
+    FTimesList : TPCThreadList;
+    FTimeOffset : Integer;
+    FLock : TCriticalSection;
+    FTotalCounter : Integer;
+    Function IndexOfClientIp(list : TList; const clientIp : AnsiString) : Integer;
+    Procedure UpdateMedian(list : TList);
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure AddNewIp(const clientIp : AnsiString; clientTimestamp : Cardinal);
+    procedure RemoveIp(const clientIp : AnsiString);
+    function GetAdjustedTime : Cardinal;
+    property TimeOffset : Integer read FTimeOffset;
+    function GetMaxAllowedTimestampForNewBlock : Cardinal;
+  end;
+
   TNetData = Class(TComponent)
   private
     FNetDataNotifyEventsThread : TNetDataNotifyEventsThread;
@@ -186,8 +204,8 @@ Type
     FNetClientsDestroyThread : TNetClientsDestroyThread;
     FNetConnectionsActive: Boolean;
     FMaxConnections : Integer;
+    FNetworkAdjustedTime : TNetworkAdjustedTime;
     Procedure IncStatistics(incActiveConnections,incClientsConnections,incServersConnections,incServersConnectionsWithResponse : Integer; incBytesReceived, incBytesSend : Int64);
-
     procedure SetNetConnectionsActive(const Value: Boolean);  protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     Function IndexOfNetClient(ListToSearch : TList; ip : AnsiString; port : Word; indexStart : Integer = 0) : Integer;
@@ -247,6 +265,7 @@ Type
     Procedure NotifyReceivedHelloMessage;
     Procedure NotifyStatisticsChanged;
     Property NetConnectionsActive : Boolean read FNetConnectionsActive write SetNetConnectionsActive;
+    Property NetworkAdjustedTime : TNetworkAdjustedTime read FNetworkAdjustedTime;
   End;
 
   TNetConnection = Class(TComponent)
@@ -259,7 +278,7 @@ Type
     FClientBufferRead : TStream;
     FNetLock : TPCCriticalSection;
     FIsWaitingForResponse : Boolean;
-    FLastKnownTimestampDiff : Int64;
+    FTimestampDiff : Integer;
     FIsMyselfServer : Boolean;
     FClientPublicKey : TAccountKey;
     FCreatedTime: TDateTime;
@@ -272,6 +291,7 @@ Type
     FRandomWaitSecondsSendHello : Cardinal;
     FBufferReceivedOperationsHash : TOrderedRawList;
     FBufferToSendOperations : TOperationsHashTree;
+    FClientTimestampIp : AnsiString;
     function GetConnected: Boolean;
     procedure SetConnected(const Value: Boolean);
     procedure TcpClient_OnConnect(Sender: TObject);
@@ -299,13 +319,14 @@ Type
     Function ConnectTo(ServerIP: String; ServerPort:Word) : Boolean;
     Property Connected : Boolean read GetConnected write SetConnected;
     Function Send_Hello(NetTranferType : TNetTransferType; request_id : Integer) : Boolean;
-    Function Send_NewBlockFound : Boolean;
+    Function Send_NewBlockFound(Const NewBlock : TPCOperationsComp) : Boolean;
     Function Send_GetBlocks(StartAddress, quantity : Cardinal; var request_id : Cardinal) : Boolean;
     Function Send_AddOperations(Operations : TOperationsHashTree) : Boolean;
     Function Send_Message(Const TheMessage : AnsiString) : Boolean;
     Function AddOperationsToBufferForSend(Operations : TOperationsHashTree) : Integer;
     Property Client : TNetTcpIpClient read GetClient;
     Function ClientRemoteAddr : AnsiString;
+    property TimestampDiff : Integer read FTimestampDiff;
     //
     Property NetProtocolVersion : TNetProtocolVersion read FNetProtocolVersion;
     //
@@ -625,6 +646,7 @@ begin
   FThreadCheckConnections := TThreadCheckConnections.Create(Self);
   FNetDataNotifyEventsThread := TNetDataNotifyEventsThread.Create(Self);
   FNetClientsDestroyThread := TNetClientsDestroyThread.Create(Self);
+  FNetworkAdjustedTime := TNetworkAdjustedTime.Create;
   If Not Assigned(_NetData) then _NetData := Self;
 end;
 
@@ -696,6 +718,7 @@ begin
   FreeAndNil(FNetDataNotifyEventsThread);
   SetLength(FFixedServers,0);
   FreeAndNil(FRegisteredRequests);
+  FreeAndNil(FNetworkAdjustedTime);
   inherited;
   if (_NetData=Self) then _NetData := Nil;
   TLog.NewLog(ltInfo,ClassName,'TNetData.Destroy END');
@@ -766,7 +789,7 @@ 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');
+  {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,Classname,'Discover servers start process searching up to '+inttostr(j)+' servers');{$ENDIF}
   // can discover up to j servers
   l := TList.Create;
   try
@@ -1081,7 +1104,7 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
               OpComp.SaveBlockToStream(false,ms);
               ms.Position := 0;
               OpExecute.LoadBlockFromStream(ms,errors);
-              if Bank.AddNewBlockChainBlock(OpExecute,newBlock,errors) then begin
+              if Bank.AddNewBlockChainBlock(OpExecute,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,newBlock,errors) then begin
                 inc(i);
               end else begin
                 TLog.NewLog(lterror,CT_LogSender,'Error creating new bank with client Operations. Block:'+TPCOperationsComp.OperationBlockToText(OpExecute.OperationBlock)+' Error:'+errors);
@@ -1474,6 +1497,7 @@ end;
 procedure TNetServer.OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient);
 Var n : TNetServerClient;
   DebugStep : String;
+  tc : Cardinal;
 begin
   DebugStep := '';
   Try
@@ -1506,11 +1530,13 @@ begin
         TLog.NewLog(ltdebug,Classname,'Finalizing ServerAccept '+IntToHex(PtrInt(n),8)+' '+n.ClientRemoteAddr);
         DebugStep := 'Disconnecting NetServerClient';
         n.Connected := false;
-        sleep(10);
+        tc := GetTickCount;
+        Repeat
+          sleep(10); // 1.5.4 -> To prevent that not client disconnected (and not called OnDisconnect), increase sleep time
+        Until (Not n.Connected) Or (tc + 5000 < GetTickCount);
+        sleep(5);
         DebugStep := 'Assigning old client';
         n.SetClient( NetTcpIpClientClass.Create(Nil) );
-        DebugStep := 'Finalizing connection';
-        n.FinalizeConnection;
         sleep(500); // Delay - Sleep time before destroying (1.5.3)
         DebugStep := 'Freeing NetServerClient';
       Finally
@@ -1622,7 +1648,7 @@ begin
   FClientPublicKey := CT_TECDSA_Public_Nul;
   FCreatedTime := Now;
   FIsMyselfServer := false;
-  FLastKnownTimestampDiff := 0;
+  FTimestampDiff := 0;
   FIsWaitingForResponse := false;
   FClientBufferRead := TMemoryStream.Create;
   FNetLock := TPCCriticalSection.Create('TNetConnection_NetLock');
@@ -1637,6 +1663,7 @@ begin
   TNetData.NetData.NotifyNetConnectionUpdated;
   FBufferReceivedOperationsHash := TOrderedRawList.Create;
   FBufferToSendOperations := TOperationsHashTree.Create;
+  FClientTimestampIp := '';
 end;
 
 destructor TNetConnection.Destroy;
@@ -1925,7 +1952,7 @@ begin
            exit;
         end;
         if (op.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
-          if (TNode.Node.Bank.AddNewBlockChainBlock(op,newBlockAccount,errors)) then begin
+          if (TNode.Node.Bank.AddNewBlockChainBlock(op,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock, newBlockAccount,errors)) then begin
             // Ok, one more!
           end else begin
             // Is not a valid entry????
@@ -2040,48 +2067,6 @@ begin
 end;
 
 procedure TNetConnection.DoProcess_Hello(HeaderData: TNetHeaderData; DataBuffer: TStream);
-  Function IsValidTime(connection_ts : Cardinal) : Boolean;
-  Var l : TList;
-    i : Integer;
-    nc : TNetConnection;
-    min_valid_time,max_valid_time : Cardinal;
-    showmessage : Boolean;
-  Begin
-    if ((FLastKnownTimestampDiff<((-1)*(CT_MaxSecondsDifferenceOfNetworkNodes DIV 2)))
-        OR (FLastKnownTimestampDiff>(CT_MaxSecondsDifferenceOfNetworkNodes DIV 2))) then begin
-      TLog.NewLog(ltdebug,Classname,'Processing a hello from a client with different time. Difference: '+Inttostr(FLastKnownTimestampDiff));
-    end;
-    min_valid_time := (UnivDateTimeToUnix(DateTime2UnivDateTime(now))-CT_MaxSecondsDifferenceOfNetworkNodes);
-    max_valid_time := (UnivDateTimeToUnix(DateTime2UnivDateTime(now))+CT_MaxSecondsDifferenceOfNetworkNodes);
-    If (connection_ts < min_valid_time) or (connection_ts > max_valid_time) then begin
-      Result := false;
-      showmessage := true;
-      // This message only appears if there is no other valid connections
-      if TNetData.NetData.NetConnections.TryLockList(5000,l) then begin
-        try
-          for i := 0 to l.Count - 1 do begin
-            nc :=(TNetConnection(l[i]));
-            if (nc<>self) and (nc.FHasReceivedData) and (nc.Connected)
-              and (nc.FLastKnownTimestampDiff>=((-1)*CT_MaxSecondsDifferenceOfNetworkNodes))
-              and (nc.FLastKnownTimestampDiff<=(CT_MaxSecondsDifferenceOfNetworkNodes))
-              then begin
-              showmessage := false;
-              break;
-            end;
-          end;
-        finally
-          TNetData.NetData.NetConnections.UnlockList;
-        end;
-        if showmessage then begin
-          TNode.Node.NotifyNetClientMessage(Nil,'Detected a different time in an other node... check that your PC time and timezone is correct or you will be Blacklisted! '+
-            'Your time: '+TimeToStr(now)+' - '+Client.ClientRemoteAddr+' time: '+TimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(connection_ts)))+' Difference: '+inttostr(FLastKnownTimestampDiff)+' seconds. '+
-            '(If this message appears on each connection, then you have a bad configured time, if not, do nothing)' );
-        end;
-      end;
-    end else begin
-      Result := true;
-    end;
-  End;
 var op, myLastOp : TPCOperationsComp;
     errors : AnsiString;
     connection_has_a_server : Word;
@@ -2114,10 +2099,18 @@ Begin
       DisconnectInvalidClient(false,'Invalid data on buffer. No TS: '+TNetData.HeaderDataToText(HeaderData));
       exit;
     end;
-    FLastKnownTimestampDiff := Int64(connection_ts) - Int64(UnivDateTimeToUnix( DateTime2UnivDateTime(now)));
-    // Check valid time
-    if Not IsValidTime(connection_ts) then begin
-      DisconnectInvalidClient(false,'Invalid remote timestamp. Difference:'+inttostr(FLastKnownTimestampDiff)+' > '+inttostr(CT_MaxSecondsDifferenceOfNetworkNodes));
+    FTimestampDiff := Integer( Int64(connection_ts) - Int64(TNetData.NetData.NetworkAdjustedTime.GetAdjustedTime) );
+    If FClientTimestampIp='' then begin
+      FClientTimestampIp := FTcpIpClient.RemoteHost;
+      TNetData.NetData.NetworkAdjustedTime.AddNewIp(FClientTimestampIp,connection_ts);
+      if (Abs(TNetData.NetData.NetworkAdjustedTime.TimeOffset)>CT_MaxFutureBlockTimestampOffset) then begin
+        TNode.Node.NotifyNetClientMessage(Nil,'The detected network time is different from this system time in '+
+          IntToStr(TNetData.NetData.NetworkAdjustedTime.TimeOffset)+' seconds! Please check your local time/timezone');
+      end;
+      //
+      if (Abs(FTimestampDiff) > CT_MaxFutureBlockTimestampOffset) then begin
+        TLog.NewLog(ltError,ClassName,'Detected a node ('+ClientRemoteAddr+') with incorrect timestamp: '+IntToStr(connection_ts)+' offset '+IntToStr(FTimestampDiff) );
+      end;
     end;
     if (connection_has_a_server>0) And (Not SameText(Client.RemoteHost,'localhost')) And (Not SameText(Client.RemoteHost,'127.0.0.1'))
       And (Not SameText('192.168.',Copy(Client.RemoteHost,1,8)))
@@ -2126,7 +2119,6 @@ Begin
       nsa := CT_TNodeServerAddress_NUL;
       nsa.ip := Client.RemoteHost;
       nsa.port := connection_has_a_server;
-      // BUG corrected 1.1.1: nsa.last_connection_by_server := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
       nsa.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
       TNetData.NetData.AddServer(nsa);
     end;
@@ -2271,8 +2263,11 @@ 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');
+                // Really is a new block? (Check it)
+                if (op.OperationBlock.block=TNode.Node.Bank.BlocksCount) 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;
             end else begin
               // Received a new higher work
@@ -2785,48 +2780,39 @@ begin
   End;
 end;
 
-function TNetConnection.Send_NewBlockFound: Boolean;
+function TNetConnection.Send_NewBlockFound(Const NewBlock : TPCOperationsComp) : Boolean;
 var data : TStream;
   request_id : Integer;
-  op : TPCOperationsComp;
 begin
   Result := false;
-  if TNetData.NetData.Bank.BlocksCount=0 then exit;
   if Not Connected then exit;
-  if Connected then begin
-    FNetLock.Acquire;
-    Try
-      // Clear buffers
-      FBufferReceivedOperationsHash.Clear;
-      FBufferToSendOperations.ClearHastThree;
-      // Checking if operationblock is the same to prevent double messaging...
-      If (TPCOperationsComp.EqualsOperationBlock(FRemoteOperationBlock,TNode.Node.Bank.LastOperationBlock)) then exit;
-      // Send Hello command:
-      data := TMemoryStream.Create;
-      try
-        request_id := TNetData.NetData.NewRequestId;
-        op := TPCOperationsComp.Create(nil);
-        try
-          op.bank := TNetData.NetData.Bank;
-          if Not TNetData.NetData.Bank.LoadOperations(op,TNetData.NetData.Bank.BlocksCount-1) then begin
-            TLog.NewLog(lterror,Classname,'Error on Send_NewBlockFound. Cannot load BlockOperations '+inttostr(TNetData.NetData.Bank.BlocksCount-1));
-            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;
-        end;
-      finally
-        data.Free;
-      end;
-    Finally
-      FNetLock.Release;
-    End;
-    Result := Connected;
-  end;
+  FNetLock.Acquire;
+  Try
+    // Clear buffers
+    FBufferReceivedOperationsHash.Clear;
+    FBufferToSendOperations.ClearHastThree;
+    // Checking if operationblock is the same to prevent double messaging...
+    If (TPCOperationsComp.EqualsOperationBlock(FRemoteOperationBlock,NewBlock.OperationBlock)) then begin
+      TLog.NewLog(ltDebug,ClassName,'This connection has the same block, does not need to send');
+      exit;
+    end;
+    if (TNode.Node.Bank.BlocksCount<>NewBlock.OperationBlock.block+1) then begin
+      TLog.NewLog(ltDebug,ClassName,'The block number '+IntToStr(NewBlock.OperationBlock.block)+' is not equal to current blocks stored in bank ('+IntToStr(TNode.Node.Bank.BlocksCount)+'), finalizing');
+      exit;
+    end;
+    data := TMemoryStream.Create;
+    try
+      request_id := TNetData.NetData.NewRequestId;
+      NewBlock.SaveBlockToStream(false,data);
+      data.Write(TNode.Node.Bank.SafeBox.WorkSum,SizeOf(TNode.Node.Bank.SafeBox.WorkSum));
+      Send(ntp_autosend,CT_NetOp_NewBlock,0,request_id,data);
+    finally
+      data.Free;
+    end;
+  Finally
+    FNetLock.Release;
+  End;
+  Result := Connected;
 end;
 
 procedure TNetConnection.SetClient(const Value: TNetTcpIpClient);
@@ -2834,10 +2820,11 @@ Var old : TNetTcpIpClient;
 begin
   if FTcpIpClient<>Value then begin
     if Assigned(FTcpIpClient) then begin
+      FTcpIpClient.OnConnect := Nil;
+      FTcpIpClient.OnDisconnect := Nil;
       FTcpIpClient.RemoveFreeNotification(Self);
     end;
     TNetData.NetData.UnRegisterRequest(Self,0,0);
-    // Build 1.0.4 -> Prior to free, must ensure FClient is valid
     old := FTcpIpClient;
     FTcpIpClient := Value;
     if Assigned(old) then begin
@@ -2858,7 +2845,10 @@ procedure TNetConnection.SetConnected(const Value: Boolean);
 begin
   if (Value = GetConnected) then exit;
   if Value then ConnectTo(Client.RemoteHost,Client.RemotePort)
-  else Client.Disconnect;
+  else begin
+    FinalizeConnection;
+    Client.Disconnect;
+  end;
 end;
 
 procedure TNetConnection.TcpClient_OnConnect(Sender: TObject);
@@ -2877,6 +2867,9 @@ begin
   end;
   TLog.NewLog(ltInfo,Classname,'Disconnected from '+ClientRemoteAddr);
   TNetData.NetData.NotifyNetConnectionUpdated;
+  if (FClientTimestampIp<>'') then begin
+    TNetData.NetData.NetworkAdjustedTime.RemoveIp(FClientTimestampIp);
+  end;
 end;
 
 { TNetClientThread }
@@ -3258,4 +3251,138 @@ begin
   end;
 end;
 
+{ TNetworkAdjustedTime }
+
+Type TNetworkAdjustedTimeReg = Record
+     clientIp : AnsiString; // Client IP allows only 1 connection per IP (not using port)
+     timeOffset : Integer;
+     counter : Integer; // To prevent a time attack from a single IP with multiple connections, only 1 will be used for calc NAT
+   End;
+   PNetworkAdjustedTimeReg = ^TNetworkAdjustedTimeReg;
+
+procedure TNetworkAdjustedTime.AddNewIp(const clientIp: AnsiString; clientTimestamp : Cardinal);
+Var l : TList;
+  i : Integer;
+  P : PNetworkAdjustedTimeReg;
+begin
+  l := FTimesList.LockList;
+  try
+    i := IndexOfClientIp(l,clientIp);
+    if i<0 then begin
+      New(P);
+      P^.clientIp := clientIp;
+      P^.counter := 0;
+      l.Add(P);
+    end else begin
+      P := l[i];
+    end;
+    P^.timeOffset := clientTimestamp - UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+    inc(P^.counter);
+    inc(FTotalCounter);
+    UpdateMedian(l);
+    TLog.NewLog(ltDebug,ClassName,Format('AddNewIp (%s,%d) - Total:%d/%d Offset:%d',[clientIp,clientTimestamp,l.Count,FTotalCounter,FTimeOffset]));
+  finally
+    FTimesList.UnlockList;
+  end;
+end;
+
+constructor TNetworkAdjustedTime.Create;
+begin
+  FTimesList := TPCThreadList.Create('TNetworkAdjustedTime_TimesList');
+  FTimeOffset := 0;
+  FTotalCounter := 0;
+end;
+
+destructor TNetworkAdjustedTime.Destroy;
+Var P : PNetworkAdjustedTimeReg;
+  i : Integer;
+  l : TList;
+begin
+  l := FTimesList.LockList;
+  try
+    for i := 0 to l.Count - 1 do begin
+      P := l[i];
+      Dispose(P);
+    end;
+    l.Clear;
+  finally
+    FTimesList.UnlockList;
+  end;
+  FreeAndNil(FTimesList);
+  inherited;
+end;
+
+function TNetworkAdjustedTime.GetAdjustedTime: Cardinal;
+begin
+  Result := UnivDateTimeToUnix(DateTime2UnivDateTime(now)) + FTimeOffset;
+end;
+
+function TNetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock: Cardinal;
+var l : TList;
+begin
+  l := FTimesList.LockList;
+  try
+    Result := (GetAdjustedTime + CT_MaxFutureBlockTimestampOffset);
+  finally
+    FTimesList.UnlockList;
+  end;
+end;
+
+function TNetworkAdjustedTime.IndexOfClientIp(list: TList; const clientIp: AnsiString): Integer;
+begin
+  for Result := 0 to list.Count - 1 do begin
+    if AnsiSameStr(PNetworkAdjustedTimeReg(list[result])^.clientIp,clientIp) then exit;
+  end;
+  Result := -1;
+end;
+
+procedure TNetworkAdjustedTime.RemoveIp(const clientIp: AnsiString);
+Var l : TList;
+  i : Integer;
+  P : PNetworkAdjustedTimeReg;
+begin
+  l := FTimesList.LockList;
+  try
+    i := IndexOfClientIp(l,clientIp);
+    if (i>=0) then begin
+      P := l[i];
+      Dec(P^.counter);
+      if (P^.counter<=0) then begin
+        l.Delete(i);
+        Dispose(P);
+      end;
+      Dec(FTotalCounter);
+    end;
+    UpdateMedian(l);
+    if (i>=0) then
+      TLog.NewLog(ltDebug,ClassName,Format('RemoveIp (%s) - Total:%d/%d Offset:%d',[clientIp,l.Count,FTotalCounter,FTimeOffset]))
+    else TLog.NewLog(ltError,ClassName,Format('RemoveIp not found (%s) - Total:%d/%d Offset:%d',[clientIp,l.Count,FTotalCounter,FTimeOffset]))
+  finally
+    FTimesList.UnlockList;
+  end;
+end;
+
+function SortPNetworkAdjustedTimeReg(p1, p2: pointer): integer;
+begin
+  Result := PNetworkAdjustedTimeReg(p1)^.timeOffset - PNetworkAdjustedTimeReg(p2)^.timeOffset;
+end;
+
+procedure TNetworkAdjustedTime.UpdateMedian(list : TList);
+Var last : Integer;
+begin
+  last := FTimeOffset;
+  list.Sort(SortPNetworkAdjustedTimeReg);
+  if list.Count<CT_MinNodesToCalcNAT then begin
+    FTimeOffset := 0;
+  end else if ((list.Count MOD 2)=0) then begin
+    FTimeOffset := (PNetworkAdjustedTimeReg(list[(list.Count DIV 2)-1])^.timeOffset + PNetworkAdjustedTimeReg(list[(list.Count DIV 2)])^.timeOffset) DIV 2;
+  end else begin
+    FTimeOffset := PNetworkAdjustedTimeReg(list[list.Count DIV 2])^.timeOffset;
+  end;
+  if (last<>FTimeOffset) then begin
+    TLog.NewLog(ltinfo,ClassName,
+      Format('Updated NAT median offset. My offset is now %d (before %d) based on %d/%d connections',[FTimeOffset,last,list.Count,FTotalCounter]));
+  end;
+end;
+
 end.

+ 91 - 17
Units/PascalCoin/UNode.pas

@@ -32,6 +32,8 @@ interface
 uses
   Classes, UBlockChain, UNetProtocol, UAccounts, UCrypto, UThread, SyncObjs, ULog;
 
+{$I config.inc}
+
 Type
 
   { TNode }
@@ -47,6 +49,7 @@ Type
     FBCBankNotify : TPCBankNotify;
     FPeerCache : AnsiString;
     FDisabledsNewBlocksCount : Integer;
+    FSentOperations : TOrderedRawList;
     Procedure OnBankNewBlock(Sender : TObject);
     procedure SetNodeLogFilename(const Value: AnsiString);
     function GetNodeLogFilename: AnsiString;
@@ -121,9 +124,12 @@ Type
 
   TThreadNodeNotifyNewBlock = Class(TPCThread)
     FNetConnection : TNetConnection;
+    FSanitizedOperationsHashTree : TOperationsHashTree;
+    FNewBlockOperations : TPCOperationsComp;
   protected
     procedure BCExecute; override;
-    Constructor Create(NetConnection : TNetConnection);
+    Constructor Create(NetConnection : TNetConnection; MakeACopyOfNewBlockOperations: TPCOperationsComp; MakeACopyOfSanitizedOperationsHashTree : TOperationsHashTree);
+    destructor Destroy; override;
   End;
 
   TThreadNodeNotifyOperations = Class(TPCThread)
@@ -151,6 +157,7 @@ Var i,j : Integer;
   s : String;
   errors2 : AnsiString;
   OpBlock : TOperationBlock;
+  opsht : TOperationsHashTree;
 begin
   Result := false;
   errors := '';
@@ -174,10 +181,15 @@ begin
     if TThread.CurrentThread.ThreadID=MainThreadID then raise Exception.Create(s) else exit;
   end;
   try
+    // Check block number:
+    if TPCOperationsComp.EqualsOperationBlock(Bank.LastOperationBlock,NewBlockOperations.OperationBlock) then begin
+      errors := 'Duplicated block';
+      exit;
+    end;
     ms := TMemoryStream.Create;
     try
       FOperations.SaveBlockToStream(false,ms);
-      Result := Bank.AddNewBlockChainBlock(NewBlockOperations,newBlockAccount,errors);
+      Result := Bank.AddNewBlockChainBlock(NewBlockOperations,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,newBlockAccount,errors);
       if Result then begin
         if Assigned(SenderConnection) then begin
           FNodeLog.NotifyNewLog(ltupdate,SenderConnection.ClassName,Format(';%d;%s;%s;;%d;%d;%d;%s',[OpBlock.block,SenderConnection.ClientRemoteAddr,OpBlock.block_payload,
@@ -206,19 +218,57 @@ begin
       ms.Free;
     end;
     FOperations.SanitizeOperations;
+    if Result then begin
+      // 1.5.4 - Prevent continuous sending non included operations
+      // Using a Sent operations buffer (FSentOperations) will allow to only "resend" operations once
+      opsht := TOperationsHashTree.Create;
+      Try
+        for i := 0 to FOperations.Count - 1 do begin
+          j := FSentOperations.GetTag(FOperations.Operation[i].Sha256);
+          if (j=0) Or (j=Bank.LastBlockFound.OperationBlock.block) then begin
+            // Only will "re-send" operations that where received on last block and not included in this one
+            opsht.AddOperationToHashTree(FOperations.Operation[i]);
+          end else begin
+            TLog.NewLog(ltError,ClassName,'Sanitized operation not included (j='+IntToStr(j)+') ('+inttostr(i+1)+'/'+inttostr(FOperations.Count)+'): '+FOperations.Operation[i].ToString);
+          end;
+        end;
+        if opsht.OperationsCount>0 then begin
+          TLog.NewLog(ltinfo,classname,'Resending '+IntToStr(opsht.OperationsCount)+' operations for new block');
+          for i := 0 to opsht.OperationsCount - 1 do begin
+            TLog.NewLog(ltInfo,ClassName,'Resending ('+inttostr(i+1)+'/'+inttostr(opsht.OperationsCount)+'): '+opsht.GetOperation(i).ToString);
+          end;
+        end;
+        // Clean sent operations buffer
+        j := 0;
+        for i := FSentOperations.Count-1 downto 0 do begin
+          If (FSentOperations.GetTag(i)<Bank.LastBlockFound.OperationBlock.block-3) then begin
+            FSentOperations.Delete(i);
+            inc(j);
+          end;
+        end;
+        if j>0 then begin
+          TLog.NewLog(ltdebug,ClassName,'Buffer Sent operations: Deleted '+IntToStr(j)+' old operations');
+        end;
+        TLog.NewLog(ltdebug,ClassName,'Buffer Sent operations: '+IntToStr(FSentOperations.Count));
+        // Notify to clients
+        j := TNetData.NetData.ConnectionsCountAll;
+        for i:=0 to j-1 do begin
+          if (TNetData.NetData.GetConnection(i,nc)) then begin
+            if (nc<>SenderConnection) And (nc.Connected) then begin
+              TThreadNodeNotifyNewBlock.Create(nc,Bank.LastBlockFound,opsht);
+            end;
+          end;
+        end;
+      Finally
+        opsht.Free;
+      End;
+    end;
   finally
     FLockNodeOperations.Release;
     TLog.NewLog(ltdebug,Classname,Format('Finalizing AddNewBlockChain Connection:%s NewBlock:%s',[
       Inttohex(PtrInt(SenderConnection),8),TPCOperationsComp.OperationBlockToText(OpBlock) ]));
   End;
   if Result then begin
-    // Notify to clients
-    j := TNetData.NetData.ConnectionsCountAll;
-    for i:=0 to j-1 do begin
-      if (TNetData.NetData.GetConnection(i,nc)) then begin
-        if (nc<>SenderConnection) And (nc.Connected) then TThreadNodeNotifyNewBlock.Create(nc);
-      end;
-    end;
     // Notify it!
     NotifyBlocksChanged;
   end;
@@ -269,7 +319,9 @@ begin
     try
       for j := 0 to Operations.OperationsCount-1 do begin
         ActOp := Operations.GetOperation(j);
-        If FOperations.OperationsHashTree.IndexOfOperation(ActOp)<0 then begin
+        If (FOperations.OperationsHashTree.IndexOfOperation(ActOp)<0) And (FSentOperations.GetTag(ActOp.Sha256)=0) then begin
+          // Buffer to prevent cyclic sending new on 1.5.4
+          FSentOperations.Add(ActOp.Sha256,FOperations.OperationBlock.block);
           if (FOperations.AddOperation(true,ActOp,e)) then begin
             inc(Result);
             valids_operations.AddOperationToHashTree(ActOp);
@@ -295,8 +347,7 @@ begin
             end;
           end;
         end else begin
-          // XXXXX DEBUG ONLY
-          // TLog.NewLog(ltdebug,Classname,Format('AddOperation made before %d/%d: %s',[(j+1),Operations.OperationsCount,ActOp.ToString]));
+          {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,Classname,Format('AddOperation made before %d/%d: %s',[(j+1),Operations.OperationsCount,ActOp.ToString]));{$ENDIF}
         end;
       end;
     finally
@@ -338,6 +389,7 @@ end;
 
 constructor TNode.Create(AOwner: TComponent);
 begin
+  FSentOperations := TOrderedRawList.Create;
   FNodeLog := TLog.Create(Self);
   FNodeLog.ProcessGlobalLogs := false;
   RegisterOperationsClass;
@@ -424,6 +476,8 @@ begin
     FreeAndNil(FOperations);
     step := 'Assigning NIL to node var';
     if _Node=Self then _Node := Nil;
+    Step := 'Destroying SentOperations list';
+    FreeAndNil(FSentOperations);
 
     step := 'Destroying Bank';
     FreeAndNil(FBCBankNotify);
@@ -843,28 +897,48 @@ end;
 
 procedure TThreadNodeNotifyNewBlock.BCExecute;
 begin
+  DebugStep := 'Locking';
   if TNetData.NetData.ConnectionLock(Self,FNetConnection,500) then begin
     try
+      DebugStep := 'Checking connected';
       if Not FNetconnection.Connected then exit;
       TLog.NewLog(ltdebug,ClassName,'Sending new block found to '+FNetConnection.Client.ClientRemoteAddr);
-      FNetConnection.Send_NewBlockFound;
-      if TNode.Node.Operations.OperationsHashTree.OperationsCount>0 then begin
-         TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(TNode.Node.Operations.OperationsHashTree.OperationsCount)+' sanitized operations to '+FNetConnection.ClientRemoteAddr);
-         FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
+      DebugStep := 'Sending';
+      FNetConnection.Send_NewBlockFound(FNewBlockOperations);
+      DebugStep := 'Checking connected again';
+      if Not FNetConnection.Connected then exit;
+      DebugStep := 'Need send opreations?';
+      if FSanitizedOperationsHashTree.OperationsCount>0 then begin
+        DebugStep := 'Sending '+inttostr(FSanitizedOperationsHashTree.OperationsCount)+' sanitized operations';
+        TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(FSanitizedOperationsHashTree.OperationsCount)+' sanitized operations to '+FNetConnection.ClientRemoteAddr);
+        TThreadNodeNotifyOperations.Create(FNetConnection,FSanitizedOperationsHashTree);
       end;
+      DebugStep := 'Unlocking';
     finally
       TNetData.NetData.ConnectionUnlock(FNetConnection);
     end;
   end;
+  DebugStep := 'Finalizing';
 end;
 
-constructor TThreadNodeNotifyNewBlock.Create(NetConnection: TNetConnection);
+constructor TThreadNodeNotifyNewBlock.Create(NetConnection: TNetConnection; MakeACopyOfNewBlockOperations: TPCOperationsComp; MakeACopyOfSanitizedOperationsHashTree : TOperationsHashTree);
 begin
   FNetConnection := NetConnection;
+  FSanitizedOperationsHashTree := TOperationsHashTree.Create;
+  FSanitizedOperationsHashTree.CopyFromHashTree(MakeACopyOfSanitizedOperationsHashTree);
+  FNewBlockOperations := TPCOperationsComp.Create(Nil);
+  FNewBlockOperations.CopyFrom(MakeACopyOfNewBlockOperations);
   Inherited Create(false);
   FreeOnTerminate := true;
 end;
 
+destructor TThreadNodeNotifyNewBlock.Destroy;
+begin
+  FreeAndNil(FSanitizedOperationsHashTree);
+  FreeAndNil(FNewBlockOperations);
+  inherited;
+end;
+
 { TThreadNodeNotifyOperations }
 
 procedure TThreadNodeNotifyOperations.BCExecute;

+ 4 - 4
Units/PascalCoin/UPoolMining.pas

@@ -156,7 +156,7 @@ Const
 
 implementation
 
-Uses ULog, Variants, UTime;
+Uses ULog, Variants, UTime, UNetProtocol;
 
 Type TPendingResponseMessage = Record
        sendDateTime : TDateTime;
@@ -532,7 +532,7 @@ begin
     if doAdd then begin
       New(P);
       P^.SentDateTime := now;
-      P^.SentMinTimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+      P^.SentMinTimestamp := TNetData.NetData.NetworkAdjustedTime.GetAdjustedTime;
       if (P^.SentMinTimestamp<FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp) then begin
         P^.SentMinTimestamp := FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp;
       end;
@@ -835,7 +835,7 @@ begin
         TLog.NewLog(ltInfo,ClassName,'Creating new job for miner');
         New(P);
         P^.SentDateTime := now;
-        P^.SentMinTimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+        P^.SentMinTimestamp := TNetData.NetData.NetworkAdjustedTime.GetAdjustedTime;
         if (P^.SentMinTimestamp<FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp) then begin
           P^.SentMinTimestamp := FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp;
         end;
@@ -872,7 +872,7 @@ begin
     params.GetAsVariant('target').Value := Operations.OperationBlock.compact_target;
     params.GetAsVariant('target_pow').Value := TCrypto.ToHexaString(TPCBank.TargetFromCompact(Operations.OperationBlock.compact_target));
 
-    ts := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+    ts := TNetData.NetData.NetworkAdjustedTime.GetAdjustedTime;
     if (ts<FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp) then begin
       ts := FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp;
     end;

+ 3 - 0
Units/PascalCoin/URPC.pas

@@ -600,6 +600,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         obj.GetAsVariant('appver').Value:=nc.ClientAppVersion;
         obj.GetAsVariant('netver').Value:=nc.NetProtocolVersion.protocol_version;
         obj.GetAsVariant('netver_a').Value:=nc.NetProtocolVersion.protocol_available;
+        obj.GetAsVariant('timediff').Value:=nc.TimestampDiff;
       end;
     finally
       TNetData.NetData.NetConnections.UnlockList;
@@ -1065,6 +1066,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           GetResultObject.GetAsVariant('result').Value:= true;
           GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
           GetResultObject.GetAsVariant('unenc_payload').Value:= decrypted_payload;
+          GetResultObject.GetAsVariant('unenc_hexpayload').Value:= TCrypto.ToHexaString(decrypted_payload);
           GetResultObject.GetAsVariant('payload_method').Value:= 'key';
           GetResultObject.GetAsVariant('enc_pubkey').Value:= TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(pkey.PublicKey));
           // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
@@ -1078,6 +1080,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         GetResultObject.GetAsVariant('result').Value:= true;
         GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
         GetResultObject.GetAsVariant('unenc_payload').Value:= decrypted_payload;
+        GetResultObject.GetAsVariant('unenc_hexpayload').Value:= TCrypto.ToHexaString(decrypted_payload);
         GetResultObject.GetAsVariant('payload_method').Value:= 'pwd';
         GetResultObject.GetAsVariant('pwd').Value:= jsonArrayPwds.GetAsVariant(i).AsString('');
         // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)

+ 30 - 11
Units/PascalCoin/UTCPIP.pas

@@ -269,6 +269,8 @@ end;
 constructor TNetTcpIpClient.Create(AOwner : TComponent);
 begin
   inherited;
+  FOnConnect := Nil;
+  FOnDisconnect := Nil;
   FTcpBlockSocket := Nil;
   FSocketError := 0;
   FLastCommunicationTime := 0;
@@ -300,24 +302,39 @@ begin
   {$ENDIF}
   inherited;
   FreeAndNil(FTcpBlockSocket);
-  TLog.NewLog(ltdebug,ClassName,'Destroying Socket end');
+  {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,ClassName,'Destroying Socket end');{$ENDIF}
 end;
 
 procedure TNetTcpIpClient.Disconnect;
+Var DebugStep : AnsiString;
 begin
   {$IFDEF DelphiSockets}
   FTcpBlockSocket.Disconnect;
   {$ENDIF}
   {$IFDEF Synapse}
-  FLock.Acquire;
+  if Not FConnected then exit;
   Try
-    if Not FConnected then exit;
-    FConnected := false;
-    FTcpBlockSocket.CloseSocket;
-  Finally
-    FLock.Release;
-  End;
-  if Assigned(FOnDisconnect) then FOnDisconnect(Self);
+    DebugStep := '';
+    FLock.Acquire;
+    Try
+      DebugStep := 'disconnecting';
+      if Not FConnected then exit;
+      DebugStep := 'Closing socket';
+      FTcpBlockSocket.CloseSocket;
+      DebugStep := 'Relasing flock';
+      FConnected := false;
+    Finally
+      FLock.Release;
+    End;
+    DebugStep := 'Calling OnDisconnect';
+    if Assigned(FOnDisconnect) then FOnDisconnect(Self)
+    else TLog.NewLog(ltError,ClassName,'OnDisconnect is nil');
+  Except
+    On E:Exception do begin
+      E.Message := 'Exception at TNetTcpIpClient.Discconnect step '+DebugStep+' - '+E.Message;
+      Raise;
+    end;
+  end;
   {$ENDIF}
 end;
 
@@ -388,12 +405,13 @@ begin
   Result := FTcpBlockSocket.ReceiveBuf(Buf,BufSize);
   {$ENDIF}
   {$IFDEF Synapse}
+  Result := 0;
   FLock.Acquire;
   Try
     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);
+        TLog.NewLog(ltDebug,ClassName,'Closing connection from '+ClientRemoteAddr+' (Receiving error): '+Inttostr(FTcpBlockSocket.LastError)+' '+FTcpBlockSocket.GetErrorDescEx);
         Result := 0;
         Disconnect;
       end else if Result>0 then inc(FBytesReceived,Result);
@@ -421,12 +439,13 @@ begin
   Result := Stream.Position - sp;
   {$ENDIF}
   {$IFDEF Synapse}
+  Result := 0;
   FLock.Acquire;
   Try
     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);
+        TLog.NewLog(ltDebug,ClassName,'Closing connection from '+ClientRemoteAddr+' (Sending error): '+Inttostr(FTcpBlockSocket.LastError)+' '+FTcpBlockSocket.GetErrorDescEx);
         Result := -1;
         Disconnect;
       end else begin

+ 6 - 10
Units/PascalCoin/UThread.pas

@@ -27,6 +27,8 @@ uses
 {$ENDIF}
   Classes, SyncObjs;
 
+{$I config.inc}
+
 Type
   TPCCriticalSection = Class(TCriticalSection)
   private
@@ -100,7 +102,7 @@ Var _threads : TPCThreadList;
 constructor TPCThread.Create(CreateSuspended: Boolean);
 begin
   inherited Create(CreateSuspended);
-  TLog.NewLog(ltdebug,Classname,'Created Thread '+IntToHex(PtrInt(Self),8));
+  {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,Classname,'Created Thread '+IntToHex(PtrInt(Self),8));{$ENDIF}
 end;
 
 destructor TPCThread.Destroy;
@@ -121,7 +123,7 @@ begin
   FDebugStep := '';
   i := _threads.Add(Self);
   try
-    TLog.NewLog(ltdebug,Classname,'Starting Thread '+IntToHex(PtrInt(Self),8)+' in pos '+inttostr(i+1));
+    {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,Classname,'Starting Thread '+IntToHex(PtrInt(Self),8)+' in pos '+inttostr(i+1));{$ENDIF}
     Try
       Try
         BCExecute;
@@ -139,7 +141,7 @@ begin
     l := _threads.LockList;
     Try
       i := l.Remove(Self);
-      TLog.NewLog(ltdebug,Classname,'Finalizing Thread in pos '+inttostr(i+1)+'/'+inttostr(l.Count+1)+' working time: '+FormatFloat('0.000',(GetTickCount-FStartTickCount) / 1000)+' sec');
+      {$IFDEF HIGHLOG}TLog.NewLog(ltdebug,Classname,'Finalizing Thread in pos '+inttostr(i+1)+'/'+inttostr(l.Count+1)+' working time: '+FormatFloat('0.000',(GetTickCount-FStartTickCount) / 1000)+' sec');{$ENDIF}
     Finally
       _threads.UnlockList;
     End;
@@ -180,13 +182,8 @@ end;
 
 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',[
-//      Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
     Lock.Acquire;
-//    TLog.NewLog(ltdebug,Sender.Classname,Format('UnLocked critical section (ENTER): LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
-//      Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
   end;
 end;
 
@@ -385,8 +382,7 @@ begin
   FStartedTimestamp := 0;
   FName := AName;
   inherited Create;
-  // XXXXX DEBUG ONLY
-  // TLog.NewLog(ltDebug,ClassName,'Created critical section '+IntToHex(PtrInt(Self),8)+' '+AName );
+  {$IFDEF HIGHLOG}TLog.NewLog(ltDebug,ClassName,'Created critical section '+IntToHex(PtrInt(Self),8)+' '+AName );{$ENDIF}
 end;
 
 destructor TPCCriticalSection.Destroy;

+ 2 - 4
Units/PascalCoin/UTime.pas

@@ -75,8 +75,7 @@ End;
 Function DateTime2UnivDateTime(d:TDateTime):TDateTime;
 {$IFDEF FPC}
 begin
-  Result := UniversalTimeToLocal(d);
-//  Result := LocalTimeToUniversal(d);
+  Result := LocalTimeToUniversal(d,-GetLocalTimeOffset);
 end;
 {$ELSE}
 var
@@ -93,8 +92,7 @@ end;
 Function UnivDateTime2LocalDateTime(d:TDateTime):TDateTime;
 {$IFDEF FPC}
 begin
-//  Result := UniversalTimeToLocal(d);
-  Result := LocalTimeToUniversal(d);
+  Result := UniversalTimeToLocal(d,-GetLocalTimeOffset);
 end;
 
 {$ELSE}

+ 4 - 0
Units/PascalCoin/config.inc

@@ -31,6 +31,10 @@
 
   {$DEFINE PRODUCTION}
   {.$DEFINE TESTNET}
+  
+  
+  // HighLog will result in a higher log generation
+  {.$DEFINE HIGHLOG}
 
 { ********************************************************************
   Don't touch more code, it will addapt based on your preferences