Browse Source

Build 1.5.2

PascalCoin 8 years ago
parent
commit
be77fadc4e

+ 8 - 0
README.md

@@ -34,6 +34,14 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.5.2.0 - 2017-03-03
+
+- Added a jobs buffer for miners. This will allow to submit old job solutions (limited buffer). (Fix the "tx" issue)
+- Miner jobs will not be sent every time a transaction is received, thet will be buffered and sent every few seconds (Fix the "tx" issue)
+- Better network performance, allowing more operations and nodes thanks to buffering before relaying
+- Daemon: Allow select on ini file how many connections can handle
+- Fixed a locking when deleting connections
+
 ### Build 1.5.1.0 - 2017-02-20
 
 - Memory leak fixed on RPC-JSON commands

+ 8 - 0
README.txt

@@ -34,6 +34,14 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ## History:  
 
+### Build 1.5.2.0 - 2017-03-03
+
+- Added a jobs buffer for miners. This will allow to submit old job solutions (limited buffer). (Fix the "tx" issue)
+- Miner jobs will not be sent every time a transaction is received, thet will be buffered and sent every few seconds (Fix the "tx" issue)
+- Better network performance, allowing more operations and nodes thanks to buffering before relaying
+- Daemon: Allow select on ini file how many connections can handle
+- Fixed a locking when deleting connections
+
 ### Build 1.5.1.0 - 2017-02-20
 
 - Memory leak fixed on RPC-JSON commands

+ 1 - 5
Units/Forms/UFRMWallet.dfm

@@ -981,10 +981,6 @@ object FRMWallet: TFRMWallet
     object tsNodeStats: TTabSheet
       Caption = 'Node Stats'
       ImageIndex = 3
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       DesignSize = (
         841
         404)
@@ -1284,7 +1280,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Top = 180
     Bitmap = {
-      494C010102000800CC0110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000800E00110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 0 - 63
Units/Forms/UFRMWallet.pas

@@ -597,69 +597,6 @@ begin
   FMustProcessWalletChanged := false;
 end;
 
-{
-procedure TFRMWallet.CheckMining;
-  Procedure Stop;
-  var i : Integer;
-    mtl : TList;
-  begin
-    if ForceMining then exit;
-    // Stop mining
-    mtl := FNode.MinerThreads.LockList;
-    try
-      for i:=mtl.Count-1 downto 0 do begin
-        if Not TMinerThread(mtl[i]).Paused then begin
-          TLog.NewLog(ltinfo,ClassName,'Stoping miner');
-        end;
-        TMinerThread(mtl[i]).Paused := true;
-      end;
-    finally
-      FNode.MinerThreads.UnlockList;
-    end;
-  end;
-Var i, n : Integer;
-  MT : TMinerThread;
-  mtl : TList;
-begin
-  if Not Assigned(FNode) then exit;
-  if (ForceMining) Or
-    (
-      (TNetData.NetData.NetStatistics.ActiveConnections>0) And
-      // Build 1.0.2 allows mine if there was at least 1 client connection (working as a server)
-      // or (new) there are 2 active connections to a servers (allowing non servers to mine too)
-      ( (TNetData.NetData.NetStatistics.TotalClientsConnections>0)
-        Or (TNetData.NetData.NetStatistics.ServersConnectionsWithResponse>=2) ) And
-      (TNetData.NetData.MaxRemoteOperationBlock.block<=FNode.Operations.OperationBlock.block)
-    ) then begin
-    if (cbAllowMining.checked) Or (ForceMining) then begin
-      n := 0;
-      mtl := FNode.MinerThreads.LockList;
-      try
-        for i:=mtl.Count-1 downto 0 do begin
-          if TMinerThread(mtl[i]).Paused then begin
-            TMinerThread(mtl[i]).Paused := false;
-            TLog.NewLog(ltinfo,ClassName,'Starting miner');
-          end;
-          inc(n);
-        end;
-        if n<FMaxCPUs then begin
-          MT := FNode.AddMiner(GetAccountKeyForMiner);
-          MT.OnThreadSafeNewBlockFound := OnMinerNewBlockFound;
-          MT.Paused := false;
-        end else begin
-          while (mtl.Count>FMaxCPUs) do FNode.DeleteMiner(mtl.Count-1);
-        end;
-      Finally
-        FNode.MinerThreads.UnlockList;
-      End;
-    end else begin
-      Stop;
-    end;
-  end else Stop;
-end;
-
-}
-
 procedure TFRMWallet.dgAccountsClick(Sender: TObject);
 begin
   UpdateOperations;

+ 105 - 0
Units/PascalCoin/UAccounts.pas

@@ -188,6 +188,22 @@ Type
     Function Get(index : Integer) : TAccount;
   End;
 
+  // Maintains a TRawBytes (AnsiString) list ordered to quick search withoud duplicates
+  TOrderedRawList = Class
+  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 Count : Integer;
+    Function Get(index : Integer) : TRawBytes;
+    Procedure Delete(index : Integer);
+    Function IndexOf(Const RawData : TRawBytes) : Integer;
+  End;
+
 
   TPCSafeBoxTransaction = Class
   private
@@ -1611,4 +1627,93 @@ begin
   end;
 end;
 
+{ TOrderedRawList }
+
+function TOrderedRawList.Add(const RawData: TRawBytes): Integer;
+Var P : PRawBytes;
+begin
+  if Find(RawData,Result) then exit
+  else begin
+    New(P);
+    P^ := RawData;
+    FList.Insert(Result,P);
+  end;
+end;
+
+procedure TOrderedRawList.Clear;
+Var P : PRawBytes;
+  i : Integer;
+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;
+
+constructor TOrderedRawList.Create;
+begin
+  FList := TList.Create;
+end;
+
+
+procedure TOrderedRawList.Delete(index: Integer);
+Var P : PRawBytes;
+begin
+  P := PRawBytes(FList[index]);
+  FList.Delete(index);
+  Dispose(P);
+end;
+
+destructor TOrderedRawList.Destroy;
+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;
+begin
+  Result := False;
+  L := 0;
+  H := FList.Count - 1;
+  PRawData := PAnsiChar(RawData);
+  while L <= H do
+  begin
+    I := (L + H) shr 1;
+    c := StrComp(PAnsiChar(PRawBytes(FList[i])^),PRawData);
+    if C < 0 then L := I + 1 else
+    begin
+      H := I - 1;
+      if C = 0 then
+      begin
+        Result := True;
+        L := I;
+      end;
+    end;
+  end;
+  Index := L;
+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.
+

+ 56 - 7
Units/PascalCoin/UBlockChain.pas

@@ -194,6 +194,7 @@ Type
     Property HasValidSignature : Boolean read FHasValidSignature;
     Class function OperationHash(op : TPCOperation; Block : Cardinal) : TRawBytes;
     Class function DecodeOperationHash(Const operationHash : TRawBytes; var block, account,n_operation : Cardinal) : Boolean;
+    function Sha256 : TRawBytes;
   End;
 
   TOperationsHashTree = Class
@@ -218,6 +219,7 @@ Type
     function SaveOperationsHashTreeToStream(Stream: TStream; SaveToStorage : Boolean): Boolean;
     function LoadOperationsHashTreeFromStream(Stream: TStream; LoadingFromStorage : Boolean; var errors : AnsiString): Boolean;
     function IndexOfOperation(op : TPCOperation) : Integer;
+    Procedure Delete(index : Integer);
   End;
 
   { TPCOperationsComp }
@@ -1731,7 +1733,8 @@ end;
 { TOperationsHashTree }
 
 Type TOperationHashTreeReg = Record
-       Hash : TRawBytes;
+       OpSha256 : TRawBytes;
+       AccHashTree : TRawBytes;
        Op : TPCOperation;
      end;
      POperationHashTreeReg = ^TOperationHashTreeReg;
@@ -1804,6 +1807,46 @@ begin
   FHashTreeOperations := TPCThreadList.Create('TOperationsHashTree_HashTreeOperations');
 end;
 
+procedure TOperationsHashTree.Delete(index: Integer);
+Var l : TList;
+  P : POperationHashTreeReg;
+  i : Integer;
+  ms : TMemoryStream;
+  h : TRawBytes;
+begin
+  l := FHashTreeOperations.LockList;
+  try
+    P := l[index];
+    l.Delete(index);
+    P^.Op.Free;
+    Dispose(P);
+    // Recalc operations hash
+    FTotalAmount := 0;
+    FTotalFee := 0;
+    FHashTree := '';
+    ms := TMemoryStream.Create;
+    try
+      for i := 0 to l.Count - 1 do begin
+        ms.Clear;
+        P := l[i];
+        P^.Op.SaveToStream(ms);
+        ms.Position := 0;
+        h := TCrypto.DoSha256(ms.Memory,ms.Size);
+        P^.Op.tag := i;
+        // Include to hash tree
+        FHashTree := TCrypto.DoSha256(FHashTree+h);
+        P^.AccHashTree := FHashTree;
+        inc(FTotalAmount,P^.Op.OperationAmount);
+        inc(FTotalFee,P^.Op.OperationFee);
+      end;
+    finally
+      ms.Free;
+    end;
+  finally
+    FHashTreeOperations.UnlockList;
+  end;
+end;
+
 destructor TOperationsHashTree.Destroy;
 begin
   ClearHastThree;
@@ -1850,13 +1893,13 @@ end;
 function TOperationsHashTree.IndexOfOperation(op: TPCOperation): Integer;
 Var
   l : TList;
-  hash : TRawBytes;
+  OpSha256 : TRawBytes;
 begin
-  hash := TCrypto.DoSha256(op.GetOperationBufferToHash);
+  OpSha256 := op.Sha256;
   l := FHashTreeOperations.LockList;
   Try
     for Result := 0 to l.Count - 1 do begin
-      if POperationHashTreeReg(l[Result])^.Hash=hash then exit;
+      if POperationHashTreeReg(l[Result])^.OpSha256=OpSha256 then exit;
     end;
     Result := -1;
   Finally
@@ -1880,13 +1923,14 @@ begin
     P^.Op.FPrevious_Destination_updated_block := op.FPrevious_Destination_updated_block;
     h := TCrypto.DoSha256(ms.Memory,ms.Size);
     P^.Op.tag := list.Count;
-    P^.Hash := TCrypto.DoSha256(op.GetOperationBufferToHash);
+    P^.OpSha256 := op.Sha256;
+    // Include to hash tree
+    FHashTree := TCrypto.DoSha256(FHashTree+h);
+    P^.AccHashTree := FHashTree;
     list.Add(P);
   finally
     ms.Free;
   end;
-  // Include to hash tree
-  FHashTree := TCrypto.DoSha256(FHashTree+h);
   inc(FTotalAmount,op.OperationAmount);
   inc(FTotalFee,op.OperationFee);
 end;
@@ -2174,6 +2218,11 @@ begin
   Result := true;
 end;
 
+function TPCOperation.Sha256: TRawBytes;
+begin
+  Result := TCrypto.DoSha256(GetOperationBufferToHash);
+end;
+
 { TOperationsResumeList }
 
 Type POperationResume = ^TOperationResume;

+ 4 - 5
Units/PascalCoin/UConst.pas

@@ -74,7 +74,7 @@ Const
   CT_MinServersConnected = 3;
   CT_MaxServersConnected = 5;
 
-  CT_MaxClientsConnected = 500;
+  CT_MaxClientsConnected = 100;
 
   CT_BankToDiskEveryNBlocks = 100; // Build 1.5 changed from 500 to 100; // Build 1.3.0 Changed from 1000 to 500
 
@@ -83,9 +83,8 @@ Const
   CT_BlockChain_Protocol_Version: Word = $0001; // Version 1
   CT_BlockChain_Protocol_Available: Word = $0001; // Build 1.4 Protocol available changed 0->1
 
-  CT_MagicNetIdentification = $0A043580; // Unix timestamp 168048000 ... It's Albert birthdate!
+  CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}$0A04FFFF{$ENDIF}; // Unix timestamp 168048000 ... It's Albert birthdate!
 
-  // Build 1.0.4 - introducing NetProtocol versioning:
   CT_NetProtocol_Version: Word = $0004;
   // IMPORTANT NOTE!!!
   // NetProtocol_Available MUST BE always >= NetProtocol_version
@@ -93,14 +92,14 @@ Const
 
   CT_SafeBoxBankVersion : Word = 2;
 
-  CT_MagicIdentificator: AnsiString = 'PascalCoin'; //
+  CT_MagicIdentificator: AnsiString = {$IFDEF PRODUCTION}'PascalCoin'{$ELSE}'PascalCoinTESTNET'{$ENDIF}; //
 
   // Value of Operations type in Protocol 1
   CT_Op_Transaction = $01;
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
 
-  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.5.1'{$ELSE}{$IFDEF TESTNET}'TESTNET 1.5.1'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.5.2'{$ELSE}{$IFDEF TESTNET}'TESTNET 1.5.2'{$ELSE}{$ENDIF}{$ENDIF};
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
 

+ 237 - 140
Units/PascalCoin/UNetProtocol.pas

@@ -185,6 +185,7 @@ Type
     FFixedServers : TNodeServerAddressArray;
     FNetClientsDestroyThread : TNetClientsDestroyThread;
     FNetConnectionsActive: Boolean;
+    FMaxConnections : Integer;
     Procedure IncStatistics(incActiveConnections,incClientsConnections,incServersConnections,incServersConnectionsWithResponse : Integer; incBytesReceived, incBytesSend : Int64);
 
     procedure SetNetConnectionsActive(const Value: Boolean);  protected
@@ -269,6 +270,8 @@ Type
     FHasReceivedData : Boolean;
     FIsDownloadingBlocks : Boolean;
     FRandomWaitSecondsSendHello : Cardinal;
+    FBufferReceivedOperationsHash : TOrderedRawList;
+    FBufferToSendOperations : TOperationsHashTree;
     function GetConnected: Boolean;
     procedure SetConnected(const Value: Boolean);
     procedure TcpClient_OnConnect(Sender: TObject);
@@ -300,6 +303,7 @@ Type
     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;
     //
@@ -332,11 +336,14 @@ Type
 
   TNetServerClient = Class(TNetConnection);
 
+  { TNetServer }
+
   TNetServer = Class(TNetTcpIpServer)
   private
   protected
     Procedure OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient); override;
     procedure SetActive(const Value: Boolean); override;
+    procedure SetMaxConnections(AValue: Integer); override;
   public
     Constructor Create; override;
   End;
@@ -489,18 +496,24 @@ end;
 function TNetData.ConnectionLock(Sender : TObject; ObjectPointer: TObject; MaxWaitMiliseconds : Cardinal) : Boolean;
 var i : Integer;
   l : TList;
+  nc : TNetConnection;
 begin
-  Result := false;
+  Result := false; nc := Nil;
   l := FNetConnections.LockList;
   try
     for i := 0 to l.Count - 1 do begin
-      if TObject(l[i])=ObjectPointer then begin
-        Result := TPCThread.TryProtectEnterCriticalSection(Sender,MaxWaitMiliseconds,TNetConnection(l[i]).FNetLock);
-        exit;
+      if (TObject(l[i])=ObjectPointer) then begin
+        if (Not (TNetConnection(l[i]).FDoFinalizeConnection)) And (TNetConnection(l[i]).Connected) then begin
+          nc := TNetConnection(l[i]);
+          exit;
+        end else exit;
       end;
     end;
   finally
     FNetConnections.UnlockList;
+    if Assigned(nc) then begin
+      Result := TPCThread.TryProtectEnterCriticalSection(Sender,MaxWaitMiliseconds,nc.FNetLock);
+    end;
   end;
 end;
 
@@ -563,6 +576,7 @@ end;
 procedure TNetData.ConnectionUnlock(ObjectPointer: TObject);
 var i : Integer;
   l : TList;
+  nc : TNetConnection;
 begin
   l := FNetConnections.LockList;
   try
@@ -575,11 +589,22 @@ begin
   finally
     FNetConnections.UnlockList;
   end;
+  Try
+    nc := (ObjectPointer as TNetConnection);
+    if (not assigned(nc.FNetLock)) then raise Exception.Create('NetLock object not assigned');
+    nc.FNetLock.Release;
+  Except
+    on E:Exception do begin
+      TLog.NewLog(ltError,Classname,'Error unlocking Object '+IntToHex(PtrInt(ObjectPointer),8)+' Errors ('+E.ClassName+'): '+E.Message);
+    end;
+  End;
+  TLog.NewLog(ltDebug,ClassName,'Unlocked a NetLock object out of connections list');
 end;
 
 constructor TNetData.Create;
 begin
   TLog.NewLog(ltInfo,ClassName,'TNetData.Create');
+  FMaxConnections := CT_MaxClientsConnected;
   FNetConnectionsActive := true;
   SetLength(FFixedServers,0);
   FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
@@ -1484,6 +1509,7 @@ begin
         sleep(10);
         DebugStep := 'Assigning old client';
         n.SetClient( NetTcpIpClientClass.Create(Nil) );
+        n.FinalizeConnection;
       Finally
         DebugStep := 'Freeing NetServerClient';
         n.Free;
@@ -1511,8 +1537,34 @@ begin
   end;
 end;
 
+procedure TNetServer.SetMaxConnections(AValue: Integer);
+begin
+  inherited SetMaxConnections(AValue);
+  TNetData.NetData.FMaxConnections:=AValue;
+end;
+
 { TNetConnection }
 
+function TNetConnection.AddOperationsToBufferForSend(Operations: TOperationsHashTree): Integer;
+Var i : Integer;
+begin
+  Result := 0;
+  FNetLock.Acquire;
+  try
+    for i := 0 to Operations.OperationsCount - 1 do begin
+      if FBufferReceivedOperationsHash.IndexOf(Operations.GetOperation(i).Sha256)<0 then begin
+        FBufferReceivedOperationsHash.Add(Operations.GetOperation(i).Sha256);
+        If FBufferToSendOperations.IndexOfOperation(Operations.GetOperation(i))<0 then begin
+          FBufferToSendOperations.AddOperationToHashTree(Operations.GetOperation(i));
+          Inc(Result);
+        end;
+      end;
+    end;
+  finally
+    FNetLock.Release;
+  end;
+end;
+
 function TNetConnection.ClientRemoteAddr: AnsiString;
 begin
   If Assigned(FTcpIpClient) then begin
@@ -1581,6 +1633,8 @@ begin
   SetClient( TBufferedNetTcpIpClient.Create(Self) );
   TNetData.NetData.FNetConnections.Add(Self);
   TNetData.NetData.NotifyNetConnectionUpdated;
+  FBufferReceivedOperationsHash := TOrderedRawList.Create;
+  FBufferToSendOperations := TOperationsHashTree.Create;
 end;
 
 destructor TNetConnection.Destroy;
@@ -1588,22 +1642,25 @@ Var Pnsa : PNodeServerAddress;
   lns : TList;
   i : Integer;
 begin
-  TLog.NewLog(ltdebug,ClassName,'Destroying '+Classname+' '+IntToHex(PtrInt(Self),8));
+  Try
+    TLog.NewLog(ltdebug,ClassName,'Destroying '+Classname+' '+IntToHex(PtrInt(Self),8));
 
-  Connected := false;
+    Connected := false;
 
-  lns := TNetData.NetData.NodeServersAddresses.LockList;
-  try
-    for i := lns.Count - 1 downto 0 do begin
-      Pnsa := lns[i];
-      if Pnsa^.netConnection=Self then Begin
-        Pnsa^.netConnection := Nil;
-      End;
+    lns := TNetData.NetData.NodeServersAddresses.LockList;
+    try
+      for i := lns.Count - 1 downto 0 do begin
+        Pnsa := lns[i];
+        if Pnsa^.netConnection=Self then Begin
+          Pnsa^.netConnection := Nil;
+        End;
+      end;
+    finally
+      TNetData.NetData.NodeServersAddresses.UnlockList;
     end;
-  finally
-    TNetData.NetData.NodeServersAddresses.UnlockList;
-  end;
-  TNetData.NetData.FNetConnections.Remove(Self);
+  Finally
+    TNetData.NetData.FNetConnections.Remove(Self);
+  End;
   TNetData.NetData.UnRegisterRequest(Self,0,0);
   Try
     TNetData.NetData.NotifyNetConnectionUpdated;
@@ -1611,6 +1668,8 @@ begin
     FreeAndNil(FNetLock);
     FreeAndNil(FClientBufferRead);
     FreeAndNil(FTcpIpClient);
+    FreeAndNil(FBufferReceivedOperationsHash);
+    FreeAndNil(FBufferToSendOperations);
     inherited;
   End;
 end;
@@ -1741,6 +1800,18 @@ begin
       if DoDisconnect then begin
         DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
       end else begin
+        // Add to received buffer
+        FNetLock.Acquire;
+        Try
+          for i := 0 to operations.OperationsCount - 1 do begin
+            op := operations.GetOperation(i);
+            FBufferReceivedOperationsHash.Add(op.Sha256);
+            c := FBufferToSendOperations.IndexOfOperation(op);
+            if (c>=0) then FBufferToSendOperations.Delete(c);
+          end;
+        Finally
+          FNetLock.Release;
+        End;
         TNode.Node.AddOperations(Self,operations,Nil,errors);
       end;
     finally
@@ -2239,80 +2310,84 @@ begin
     If Not Assigned(FTcpIpClient) then exit;
     if Not Client.Connected then exit;
     iDebugStep := 110;
-    TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
-    Try
-      iDebugStep := 120;
-      was_waiting_for_response := RequestId>0;
-      try
-        if was_waiting_for_response then begin
-          iDebugStep := 200;
-          FIsWaitingForResponse := true;
-          Send(ntp_request,operation,0,RequestId,SendDataBuffer);
-        end;
-        iDebugStep := 300;
-        tc := GetTickCount;
-        Repeat
-          iDebugStep := 400;
-          if (ReadTcpClientBuffer(MaxWaitTime,HeaderData,ReceiveDataBuffer)) then begin
-            iDebugStep := 500;
-            l := TNetData.NetData.NodeServersAddresses.LockList;
-            try
-              iDebugStep := 600;
-              for i := 0 to l.Count - 1 do begin
-                If PNodeServerAddress( l[i] )^.netConnection=Self then begin
-                  PNodeServerAddress( l[i] )^.last_connection := (UnivDateTimeToUnix(DateTime2UnivDateTime(now)));
-                  PNodeServerAddress( l[i] )^.total_failed_attemps_to_connect := 0;
+    tc := GetTickCount;
+    If TPCThread.TryProtectEnterCriticalSection(Self,MaxWaitTime,FNetLock) then begin
+      Try
+        iDebugStep := 120;
+        was_waiting_for_response := RequestId>0;
+        try
+          if was_waiting_for_response then begin
+            iDebugStep := 200;
+            FIsWaitingForResponse := true;
+            Send(ntp_request,operation,0,RequestId,SendDataBuffer);
+          end;
+          iDebugStep := 300;
+          Repeat
+            iDebugStep := 400;
+            if (MaxWaitTime > GetTickCount - tc) then MaxWaitTime := MaxWaitTime - (GetTickCount - tc)
+            else MaxWaitTime := 1;
+            tc := GetTickCount;
+            if (ReadTcpClientBuffer(MaxWaitTime,HeaderData,ReceiveDataBuffer)) then begin
+              iDebugStep := 500;
+              l := TNetData.NetData.NodeServersAddresses.LockList;
+              try
+                iDebugStep := 600;
+                for i := 0 to l.Count - 1 do begin
+                  If PNodeServerAddress( l[i] )^.netConnection=Self then begin
+                    PNodeServerAddress( l[i] )^.last_connection := (UnivDateTimeToUnix(DateTime2UnivDateTime(now)));
+                    PNodeServerAddress( l[i] )^.total_failed_attemps_to_connect := 0;
+                  end;
                 end;
+              finally
+                iDebugStep := 700;
+                TNetData.netData.NodeServersAddresses.UnlockList;
               end;
-            finally
-              iDebugStep := 700;
-              TNetData.netData.NodeServersAddresses.UnlockList;
-            end;
-            iDebugStep := 800;
-            TLog.NewLog(ltDebug,Classname,'Received '+CT_NetTransferType[HeaderData.header_type]+' operation:'+TNetData.OperationToText(HeaderData.operation)+' id:'+Inttostr(HeaderData.request_id)+' Buffer size:'+Inttostr(HeaderData.buffer_data_length) );
-            if (RequestId=HeaderData.request_id) And (HeaderData.header_type=ntp_response) then begin
-              Result := true;
-            end else begin
-              iDebugStep := 1000;
-              case HeaderData.operation of
-                CT_NetOp_Hello : Begin
-                  DoProcess_Hello(HeaderData,ReceiveDataBuffer);
-                End;
-                CT_NetOp_Message : Begin
-                  DoProcess_Message(HeaderData,ReceiveDataBuffer);
-                End;
-                CT_NetOp_GetBlocks : Begin
-                  if HeaderData.header_type=ntp_request then
-                    DoProcess_GetBlocks_Request(HeaderData,ReceiveDataBuffer)
-                  else if HeaderData.header_type=ntp_response then
-                    DoProcess_GetBlocks_Response(HeaderData,ReceiveDataBuffer)
-                  else DisconnectInvalidClient(false,'Not resquest or response: '+TNetData.HeaderDataToText(HeaderData));
-                End;
-                CT_NetOp_GetOperationsBlock : Begin
-                  if HeaderData.header_type=ntp_request then
-                    DoProcess_GetOperationsBlock_Request(HeaderData,ReceiveDataBuffer)
-                  else TLog.NewLog(ltdebug,Classname,'Received old response of: '+TNetData.HeaderDataToText(HeaderData));
-                End;
-                CT_NetOp_NewBlock : Begin
-                  DoProcess_NewBlock(HeaderData,ReceiveDataBuffer);
-                End;
-                CT_NetOp_AddOperations : Begin
-                  DoProcess_AddOperations(HeaderData,ReceiveDataBuffer);
-                End;
-              else
-                DisconnectInvalidClient(false,'Invalid operation: '+TNetData.HeaderDataToText(HeaderData));
+              iDebugStep := 800;
+              TLog.NewLog(ltDebug,Classname,'Received '+CT_NetTransferType[HeaderData.header_type]+' operation:'+TNetData.OperationToText(HeaderData.operation)+' id:'+Inttostr(HeaderData.request_id)+' Buffer size:'+Inttostr(HeaderData.buffer_data_length) );
+              if (RequestId=HeaderData.request_id) And (HeaderData.header_type=ntp_response) then begin
+                Result := true;
+              end else begin
+                iDebugStep := 1000;
+                case HeaderData.operation of
+                  CT_NetOp_Hello : Begin
+                    DoProcess_Hello(HeaderData,ReceiveDataBuffer);
+                  End;
+                  CT_NetOp_Message : Begin
+                    DoProcess_Message(HeaderData,ReceiveDataBuffer);
+                  End;
+                  CT_NetOp_GetBlocks : Begin
+                    if HeaderData.header_type=ntp_request then
+                      DoProcess_GetBlocks_Request(HeaderData,ReceiveDataBuffer)
+                    else if HeaderData.header_type=ntp_response then
+                      DoProcess_GetBlocks_Response(HeaderData,ReceiveDataBuffer)
+                    else DisconnectInvalidClient(false,'Not resquest or response: '+TNetData.HeaderDataToText(HeaderData));
+                  End;
+                  CT_NetOp_GetOperationsBlock : Begin
+                    if HeaderData.header_type=ntp_request then
+                      DoProcess_GetOperationsBlock_Request(HeaderData,ReceiveDataBuffer)
+                    else TLog.NewLog(ltdebug,Classname,'Received old response of: '+TNetData.HeaderDataToText(HeaderData));
+                  End;
+                  CT_NetOp_NewBlock : Begin
+                    DoProcess_NewBlock(HeaderData,ReceiveDataBuffer);
+                  End;
+                  CT_NetOp_AddOperations : Begin
+                    DoProcess_AddOperations(HeaderData,ReceiveDataBuffer);
+                  End;
+                else
+                  DisconnectInvalidClient(false,'Invalid operation: '+TNetData.HeaderDataToText(HeaderData));
+                end;
               end;
-            end;
-          end else sleep(1);
-          iDebugStep := 900;
-        Until (Result) Or (GetTickCount>(MaxWaitTime+tc));
-      finally
-        if was_waiting_for_response then FIsWaitingForResponse := false;
-      end;
-      iDebugStep := 990;
-    Finally
-      FNetLock.Release;
-    End;
+            end else sleep(1);
+            iDebugStep := 900;
+          Until (Result) Or (GetTickCount>(MaxWaitTime+tc));
+        finally
+          if was_waiting_for_response then FIsWaitingForResponse := false;
+        end;
+        iDebugStep := 990;
+      Finally
+        FNetLock.Release;
+      End;
+    end;
   Except
     On E:Exception do begin
       E.Message := E.Message+' DoSendAndWaitForResponse step '+Inttostr(iDebugStep);
@@ -2550,21 +2625,39 @@ Var data : TMemoryStream;
   optype : Byte;
 begin
   Result := false;
-  data := TMemoryStream.Create;
+  if Not Connected then exit;
+  FNetLock.Acquire;
   try
-    request_id := TNetData.NetData.NewRequestId;
-    c1 := Operations.OperationsCount;
-    data.Write(c1,4);
-    for i := 0 to Operations.OperationsCount-1 do begin
-      optype := Operations.GetOperation(i).OpType;
-      data.Write(optype,1);
-      Operations.GetOperation(i).SaveToStream(data);
+    for i := 0 to Operations.OperationsCount - 1 do begin
+      if FBufferReceivedOperationsHash.IndexOf(Operations.GetOperation(i).Sha256)<0 then begin
+        FBufferReceivedOperationsHash.Add(Operations.GetOperation(i).Sha256);
+        If FBufferToSendOperations.IndexOfOperation(Operations.GetOperation(i))<0 then begin
+          FBufferToSendOperations.AddOperationToHashTree(Operations.GetOperation(i));
+        end;
+      end;
+    end;
+    if FBufferToSendOperations.OperationsCount>0 then begin
+      TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(FBufferToSendOperations.OperationsCount)+' Operations to '+ClientRemoteAddr);
+      data := TMemoryStream.Create;
+      try
+        request_id := TNetData.NetData.NewRequestId;
+        c1 := FBufferToSendOperations.OperationsCount;
+        data.Write(c1,4);
+        for i := 0 to FBufferToSendOperations.OperationsCount-1 do begin
+          optype := FBufferToSendOperations.GetOperation(i).OpType;
+          data.Write(optype,1);
+          FBufferToSendOperations.GetOperation(i).SaveToStream(data);
+        end;
+        Send(ntp_autosend,CT_NetOp_AddOperations,0,request_id,data);
+        FBufferToSendOperations.ClearHastThree;
+      finally
+        data.Free;
+      end;
     end;
-    Send(ntp_autosend,CT_NetOp_AddOperations,0,request_id,data);
-    Result := Connected;
   finally
-    data.Free;
+    FNetLock.Release;
   end;
+  Result := Connected;
 end;
 
 function TNetConnection.Send_GetBlocks(StartAddress, quantity : Cardinal; var request_id : Cardinal) : Boolean;
@@ -2574,6 +2667,7 @@ begin
   Result := false;
   request_id := 0;
   if (FRemoteOperationBlock.block<TNetData.NetData.Bank.BlocksCount) Or (FRemoteOperationBlock.block=0) then exit;
+  if Not Connected then exit;
   // First receive operations from
   data := TMemoryStream.Create;
   try
@@ -2696,30 +2790,39 @@ var data : TStream;
 begin
   Result := false;
   if TNetData.NetData.Bank.BlocksCount=0 then exit;
+  if Not Connected then exit;
   if Connected then begin
-    // 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);
+    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
-        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;
+        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;
-        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;
+        data.Free;
       end;
-    finally
-      data.Free;
-    end;
+    Finally
+      FNetLock.Release;
+    End;
     Result := Connected;
   end;
 end;
@@ -2895,8 +2998,6 @@ Var l : TList;
   i, nactive,ndeleted,ntotal,nserverclients : Integer;
   netconn : TNetConnection;
   netserverclientstop : TNetServerClient;
-  aux : AnsiString;
-  needother : Boolean;
   newstats : TNetStatistics;
 begin
   FLastCheckTS := GetTickCount;
@@ -2907,7 +3008,6 @@ begin
       ntotal := 0;
       nserverclients := 0;
       netserverclientstop := Nil;
-      needother := true;
       FLastCheckTS := GetTickCount;
       If (FNetData.FNetConnections.TryLockList(100,l)) then begin
         try
@@ -2934,15 +3034,8 @@ begin
                 // Build 1.0.9 BUG-101 Only disconnect old versions prior to 1.0.9
                 if not assigned(netserverclientstop) then begin
                   netserverclientstop := TNetServerClient(netconn);
-                  aux := Copy(netconn.FClientAppVersion,1,5);
-                  needother := Not ((aux='1.0.6') or (aux='1.0.7') or (aux='1.0.8'));
-                end else begin
-                  aux := Copy(netconn.FClientAppVersion,1,5);
-                  if ((aux='1.0.6') or (aux='1.0.7') or (aux='1.0.8'))
-                    And ((needother) Or (netconn.CreatedTime<netserverclientstop.CreatedTime)) then begin
-                    needother := false;
-                    netserverclientstop := TNetServerClient(netconn);
-                  end;
+                end else if (netconn.CreatedTime<netserverclientstop.CreatedTime) then begin
+                  netserverclientstop := TNetServerClient(netconn);
                 end;
               end;
             end;
@@ -2954,8 +3047,11 @@ begin
           FNetData.FNetStatistics.ServersConnectionsWithResponse := newstats.ServersConnectionsWithResponse;
           // Must stop clients?
           if (nserverclients>CT_MaxServersConnected) And // This is to ensure there are more serverclients than clients
-             ((nserverclients + nactive + ndeleted)>=CT_MaxClientsConnected) And (Assigned(netserverclientstop)) then begin
-            TLog.NewLog(ltinfo,Classname,Format('Sending FinalizeConnection NetServerClients:%d Servers_active:%d Servers_deleted:%d',[nserverclients,nactive,ndeleted]));
+             ((nserverclients + nactive + ndeleted)>=FNetData.FMaxConnections) And (Assigned(netserverclientstop)) then begin
+            TLog.NewLog(ltinfo,Classname,Format('Sending FinalizeConnection to NodeConnection %s created on %s (working time %s) - NetServerClients:%d Servers_active:%d Servers_deleted:%d',
+              [netserverclientstop.Client.ClientRemoteAddr,FormatDateTime('hh:nn:ss',netserverclientstop.CreatedTime),
+               FormatDateTime('hh:nn:ss',Now - netserverclientstop.CreatedTime),
+               nserverclients,nactive,ndeleted]));
             netserverclientstop.FinalizeConnection;
           end;
         finally
@@ -3124,16 +3220,17 @@ begin
       finally
         FNetData.NetConnections.UnlockList;
       end;
-
-      for i := 0 to l_to_del.Count - 1 do begin
-        If FNetData.ConnectionLock(Self,TNetConnection(l_to_del[i]),500) then begin
-          try
+      if l_to_del.Count>0 then begin
+        TLog.NewLog(ltDebug,ClassName,'Destroying NetClients: '+inttostr(l_to_del.Count));
+        for i := 0 to l_to_del.Count - 1 do begin
+          Try
             DebugStep := 'Destroying NetClient '+TNetConnection(l_to_del[i]).ClientRemoteAddr;
             TNetConnection(l_to_del[i]).Free;
-          finally
-            // Not Necessary because on Freeing then Lock is deleted.
-            // -> TNetData.NetData.ConnectionUnlock(FNetClient);
-          end;
+          Except
+            On E:Exception do begin
+              TLog.NewLog(ltError,ClassName,'Exception destroying TNetConnection '+IntToHex(PtrInt(l_to_del[i]),8)+': ('+E.ClassName+') '+E.Message );
+            end;
+          End;
         end;
       end;
       Sleep(100);

+ 26 - 10
Units/PascalCoin/UNode.pas

@@ -175,15 +175,19 @@ begin
       Result := Bank.AddNewBlockChainBlock(NewBlockOperations,newBlockAccount,errors);
       if Result then begin
         if Assigned(SenderConnection) then begin
-          FNodeLog.NotifyNewLog(ltupdate,SenderConnection.ClassName,Format(';%d;%s;%s',[OpBlock.block,SenderConnection.ClientRemoteAddr,OpBlock.block_payload]));
+          FNodeLog.NotifyNewLog(ltupdate,SenderConnection.ClassName,Format(';%d;%s;%s;;%d;%d;%d',[OpBlock.block,SenderConnection.ClientRemoteAddr,OpBlock.block_payload,
+            OpBlock.timestamp,UnivDateTimeToUnix(DateTime2UnivDateTime(Now)),UnivDateTimeToUnix(DateTime2UnivDateTime(Now)) - OpBlock.timestamp]));
         end else begin
-          FNodeLog.NotifyNewLog(ltupdate,ClassName,Format(';%d;%s;%s',[OpBlock.block,'NIL',OpBlock.block_payload]));
+          FNodeLog.NotifyNewLog(ltupdate,ClassName,Format(';%d;%s;%s;;%d;%d;%d',[OpBlock.block,'NIL',OpBlock.block_payload,
+            OpBlock.timestamp,UnivDateTimeToUnix(DateTime2UnivDateTime(Now)),UnivDateTimeToUnix(DateTime2UnivDateTime(Now)) - OpBlock.timestamp]));
         end;
       end else begin
         if Assigned(SenderConnection) then begin
-          FNodeLog.NotifyNewLog(lterror,SenderConnection.ClassName,Format(';%d;%s;%s;%s',[OpBlock.block,SenderConnection.ClientRemoteAddr,OpBlock.block_payload,errors]));
+          FNodeLog.NotifyNewLog(lterror,SenderConnection.ClassName,Format(';%d;%s;%s;%s;%d;%d;%d',[OpBlock.block,SenderConnection.ClientRemoteAddr,OpBlock.block_payload,errors,
+            OpBlock.timestamp,UnivDateTimeToUnix(DateTime2UnivDateTime(Now)),UnivDateTimeToUnix(DateTime2UnivDateTime(Now)) - OpBlock.timestamp]));
         end else begin
-          FNodeLog.NotifyNewLog(lterror,ClassName,Format(';%d;%s;%s;%s',[OpBlock.block,'NIL',OpBlock.block_payload,errors]));
+          FNodeLog.NotifyNewLog(lterror,ClassName,Format(';%d;%s;%s;%s;%d;%d;%d',[OpBlock.block,'NIL',OpBlock.block_payload,errors,
+            OpBlock.timestamp,UnivDateTimeToUnix(DateTime2UnivDateTime(Now)),UnivDateTimeToUnix(DateTime2UnivDateTime(Now)) - OpBlock.timestamp]));
         end;
       end;
       FOperations.Clear(true);
@@ -207,7 +211,7 @@ begin
     j := TNetData.NetData.ConnectionsCountAll;
     for i:=0 to j-1 do begin
       if (TNetData.NetData.GetConnection(i,nc)) then begin
-        if (nc<>SenderConnection) then TThreadNodeNotifyNewBlock.Create(nc);
+        if (nc<>SenderConnection) And (nc.Connected) then TThreadNodeNotifyNewBlock.Create(nc);
       end;
     end;
     // Notify it!
@@ -302,7 +306,7 @@ begin
     j := TNetData.NetData.ConnectionsCountAll;
     for i:=0 to j-1 do begin
       If TNetData.NetData.GetConnection(i,nc) then begin
-        if (nc<>SenderConnection) then TThreadNodeNotifyOperations.Create(nc,valids_operations);
+        if (nc<>SenderConnection) And (nc.Connected) then TThreadNodeNotifyOperations.Create(nc,valids_operations);
       end;
     end;
   finally
@@ -833,6 +837,7 @@ procedure TThreadNodeNotifyNewBlock.BCExecute;
 begin
   if TNetData.NetData.ConnectionLock(Self,FNetConnection,500) then begin
     try
+      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
@@ -855,11 +860,23 @@ end;
 { TThreadNodeNotifyOperations }
 
 procedure TThreadNodeNotifyOperations.BCExecute;
+Var nOpsCount : Integer;
 begin
+  nOpsCount := FOperationsHashTree.OperationsCount;
+  if nOpsCount<=0 then exit;
   if TNetData.NetData.ConnectionLock(Self, FNetConnection, 500) then begin
     try
-      if FOperationsHashTree.OperationsCount<=0 then exit;
-      TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(FOperationsHashTree.OperationsCount)+' Operations to '+FNetConnection.ClientRemoteAddr);
+      if Not FNetconnection.Connected then exit;
+      nOpsCount := FNetConnection.AddOperationsToBufferForSend(FOperationsHashTree);
+    finally
+      TNetData.NetData.ConnectionUnlock(FNetConnection);
+    end;
+  end;
+  if nOpsCount<=0 then exit;
+  Sleep(Random(5000)); // Delay 0..5 seconds to allow receive data and don't send if not necessary
+  if TNetData.NetData.ConnectionLock(Self, FNetConnection, 500) then begin
+    try
+      if Not FNetconnection.Connected then exit;
       FNetConnection.Send_AddOperations(FOperationsHashTree);
     finally
       TNetData.NetData.ConnectionUnlock(FNetConnection);
@@ -867,8 +884,7 @@ begin
   end;
 end;
 
-constructor TThreadNodeNotifyOperations.Create(NetConnection: TNetConnection;
-  MakeACopyOfOperationsHashTree: TOperationsHashTree);
+constructor TThreadNodeNotifyOperations.Create(NetConnection: TNetConnection; MakeACopyOfOperationsHashTree: TOperationsHashTree);
 begin
   FOperationsHashTree := TOperationsHashTree.Create;
   FOperationsHashTree.CopyFromHashTree(MakeACopyOfOperationsHashTree);

+ 262 - 97
Units/PascalCoin/UPoolMining.pas

@@ -26,7 +26,7 @@ Uses
   {LCLIntf, LCLType, LMessages,}
 {$ENDIF}
   UTCPIP, SysUtils, UThread, SyncObjs, Classes, UJSONFunctions, UAES, UNode,
-  UCrypto, UAccounts, UConst;
+  UCrypto, UAccounts, UConst, UBlockChain;
 
 Const
   CT_PoolMining_Method_STATUS = 'status';
@@ -102,6 +102,19 @@ Type
     Property Stratum_Target_PoW : TRawBytes read FStratum_Target_PoW;
   End;
 
+  TPoolMiningServer = Class;
+
+  TPoolMiningServerThread = Class(TPCThread)
+  private
+    FPoolMiningServer : TPoolMiningServer;
+  protected
+    procedure BCExecute; override;
+  public
+    Constructor Create(APoolMiningServer : TPoolMiningServer);
+    Destructor Destroy; override;
+  End;
+
+
   TPoolMiningServer = Class(TNetTcpIpServer)
   private
     FIncomingsCounter : Integer;
@@ -111,14 +124,17 @@ Type
     FClientsWins: Integer;
     FClientsCount: Integer;
     FOnMiningServerNewBlockFound: TNotifyEvent;
+    FPoolJobs : TPCThreadList;
+    FPoolThread : TPoolMiningServerThread;
     Procedure DoProcessJSON(json : TPCJSONObject; ResponseMethod : String; Client : TJSONRPCTcpIpClient);
     Procedure OnNodeNewBlock(Sender : TObject);
     Procedure OnNodeOperationsChanged(Sender : TObject);
-    Procedure Send_mine_values_to_all;
-    Procedure FillMineValue(mine_values : TPCJSONObject; Client : TJSONRPCTcpIpClient);
     Function MinerSubmit(Client : TJSONRPCTcpIpClient; params : TPCJSONObject; const id : Variant) : Boolean;
     procedure SetMinerAccountKey(const Value: TAccountKey);
     procedure SetMinerPayload(const Value: TRawBytes);
+    Procedure ClearPoolJobs;
+    Procedure CaptureNewJobAndSendToMiners;
+    Procedure SendJobToMiner(Operations : TPCOperationsComp; Client : TJSONRPCTcpIpClient; IsResponse : Boolean; idResponse : Variant);
   protected
     Procedure OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient); override;
     procedure SetActive(const Value: Boolean); override;
@@ -140,7 +156,7 @@ Const
 
 implementation
 
-Uses ULog, Variants, UTime, UBlockChain;
+Uses ULog, Variants, UTime;
 
 Type TPendingResponseMessage = Record
        sendDateTime : TDateTime;
@@ -478,6 +494,89 @@ end;
 
 { TPoolMiningServer }
 
+Const CT_WAIT_SECONDS_BEFORE_SEND_NEW_JOB = 10;
+
+Type
+  TPoolJob = Record
+    OperationsComp : TPCOperationsComp;
+    SentDateTime : TDateTime;
+  End;
+  PPoolJob = ^TPoolJob;
+
+procedure TPoolMiningServer.CaptureNewJobAndSendToMiners;
+Var P : PPoolJob;
+  i : Integer;
+  l : TList;
+  doAdd : Boolean;
+  params : TPCJSONObject;
+  OpB : TOperationBlock;
+begin
+  if Not Active then exit;
+  doAdd := false;
+  l := FPoolJobs.LockList;
+  Try
+    if l.count=0 then doAdd := true
+    else begin
+      P := l[l.Count-1];
+      if (FNodeNotifyEvents.Node.Operations.OperationsHashTree.HashTree<>P^.OperationsComp.OperationsHashTree.HashTree) then begin
+        doAdd := (P^.SentDateTime + EncodeTime(0,0,CT_WAIT_SECONDS_BEFORE_SEND_NEW_JOB,0)) < Now;
+      end;
+    end;
+    P := Nil;
+    if doAdd then begin
+      New(P);
+      P^.SentDateTime := now;
+      P^.OperationsComp := TPCOperationsComp.Create(Nil);
+      P^.OperationsComp.CopyFrom(FNodeNotifyEvents.Node.Operations);
+      P^.OperationsComp.AccountKey := FMinerAccountKey;
+      P^.OperationsComp.BlockPayload := FMinerPayload;
+      OpB := P^.OperationsComp.OperationBlock;
+      if (OpB.block<>0) And (OpB.block <> (FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.block+1)) then begin
+        raise Exception.Create('ERROR DEV 20170228-1');
+      end;
+      l.Add(P);
+    end;
+  Finally
+    FPoolJobs.UnlockList;
+  End;
+  if (doAdd) And (Assigned(P)) then begin
+    params := TPCJSONObject.Create;
+    Try
+      l := NetTcpIpClientsLock;
+      Try
+        for i := 0 to l.Count - 1 do begin
+          if Not Active then exit;
+          SendJobToMiner(P^.OperationsComp,l[i],false,null);
+        end;
+        TLog.NewLog(ltDebug,ClassName,'Sending job to miners: '+TPCOperationsComp.OperationBlockToText(P^.OperationsComp.OperationBlock)+' Cache blocks:'+Inttostr(l.Count));
+      Finally
+        NetTcpIpClientsUnlock;
+      End;
+    Finally
+      params.Free;
+    End;
+  end;
+end;
+
+procedure TPoolMiningServer.ClearPoolJobs;
+Var P : PPoolJob;
+  i : Integer;
+  l : TList;
+begin
+  l := FPoolJobs.LockList;
+  Try
+    for i := l.Count - 1 downto 0 do begin
+      P := l[i];
+      l.Delete(i);
+      P^.OperationsComp.Free;
+      Dispose(P);
+    end;
+    l.Clear;
+  Finally
+    FPoolJobs.UnlockList;
+  End;
+end;
+
 constructor TPoolMiningServer.Create;
 begin
   inherited;
@@ -492,14 +591,22 @@ begin
   FNodeNotifyEvents.OnOperationsChanged := OnNodeOperationsChanged;
   FNodeNotifyEvents.Node := TNode.Node;
   FMinerAccountKey := CT_TECDSA_Public_Nul;
+  FMinerPayload := '';
+  FPoolJobs := TPCThreadList.Create('TPoolMiningServer_PoolJobs');
+  FPoolThread := TPoolMiningServerThread.Create(Self);
 end;
 
 destructor TPoolMiningServer.Destroy;
 begin
+  FPoolThread.Terminate;
+  FPoolThread.WaitFor;
+  FreeAndNil(FPoolThread);
   FNodeNotifyEvents.Node := Nil;
   FNodeNotifyEvents.OnBlocksChanged := Nil;
   FNodeNotifyEvents.OnOperationsChanged := Nil;
   FreeAndNil(FNodeNotifyEvents);
+  ClearPoolJobs;
+  FreeAndNil(FPoolJobs);
   inherited;
 end;
 
@@ -544,13 +651,7 @@ begin
       response_result.Free;
     End;
   end else if method=CT_PoolMining_Method_MINER_NOTIFY then begin
-    response_result := TPCJSONObject.Create;
-    Try
-      FillMineValue(response_result,Client);
-      Client.SendJSONRPCResponse(response_result,id_value);
-    Finally
-      response_result.Free;
-    End;
+    SendJobToMiner(Nil,Client,true,id_value);
   end else if method=CT_PoolMining_Method_MINER_SUBMIT then begin
     // Try to submit a PoW
     if params.Count=1 then MinerSubmit(Client,params.GetAsObject(0),id_value)
@@ -563,41 +664,19 @@ begin
   end;
 end;
 
-procedure TPoolMiningServer.FillMineValue(mine_values: TPCJSONObject; Client : TJSONRPCTcpIpClient);
-Var Op : TPCOperationsComp;
-  ts : Cardinal;
-begin
-  mine_values.GetAsVariant('block').Value := FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.block+1;
-  mine_values.GetAsVariant('version').Value := FNodeNotifyEvents.Node.Operations.OperationBlock.protocol_version;
-  Op := TPCOperationsComp.Create(Nil);
-  try
-    Op.CopyFrom(FNodeNotifyEvents.Node.Operations);
-    Op.AccountKey := FMinerAccountKey;
-    Op.BlockPayload := FMinerPayload;
-    mine_values.GetAsVariant('part1').Value := TCrypto.ToHexaString( Op.PoW_Digest_Part1 );
-    mine_values.GetAsVariant('payload_start').Value := TCrypto.ToHexaString( Op.OperationBlock.block_payload );
-    mine_values.GetAsVariant('part3').Value := TCrypto.ToHexaString( Op.PoW_Digest_Part3 );
-    mine_values.GetAsVariant('target').Value := Op.OperationBlock.compact_target;
-    mine_values.GetAsVariant('target_pow').Value := TCrypto.ToHexaString(FNodeNotifyEvents.Node.Bank.GetActualTargetHash);
-  finally
-    Op.Free;
-  end;
-  // Build 1.4.3 Prevent past time mining
-  ts := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
-  if (ts<FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp) then begin
-    ts := FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp;
-  end;
-  mine_values.GetAsVariant('timestamp').Value := ts;
-end;
-
 function TPoolMiningServer.MinerSubmit(Client: TJSONRPCTcpIpClient; params: TPCJSONObject; const id : Variant): Boolean;
 Var s : String;
   nbOperations : TPCOperationsComp;
   errors : AnsiString;
   nba : TBlockAccount;
-  payload : TRawBytes;
   json : TPCJSONObject;
   p1,p2,p3 : TRawBytes;
+  P : PPoolJob;
+  i : Integer;
+  l : TList;
+  _payloadHexa,_payload : AnsiString;
+  _timestamp, _nOnce : Cardinal;
+  _targetPoW : TRawBytes;
 begin
   { Miner params must submit:
     - "payload" as an Hexadecimal
@@ -609,51 +688,70 @@ begin
     If calculated PoW does not match valid PoW then error
     If all ok... congrats!!! }
   Result := false;
-  nbOperations := TPCOperationsComp.Create(Nil);
-  try
-    nbOperations.bank := FNodeNotifyEvents.Node.Bank;
-    nbOperations.CopyFrom(FNodeNotifyEvents.Node.Operations);
-    nbOperations.AccountKey := MinerAccountKey;
-    s := params.AsString('payload','');
-    payload := TCrypto.HexaToRaw(AnsiString(s));
+  // Must chek on previous sent jobs
+  nbOperations := Nil;
+  Try
+    _payloadHexa := params.AsString('payload','');
+    _payload := TCrypto.HexaToRaw(_payloadHexa);
     if FMinerPayload<>'' then begin
-      if (copy(payload,1,length(FMinerPayload))<>FMinerPayload) then begin
-        Client.SendJSONRPCErrorResponse(id,'Invalid payload ('+payload+'). Need start with: '+FMinerPayload);
+      if (copy(_payload,1,length(FMinerPayload))<>FMinerPayload) then begin
+        if _payload='' then _payload := _payloadHexa;
+        Client.SendJSONRPCErrorResponse(id,'Invalid payload ('+_payload+'). Need start with: '+FMinerPayload);
         exit;
       end;
     end;
-    nbOperations.BlockPayload := payload;
-    nbOperations.timestamp := params.AsCardinal('timestamp',0);
-    nbOperations.nonce := params.AsCardinal('nonce',0);
-    p1 := nbOperations.PoW_Digest_Part1;
-    p2 := nbOperations.PoW_Digest_Part2_Payload;
-    p3 := nbOperations.PoW_Digest_Part3;
-    If FNodeNotifyEvents.Node.AddNewBlockChain(nil,nbOperations,nba,errors) then begin
-      // CONGRATS !!!
-      json := TPCJSONObject.Create;
-      try
-        json.GetAsVariant('block').Value := FNodeNotifyEvents.Node.Bank.LastOperationBlock.block;
-        json.GetAsVariant('pow').Value := TCrypto.ToHexaString( FNodeNotifyEvents.Node.Bank.LastOperationBlock.proof_of_work );
-        json.GetAsVariant('payload').Value := nbOperations.BlockPayload;
-        json.GetAsVariant('timestamp').Value := nbOperations.timestamp;
-        json.GetAsVariant('nonce').Value := nbOperations.nonce;
-        inc(FClientsWins);
-        Client.SendJSONRPCResponse(json,id);
-      finally
-        json.Free;
+    _timestamp := params.AsCardinal('timestamp',0);
+    _nOnce := params.AsCardinal('nonce',0);
+    _targetPoW := FNodeNotifyEvents.Node.Bank.GetActualTargetHash;
+    l := FPoolJobs.LockList;
+    Try
+      i := l.Count-1;
+      while (i>=0) And (Not Assigned(nbOperations)) do begin
+        P := l[i];
+        P^.OperationsComp.BlockPayload := _payload;
+        P^.OperationsComp.timestamp := _timestamp;
+        P^.OperationsComp.nonce := _nOnce;
+        if (P^.OperationsComp.OperationBlock.proof_of_work<=_targetPoW) then begin
+          // Candidate!
+          nbOperations := TPCOperationsComp.Create(Nil);
+          nbOperations.bank := FNodeNotifyEvents.Node.Bank;
+          nbOperations.CopyFrom(P^.OperationsComp);
+          nbOperations.AccountKey := MinerAccountKey;
+        end;
+        dec(i);
+      end;
+    Finally
+      FPoolJobs.UnlockList;
+    End;
+    if Assigned(nbOperations) then begin
+      If FNodeNotifyEvents.Node.AddNewBlockChain(nil,nbOperations,nba,errors) then begin
+        // CONGRATS !!!
+        json := TPCJSONObject.Create;
+        try
+          json.GetAsVariant('block').Value := FNodeNotifyEvents.Node.Bank.LastOperationBlock.block;
+          json.GetAsVariant('pow').Value := TCrypto.ToHexaString( FNodeNotifyEvents.Node.Bank.LastOperationBlock.proof_of_work );
+          json.GetAsVariant('payload').Value := nbOperations.BlockPayload;
+          json.GetAsVariant('timestamp').Value := nbOperations.timestamp;
+          json.GetAsVariant('nonce').Value := nbOperations.nonce;
+          inc(FClientsWins);
+          Client.SendJSONRPCResponse(json,id);
+        finally
+          json.Free;
+        end;
+        if Assigned(FOnMiningServerNewBlockFound) then FOnMiningServerNewBlockFound(Self);
+      end else begin
+        Client.SendJSONRPCErrorResponse(id,'Error: '+errors+' payload:'+nbOperations.BlockPayload+' timestamp:'+InttoStr(nbOperations.timestamp)+' nonce:'+IntToStr(nbOperations.nonce));
       end;
-      if Assigned(FOnMiningServerNewBlockFound) then FOnMiningServerNewBlockFound(Self);
     end else begin
-      Client.SendJSONRPCErrorResponse(id,'Error: '+errors+' payload:'+nbOperations.BlockPayload+' timestamp:'+InttoStr(nbOperations.timestamp)+' nonce:'+IntToStr(nbOperations.nonce));
+      Client.SendJSONRPCErrorResponse(id,'Error: No valid job found with these values! payload:'+_payload+' timestamp:'+InttoStr(_timestamp)+' nonce:'+IntToStr(_nonce));
     end;
-  finally
-    nbOperations.Free;
-  end;
+  Finally
+    if Assigned(nbOperations) then nbOperations.Free;
+  End;
 end;
 
 procedure TPoolMiningServer.OnNewIncommingConnection(Sender: TObject; Client: TNetTcpIpClient);
 var bClient : TJSONRPCTcpIpClient;
-  init_json : TPCJSONObject;
   jsonobj : TPCJSONObject;
   doDelete : Boolean;
   rmethod : String;
@@ -664,13 +762,7 @@ begin
     TLog.NewLog(ltinfo,ClassName,'New Mining Pool Connection: '+Client.ClientRemoteAddr);
     bClient := TJSONRPCTcpIpClient(Client);
     inc(FIncomingsCounter);
-    init_json := TPCJSONObject.Create;
-    Try
-      FillMineValue(init_json,bClient);
-      bClient.SendJSONRPCMethod(CT_PoolMining_Method_MINER_NOTIFY,init_json,null);
-    Finally
-      init_json.Free;
-    End;
+    SendJobToMiner(nil,bClient,false,null);
     while (Active) And (Client.Connected) do begin
       doDelete := bClient.LastReadTC+1000<GetTickCount;  // TODO: Protect GetTickCount overflow
       jsonobj := TPCJSONObject.Create;
@@ -691,33 +783,78 @@ end;
 
 procedure TPoolMiningServer.OnNodeNewBlock(Sender: TObject);
 begin
-  // Send mine values to all clients
-  Send_mine_values_to_all;
+  // Delete Jobs cache, because a new block was found prior to us
+  ClearPoolJobs;
+  CaptureNewJobAndSendToMiners;
 end;
 
 procedure TPoolMiningServer.OnNodeOperationsChanged(Sender: TObject);
 begin
-  // Send mine values to all clients
-  Send_mine_values_to_all;
+  CaptureNewJobAndSendToMiners;
 end;
 
-procedure TPoolMiningServer.Send_mine_values_to_all;
+procedure TPoolMiningServer.SendJobToMiner(Operations: TPCOperationsComp; Client: TJSONRPCTcpIpClient; IsResponse : Boolean; idResponse : Variant);
 var params : TPCJSONObject;
-  i : Integer;
+  ts : Cardinal;
+Var P : PPoolJob;
+  i,nJobs : Integer;
   l : TList;
 begin
-  params := TPCJSONObject.Create;
-  Try
-    l := NetTcpIpClientsLock;
+  if (Not Assigned(Operations)) then begin
+    P := Nil;
+    l := FPoolJobs.LockList;
     Try
-      for i := 0 to l.Count - 1 do begin
-        if Not Active then exit;
-        FillMineValue(params,TJSONRPCTcpIpClient(l[i]));
-        TJSONRPCTcpIpClient(l[i]).SendJSONRPCMethod(CT_PoolMining_Method_MINER_NOTIFY,params,Null);
+      if l.count>0 then P := l[l.Count-1] // The last
+      else begin
+        TLog.NewLog(ltInfo,ClassName,'Creating new job for miner');
+        New(P);
+        P^.SentDateTime := now;
+        P^.OperationsComp := TPCOperationsComp.Create(Nil);
+        P^.OperationsComp.CopyFrom(FNodeNotifyEvents.Node.Operations);
+        P^.OperationsComp.AccountKey := FMinerAccountKey;
+        P^.OperationsComp.BlockPayload := FMinerPayload;
+        if (P^.OperationsComp.OperationBlock.block<>0) And (P^.OperationsComp.OperationBlock.block <> (FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.block+1)) then begin
+          raise Exception.Create('ERROR DEV 20170228-2');
+        end;
+        l.Add(P);
       end;
     Finally
-      NetTcpIpClientsUnlock;
+      FPoolJobs.UnlockList;
     End;
+    Operations := P^.OperationsComp;
+  end;
+  l := FPoolJobs.LockList;
+  Try
+    nJobs := l.Count;
+  Finally
+    FPoolJobs.UnlockList;
+  End;
+  params := TPCJSONObject.Create;
+  Try
+    if Not Active then exit;
+    params.GetAsVariant('block').Value := Operations.OperationBlock.block;
+    params.GetAsVariant('version').Value := Operations.OperationBlock.protocol_version;
+    params.GetAsVariant('part1').Value := TCrypto.ToHexaString( Operations.PoW_Digest_Part1 );
+    params.GetAsVariant('payload_start').Value := TCrypto.ToHexaString( Operations.OperationBlock.block_payload );
+    params.GetAsVariant('part3').Value := TCrypto.ToHexaString( Operations.PoW_Digest_Part3 );
+    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));
+    if (ts<FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp) then begin
+      ts := FNodeNotifyEvents.Node.Bank.LastBlockFound.OperationBlock.timestamp;
+    end;
+    params.GetAsVariant('timestamp').Value := ts;
+
+    if IsResponse then begin
+      Client.SendJSONRPCResponse(params,idResponse);
+    end else begin
+      Client.SendJSONRPCMethod(CT_PoolMining_Method_MINER_NOTIFY,params,Null);
+    end;
+
+    TLog.NewLog(ltInfo,ClassName,
+      Format('Sending job %d to miner - Block:%d Ops:%d Target:%s PayloadStart:%s',
+      [nJobs,Operations.OperationBlock.block,Operations.Count,IntToHex(Operations.OperationBlock.compact_target,8),Operations.OperationBlock.block_payload]));
   Finally
     params.Free;
   End;
@@ -734,16 +871,17 @@ end;
 
 procedure TPoolMiningServer.SetMinerAccountKey(const Value: TAccountKey);
 begin
+  if TAccountComp.Equal(FMinerAccountKey,Value) then exit;
   FMinerAccountKey := Value;
   TLog.NewLog(ltdebug,ClassName,'Assigning Miner account key to: '+TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(Value)));
-  Send_mine_values_to_all;
+  CaptureNewJobAndSendToMiners;
 end;
 
 procedure TPoolMiningServer.SetMinerPayload(const Value: TRawBytes);
 begin
   FMinerPayload := Value;
   TLog.NewLog(ltdebug,ClassName,'Assigning Miner new Payload: '+TCrypto.ToHexaString(Value));
-  Send_mine_values_to_all;
+  CaptureNewJobAndSendToMiners;
 end;
 
 procedure TPoolMiningServer.UpdateAccountAndPayload(
@@ -753,7 +891,7 @@ begin
   TLog.NewLog(ltdebug,ClassName,'Assigning Miner account key to: '+TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(AMinerAccountKey)));
   FMinerPayload := AMinerPayload;
   TLog.NewLog(ltdebug,ClassName,'Assigning Miner new Payload: '+TCrypto.ToHexaString(AMinerPayload));
-  Send_mine_values_to_all;
+  CaptureNewJobAndSendToMiners;
 end;
 
 { TPoolMinerClient }
@@ -950,4 +1088,31 @@ begin
   End;
 end;
 
+{ TPoolMiningServerThread }
+
+procedure TPoolMiningServerThread.BCExecute;
+Var i : Integer;
+begin
+  i := 0;
+  Repeat
+    Sleep(100);
+    inc(i);
+    if (not terminated) And ((i mod 10)=0) then begin
+      FPoolMiningServer.CaptureNewJobAndSendToMiners;
+    end;
+  Until terminated;
+end;
+
+constructor TPoolMiningServerThread.Create(APoolMiningServer: TPoolMiningServer);
+begin
+  FPoolMiningServer := APoolMiningServer;
+  inherited Create(false);
+end;
+
+destructor TPoolMiningServerThread.Destroy;
+begin
+
+  inherited;
+end;
+
 end.

+ 17 - 5
Units/PascalCoin/UTCPIP.pas

@@ -154,6 +154,8 @@ type
   End;
   {$ENDIF}
 
+  { TNetTcpIpServer }
+
   TNetTcpIpServer = Class(TObject)
   private
     {$IFDEF DelphiSockets}
@@ -175,12 +177,13 @@ type
   protected
     Procedure OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient); virtual;
     procedure SetActive(const Value: Boolean); virtual;
+    procedure SetMaxConnections(AValue: Integer); virtual;
   public
     Constructor Create; virtual;
     Destructor Destroy; override;
     Property Active : Boolean read GetActive write SetActive;
     Property Port : Word read GetPort Write SetPort;
-    Property MaxConnections : Integer read FMaxConnections Write FMaxConnections;
+    Property MaxConnections : Integer read FMaxConnections Write SetMaxConnections;
     Property NetTcpIpClientClass : TNetTcpIpClientClass read FNetTcpIpClientClass write SetNetTcpIpClientClass;
     Function NetTcpIpClientsLock : TList;
     Procedure NetTcpIpClientsUnlock;
@@ -337,6 +340,7 @@ Begin
     Except
       On E:Exception do begin
         SocketError := FTcpBlockSocket.LastError;
+        HasData := false;
         TLog.NewLog(lterror,ClassName,'Error WaitingForData from '+ClientRemoteAddr+': '+FTcpBlockSocket.GetErrorDescEx);
         Disconnect;
       end;
@@ -390,12 +394,13 @@ begin
       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);
+        Result := 0;
         Disconnect;
       end else if Result>0 then inc(FBytesReceived,Result);
     Except
       On E:Exception do begin
         SocketError := FTcpBlockSocket.LastError;
-        TLog.NewLog(lterror,ClassName,'Exception receiving buffer from '+ClientRemoteAddr+' '+FTcpBlockSocket.GetErrorDescEx);
+        TLog.NewLog(lterror,ClassName,'Exception receiving buffer from '+ClientRemoteAddr+' '+FTcpBlockSocket.GetErrorDescEx+' ('+E.ClassName+'):'+E.Message);
         Disconnect;
       end;
     End;
@@ -516,11 +521,12 @@ var SendBuffStream : TStream;
         if last_bytes_read<>0 then begin
           // This is to prevent a 4096 buffer transmission only... and a loop
           If Not FBufferedNetTcpIpClient.DoWaitForDataInherited(10) then begin
-            if FBufferedNetTcpIpClient.SocketError<>0 then FBufferedNetTcpIpClient.Disconnect
-            else exit;
+            if FBufferedNetTcpIpClient.SocketError<>0 then FBufferedNetTcpIpClient.Disconnect;
+            exit;
           end;
         end;
 
+
         last_bytes_read := FBufferedNetTcpIpClient.ReceiveBuf(ReceiveBuffer,sizeof(ReceiveBuffer));
         if (last_bytes_read>0) then begin
           ms := FBufferedNetTcpIpClient.ReadBufferLock;
@@ -661,7 +667,7 @@ constructor TNetTcpIpServer.Create;
 begin
   FNetTcpIpClientClass := TNetTcpIpClient;
   FTcpIpServer := Nil;
-  FMaxConnections := 10;
+  FMaxConnections := CT_MaxClientsConnected;
   {$IFDEF DelphiSockets}
   FTcpIpServer := TTcpServer.Create(Nil);
   FTcpIpServer.OnAccept := OnTcpServerAccept;
@@ -691,6 +697,12 @@ begin
   {$ENDIF}
 end;
 
+procedure TNetTcpIpServer.SetMaxConnections(AValue: Integer);
+begin
+  if FMaxConnections=AValue then Exit;
+  FMaxConnections:=AValue;
+end;
+
 function TNetTcpIpServer.GetPort: Word;
 begin
   {$IFDEF DelphiSockets}

+ 4 - 0
Units/PascalCoin/upcdaemon.pas

@@ -26,6 +26,8 @@ uses
 Const
   CT_INI_SECTION_GLOBAL = 'GLOBAL';
   CT_INI_IDENT_SAVELOGS = 'SAVELOGS';
+  CT_INI_IDENT_NODE_PORT = 'NODE_PORT';
+  CT_INI_IDENT_NODE_MAX_CONNECTIONS = 'NODE_MAX_CONNECTIONS';
   CT_INI_IDENT_RPC_PORT = 'RPC_PORT';
   CT_INI_IDENT_RPC_WHITELIST = 'RPC_WHITELIST';
   CT_INI_IDENT_RPC_SAVELOGS = 'RPC_SAVELOGS';
@@ -201,6 +203,8 @@ begin
         // Reading database
         FNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
         FWalletKeys.SafeBox := FNode.Node.Bank.SafeBox;
+        FNode.Node.NetServer.Port:=FIniFile.ReadInteger(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_NODE_PORT,CT_NetServer_Port);
+        FNode.Node.NetServer.MaxConnections:=FIniFile.ReadInteger(CT_INI_SECTION_GLOBAL,CT_INI_IDENT_NODE_MAX_CONNECTIONS,CT_MaxClientsConnected);
         FNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
         FNode.Node.NetServer.Active := true;
 

+ 5 - 1
Units/Utils/UAppParams.pas

@@ -477,7 +477,11 @@ begin
     else fm := fmCreate;
 
     FParamsStream := TFileStream.Create(Value,fm+fmShareExclusive);
-    LoadFromStream(FParamsStream);
+    Try
+      LoadFromStream(FParamsStream);
+    Except
+      // Do nothing
+    End;
   end;
 end;
 

+ 6 - 0
pascalcoin_daemon.ini

@@ -2,6 +2,12 @@
 ;SAVELOGS : Boolean
 ;If 1 (true) logs will be saved to a file at $HOME/PascalCoin
 SAVELOGS=0
+;NODE_PORT : Integer (Default 4004)
+;Port P2P of PascalCoin
+NODE_PORT=4004
+;NODE_MAX_CONNECTIONS : Integer (Default 100)
+;Max node connections P2P
+NODE_MAX_CONNECTIONS=100
 ;RPC_PORT : Integer (Default 4003)
 ;Port to use by TCP/IP JSON-RPC commands
 RPC_PORT=4003