ソースを参照

Max node servers buffer and minor code changes

Added new feature to keep server nodes buffer small, also added some
minor code changes to allow Delphi/Lazarus compilation
PascalCoin 7 年 前
コミット
50484dc10a
3 ファイル変更91 行追加14 行削除
  1. 1 1
      Units/Forms/UFRMOperation.pas
  2. 87 10
      Units/PascalCoin/UNetProtocol.pas
  3. 3 3
      Units/Utils/UCommon.pas

+ 1 - 1
Units/Forms/UFRMOperation.pas

@@ -204,7 +204,7 @@ Var errors : AnsiString;
   _newName : TRawBytes;
   _newType : Word;
   _changeName, _changeType, _V2, _executeSigner  : Boolean;
-  _senderAccounts : array of Cardinal;
+  _senderAccounts : TCardinalsArray;
 label loop_start;
 begin
   if Not Assigned(WalletKeys) then raise Exception.Create('No wallet keys');

+ 87 - 10
Units/PascalCoin/UNetProtocol.pas

@@ -52,6 +52,12 @@ Const
   CT_NetError_InvalidNewAccount = $0012;
   CT_NetError_SafeboxNotFound = $00020;
 
+  CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES = 60*60*3;
+  CT_LAST_CONNECTION_MAX_MINUTES = 60*60;
+  CT_MAX_NODESERVERS_ON_HELLO = 10;
+  CT_MIN_NODESERVERS_BUFFER = 50;
+  CT_MAX_NODESERVERS_BUFFER = 300;
+
 Type
   {
   Net Protocol:
@@ -124,6 +130,8 @@ Type
     TotalServersConnections : Integer;
     BytesReceived : Int64;
     BytesSend : Int64;
+    NodeServersListCount : Integer;
+    NodeServersDeleted : Integer;
   end;
 
   TNetData = Class;
@@ -186,6 +194,7 @@ Type
 
   TNetData = Class(TComponent)
   private
+    FMaxNodeServersAddressesBuffer: Integer;
     FNetDataNotifyEventsThread : TNetDataNotifyEventsThread;
     FNodePrivateKey : TECPrivateKey;
     FNetConnections : TPCThreadList;
@@ -208,6 +217,7 @@ Type
     FMaxConnections : Integer;
     FNetworkAdjustedTime : TNetworkAdjustedTime;
     Procedure IncStatistics(incActiveConnections,incClientsConnections,incServersConnections,incServersConnectionsWithResponse : Integer; incBytesReceived, incBytesSend : Int64);
+    procedure SetMaxNodeServersAddressesBuffer(AValue: Integer);
     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;
@@ -256,6 +266,7 @@ Type
     Property MaxRemoteOperationBlock : TOperationBlock read FMaxRemoteOperationBlock;
     Property NodePrivateKey : TECPrivateKey read FNodePrivateKey;
     Function GetValidNodeServers(OnlyWhereIConnected : Boolean; Max : Integer): TNodeServerAddressArray;
+    procedure CleanNodeServersList;
     Property OnNetConnectionsUpdated : TNotifyEvent read FOnNetConnectionsUpdated write FOnNetConnectionsUpdated;
     Property OnNodeServersUpdated : TNotifyEvent read FOnNodeServersUpdated write FOnNodeServersUpdated;
     Property OnBlackListUpdated : TNotifyEvent read FOnBlackListUpdated write FOnBlackListUpdated;
@@ -268,6 +279,7 @@ Type
     Procedure NotifyStatisticsChanged;
     Property NetConnectionsActive : Boolean read FNetConnectionsActive write SetNetConnectionsActive;
     Property NetworkAdjustedTime : TNetworkAdjustedTime read FNetworkAdjustedTime;
+    Property MaxNodeServersAddressesBuffer : Integer read FMaxNodeServersAddressesBuffer write SetMaxNodeServersAddressesBuffer;
   End;
 
   { TNetConnection }
@@ -394,7 +406,7 @@ Type
 
 Const
   CT_TNodeServerAddress_NUL : TNodeServerAddress = (ip:'';port:0;last_connection:0;last_connection_by_server:0; netConnection:nil;its_myself:false;last_attempt_to_connect:0;total_failed_attemps_to_connect:0;is_blacklisted:false;BlackListText:'');
-  CT_TNetStatistics_NUL : TNetStatistics = (ActiveConnections:0;ClientsConnections:0;ServersConnections:0;ServersConnectionsWithResponse:0;TotalConnections:0;TotalClientsConnections:0;TotalServersConnections:0;BytesReceived:0;BytesSend:0);
+  CT_TNetStatistics_NUL : TNetStatistics = (ActiveConnections:0;ClientsConnections:0;ServersConnections:0;ServersConnectionsWithResponse:0;TotalConnections:0;TotalClientsConnections:0;TotalServersConnections:0;BytesReceived:0;BytesSend:0;NodeServersListCount:0;NodeServersDeleted:0);
 
 implementation
 
@@ -424,8 +436,16 @@ procedure TNetData.AddServer(NodeServerAddress: TNodeServerAddress);
 Var P : PNodeServerAddress;
   i : Integer;
   l : TList;
+  currunixtimestamp : Cardinal;
 begin
   if trim(NodeServerAddress.ip)='' then exit;
+  // Protection against fill with invalid nodes
+  currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+  // If not connected CT_LAST_CONNECTION_MAX_MINUTES minutes ago...
+  If (NodeServerAddress.last_connection_by_server=0) AND (NodeServerAddress.last_connection>0) AND ((NodeServerAddress.last_connection + (CT_LAST_CONNECTION_MAX_MINUTES)) < (currunixtimestamp)) then exit;
+  // If not connected CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES minutes ago...
+  If (NodeServerAddress.last_connection=0) AND (NodeServerAddress.last_connection_by_server>0) AND ((NodeServerAddress.last_connection_by_server + (CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES)) < (currunixtimestamp)) then exit;
+  If (NodeServerAddress.last_connection_by_server>currunixtimestamp) OR (NodeServerAddress.last_connection>currunixtimestamp) then exit;
   l := FNodeServersAddresses.LockList;
   try
     i := IndexOfNetClient(l,NodeServerAddress.ip,NodeServerAddress.port);
@@ -436,10 +456,12 @@ begin
       if NodeServerAddress.last_attempt_to_connect>P^.last_attempt_to_connect then P^.last_attempt_to_connect := NodeServerAddress.last_attempt_to_connect;
       exit;
     end;
+    If (l.Count>=FMaxNodeServersAddressesBuffer) then exit; // In order to prevent fill buffer
     New(P);
     P^ := NodeServerAddress;
     l.Add(P);
     l.Sort(SortNodeServerAddress);
+    Inc(FNetStatistics.NodeServersListCount);
     TLog.NewLog(ltdebug,Classname,'Adding new server: '+NodeServerAddress.ip+':'+Inttostr(NodeServerAddress.port));
   finally
     FNodeServersAddresses.UnlockList;
@@ -457,6 +479,7 @@ Var P,Pns : PNodeServerAddress;
   i,n,j : Integer;
   l,lns : TList;
 begin
+  CleanNodeServersList;
   // This procedure cleans old blacklisted IPs
   n := 0;
   l := FNodeServersAddresses.LockList;
@@ -464,10 +487,12 @@ begin
     for i := l.Count - 1 downto 0 do begin
       P := l[i];
       // Is an old blacklisted IP? (More than 1 hour)
-      If (P^.is_blacklisted) AND ((P^.last_connection+(60*60)) < (UnivDateTimeToUnix(DateTime2UnivDateTime(now)))) then begin
+      If (P^.is_blacklisted) AND ((P^.last_connection+(CT_LAST_CONNECTION_MAX_MINUTES)) < (UnivDateTimeToUnix(DateTime2UnivDateTime(now)))) then begin
         l.Delete(i);
         Dispose(P);
         inc(n);
+        dec(FNetStatistics.NodeServersListCount);
+        inc(FNetStatistics.NodeServersDeleted);
       end;
     end;
   Finally
@@ -476,6 +501,46 @@ begin
   if (n>0) then NotifyBlackListUpdated;
 end;
 
+procedure TNetData.CleanNodeServersList;  // Will mantain NodeServersAddesses with few nodes in order to keep memory and cpu speed
+var i,j : Integer;
+  nsa : TNodeServerAddress;
+  currunixtimestamp : Cardinal;
+  l : TList;
+  Aux : TNodeServerAddressArray;
+begin
+  currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+  l := FNodeServersAddresses.LockList;
+  try
+    i := l.Count-1;
+    while (i>=0) do begin
+      nsa := PNodeServerAddress( l[i] )^;
+      If (Not (nsa.is_blacklisted)) // Not blacklisted
+        And ((nsa.netConnection = Nil)  // No connection
+             OR  // Connected but a lot of time without data...
+             ((Assigned(nsa.netConnection)) AND ((nsa.last_connection + (CT_LAST_CONNECTION_MAX_MINUTES)) < currunixtimestamp )))
+        And (
+          (nsa.total_failed_attemps_to_connect>0)
+          OR
+          (
+           // I've not connected CT_LAST_CONNECTION_MAX_MINUTES minutes before
+           ((nsa.last_connection + (CT_LAST_CONNECTION_MAX_MINUTES)) < (currunixtimestamp))
+           And // Others have connected CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES minutes before
+           ((nsa.last_connection_by_server + (CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES)) < (currunixtimestamp))
+           And
+           ((nsa.last_connection>0) Or (nsa.last_connection_by_server>0))
+          ))
+      then begin
+        DeleteNetClient(l,i);
+        dec(FNetStatistics.NodeServersListCount);
+        inc(FNetStatistics.NodeServersDeleted);
+      end;
+      dec(i);
+    end;
+  finally
+    FNodeServersAddresses.UnlockList;
+  end;
+end;
+
 function TNetData.Connection(index: Integer): TNetConnection;
 Var l : TList;
 begin
@@ -631,7 +696,7 @@ begin
   TLog.NewLog(ltDebug,ClassName,'Unlocked a NetLock object out of connections list');
 end;
 
-constructor TNetData.Create;
+constructor TNetData.Create(AOwner: TComponent);
 begin
   TLog.NewLog(ltInfo,ClassName,'TNetData.Create');
   FMaxConnections := CT_MaxClientsConnected;
@@ -656,6 +721,7 @@ begin
   FNetDataNotifyEventsThread := TNetDataNotifyEventsThread.Create(Self);
   FNetClientsDestroyThread := TNetClientsDestroyThread.Create(Self);
   FNetworkAdjustedTime := TNetworkAdjustedTime.Create;
+  FMaxNodeServersAddressesBuffer:=(CT_MAX_NODESERVERS_BUFFER DIV 2);
   If Not Assigned(_NetData) then _NetData := Self;
 end;
 
@@ -949,7 +1015,8 @@ begin
   end;
 end;
 
-procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; const Why : String);
+procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection;
+  const why: String);
 Const CT_LogSender = 'GetNewBlockChainFromClient';
 
   function Do_GetOperationsBlock(AssignToBank : TPCBank; block_start,block_end, MaxWaitMilliseconds : Cardinal; OnlyOperationBlock : Boolean; BlocksList : TList) : Boolean;
@@ -1412,6 +1479,7 @@ begin
   SetLength(Result,0);
   SetLength(Aux,0);
   currunixtimestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+  CleanNodeServersList;
   // Save other node servers
   l := FNodeServersAddresses.LockList;
   try
@@ -1419,10 +1487,10 @@ begin
       nsa := PNodeServerAddress( l[i] )^;
       if (Not IsBlackListed(nsa.ip,0))
         And
-        ( // I've connected 24h before
-         ((nsa.last_connection>0) And ((Assigned(nsa.netConnection)) Or ((nsa.last_connection + (60*60*24)) > (currunixtimestamp))))
-         Or // Others have connected 24h before
-         ((nsa.last_connection_by_server>0) And ((nsa.last_connection_by_server + (60*60*24)) > (currunixtimestamp)))
+        ( // I've connected 1h before
+         ((nsa.last_connection>0) And ((Assigned(nsa.netConnection)) Or ((nsa.last_connection + (CT_LAST_CONNECTION_MAX_MINUTES)) > (currunixtimestamp))))
+         Or // Others have connected 3h before
+         ((nsa.last_connection_by_server>0) And ((nsa.last_connection_by_server + (CT_LAST_CONNECTION_BY_SERVER_MAX_MINUTES)) > (currunixtimestamp)))
          Or // Peer cache
          ((nsa.last_connection=0) And (nsa.last_connection_by_server=0))
         )
@@ -1492,6 +1560,14 @@ begin
   end;
 end;
 
+procedure TNetData.SetMaxNodeServersAddressesBuffer(AValue: Integer);
+begin
+  if FMaxNodeServersAddressesBuffer=AValue then Exit;
+  if (AValue<CT_MIN_NODESERVERS_BUFFER) then FMaxNodeServersAddressesBuffer:=CT_MIN_NODESERVERS_BUFFER
+  else if (AValue>CT_MAX_NODESERVERS_BUFFER) then FMaxNodeServersAddressesBuffer:=CT_MAX_NODESERVERS_BUFFER
+  else FMaxNodeServersAddressesBuffer:=AValue;
+end;
+
 function TNetData.IndexOfNetClient(ListToSearch: TList; ip: AnsiString; port: Word; indexStart : Integer = 0): Integer;
 Var P : PNodeServerAddress;
 begin
@@ -2395,7 +2471,8 @@ Begin
           TStreamOp.ReadAnsiString(DataBuffer,nsa.ip);
           DataBuffer.Read(nsa.port,2);
           DataBuffer.Read(nsa.last_connection_by_server,4);
-          TNetData.NetData.AddServer(nsa);
+          If (nsa.last_connection_by_server>0) And (i<=CT_MAX_NODESERVERS_ON_HELLO) then // Protect massive data
+            TNetData.NetData.AddServer(nsa);
         end;
         if TStreamOp.ReadAnsiString(DataBuffer,other_version)>=0 then begin
           // Captures version
@@ -3016,7 +3093,7 @@ begin
     data.Write(currunixtimestamp,4);
     // Save last operations block
     TPCOperationsComp.SaveOperationBlockToStream(TNode.Node.Bank.LastOperationBlock,data);
-    nsarr := TNetData.NetData.GetValidNodeServers(true,20);
+    nsarr := TNetData.NetData.GetValidNodeServers(true,CT_MAX_NODESERVERS_ON_HELLO);
     i := length(nsarr);
     data.Write(i,4);
     for i := 0 to High(nsarr) do begin

+ 3 - 3
Units/Utils/UCommon.pas

@@ -40,7 +40,7 @@ type
   { TArrayTool }
   TArrayTool<T> = class
     public
-      class procedure Swap(var Values : array of T; Item1Index, Item2Index : SizeInt);
+      class procedure Swap(var Values : array of T; Item1Index, Item2Index : Integer);
     end;
 
 
@@ -141,8 +141,8 @@ end;
 
 {%region TArrayTool }
 
-class procedure TArrayTool<T>.Swap(var Values : array of T; Item1Index, Item2Index : SizeInt);
-var temp : T; len, recSize : SizeInt; itemSize : SizeInt;
+class procedure TArrayTool<T>.Swap(var Values : array of T; Item1Index, Item2Index : Integer);
+var temp : T; len, recSize : Integer; itemSize : Integer;
 begin
   len := Length(Values);
   recSize := SizeOf(T);