Browse Source

Build 1.0.4 Final

PascalCoin 9 years ago
parent
commit
45ac3a647e

BIN
Instaler/PascalCoinWalletB1.0.3.0.exe


+ 2 - 1
PascalCoinWallet.dpr

@@ -27,7 +27,8 @@ uses
   UFRMWalletKeys in 'Units\Forms\UFRMWalletKeys.pas' {FRMWalletKeys},
   UFRMNewPrivateKeyType in 'Units\Forms\UFRMNewPrivateKeyType.pas' {FRMNewPrivateKeyType},
   UAES in 'Units\Utils\UAES.pas',
-  UFRMPayloadDecoder in 'Units\Forms\UFRMPayloadDecoder.pas' {FRMPayloadDecoder};
+  UFRMPayloadDecoder in 'Units\Forms\UFRMPayloadDecoder.pas' {FRMPayloadDecoder},
+  UFRMNodesIp in 'Units\Forms\UFRMNodesIp.pas' {FRMNodesIp};
 
 {$R *.res}
 

BIN
PascalCoinWallet.res


+ 9 - 0
README.md

@@ -38,6 +38,15 @@ If you like it, consider a donation using BitCoin:
 
 History:
 
+Build 1.0.4.0 - 2016-09-16
+--------------------------
+- IMPORTANT: Introducing net protocol changes: Must update!
+- More and more and more stable
+- Prevents "Alone in the world" if everybody is updated ;-)
+- Invalid local time detector with corrections
+- IP nodes configurator
+
+
 Build 1.0.3.0 - 2016-09-08
 --------------------------
 - Important changes to database 

+ 9 - 0
README.txt

@@ -38,6 +38,15 @@ If you like it, consider a donation using BitCoin:
 
 History:
 
+Build 1.0.4.0 - 2016-09-16
+--------------------------
+- IMPORTANT: Introducing net protocol changes: Must update!
+- More and more and more stable
+- Prevents "Alone in the world" if everybody is updated ;-)
+- Invalid local time detector with corrections
+- IP nodes configurator
+
+
 Build 1.0.3.0 - 2016-09-08
 --------------------------
 - Important changes to database 

+ 86 - 0
Units/Forms/UFRMNodesIp.dfm

@@ -0,0 +1,86 @@
+object FRMNodesIp: TFRMNodesIp
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu]
+  BorderStyle = bsSingle
+  Caption = 'Nodes IP'
+  ClientHeight = 367
+  ClientWidth = 334
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poOwnerFormCenter
+  OnCreate = FormCreate
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Label1: TLabel
+    Left = 30
+    Top = 25
+    Width = 143
+    Height = 13
+    Caption = 'Available Nodes Ip to connect'
+  end
+  object memoNodesIp: TMemo
+    Left = 30
+    Top = 45
+    Width = 276
+    Height = 226
+    Lines.Strings = (
+      'memoNodesIp')
+    ScrollBars = ssBoth
+    TabOrder = 0
+  end
+  object bbOk: TBitBtn
+    Left = 138
+    Top = 317
+    Width = 75
+    Height = 25
+    Caption = 'OK'
+    Default = True
+    DoubleBuffered = True
+    Glyph.Data = {
+      DE010000424DDE01000000000000760000002800000024000000120000000100
+      0400000000006801000000000000000000001000000000000000000000000000
+      80000080000000808000800000008000800080800000C0C0C000808080000000
+      FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333333333333
+      3333333333333333333333330000333333333333333333333333F33333333333
+      00003333344333333333333333388F3333333333000033334224333333333333
+      338338F3333333330000333422224333333333333833338F3333333300003342
+      222224333333333383333338F3333333000034222A22224333333338F338F333
+      8F33333300003222A3A2224333333338F3838F338F33333300003A2A333A2224
+      33333338F83338F338F33333000033A33333A222433333338333338F338F3333
+      0000333333333A222433333333333338F338F33300003333333333A222433333
+      333333338F338F33000033333333333A222433333333333338F338F300003333
+      33333333A222433333333333338F338F00003333333333333A22433333333333
+      3338F38F000033333333333333A223333333333333338F830000333333333333
+      333A333333333333333338330000333333333333333333333333333333333333
+      0000}
+    NumGlyphs = 2
+    ParentDoubleBuffered = False
+    TabOrder = 1
+    OnClick = bbOkClick
+  end
+  object bbCancel: TBitBtn
+    Left = 231
+    Top = 317
+    Width = 75
+    Height = 25
+    DoubleBuffered = True
+    Kind = bkCancel
+    ParentDoubleBuffered = False
+    TabOrder = 2
+  end
+  object cbTryOnlyWithThisServers: TCheckBox
+    Left = 35
+    Top = 285
+    Width = 271
+    Height = 17
+    Caption = 'Try to connect ONLY with this servers'
+    TabOrder = 3
+    OnClick = cbTryOnlyWithThisServersClick
+  end
+end

+ 124 - 0
Units/Forms/UFRMNodesIp.pas

@@ -0,0 +1,124 @@
+unit UFRMNodesIp;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, Buttons, UAppParams;
+
+type
+  TFRMNodesIp = class(TForm)
+    memoNodesIp: TMemo;
+    Label1: TLabel;
+    bbOk: TBitBtn;
+    bbCancel: TBitBtn;
+    cbTryOnlyWithThisServers: TCheckBox;
+    procedure bbOkClick(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure cbTryOnlyWithThisServersClick(Sender: TObject);
+  private
+    FAppParams: TAppParams;
+    procedure SetAppParams(const Value: TAppParams);
+    { Private declarations }
+  public
+    { Public declarations }
+    Procedure PrepareData;
+    Property AppParams : TAppParams read FAppParams write SetAppParams;
+  end;
+
+implementation
+
+uses
+  UNetProtocol, UFRMWallet, UNode;
+
+{$R *.dfm}
+
+{ TFRMNodesIp }
+
+procedure TFRMNodesIp.bbOkClick(Sender: TObject);
+Var nsarr : TNodeServerAddressArray;
+  ips : AnsiString;
+begin
+  TNode.DecodeIpStringToNodeServerAddressArray(memoNodesIp.Lines.Text,nsarr);
+  if (length(nsarr)=0) And (cbTryOnlyWithThisServers.Checked) then begin
+    raise Exception.Create('No valid IP in list!');
+  end;
+  // Encode
+  ips := TNode.EncodeNodeServerAddressArrayToIpString(nsarr);
+  if Assigned(FAppParams) then begin
+    FAppParams.ParamByName[CT_PARAM_PeerCache].SetAsString(ips);
+    if cbTryOnlyWithThisServers.Checked then Begin
+      FAppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].SetAsString(ips);
+      TNetData.NetData.DiscoverFixedServersOnly(nsarr);
+      Application.MessageBox(PChar('Restart application to take effect'),PChar(Application.Title),MB_OK);
+    end else begin
+      FAppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].SetAsString('');
+      setlength(nsarr,0);
+      TNetData.NetData.DiscoverFixedServersOnly(nsarr);
+    end;
+  end;
+  setlength(nsarr,0);
+  ModalResult := MrOk;
+end;
+
+procedure TFRMNodesIp.cbTryOnlyWithThisServersClick(Sender: TObject);
+begin
+  if cbTryOnlyWithThisServers.Checked then begin
+    cbTryOnlyWithThisServers.Font.Color := clRed;
+    cbTryOnlyWithThisServers.Font.Style := [fsBold];
+  end else begin
+    cbTryOnlyWithThisServers.ParentFont := true;
+  end;
+  if cbTryOnlyWithThisServers.Checked then begin
+    Application.MessageBox(PChar('ALERT:'+#10+
+      'If "'+cbTryOnlyWithThisServers.Caption+'" is checked '+#10+
+      'and no valid server found, you will be alone!')
+      ,PChar(Application.Title),MB_OK+MB_ICONWARNING);
+  end;
+end;
+
+procedure TFRMNodesIp.FormCreate(Sender: TObject);
+begin
+  FAppParams := Nil;
+  PrepareData;
+end;
+
+procedure TFRMNodesIp.PrepareData;
+Var
+  nsarr : TNodeServerAddressArray;
+  i : Integer;
+  ips : AnsiString;
+  aux : AnsiString;
+begin
+  memoNodesIp.Clear;
+  if Not Assigned(FAppParams) then exit;
+  setlength(nsarr,0);
+  ips := FAppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].GetAsString('');
+  if trim(ips)<>'' then begin
+    cbTryOnlyWithThisServers.Checked := true;
+    TNode.DecodeIpStringToNodeServerAddressArray(ips,nsarr);
+  end else begin
+    cbTryOnlyWithThisServers.Checked := false;
+    nsarr := TNetData.NetData.GetValidNodeServers;
+  end;
+  for i := low(nsarr) to high(nsarr) do begin
+    aux := nsarr[i].ip;
+    if nsarr[i].port>0 then aux := aux +':'+ InttoStr(nsarr[i].port);
+    memoNodesIp.Lines.Add( aux );
+  end;
+  if cbTryOnlyWithThisServers.Checked then begin
+    cbTryOnlyWithThisServers.Font.Color := clRed;
+    cbTryOnlyWithThisServers.Font.Style := [fsBold];
+  end else begin
+    cbTryOnlyWithThisServers.ParentFont := true;
+  end;
+  setlength(nsarr,0);
+end;
+
+procedure TFRMNodesIp.SetAppParams(const Value: TAppParams);
+begin
+  FAppParams := Value;
+  PrepareData;
+end;
+
+end.

+ 5 - 17
Units/Forms/UFRMWallet.dfm

@@ -513,10 +513,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
@@ -564,10 +560,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
@@ -651,10 +643,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
@@ -755,10 +743,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
@@ -1010,6 +994,10 @@ object FRMWallet: TFRMWallet
         ShortCut = 16463
         OnClick = miOptionsClick
       end
+      object IPnodes1: TMenuItem
+        Caption = 'IP nodes'
+        OnClick = IPnodes1Click
+      end
       object N1: TMenuItem
         Caption = '-'
       end
@@ -1031,7 +1019,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Top = 180
     Bitmap = {
-      494C010102000800E40010003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000800EC0010003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 23 - 2
Units/Forms/UFRMWallet.pas

@@ -39,6 +39,7 @@ Const
   CT_PARAM_ShowModalMessages = 'ShowModalMessages';
   CT_PARAM_MaxCPUs = 'MaxCPUs';
   CT_PARAM_PeerCache = 'PeerCache';
+  CT_PARAM_TryToConnectOnlyWithThisFixedServers = 'TryToConnectOnlyWithFixedServers';
 
 type
   TStringListAux = Class(TStringList)
@@ -148,6 +149,7 @@ type
     lblBuild: TLabel;
     ebFindAccountNumber: TEdit;
     Label18: TLabel;
+    IPnodes1: TMenuItem;
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure TimerUpdateStatusTimer(Sender: TObject);
@@ -177,6 +179,7 @@ type
     procedure lblReceivedMessagesClick(Sender: TObject);
     procedure ebFindAccountNumberChange(Sender: TObject);
     procedure ebFindAccountNumberExit(Sender: TObject);
+    procedure IPnodes1Click(Sender: TObject);
   private
     FMinersBlocksFound: Integer;
     procedure SetMinersBlocksFound(const Value: Integer);
@@ -238,7 +241,7 @@ implementation
 
 Uses UFolderHelper, ssl_lib, UConst, UTime,
   UDBStorage, UThread, UOpTransaction, UECIES, UFRMPascalCoinWalletConfig,
-  UFRMAbout, UFRMOperation, UFRMWalletKeys, UFRMPayloadDecoder;
+  UFRMAbout, UFRMOperation, UFRMWalletKeys, UFRMPayloadDecoder, UFRMNodesIp;
 
 Type
   TThreadActivate = Class(TPCThread)
@@ -260,6 +263,8 @@ end;
 { TFRMWallet }
 
 procedure TFRMWallet.Activate;
+Var ips : AnsiString;
+  nsarr : TNodeServerAddressArray;
 begin
   inherited;
   if FIsActivated then exit;
@@ -277,6 +282,10 @@ begin
         Raise;
       end;
     End;
+    ips := FAppParams.ParamByName[CT_PARAM_TryToConnectOnlyWithThisFixedServers].GetAsString('');
+    TNode.DecodeIpStringToNodeServerAddressArray(ips,nsarr);
+    TNetData.NetData.DiscoverFixedServersOnly(nsarr);
+    setlength(nsarr,0);
     // Creating Node:
     FNode := TNode.Node;
     FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
@@ -298,7 +307,7 @@ begin
     FBlockChainDBGrid.Node := FNode;
     FBlockChainDBGrid.AdoConnection := TDBStorage(FNode.Bank.Storage).ADOConnection;
     FBlockChainDBGrid.DBGrid := dbGridBlockChain;
-    // Init TNode
+    // Init
     TNetData.NetData.OnReceivedHelloMessage := OnReceivedHelloMessage;
     TNetData.NetData.OnStatisticsChanged := OnNetStatisticsChanged;
     TNetData.NetData.OnNetConnectionsUpdated := onNetConnectionsUpdated;
@@ -800,6 +809,18 @@ begin
   Result := PublicK;
 end;
 
+procedure TFRMWallet.IPnodes1Click(Sender: TObject);
+Var FRM : TFRMNodesIp;
+begin
+  FRM := TFRMNodesIp.Create(Self);
+  Try
+    FRM.AppParams := FAppParams;
+    FRM.ShowModal;
+  Finally
+    FRM.Free;
+  End;
+end;
+
 procedure TFRMWallet.lblReceivedMessagesClick(Sender: TObject);
 begin
   PageControl.ActivePage := tsMessages;

+ 5 - 2
Units/PascalCoin/UConst.pas

@@ -58,15 +58,18 @@ Const
 
   CT_MaxClientsConnected = 100;
 
-  CT_BankToDiskEveryNBlocks = 500;
+  CT_BankToDiskEveryNBlocks = 1000;
 
   CT_Default_EC_OpenSSL_NID = NID_secp256k1;
 
   CT_BlockChain_Protocol_Version: Word = $0001; // Version 1
   CT_BlockChain_Protocol_Available: Word = $0000;
 
+  // Build 1.0.4 - introducing NetProtocol versioning:
   CT_NetProtocol_Version: Word = $0001;
-  CT_NetProtocol_Available: Word = $0002; // Build 1.0.4
+  // IMPORTANT NOTE!!!
+  // NetProtocol_Available MUST BE allways >= NetProtocol_version
+  CT_NetProtocol_Available: Word = $0002;  // Remember, >= NetProtocol_version !!!
 
   CT_MagicIdentificator: AnsiString = 'PascalCoin'; //
 

+ 1 - 1
Units/PascalCoin/UCrypto.pas

@@ -454,7 +454,7 @@ Var i : Integer;
 Begin
   Result := true;
   for i := 1 to length(ReadableText) do begin
-    if (ord(ReadableText[i])<32) Or (ord(ReadableText[i])>=127) then begin
+    if (ord(ReadableText[i])<32) Or (ord(ReadableText[i])>=255) then begin
       Result := false;
       Exit;
     end;

+ 2 - 11
Units/PascalCoin/UDBStorage.pas

@@ -241,18 +241,9 @@ begin
 end;
 
 class function TDBStorage.DBPayloadToReadableText(const DBRawPayload: TRawBytes; var ReadableText: AnsiString): Boolean;
-Var i : Integer;
-  P : PAnsiChar;
-  lc : AnsiString;
 begin
-  Result := false;
-  for i := 1 to length(DBRawPayload) do begin
-    if (ord(DBRawPayload[i])<32) Or (ord(DBRawPayload[i])>=127) then begin
-      Exit;
-    end;
-  end;
-  Result := true;
-  ReadableText := DBRawPayload;
+  Result := TCrypto.IsHumanReadable(DBRawPayload);
+  if Result then ReadableText := DBRawPayload;
 end;
 
 class procedure TDBStorage.DBRawToStringField(Field: TField; const raw: TRawBytes);

+ 86 - 14
Units/PascalCoin/UNetProtocol.pas

@@ -161,6 +161,7 @@ Type
     FNetStatistics: TNetStatistics;
     FOnStatisticsChanged: TNotifyEvent;
     FMaxRemoteOperationBlock : TOperationBlock;
+    FFixedServers : TNodeServerAddressArray;
     Procedure IncStatistics(incActiveConnections,incClientsConnections,incServersConnections,incServersConnectionsWithResponse : Integer; incBytesReceived, incBytesSend : Int64);
   protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
@@ -185,6 +186,8 @@ Type
     Procedure AddServer(NodeServerAddress : TNodeServerAddress);
     Function IsBlackListed(const ip : AnsiString; port : Word) : Boolean;
     //
+    Procedure DiscoverFixedServersOnly(const FixedServers : TNodeServerAddressArray);
+    //
     Function ConnectionsCount(CountOnlyNetClients : Boolean) : Integer;
     Function Connection(index : Integer) : TNetConnection;
     Function ConnectionExistsAndActive(ObjectPointer : TObject) : Boolean;
@@ -541,7 +544,8 @@ end;
 
 constructor TNetData.Create;
 begin
-  FMaxRemoteOperationBlock := CT_OperationBlock_NUL;  
+  SetLength(FFixedServers,0);
+  FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
   FNetStatistics := CT_TNetStatistics_NUL;
   FOnStatisticsChanged := Nil;
   FOnNetConnectionsUpdated := Nil;
@@ -598,6 +602,7 @@ begin
   FreeAndNil(FNodePrivateKey);
   FNetDataNotifyEventsThread.Terminate;
   FNetDataNotifyEventsThread.WaitFor;
+  SetLength(FFixedServers,0);
   inherited;
 end;
 
@@ -617,6 +622,24 @@ begin
   End;
 end;
 
+procedure TNetData.DiscoverFixedServersOnly(const FixedServers: TNodeServerAddressArray);
+Var i : Integer;
+  l : TList;
+begin
+  l := FNodeServers.LockList;
+  try
+    SetLength(FFixedServers,length(FixedServers));
+    for i := low(FixedServers) to high(FixedServers) do begin
+      FFixedServers[i] := FixedServers[i];
+    end;
+    for i := low(FixedServers) to high(FixedServers) do begin
+      AddServer(FixedServers[i]);
+    end;
+  finally
+    FNodeServers.UnlockList;
+  end;
+end;
+
 procedure TNetData.DiscoverServers;
   Procedure sw(l : TList);
   Var i,j,x,y : Integer;
@@ -630,9 +653,10 @@ procedure TNetData.DiscoverServers;
     end;
   end;
 Var P : PNodeServerAddress;
-  i,j : Integer;
+  i,j,k : Integer;
   l,lns : TList;
   tdc : TThreadDiscoverConnection;
+  canAdd : Boolean;
 begin
   if TPCThread.ThreadClassFound(TThreadDiscoverConnection,nil)>=0 then begin
     TLog.NewLog(ltInfo,ClassName,'Allready discovering servers...');
@@ -652,7 +676,18 @@ begin
         If (Not Assigned(P.netConnection)) AND (Not IsBlackListed(P^.ip,P^.port)) AND (Not P^.its_myself) And
           ((P^.last_attempt_to_connect=0) Or ((P^.last_attempt_to_connect+EncodeTime(0,5,0,0)<now))) And
           ((P^.total_failed_attemps_to_connect<3) Or (P^.last_attempt_to_connect+EncodeTime(2,0,0,0)<now)) then begin
-          l.Add(P);
+
+          if Length(FFixedServers)>0 then begin
+            canAdd := false;
+            for k := low(FFixedServers) to high(FFixedServers) do begin
+              if (FFixedServers[k].ip=P^.ip) And
+                 ((FFixedServers[k].port=P.port)) then begin
+                 canAdd := true;
+                 break;
+              end;
+            end;
+          end else canAdd := true;
+          if canAdd then l.Add(P);
         end;
       end;
       if l.Count<=0 then exit;
@@ -1028,7 +1063,6 @@ begin
       if (Not (nsa.its_myself)) And
         (nsa.BlackListText='') And
         (nsa.last_connection>0) And
-        // New on build 1.0.2
         ((Assigned(nsa.netConnection)) Or
          (nsa.last_connection + (60*60*24) > (currunixtimestamp))) // Only If connected 24h before...
         then begin
@@ -1503,7 +1537,9 @@ begin
     TLog.NewLog(lterror,Classname,'Disconecting '+ClientRemoteAddr+' > '+Why);
   end;
   FIsMyselfServer := ItsMyself;
-  include_in_list := (Not SameText(Client.RemoteHost,'localhost')) And (Not SameText(Client.RemoteHost,'127.0.0.1'))  And (Not SameText('192.168',Copy(Client.RemoteHost,1,7)));
+  include_in_list := (Not SameText(Client.RemoteHost,'localhost')) And (Not SameText(Client.RemoteHost,'127.0.0.1'))
+    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;
     try
@@ -1835,6 +1871,47 @@ 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
+      l := TNetData.NetData.NetConnections.LockList;
+      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.RemoteHost+':'+Client.RemotePort+' 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 else begin
+      Result := true;
+    end;
+  End;
 var op, myLastOp : TPCOperationsComp;
     errors : AnsiString;
     messagehello : TNetMessage_Hello;
@@ -1869,17 +1946,13 @@ Begin
       exit;
     end;
     FLastKnownTimestampDiff := Int64(connection_ts) - Int64(UnivDateTimeToUnix( DateTime2UnivDateTime(now)));
-    if (FLastKnownTimestampDiff<>0) then begin
-      TLog.NewLog(ltdebug,Classname,'Processing a hello from a client with different time. Difference: '+Inttostr(FLastKnownTimestampDiff));
-    end;
-    If (connection_ts > (UnivDateTimeToUnix(DateTime2UnivDateTime(now))+CT_MaxSecondsDifferenceOfNetworkNodes)) then begin
-      TNode.Node.NotifyNetClientMessage(Nil,'Detected a different time in an other node... check that your PC time is correct or you will be Blacklisted! '+
-        'Your time: '+TimeToStr(now)+' - '+Client.RemoteHost+':'+Client.RemotePort+' 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)' );
+    // Check valid time
+    if Not IsValidTime(connection_ts) then begin
       DisconnectInvalidClient(false,'Invalid remote timestamp. Difference:'+inttostr(FLastKnownTimestampDiff)+' > '+inttostr(CT_MaxSecondsDifferenceOfNetworkNodes));
     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,7)))
+      And (Not SameText('192.168.',Copy(Client.RemoteHost,1,8)))
+      And (Not SameText('10.',Copy(Client.RemoteHost,1,3)))
       And (Not TAccountComp.Equal(FClientPublicKey,TNetData.NetData.FNodePrivateKey.PublicKey)) then begin
       nsa := CT_TNodeServerAddress_NUL;
       nsa.ip := Client.RemoteHost;
@@ -2424,7 +2497,6 @@ begin
     currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
     data.Write(currunixtimestamp,4);
     // Save last operations block
-    // Build 1.0.4 changed to NIL owner ---> op := TPCOperationsComp.Create(TNode.Node.Bank);
     op := TPCOperationsComp.Create(nil);
     try
       if (TNode.Node.Bank.BlocksCount>0) then TNode.Node.Bank.LoadOperations(op,TNode.Node.Bank.BlocksCount-1);

+ 75 - 5
Units/PascalCoin/UNode.pas

@@ -47,6 +47,8 @@ Type
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
   public
     Class Function Node : TNode;
+    Class Procedure DecodeIpStringToNodeServerAddressArray(Const Ips : AnsiString; Var NodeServerAddressArray : TNodeServerAddressArray);
+    Class Function EncodeNodeServerAddressArrayToIpString(Const NodeServerAddressArray : TNodeServerAddressArray) : AnsiString;
     Constructor Create(AOwner : TComponent); override;
     Destructor Destroy; override;
     Property Bank : TPCBank read FBank;
@@ -343,7 +345,7 @@ begin
 end;
 
 procedure TNode.AutoDiscoverNodes(Const ips : AnsiString);
-  Function GetIp(var ips_string : AnsiString; var nsa : TNodeServerAddress) : Boolean;
+{  Function GetIp(var ips_string : AnsiString; var nsa : TNodeServerAddress) : Boolean;
   Const CT_IP_CHARS = ['a'..'z','A'..'Z','0'..'9','.','-','_'];
   var i : Integer;
     port : AnsiString;
@@ -373,18 +375,25 @@ procedure TNode.AutoDiscoverNodes(Const ips : AnsiString);
     ips_string := copy(ips_string,i+1,length(ips_string));
     if nsa.port=0 then nsa.port := CT_NetServer_Port;
     Result := (trim(nsa.ip)<>'');
-  end;
+  end;}
 Var i,j : Integer;
-  ips_string : AnsiString;
-  nsa : TNodeServerAddress;
+{  ips_string : AnsiString;
+  nsa : TNodeServerAddress;}
+  nsarr : TNodeServerAddressArray;
 begin
-  ips_string := ips+';'+PeerCache;
+  DecodeIpStringToNodeServerAddressArray(ips+';'+PeerCache,nsarr);
+  for i := low(nsarr) to high(nsarr) do begin
+    TNetData.NetData.AddServer(nsarr[i]);
+  end;
+
+{  ips_string := ips+';'+PeerCache;
   repeat
     If GetIp(ips_string,nsa) then begin
       TNetData.NetData.AddServer(nsa);
     end;
   until (ips_string='');
   //
+}
   j := (CT_MaxServersConnected -  TNetData.NetData.ConnectionsCount(true));
   if j<=0 then exit;
   TNetData.NetData.DiscoverServers;
@@ -409,6 +418,53 @@ begin
   if Not Assigned(_Node) then _Node := Self;
 end;
 
+class procedure TNode.DecodeIpStringToNodeServerAddressArray(Const Ips: AnsiString;
+  var NodeServerAddressArray: TNodeServerAddressArray);
+  Function GetIp(var ips_string : AnsiString; var nsa : TNodeServerAddress) : Boolean;
+  Const CT_IP_CHARS = ['a'..'z','A'..'Z','0'..'9','.','-','_'];
+  var i : Integer;
+    port : AnsiString;
+  begin
+    nsa := CT_TNodeServerAddress_NUL;
+    Result := false;
+    if length(trim(ips_string))=0 then begin
+      ips_string := '';
+      exit;
+    end;
+    i := 1;
+    while (i<length(ips_string)) AND (NOT (ips_string[i] IN CT_IP_CHARS)) do inc(i);
+    if (i>1) then ips_string := copy(ips_string,i,length(ips_string));
+    //
+    i := 1;
+    while (i<=length(ips_string)) and (ips_string[i] in CT_IP_CHARS) do inc(i);
+    nsa.ip := copy(ips_string,1,i-1);
+    if (i<=length(ips_string)) and (ips_string[i]=':') then begin
+      inc(i);
+      port := '';
+      while (i<=length(ips_string)) and (ips_string[i] in ['0'..'9']) do begin
+        port := port + ips_string[i];
+        inc(i);
+      end;
+      nsa.port := StrToIntDef(port,0);
+    end;
+    ips_string := copy(ips_string,i+1,length(ips_string));
+    if nsa.port=0 then nsa.port := CT_NetServer_Port;
+    Result := (trim(nsa.ip)<>'');
+  end;
+Var i,j : Integer;
+  ips_string : AnsiString;
+  nsa : TNodeServerAddress;
+begin
+  SetLength(NodeServerAddressArray,0);
+  ips_string := Ips;
+  repeat
+    If GetIp(ips_string,nsa) then begin
+      SetLength(NodeServerAddressArray,length(NodeServerAddressArray)+1);
+      NodeServerAddressArray[High(NodeServerAddressArray)] := nsa;
+    end;
+  until (ips_string='');
+end;
+
 procedure TNode.DeleteMiner(index: Integer);
 Var m : TMinerThread;
   mtl : TList;
@@ -468,6 +524,20 @@ begin
   TLog.NewLog(ltinfo,Classname,'Destroying Node - END');
 end;
 
+class function TNode.EncodeNodeServerAddressArrayToIpString(
+  const NodeServerAddressArray: TNodeServerAddressArray): AnsiString;
+var i : Integer;
+begin
+  Result := '';
+  for i := low(NodeServerAddressArray) to high(NodeServerAddressArray) do begin
+    if (Result<>'') then Result := Result + ';';
+    Result := Result + NodeServerAddressArray[i].ip;
+    if NodeServerAddressArray[i].port>0 then begin
+      Result := Result + ':'+IntToStr(NodeServerAddressArray[i].port);
+    end;
+  end;
+end;
+
 procedure TNode.EndLocking;
 begin
   LeaveCriticalSection(FLockNodeOperations);