Browse Source

Build 1.0.4 Release Candidate

PascalCoin 9 years ago
parent
commit
4f438ef96c

+ 2 - 5
Units/Forms/UFRMAbout.pas

@@ -52,11 +52,8 @@ Var fvi : TFileVersionInfo;
 begin
 begin
   fvi := TFolderHelper.GetTFileVersionInfo(Application.ExeName);
   fvi := TFolderHelper.GetTFileVersionInfo(Application.ExeName);
   lblBuild.Caption :=  'Build: '+fvi.FileVersion;
   lblBuild.Caption :=  'Build: '+fvi.FileVersion;
-  if CT_Protocol_Available>0 then begin
-    lblProtocolVersion.Caption := Format('Protocol: %d (Available: %d)',[CT_Protocol_Version,CT_Protocol_Available]);
-  end else begin
-    lblProtocolVersion.Caption := Format('Protocol: %d',[CT_Protocol_Version]);
-  end;
+  lblProtocolVersion.Caption := Format('BlockChain Protocol: %d (%d)  -  Net Protocol: %d (%d)',[CT_BlockChain_Protocol_Version,CT_BlockChain_Protocol_Available,
+    CT_NetProtocol_Version, CT_NetProtocol_Available]);
 end;
 end;
 
 
 procedure TFRMAbout.Label4Click(Sender: TObject);
 procedure TFRMAbout.Label4Click(Sender: TObject);

+ 4 - 0
Units/Forms/UFRMOperation.dfm

@@ -444,6 +444,10 @@ object FRMOperation: TFRMOperation
     object tsGlobalError: TTabSheet
     object tsGlobalError: TTabSheet
       ImageIndex = 1
       ImageIndex = 1
       TabVisible = False
       TabVisible = False
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object lblGlobalErrors: TLabel
       object lblGlobalErrors: TLabel
         Left = 40
         Left = 40
         Top = 50
         Top = 50

+ 3 - 2
Units/Forms/UFRMOperation.pas

@@ -300,7 +300,7 @@ end;
 procedure TFRMOperation.FormDestroy(Sender: TObject);
 procedure TFRMOperation.FormDestroy(Sender: TObject);
 begin
 begin
   if Assigned(FPAccount) then Dispose(FPAccount);
   if Assigned(FPAccount) then Dispose(FPAccount);
-  if assigned(FOperation) then FOperation.Free;
+  FreeAndNil(FOperation);
 end;
 end;
 
 
 function TFRMOperation.GetSenderAcccount: PAccount;
 function TFRMOperation.GetSenderAcccount: PAccount;
@@ -346,8 +346,9 @@ end;
 procedure TFRMOperation.SetSenderAccount(const Value: Cardinal);
 procedure TFRMOperation.SetSenderAccount(const Value: Cardinal);
 begin
 begin
   if FSenderAccount=Value then exit;
   if FSenderAccount=Value then exit;
+  if Value>TNode.Node.Bank.AccountsCount-1 then FSenderAccount := 0
+  else FSenderAccount := Value;
 
 
-  FSenderAccount := Value;
   if Assigned(FPAccount) then begin
   if Assigned(FPAccount) then begin
     Dispose(FPAccount);
     Dispose(FPAccount);
     FPAccount := Nil;
     FPAccount := Nil;

+ 2 - 10
Units/Forms/UFRMWallet.dfm

@@ -375,16 +375,12 @@ object FRMWallet: TFRMWallet
     Top = 91
     Top = 91
     Width = 899
     Width = 899
     Height = 448
     Height = 448
-    ActivePage = tsNodeStats
+    ActivePage = tsAccountsExplorer
     Align = alClient
     Align = alClient
     TabOrder = 2
     TabOrder = 2
     OnChange = PageControlChange
     OnChange = PageControlChange
     object tsAccountsExplorer: TTabSheet
     object tsAccountsExplorer: TTabSheet
       Caption = 'Accounts Explorer'
       Caption = 'Accounts Explorer'
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       object Splitter1: TSplitter
       object Splitter1: TSplitter
         Left = 380
         Left = 380
         Top = 66
         Top = 66
@@ -849,10 +845,6 @@ object FRMWallet: TFRMWallet
     object tsMessages: TTabSheet
     object tsMessages: TTabSheet
       Caption = 'Messages'
       Caption = 'Messages'
       ImageIndex = 6
       ImageIndex = 6
-      ExplicitLeft = 0
-      ExplicitTop = 0
-      ExplicitWidth = 0
-      ExplicitHeight = 0
       DesignSize = (
       DesignSize = (
         891
         891
         420)
         420)
@@ -1039,7 +1031,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Left = 105
     Top = 180
     Top = 180
     Bitmap = {
     Bitmap = {
-      494C010102000800C40010003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000800E40010003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 23 - 20
Units/Forms/UFRMWallet.pas

@@ -254,7 +254,7 @@ begin
   TNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
   TNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
   TNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
   TNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
   TNode.Node.NetServer.Active := true;
   TNode.Node.NetServer.Active := true;
-  FRMWallet.UpdateAccounts;
+  Synchronize( FRMWallet.UpdateAccounts );
 end;
 end;
 
 
 { TFRMWallet }
 { TFRMWallet }
@@ -466,7 +466,7 @@ begin
       // Build 1.0.2 allows mine if there was at least 1 client connection (working as a server)
       // 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)
       // or (new) there are 2 active connections to a servers (allowing non servers to mine too)
       ( (TNetData.NetData.NetStatistics.TotalClientsConnections>0)
       ( (TNetData.NetData.NetStatistics.TotalClientsConnections>0)
-        Or (TNetData.NetData.NetStatistics.ServersConnections>=2) ) And
+        Or (TNetData.NetData.NetStatistics.ServersConnectionsWithResponse>=2) ) And
       (TNetData.NetData.MaxRemoteOperationBlock.block<=FNode.Operations.OperationBlock.block)
       (TNetData.NetData.MaxRemoteOperationBlock.block<=FNode.Operations.OperationBlock.block)
     ) then begin
     ) then begin
     if (cbAllowMining.checked) Or (ForceMining) then begin
     if (cbAllowMining.checked) Or (ForceMining) then begin
@@ -728,15 +728,15 @@ begin
   Until i<0;
   Until i<0;
 
 
   step := 'Destroying NodeNotifyEvents';
   step := 'Destroying NodeNotifyEvents';
-  FNodeNotifyEvents.Free;
+  FreeAndNil(FNodeNotifyEvents);
   //
   //
   step := 'Assigning Nil to TNetData';
   step := 'Assigning Nil to TNetData';
   TNetData.NetData.OnReceivedHelloMessage := Nil;
   TNetData.NetData.OnReceivedHelloMessage := Nil;
   TNetData.NetData.OnStatisticsChanged := Nil;
   TNetData.NetData.OnStatisticsChanged := Nil;
 
 
   step := 'Destroying grids operators';
   step := 'Destroying grids operators';
-  FOperationsDBGrid.Free;
-  FBlockChainDBGrid.Free;
+  FreeAndNil(FOperationsDBGrid);
+  FreeAndNil(FBlockChainDBGrid);
 
 
   step := 'Ordered Accounts Key list';
   step := 'Ordered Accounts Key list';
   FreeAndNil(FOrderedAccountsKeyList);
   FreeAndNil(FOrderedAccountsKeyList);
@@ -753,7 +753,7 @@ begin
   TNode.Node.Free;
   TNode.Node.Free;
 
 
   step := 'Destroying Wallet';
   step := 'Destroying Wallet';
-  FWalletKeys.Free;
+  FreeAndNil(FWalletKeys);
   step := 'Processing messages 2';
   step := 'Processing messages 2';
   Application.ProcessMessages;
   Application.ProcessMessages;
   step := 'Destroying stringslist';
   step := 'Destroying stringslist';
@@ -954,33 +954,36 @@ begin
     Try
     Try
       for i := 0 to l.Count - 1 do begin
       for i := 0 to l.Count - 1 do begin
         NC := l[i];
         NC := l[i];
-        if (NC.ClientAppVersion='') then sClientApp:='(old version)'
-        else sClientApp := 'Version:'+NC.ClientAppVersion;
+        If NC.Client.BytesReceived>0 then begin
+          sClientApp := '['+IntToStr(NC.NetProtocolVersion.protocol_version)+'-'+IntToStr(NC.NetProtocolVersion.protocol_available)+'] '+NC.ClientAppVersion;
+        end else begin
+          sClientApp := '(no data)';
+        end;
 
 
         if NC.Connected then begin
         if NC.Connected then begin
           if NC is TNetServerClient then begin
           if NC is TNetServerClient then begin
-            sNSC.Add(Format('Client: IP:%s:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
+            sNSC.Add(Format('Client: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
+              [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
           end else begin
           end else begin
-            if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]))
+            if NC.IsMyselfServer then sNSC.Add(Format('MySelf IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
+              [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]))
             else begin
             else begin
-              sRS.Add(Format('Remote Server: IP:%s:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
-              [NC.Client.RemoteHost,NC.Client.RemotePort,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
+              sRS.Add(Format('Remote Server: IP:%s Sent/Received:%d/%d Bytes - %s - Active since %s',
+              [NC.ClientRemoteAddr,NC.Client.BytesSent,NC.Client.BytesReceived,sClientApp,DateTimeElapsedTime(NC.CreatedTime)]));
             end;
             end;
           end;
           end;
         end else begin
         end else begin
           if NC is TNetServerClient then begin
           if NC is TNetServerClient then begin
-            sDisc.Add(Format('Disconnected client: IP:%s:%s',[NC.Client.RemoteHost,NC.Client.RemotePort]));
+            sDisc.Add(Format('Disconnected client: IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
           end else if NC.IsMyselfServer then begin
           end else if NC.IsMyselfServer then begin
-            sDisc.Add(Format('Disconnected MySelf IP:%s:%s',[NC.Client.RemoteHost,NC.Client.RemotePort]));
+            sDisc.Add(Format('Disconnected MySelf IP:%s - %s',[NC.ClientRemoteAddr,sClientApp]));
           end else begin
           end else begin
-            sDisc.Add(Format('Disconnected Remote Server: IP:%s:%s',[NC.Client.RemoteHost,NC.Client.RemotePort,CT_BooleanToString[NC.Connected]]));
+            sDisc.Add(Format('Disconnected Remote Server: IP:%s %s - %s',[NC.ClientRemoteAddr,CT_BooleanToString[NC.Connected],sClientApp]));
           end;
           end;
         end;
         end;
       end;
       end;
       strings.Clear;
       strings.Clear;
-      strings.Add(Format('Connections Updated %s Clients:%d Servers:%d',[DateTimeToStr(now),sNSC.Count,sRS.Count]));
+      strings.Add(Format('Connections Updated %s Clients:%d Servers:%d (valid servers:%d)',[DateTimeToStr(now),sNSC.Count,sRS.Count,TNetData.NetData.NetStatistics.ServersConnectionsWithResponse]));
       strings.AddStrings(sRS);
       strings.AddStrings(sRS);
       strings.AddStrings(sNSC);
       strings.AddStrings(sNSC);
       if sDisc.Count>0 then begin
       if sDisc.Count>0 then begin
@@ -1049,8 +1052,8 @@ begin
       StatusBar.Panels[0].Text := 'Active (Port '+Inttostr(FNode.NetServer.Port)+')';
       StatusBar.Panels[0].Text := 'Active (Port '+Inttostr(FNode.NetServer.Port)+')';
     end else StatusBar.Panels[0].Text := 'Server stopped';
     end else StatusBar.Panels[0].Text := 'Server stopped';
     NS := TNetData.NetData.NetStatistics;
     NS := TNetData.NetData.NetStatistics;
-    StatusBar.Panels[1].Text := Format('Connections:%d Clients:%d Servers:%d - Rcvd:%d Bytes Send:%d Bytes',
-      [NS.ActiveConnections,NS.ClientsConnections,NS.ServersConnections,NS.BytesReceived,NS.BytesSend]);
+    StatusBar.Panels[1].Text := Format('Connections:%d Clients:%d Servers:%d - Rcvd:%d Kb Send:%d Kb',
+      [NS.ActiveConnections,NS.ClientsConnections,NS.ServersConnections,NS.BytesReceived DIV 1024,NS.BytesSend DIV 1024]);
   end else begin
   end else begin
     StatusBar.Panels[0].Text := '';
     StatusBar.Panels[0].Text := '';
     StatusBar.Panels[1].Text := '';
     StatusBar.Panels[1].Text := '';

+ 8 - 8
Units/PascalCoin/UAccounts.pas

@@ -720,8 +720,8 @@ begin
   for i := 0 to FListOfOrderedAccountKeysList.Count - 1 do begin
   for i := 0 to FListOfOrderedAccountKeysList.Count - 1 do begin
     TOrderedAccountKeysList( FListOfOrderedAccountKeysList[i] ).FAccountList := Nil;
     TOrderedAccountKeysList( FListOfOrderedAccountKeysList[i] ).FAccountList := Nil;
   end;
   end;
-  FBlockAccountsList.Free;
-  FListOfOrderedAccountKeysList.Free;
+  FreeAndNil(FBlockAccountsList);
+  FreeAndNil(FListOfOrderedAccountKeysList);
   DeleteCriticalSection(Flock);
   DeleteCriticalSection(Flock);
   inherited;
   inherited;
 end;
 end;
@@ -750,7 +750,7 @@ begin
     errors := 'Invalid version or corrupted stream';
     errors := 'Invalid version or corrupted stream';
     if Stream.Size<8 then exit;
     if Stream.Size<8 then exit;
     Stream.Read(w,2);
     Stream.Read(w,2);
-    if w<>CT_Protocol_Version then exit;
+    if w<>CT_BlockChain_Protocol_Version then exit;
     Stream.Read(w,2); // protocol version available, nothing to do with it
     Stream.Read(w,2); // protocol version available, nothing to do with it
     Stream.Read(blockscount,4);
     Stream.Read(blockscount,4);
     if blockscount>(CT_NewLineSecondsAvg*2000000) then exit; // Protection for corrupted data...
     if blockscount>(CT_NewLineSecondsAvg*2000000) then exit; // Protection for corrupted data...
@@ -803,8 +803,8 @@ Var
   b : TBlockAccount;
   b : TBlockAccount;
 begin
 begin
   TStreamOp.WriteAnsiString(Stream,CT_MagicIdentificator);
   TStreamOp.WriteAnsiString(Stream,CT_MagicIdentificator);
-  Stream.Write(CT_Protocol_Version,SizeOf(CT_Protocol_Version));
-  Stream.Write(CT_Protocol_Available,SizeOf(CT_Protocol_Available));
+  Stream.Write(CT_BlockChain_Protocol_Version,SizeOf(CT_BlockChain_Protocol_Version));
+  Stream.Write(CT_BlockChain_Protocol_Available,SizeOf(CT_BlockChain_Protocol_Available));
   c := BlocksCount;
   c := BlocksCount;
   Stream.Write(c,Sizeof(c));
   Stream.Write(c,Sizeof(c));
   for iblock := 0 to c-1 do begin
   for iblock := 0 to c-1 do begin
@@ -952,7 +952,7 @@ end;
 destructor TPCSafeBoxTransaction.Destroy;
 destructor TPCSafeBoxTransaction.Destroy;
 begin
 begin
   CleanTransaction;
   CleanTransaction;
-  FOrderedList.Free;
+  FreeAndNil(FOrderedList);
   inherited;
   inherited;
 end;
 end;
 
 
@@ -1105,7 +1105,7 @@ end;
 destructor TOrderedAccountList.Destroy;
 destructor TOrderedAccountList.Destroy;
 begin
 begin
   Clear;
   Clear;
-  FList.Free;
+  FreeAndNil(FList);
   inherited;
   inherited;
 end;
 end;
 
 
@@ -1244,7 +1244,7 @@ begin
     FAccountList.FListOfOrderedAccountKeysList.Remove(Self);
     FAccountList.FListOfOrderedAccountKeysList.Remove(Self);
   end;
   end;
   Clear(true);
   Clear(true);
-  FOrderedAccountKeysList.Free;
+  FreeAndNil(FOrderedAccountKeysList);
   inherited;
   inherited;
 end;
 end;
 
 

+ 138 - 71
Units/PascalCoin/UBlockChain.pas

@@ -192,6 +192,7 @@ Type
     Destructor Destroy; Override;
     Destructor Destroy; Override;
     Procedure CopyFromExceptAddressKey(Operations : TPCOperationsComp);
     Procedure CopyFromExceptAddressKey(Operations : TPCOperationsComp);
     Function CopyFromAndValidate(Operations : TPCOperationsComp; var errors : AnsiString) : Boolean;
     Function CopyFromAndValidate(Operations : TPCOperationsComp; var errors : AnsiString) : Boolean;
+    Procedure CopyFrom(Operations : TPCOperationsComp);
     Function AddOperation(Execute : Boolean; op: TPCOperation; var errors: AnsiString): Boolean;
     Function AddOperation(Execute : Boolean; op: TPCOperation; var errors: AnsiString): Boolean;
     Function AddOperations(operations: TOperationsHashTree; var errors: AnsiString): Integer;
     Function AddOperations(operations: TOperationsHashTree; var errors: AnsiString): Integer;
     Property Operation[index: Integer]: TPCOperation read GetOperation;
     Property Operation[index: Integer]: TPCOperation read GetOperation;
@@ -206,8 +207,8 @@ Type
     Property BlockPayload : TRawBytes read GetBlockPayload write SetBlockPayload;
     Property BlockPayload : TRawBytes read GetBlockPayload write SetBlockPayload;
     Function IncrementNOnce: Boolean;
     Function IncrementNOnce: Boolean;
     procedure UpdateTimestamp;
     procedure UpdateTimestamp;
-    function SaveToStream(save_header, save_only_OperationBlock : Boolean; Stream: TStream): Boolean;
-    function LoadFromStream(ExecuteOperations : Boolean; load_header : Boolean; Stream: TStream; var errors: AnsiString): Boolean;
+    function SaveBlockToStream(save_only_OperationBlock : Boolean; Stream: TStream): Boolean;
+    function LoadBlockFromStream(Stream: TStream; var errors: AnsiString): Boolean;
     //
     //
     Function ValidateOperationBlock(var errors : AnsiString) : Boolean;
     Function ValidateOperationBlock(var errors : AnsiString) : Boolean;
     Property IsOnlyOperationBlock : Boolean read FIsOnlyOperationBlock;
     Property IsOnlyOperationBlock : Boolean read FIsOnlyOperationBlock;
@@ -219,6 +220,7 @@ Type
     Class Function IndexOfOperationClassByOpType(OpType: Cardinal): Integer;
     Class Function IndexOfOperationClassByOpType(OpType: Cardinal): Integer;
     Class Function GetOperationClassByOpType(OpType: Cardinal): TPCOperationClass;
     Class Function GetOperationClassByOpType(OpType: Cardinal): TPCOperationClass;
     Class Function GetFirstBlock : TOperationBlock;
     Class Function GetFirstBlock : TOperationBlock;
+    Class Function EqualsOperationBlock(Const OperationBlock1,OperationBlock2 : TOperationBlock):Boolean;
     //
     //
     Property SafeBoxTransaction : TPCSafeBoxTransaction read FSafeBoxTransaction;
     Property SafeBoxTransaction : TPCSafeBoxTransaction read FSafeBoxTransaction;
     Property OperationsHashTree : TOperationsHashTree read FOperationsHashTree;
     Property OperationsHashTree : TOperationsHashTree read FOperationsHashTree;
@@ -276,6 +278,7 @@ Type
   private
   private
     FStorage : TStorage;
     FStorage : TStorage;
     FSafeBox: TPCSafeBox;
     FSafeBox: TPCSafeBox;
+    FLastBlockCache : TPCOperationsComp;
     FLastOperationBlock: TOperationBlock;
     FLastOperationBlock: TOperationBlock;
     FInitialSafeBoxHash: TRawBytes;
     FInitialSafeBoxHash: TRawBytes;
     FActualTargetHash: TRawBytes;
     FActualTargetHash: TRawBytes;
@@ -286,6 +289,8 @@ Type
     FStorageClass: TStorageClass;
     FStorageClass: TStorageClass;
     function GetStorage: TStorage;
     function GetStorage: TStorage;
     procedure SetStorageClass(const Value: TStorageClass);
     procedure SetStorageClass(const Value: TStorageClass);
+//    function LoadFromStream(Stream: TStream; var errors: AnsiString): Boolean;
+//    procedure SaveToStream(Stream: TStream);
   protected
   protected
   public
   public
     Constructor Create(AOwner: TComponent); Override;
     Constructor Create(AOwner: TComponent); Override;
@@ -300,8 +305,8 @@ Type
     Function GetActualCompactTargetHash: Cardinal;
     Function GetActualCompactTargetHash: Cardinal;
     function GetActualTargetHash: AnsiString;
     function GetActualTargetHash: AnsiString;
     function GetActualTargetSecondsAverage(BackBlocks : Cardinal): Real;
     function GetActualTargetSecondsAverage(BackBlocks : Cardinal): Real;
-    function LoadFromStream(Stream : TStream; var errors : AnsiString) : Boolean;
-    Procedure SaveToStream(Stream : TStream);
+    function LoadBankFromStream(Stream : TStream; var errors : AnsiString) : Boolean;
+    Procedure SaveBankToStream(Stream : TStream);
     Procedure Clear;
     Procedure Clear;
     Function LoadOperations(Operations : TPCOperationsComp; Block : Cardinal) : Boolean;
     Function LoadOperations(Operations : TPCOperationsComp; Block : Cardinal) : Boolean;
     Property SafeBox : TPCSafeBox read FSafeBox;
     Property SafeBox : TPCSafeBox read FSafeBox;
@@ -313,6 +318,7 @@ Type
     Property Storage : TStorage read GetStorage;
     Property Storage : TStorage read GetStorage;
     Property StorageClass : TStorageClass read FStorageClass write SetStorageClass;
     Property StorageClass : TStorageClass read FStorageClass write SetStorageClass;
     Function IsReady(Var CurrentProcess : AnsiString) : Boolean;
     Function IsReady(Var CurrentProcess : AnsiString) : Boolean;
+    Property LastBlockFound : TPCOperationsComp read FLastBlockCache;
   End;
   End;
 
 
 Const
 Const
@@ -351,6 +357,10 @@ begin
         errors := 'block ('+inttostr(Operations.OperationBlock.block)+') is not new position ('+inttostr(BlocksCount)+')';
         errors := 'block ('+inttostr(Operations.OperationBlock.block)+') is not new position ('+inttostr(BlocksCount)+')';
         exit;
         exit;
       end;
       end;
+      if Not Assigned(Operations.FSafeBoxTransaction) then begin
+        errors := 'Developer error 20161114-1';
+        exit;
+      end;
       if (SafeBox.TotalBalance<>(Operations.FSafeBoxTransaction.TotalBalance+Operations.FSafeBoxTransaction.TotalFee)) then begin
       if (SafeBox.TotalBalance<>(Operations.FSafeBoxTransaction.TotalBalance+Operations.FSafeBoxTransaction.TotalFee)) then begin
         errors := Format('Invalid integrity balance at SafeBox. Actual Balance:%d  New Balance:(%d + fee %d = %d)',
         errors := Format('Invalid integrity balance at SafeBox. Actual Balance:%d  New Balance:(%d + fee %d = %d)',
           [SafeBox.TotalBalance,
           [SafeBox.TotalBalance,
@@ -422,6 +432,7 @@ begin
       if Not FIsRestoringFromFile then begin
       if Not FIsRestoringFromFile then begin
         Storage.SaveBlockChainBlock(Operations);
         Storage.SaveBlockChainBlock(Operations);
       end;
       end;
+      FLastBlockCache.CopyFrom(Operations);
       Operations.Clear(true);
       Operations.Clear(true);
       Result := true;
       Result := true;
     Finally
     Finally
@@ -453,6 +464,7 @@ begin
   d.FLastOperationBlock := FLastOperationBlock;
   d.FLastOperationBlock := FLastOperationBlock;
   d.FActualTargetHash := FActualTargetHash;
   d.FActualTargetHash := FActualTargetHash;
   d.FIsRestoringFromFile := FIsRestoringFromFile;
   d.FIsRestoringFromFile := FIsRestoringFromFile;
+  d.FLastBlockCache.CopyFrom( FLastBlockCache );
 end;
 end;
 
 
 function TPCBank.BlocksCount: Cardinal;
 function TPCBank.BlocksCount: Cardinal;
@@ -465,6 +477,7 @@ begin
   SafeBox.Clear;
   SafeBox.Clear;
   FLastOperationBlock := TPCOperationsComp.GetFirstBlock;
   FLastOperationBlock := TPCOperationsComp.GetFirstBlock;
   FLastOperationBlock.initial_safe_box_hash := TCrypto.DoSha256(CT_Genesis_Magic_String_For_Old_Block_Hash); // Genesis hash
   FLastOperationBlock.initial_safe_box_hash := TCrypto.DoSha256(CT_Genesis_Magic_String_For_Old_Block_Hash); // Genesis hash
+  FLastBlockCache.Clear(true);
   FInitialSafeBoxHash := TCrypto.DoSha256(CT_Genesis_Magic_String_For_Old_Block_Hash); // Genesis hash
   FInitialSafeBoxHash := TCrypto.DoSha256(CT_Genesis_Magic_String_For_Old_Block_Hash); // Genesis hash
   FActualTargetHash := TargetFromCompact(CT_MinCompactTarget);
   FActualTargetHash := TargetFromCompact(CT_MinCompactTarget);
   NewLog(Nil, ltupdate, 'Clear Bank');
   NewLog(Nil, ltupdate, 'Clear Bank');
@@ -480,6 +493,7 @@ begin
   FOnLog := Nil;
   FOnLog := Nil;
   FSafeBox := TPCSafeBox.Create;
   FSafeBox := TPCSafeBox.Create;
   FNotifyList := TList.Create;
   FNotifyList := TList.Create;
+  FLastBlockCache := TPCOperationsComp.Create(Nil);
   Clear;
   Clear;
 end;
 end;
 
 
@@ -491,6 +505,8 @@ begin
     DeleteCriticalSection(FBankLock);
     DeleteCriticalSection(FBankLock);
     step := 'Clear';
     step := 'Clear';
     Clear;
     Clear;
+    step := 'Destroying LastBlockCache';
+    FreeAndNil(FLastBlockCache);
     step := 'Destroying SafeBox';
     step := 'Destroying SafeBox';
     FreeAndNil(FSafeBox);
     FreeAndNil(FSafeBox);
     step := 'Destroying NotifyList';
     step := 'Destroying NotifyList';
@@ -523,17 +539,26 @@ begin
     try
     try
       Clear;
       Clear;
       Storage.RestoreBank(max_block);
       Storage.RestoreBank(max_block);
+      // Restore last blockchain
+      if BlocksCount>0 then begin
+        if Not Storage.LoadBlockChainBlock(FLastBlockCache,BlocksCount-1) then begin
+          NewLog(nil,lterror,'Cannot find blockchain '+inttostr(BlocksCount-1)+' so cannot accept bank current block '+inttostr(BlocksCount));
+          Clear;
+        end;
+      end;
       NewLog(Nil, ltinfo,'Start restoring from disk operations (Max '+inttostr(max_block)+') Orphan: ' +Storage.Orphan);
       NewLog(Nil, ltinfo,'Start restoring from disk operations (Max '+inttostr(max_block)+') Orphan: ' +Storage.Orphan);
       Operations := TPCOperationsComp.Create(Self);
       Operations := TPCOperationsComp.Create(Self);
       try
       try
         while ((BlocksCount<=max_block)) do begin
         while ((BlocksCount<=max_block)) do begin
           if Storage.BlockExists(BlocksCount) then begin
           if Storage.BlockExists(BlocksCount) then begin
             if Storage.LoadBlockChainBlock(Operations,BlocksCount) then begin
             if Storage.LoadBlockChainBlock(Operations,BlocksCount) then begin
-                  if Not AddNewBlockChainBlock(Operations,newBlock,errors) then begin
-                    NewLog(Operations, lterror,'Error restoring block: ' + Inttostr(BlocksCount)+ ' Errors: ' + errors);
-                    Storage.DeleteBlockChainBlocks(BlocksCount,Storage.Orphan);
-                    break;
-                  end else Storage.SaveBank;
+              if Not AddNewBlockChainBlock(Operations,newBlock,errors) then begin
+                NewLog(Operations, lterror,'Error restoring block: ' + Inttostr(BlocksCount)+ ' Errors: ' + errors);
+                Storage.DeleteBlockChainBlocks(BlocksCount,Storage.Orphan);
+                break;
+              end else begin
+                Storage.SaveBank;
+              end;
             end else break;
             end else break;
           end else break;
           end else break;
         end;
         end;
@@ -698,7 +723,8 @@ begin
   else Result := true;
   else Result := true;
 end;
 end;
 
 
-function TPCBank.LoadFromStream(Stream: TStream; var errors : AnsiString) : Boolean;
+function TPCBank.LoadBankFromStream(Stream: TStream;
+  var errors: AnsiString): Boolean;
 Var LastReadBlock : TBlockAccount;
 Var LastReadBlock : TBlockAccount;
   op : TPCOperationsComp;
   op : TPCOperationsComp;
   i : Integer;
   i : Integer;
@@ -733,12 +759,17 @@ begin
   end;
   end;
 end;
 end;
 
 
-
 function TPCBank.LoadOperations(Operations: TPCOperationsComp; Block: Cardinal): Boolean;
 function TPCBank.LoadOperations(Operations: TPCOperationsComp; Block: Cardinal): Boolean;
 begin
 begin
   TPCThread.ProtectEnterCriticalSection(Self,FBankLock);
   TPCThread.ProtectEnterCriticalSection(Self,FBankLock);
   try
   try
-    Result := Storage.LoadBlockChainBlock(Operations,Block);
+    if (Block>0) AND (Block=FLastBlockCache.OperationBlock.block) then begin
+      // Same as cache, sending cache
+      Operations.CopyFrom(FLastBlockCache);
+      Result := true;
+    end else begin
+      Result := Storage.LoadBlockChainBlock(Operations,Block);
+    end;
   finally
   finally
     LeaveCriticalSection(FBankLock);
     LeaveCriticalSection(FBankLock);
   end;
   end;
@@ -754,11 +785,16 @@ begin
     FOnLog(Self, Operations, Logtype, Logtxt);
     FOnLog(Self, Operations, Logtype, Logtxt);
 end;
 end;
 
 
-procedure TPCBank.SaveToStream(Stream: TStream);
+procedure TPCBank.SaveBankToStream(Stream: TStream);
 begin
 begin
   SafeBox.SaveToStream(Stream);
   SafeBox.SaveToStream(Stream);
 end;
 end;
 
 
+{procedure TPCBank.SaveToStream(Stream: TStream);
+begin
+  SafeBox.SaveToStream(Stream);
+end;
+}
 procedure TPCBank.SetStorageClass(const Value: TStorageClass);
 procedure TPCBank.SetStorageClass(const Value: TStorageClass);
 begin
 begin
   if FStorageClass=Value then exit;
   if FStorageClass=Value then exit;
@@ -963,6 +999,10 @@ begin
       if Assigned(FSafeBoxTransaction) then
       if Assigned(FSafeBoxTransaction) then
         FSafeBoxTransaction.CleanTransaction;
         FSafeBoxTransaction.CleanTransaction;
     end;
     end;
+
+    // Note:
+    // This function does not initializes "account_key" nor "block_payload" fields
+
     FOperationBlock.timestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
     FOperationBlock.timestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
     if Assigned(FBank) then begin
     if Assigned(FBank) then begin
       FOperationBlock.block := bank.BlocksCount;
       FOperationBlock.block := bank.BlocksCount;
@@ -980,16 +1020,26 @@ begin
     FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
     FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
     FOperationBlock.fee := 0;
     FOperationBlock.fee := 0;
     FOperationBlock.nonce := 0;
     FOperationBlock.nonce := 0;
-
     FOperationBlock.proof_of_work := '';
     FOperationBlock.proof_of_work := '';
-    FOperationBlock.protocol_version := CT_Protocol_Version;
-    FOperationBlock.protocol_available := CT_Protocol_Available;
+    FOperationBlock.protocol_version := CT_BlockChain_Protocol_Version;
+    FOperationBlock.protocol_available := CT_BlockChain_Protocol_Available;
     FIsOnlyOperationBlock := false;
     FIsOnlyOperationBlock := false;
   Finally
   Finally
     CalcProofOfWork(true,FOperationBlock.proof_of_work);
     CalcProofOfWork(true,FOperationBlock.proof_of_work);
   End;
   End;
 end;
 end;
 
 
+procedure TPCOperationsComp.CopyFrom(Operations: TPCOperationsComp);
+begin
+  if Self=Operations then exit;
+  FOperationBlock := Operations.FOperationBlock;
+  FIsOnlyOperationBlock := Operations.FIsOnlyOperationBlock;
+  FOperationsHashTree.CopyFromHashTree(Operations.FOperationsHashTree);
+  if Assigned(FSafeBoxTransaction) And Assigned(Operations.FSafeBoxTransaction) then begin
+    FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
+  end;
+end;
+
 function TPCOperationsComp.CopyFromAndValidate(Operations: TPCOperationsComp; var errors: AnsiString): Boolean;
 function TPCOperationsComp.CopyFromAndValidate(Operations: TPCOperationsComp; var errors: AnsiString): Boolean;
 Var i : Integer;
 Var i : Integer;
   e : AnsiString;
   e : AnsiString;
@@ -1028,7 +1078,9 @@ begin
   FIsOnlyOperationBlock := Operations.FIsOnlyOperationBlock;
   FIsOnlyOperationBlock := Operations.FIsOnlyOperationBlock;
   FOperationsHashTree.CopyFromHashTree(Operations.FOperationsHashTree);
   FOperationsHashTree.CopyFromHashTree(Operations.FOperationsHashTree);
   FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
   FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
-  FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
+  if Assigned(FSafeBoxTransaction) And Assigned(Operations.FSafeBoxTransaction) then begin
+    FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
+  end;
   // Recalc all
   // Recalc all
   CalcProofOfWork(true,FOperationBlock.proof_of_work);
   CalcProofOfWork(true,FOperationBlock.proof_of_work);
 end;
 end;
@@ -1040,11 +1092,10 @@ end;
 
 
 constructor TPCOperationsComp.Create(AOwner: TComponent);
 constructor TPCOperationsComp.Create(AOwner: TComponent);
 begin
 begin
-  inherited;
+  inherited Create(AOwner);
   // New at Build 1.0.2
   // New at Build 1.0.2
   FStreamPoW := TMemoryStream.Create;
   FStreamPoW := TMemoryStream.Create;
   FStreamPoW.Position := 0;
   FStreamPoW.Position := 0;
-
   FOperationsHashTree := TOperationsHashTree.Create;
   FOperationsHashTree := TOperationsHashTree.Create;
   FBank := Nil;
   FBank := Nil;
   FOperationBlock := GetFirstBlock;
   FOperationBlock := GetFirstBlock;
@@ -1057,12 +1108,33 @@ end;
 destructor TPCOperationsComp.Destroy;
 destructor TPCOperationsComp.Destroy;
 begin
 begin
   Clear(true);
   Clear(true);
-  FOperationsHashTree.Free;
-  FSafeBoxTransaction.Free;
-  FStreamPoW.Free;
+  FreeAndNil(FOperationsHashTree);
+  if Assigned(FSafeBoxTransaction) then begin
+    FreeAndNil(FSafeBoxTransaction);
+  end;
+  FreeAndNil(FStreamPoW);
   inherited;
   inherited;
 end;
 end;
 
 
+class function TPCOperationsComp.EqualsOperationBlock(const OperationBlock1,
+  OperationBlock2: TOperationBlock): Boolean;
+begin
+
+  Result := (OperationBlock1.block=OperationBlock2.block)
+           And (TAccountComp.Equal(OperationBlock1.account_key,OperationBlock2.account_key))
+           And (OperationBlock1.reward=OperationBlock2.reward)
+           And (OperationBlock1.fee=OperationBlock2.fee)
+           And (OperationBlock1.protocol_version=OperationBlock2.protocol_version)
+           And (OperationBlock1.protocol_available=OperationBlock2.protocol_available)
+           And (OperationBlock1.timestamp=OperationBlock2.timestamp)
+           And (OperationBlock1.compact_target=OperationBlock2.compact_target)
+           And (OperationBlock1.nonce=OperationBlock2.nonce)
+           And (OperationBlock1.block_payload=OperationBlock2.block_payload)
+           And (OperationBlock1.initial_safe_box_hash=OperationBlock2.initial_safe_box_hash)
+           And (OperationBlock1.operations_hash=OperationBlock2.operations_hash)
+           And (OperationBlock1.proof_of_work=OperationBlock2.proof_of_work);
+end;
+
 function TPCOperationsComp.GetAccountKey: TAccountKey;
 function TPCOperationsComp.GetAccountKey: TAccountKey;
 begin
 begin
   Result := FOperationBlock.account_key;
   Result := FOperationBlock.account_key;
@@ -1139,13 +1211,12 @@ begin
   Result := -1;
   Result := -1;
 end;
 end;
 
 
-function TPCOperationsComp.LoadFromStream(ExecuteOperations : Boolean; load_header : Boolean; Stream: TStream; var errors: AnsiString): Boolean;
+function TPCOperationsComp.LoadBlockFromStream(Stream: TStream; var errors: AnsiString): Boolean;
 Var
 Var
   c, i, lastfee: Cardinal;
   c, i, lastfee: Cardinal;
   soob : Byte;
   soob : Byte;
   OpType: Cardinal;
   OpType: Cardinal;
   bcop: TPCOperation;
   bcop: TPCOperation;
-  pow,
   m: AnsiString;
   m: AnsiString;
   j: Integer;
   j: Integer;
   OpClass: TPCOperationClass;
   OpClass: TPCOperationClass;
@@ -1153,34 +1224,30 @@ Var
 begin
 begin
   Clear(true);
   Clear(true);
   Result := False;
   Result := False;
-  if (load_header) then begin
-    // Header: Magic string + protocol info
-    if TStreamOp.ReadAnsiString(Stream, m) < 0 then begin
-      errors := 'Invalid header';
-      exit;
-    end;
-    if (Not AnsiSameStr(CT_MagicIdentificator, m)) then begin
-      errors := 'Invalid header name';
-      exit;
-    end;
-    errors := 'Invalid header structure';
-    if (Stream.Size - Stream.Position < 4) then exit;
-    Stream.Read(FOperationBlock.protocol_version, Sizeof(FOperationBlock.protocol_version));
-    Stream.Read(FOperationBlock.protocol_available, Sizeof(FOperationBlock.protocol_available));
-    if (FOperationBlock.protocol_version<>CT_Protocol_Version) then begin
-      errors := 'Invalid protocol block: '+inttostr(FOperationBlock.protocol_version);
-      exit;
-    end;
-  end;
   //
   //
-  errors := 'Invalid structure';
+  errors := 'Invalid protocol structure. Check application version!';
   if (Stream.Size - Stream.Position < 5) then exit;
   if (Stream.Size - Stream.Position < 5) then exit;
   Stream.Read(soob,1);
   Stream.Read(soob,1);
-  if soob=0 then FIsOnlyOperationBlock:=false
-  else if soob=1 then FIsOnlyOperationBlock:=true
-  else exit; // Invalid value
+  // About soob var:
+  // In build prior to 1.0.4 soob only can have 2 values: 0 or 1
+  // In build 1.0.4 soob can has 2 more values: 2 or 3
+  // In future, old values 0 and 1 will no longer be used!
+  // - Value 0 and 2 means that contains also operations
+  // - Value 1 and 3 means that only contains operationblock info
+  // - Value 2 and 3 means that contains protocol info prior to block number
+  if (soob=0) or (soob=2) then FIsOnlyOperationBlock:=false
+  else if (soob=1) or (soob=3) then FIsOnlyOperationBlock:=true
+  else begin
+    errors := 'Invalid value in protocol header! Found:'+inttostr(soob)+' - Check if your application version is Ok';
+    exit;
+  end;
 
 
-  Stream.Read(FOperationBlock.block, Sizeof(FOperationBlock.block));
+  if (soob=2) or (soob=3) then begin
+    Stream.Read(FOperationBlock.protocol_version, Sizeof(FOperationBlock.protocol_version));
+    Stream.Read(FOperationBlock.protocol_available, Sizeof(FOperationBlock.protocol_available));
+  end;
+
+  if Stream.Read(FOperationBlock.block, Sizeof(FOperationBlock.block))<0 then exit;
 
 
   if TStreamOp.ReadAnsiString(Stream, m) < 0 then exit;
   if TStreamOp.ReadAnsiString(Stream, m) < 0 then exit;
   FOperationBlock.account_key := TAccountComp.RawString2Accountkey(m);
   FOperationBlock.account_key := TAccountComp.RawString2Accountkey(m);
@@ -1193,7 +1260,6 @@ begin
   if TStreamOp.ReadAnsiString(Stream, FOperationBlock.initial_safe_box_hash) < 0 then exit;
   if TStreamOp.ReadAnsiString(Stream, FOperationBlock.initial_safe_box_hash) < 0 then exit;
   if TStreamOp.ReadAnsiString(Stream, FOperationBlock.operations_hash) < 0 then exit;
   if TStreamOp.ReadAnsiString(Stream, FOperationBlock.operations_hash) < 0 then exit;
   if TStreamOp.ReadAnsiString(Stream, FOperationBlock.proof_of_work) < 0 then exit;
   if TStreamOp.ReadAnsiString(Stream, FOperationBlock.proof_of_work) < 0 then exit;
-  pow := OperationBlock.proof_of_work;
   If FIsOnlyOperationBlock then begin
   If FIsOnlyOperationBlock then begin
     Result := true;
     Result := true;
     exit;
     exit;
@@ -1224,7 +1290,7 @@ begin
         bcop.Free;
         bcop.Free;
         exit;
         exit;
       end;
       end;
-      if Not AddOperation(ExecuteOperations,bcop, errors2) then begin
+      if Not AddOperation(false,bcop, errors2) then begin
         errors := errors + ' '+errors2+' '+bcop.ToString;
         errors := errors + ' '+errors2+' '+bcop.ToString;
         bcop.Free;
         bcop.Free;
         exit;
         exit;
@@ -1250,12 +1316,10 @@ procedure TPCOperationsComp.Notification(AComponent: TComponent;
   Operation: TOperation);
   Operation: TOperation);
 begin
 begin
   inherited;
   inherited;
-  if (Operation = opRemove) then
-  begin
+  if (Operation = opRemove) then begin
     if AComponent = FBank then begin
     if AComponent = FBank then begin
       FBank := Nil;
       FBank := Nil;
-      FSafeBoxTransaction.Free;
-      FSafeBoxTransaction := Nil;
+      FreeAndNil(FSafeBoxTransaction);
     end;
     end;
   end;
   end;
 end;
 end;
@@ -1286,7 +1350,7 @@ procedure TPCOperationsComp.SanitizeOperations;
 Var i,n,lastn : Integer;
 Var i,n,lastn : Integer;
   op : TPCOperation;
   op : TPCOperation;
   errors : AnsiString;
   errors : AnsiString;
-  aux : TOperationsHashTree;
+  aux,aux2 : TOperationsHashTree;
 begin
 begin
   Try
   Try
     FOperationBlock.timestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
     FOperationBlock.timestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
@@ -1304,8 +1368,8 @@ begin
       FOperationBlock.initial_safe_box_hash := TCrypto.DoSha256(CT_Genesis_Magic_String_For_Old_Block_Hash);
       FOperationBlock.initial_safe_box_hash := TCrypto.DoSha256(CT_Genesis_Magic_String_For_Old_Block_Hash);
     end;
     end;
     FOperationBlock.proof_of_work := '';
     FOperationBlock.proof_of_work := '';
-    FOperationBlock.protocol_version := CT_Protocol_Version;
-    FOperationBlock.protocol_available := CT_Protocol_Available;
+    FOperationBlock.protocol_version := CT_BlockChain_Protocol_Version;
+    FOperationBlock.protocol_available := CT_BlockChain_Protocol_Available;
     n := 0;
     n := 0;
     FOperationBlock.fee := 0;
     FOperationBlock.fee := 0;
     //
     //
@@ -1325,8 +1389,9 @@ begin
       end;
       end;
       FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
       FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
     Finally
     Finally
-      FOperationsHashTree.Free;
+      aux2 := FOperationsHashTree;
       FOperationsHashTree := aux;
       FOperationsHashTree := aux;
+      aux2.Free;
     End;
     End;
   Finally
   Finally
     CalcProofOfWork(true,FOperationBlock.proof_of_work);
     CalcProofOfWork(true,FOperationBlock.proof_of_work);
@@ -1336,25 +1401,29 @@ begin
   end;
   end;
 end;
 end;
 
 
-function TPCOperationsComp.SaveToStream(save_header, save_only_OperationBlock : Boolean; Stream: TStream): Boolean;
+function TPCOperationsComp.SaveBlockToStream(save_only_OperationBlock : Boolean; Stream: TStream): Boolean;
 Var
 Var
   c, opl, i, OpType: Cardinal;
   c, opl, i, OpType: Cardinal;
   soob : Byte;
   soob : Byte;
   bcop: TPCOperation;
   bcop: TPCOperation;
   bcops, errors: AnsiString;
   bcops, errors: AnsiString;
 begin
 begin
-  if save_header then begin
-    // Header: Magic string + protocol info
-    TStreamOp.WriteAnsiString(Stream, CT_MagicIdentificator);
-    Stream.Write(CT_Protocol_Version, Sizeof(FOperationBlock.protocol_version));
-    Stream.Write(CT_Protocol_Available, Sizeof(FOperationBlock.protocol_available));
-  end;
   //
   //
-  if save_only_OperationBlock then soob := 1
-  else soob := 0;
+  if save_only_OperationBlock then begin
+    if (FOperationBlock.protocol_version=1) And (FOperationBlock.protocol_available=0) then soob := 1
+    else soob := 3;
+  end else begin
+    if (FOperationBlock.protocol_version=1) And (FOperationBlock.protocol_available=0) then soob := 0
+    else soob := 2;
+  end;
   Stream.Write(soob,1);
   Stream.Write(soob,1);
+  if (soob>=2) then begin
+    Stream.Write(FOperationBlock.protocol_version, Sizeof(FOperationBlock.protocol_version));
+    Stream.Write(FOperationBlock.protocol_available, Sizeof(FOperationBlock.protocol_available));
+  end;
   //
   //
   Stream.Write(FOperationBlock.block, Sizeof(FOperationBlock.block));
   Stream.Write(FOperationBlock.block, Sizeof(FOperationBlock.block));
+  //
   TStreamOp.WriteAnsiString(Stream,TAccountComp.AccountKey2RawString(FOperationBlock.account_key));
   TStreamOp.WriteAnsiString(Stream,TAccountComp.AccountKey2RawString(FOperationBlock.account_key));
   Stream.Write(FOperationBlock.reward, Sizeof(FOperationBlock.reward));
   Stream.Write(FOperationBlock.reward, Sizeof(FOperationBlock.reward));
   Stream.Write(FOperationBlock.fee, Sizeof(FOperationBlock.fee));
   Stream.Write(FOperationBlock.fee, Sizeof(FOperationBlock.fee));
@@ -1391,8 +1460,7 @@ procedure TPCOperationsComp.SetBank(const value: TPCBank);
 begin
 begin
   if FBank = value then exit;
   if FBank = value then exit;
   if Assigned(FBank) then begin
   if Assigned(FBank) then begin
-     FSafeBoxTransaction.Free;
-     FSafeBoxTransaction := Nil;
+     FreeAndNil(FSafeBoxTransaction);
   end;
   end;
   FBank := value;
   FBank := value;
   if Assigned(value) then begin
   if Assigned(value) then begin
@@ -1496,7 +1564,6 @@ begin
   Result := true;
   Result := true;
 end;
 end;
 
 
-
 { TPCBankNotify }
 { TPCBankNotify }
 
 
 constructor TPCBankNotify.Create(AOwner: TComponent);
 constructor TPCBankNotify.Create(AOwner: TComponent);
@@ -1613,7 +1680,7 @@ end;
 destructor TOperationsHashTree.Destroy;
 destructor TOperationsHashTree.Destroy;
 begin
 begin
   ClearHastThree;
   ClearHastThree;
-  FHashTreeOperations.Free;
+  FreeAndNil(FHashTreeOperations);
   inherited;
   inherited;
 end;
 end;
 
 

+ 10 - 4
Units/PascalCoin/UConst.pas

@@ -54,14 +54,20 @@ Const
   CT_MaxPayloadSize = 255; // Max payload size in bytes
   CT_MaxPayloadSize = 255; // Max payload size in bytes
   CT_MaxSecondsDifferenceOfNetworkNodes = 180; // 3 minutes. If a Node has a +- value difference, will be blacklisted
   CT_MaxSecondsDifferenceOfNetworkNodes = 180; // 3 minutes. If a Node has a +- value difference, will be blacklisted
 
 
-  CT_MaxServersConnected = 10;
+  CT_MaxServersConnected = 5;
+
+  CT_MaxClientsConnected = 100;
 
 
   CT_BankToDiskEveryNBlocks = 500;
   CT_BankToDiskEveryNBlocks = 500;
 
 
   CT_Default_EC_OpenSSL_NID = NID_secp256k1;
   CT_Default_EC_OpenSSL_NID = NID_secp256k1;
 
 
-  CT_Protocol_Version: Word = $0001; // Version 1
-  CT_Protocol_Available: Word = $0000;
+  CT_BlockChain_Protocol_Version: Word = $0001; // Version 1
+  CT_BlockChain_Protocol_Available: Word = $0000;
+
+  CT_NetProtocol_Version: Word = $0001;
+  CT_NetProtocol_Available: Word = $0002; // Build 1.0.4
+
   CT_MagicIdentificator: AnsiString = 'PascalCoin'; //
   CT_MagicIdentificator: AnsiString = 'PascalCoin'; //
 
 
   // Value of Operations type in Protocol 1
   // Value of Operations type in Protocol 1
@@ -69,7 +75,7 @@ Const
   CT_Op_Changekey = $02;
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
   CT_Op_Recover = $03;
 
 
-  CT_ClientAppVersion : AnsiString = '1.0.3';
+  CT_ClientAppVersion : AnsiString = '1.0.4';
 
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.ddns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.ddns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
 
 

+ 6 - 6
Units/PascalCoin/UDBStorage.pas

@@ -360,7 +360,7 @@ begin
       try
       try
         BlobSaveToStream(bf,ms);
         BlobSaveToStream(bf,ms);
         ms.Position := 0;
         ms.Position := 0;
-        Result := Operations.LoadFromStream(false,false,ms,errors);
+        Result := Operations.LoadBlockFromStream(ms,errors);
         if Not Result then begin
         if Not Result then begin
           TLog.NewLog(lterror,Classname,Format('Error reading databse Block %d: %s Stream size:%d',[Block,errors,ms.Size]));
           TLog.NewLog(lterror,Classname,Format('Error reading databse Block %d: %s Stream size:%d',[Block,errors,ms.Size]));
         end;
         end;
@@ -440,7 +440,7 @@ begin
       try
       try
         BlobSaveToStream(bf,ms);
         BlobSaveToStream(bf,ms);
         ms.Position := 0;
         ms.Position := 0;
-        Result := Bank.LoadFromStream(ms,errors);
+        Result := Bank.LoadBankFromStream(ms,errors);
         if Not Result then begin
         if Not Result then begin
           TLog.NewLog(lterror,Classname,Format('Error reading databse Bank block %d: %s',[ds.FieldByName(CT_TblFld_Bank_block).AsInteger,errors]));
           TLog.NewLog(lterror,Classname,Format('Error reading databse Bank block %d: %s',[ds.FieldByName(CT_TblFld_Bank_block).AsInteger,errors]));
         end else begin
         end else begin
@@ -486,7 +486,7 @@ begin
       bf := ds.FieldByName(CT_TblFld_Bank_bank_stream) as TBlobField;
       bf := ds.FieldByName(CT_TblFld_Bank_bank_stream) as TBlobField;
       ms := TMemoryStream.Create;
       ms := TMemoryStream.Create;
       Try
       Try
-        Bank.SaveToStream(ms);
+        Bank.SaveBankToStream(ms);
         ms.Position := 0;
         ms.Position := 0;
         BlobLoadFromStream(bf,ms);
         BlobLoadFromStream(bf,ms);
         TLog.NewLog(ltdebug,Classname,Format('Saving bank of block %d with stream size %d bytes',[Bank.BlocksCount,ms.Size]));
         TLog.NewLog(ltdebug,Classname,Format('Saving bank of block %d with stream size %d bytes',[Bank.BlocksCount,ms.Size]));
@@ -575,7 +575,7 @@ begin
       ds.FieldByName(CT_TblFld_BlockChain_orphan).Value := vOrphan;
       ds.FieldByName(CT_TblFld_BlockChain_orphan).Value := vOrphan;
       ds.FieldByName(CT_TblFld_BlockChain_operations_count).Value := Operations.Count;
       ds.FieldByName(CT_TblFld_BlockChain_operations_count).Value := Operations.Count;
       bf := ds.FieldByName(CT_TblFld_BlockChain_operations_stream) as TBlobField;
       bf := ds.FieldByName(CT_TblFld_BlockChain_operations_stream) as TBlobField;
-      Operations.SaveToStream(False,False,ms);
+      Operations.SaveBlockToStream(False,ms);
       ms.Position := 0;
       ms.Position := 0;
       BlobLoadFromStream(bf,ms);
       BlobLoadFromStream(bf,ms);
       ds.Post;
       ds.Post;
@@ -933,7 +933,7 @@ Var P : POperationResume;
 begin
 begin
   New(P);
   New(P);
   P^ := OperationResume;
   P^ := OperationResume;
-  FList.Add(P,'TOperationsResumeList.Add');
+  FList.Add(P);
 end;
 end;
 
 
 procedure TOperationsResumeList.Clear;
 procedure TOperationsResumeList.Clear;
@@ -986,7 +986,7 @@ end;
 destructor TOperationsResumeList.Destroy;
 destructor TOperationsResumeList.Destroy;
 begin
 begin
   Clear;
   Clear;
-  FList.Free;
+  FreeAndNil(FList);
   inherited;
   inherited;
 end;
 end;
 
 

+ 5 - 5
Units/PascalCoin/UFileStorage.pas

@@ -115,7 +115,7 @@ begin
   end;
   end;
   fs := TFileStream.Create(filename, fmOpenRead);
   fs := TFileStream.Create(filename, fmOpenRead);
   try
   try
-    If Operations.LoadFromStream(false,true,fs, e) then result := true
+    If Operations.LoadBlockFromStream(fs, e) then result := true
     else begin
     else begin
       TLog.NewLog(lterror,Classname,'Error reading file: '+filename+' Errors: '+e);
       TLog.NewLog(lterror,Classname,'Error reading file: '+filename+' Errors: '+e);
     end;
     end;
@@ -156,7 +156,7 @@ function TFileStorage.DoRestoreBank(max_block: Int64): Boolean;
     if FileExists(filename) then begin
     if FileExists(filename) then begin
       fs := TFileStream.Create(filename, fmOpenRead);
       fs := TFileStream.Create(filename, fmOpenRead);
       try
       try
-          Result := Operations.LoadFromStream(false,true,fs, errors);
+          Result := Operations.LoadBlockFromStream(fs, errors);
       finally
       finally
         fs.Free;
         fs.Free;
       end;
       end;
@@ -203,7 +203,7 @@ begin
     if (filename<>'') then begin
     if (filename<>'') then begin
       fs := TFileStream.Create(folder+'\'+filename,fmOpenRead);
       fs := TFileStream.Create(folder+'\'+filename,fmOpenRead);
       try
       try
-        if not Bank.LoadFromStream(fs,errors) then begin
+        if not Bank.LoadBankFromStream(fs,errors) then begin
           TLog.NewLog(lterror,ClassName,'Error reading bank from file: '+filename+ ' Error: '+errors);
           TLog.NewLog(lterror,ClassName,'Error reading bank from file: '+filename+ ' Error: '+errors);
         end;
         end;
       finally
       finally
@@ -225,7 +225,7 @@ begin
     fs := TFileStream.Create(bankfilename,fmCreate);
     fs := TFileStream.Create(bankfilename,fmCreate);
     try
     try
       fs.Size := 0;
       fs.Size := 0;
-      Bank.SaveToStream(fs);
+      Bank.SaveBankToStream(fs);
     finally
     finally
       fs.Free;
       fs.Free;
     end;
     end;
@@ -243,7 +243,7 @@ begin
     fs := TFileStream.Create(GetBlockChainFileName(folder,Operations.OperationBlock.block), fmCreate);
     fs := TFileStream.Create(GetBlockChainFileName(folder,Operations.OperationBlock.block), fmCreate);
     try
     try
       fs.Size := 0;
       fs.Size := 0;
-      Operations.SaveToStream(true,false,fs);
+      Operations.SaveBlockToStream(false,fs);
     finally
     finally
       fs.Free;
       fs.Free;
     end;
     end;

+ 4 - 6
Units/PascalCoin/ULog.pas

@@ -92,18 +92,16 @@ begin
 end;
 end;
 
 
 destructor TLog.Destroy;
 destructor TLog.Destroy;
-var f : TFileStream;
+var
   l : TList;
   l : TList;
   i : Integer;
   i : Integer;
   P : PLogData;
   P : PLogData;
 begin
 begin
   FThreadSafeLogEvent.Terminate;
   FThreadSafeLogEvent.Terminate;
   FThreadSafeLogEvent.WaitFor;
   FThreadSafeLogEvent.WaitFor;
-  FThreadSafeLogEvent.Free;
+  FreeAndNil(FThreadSafeLogEvent);
   _logs.Remove(Self);
   _logs.Remove(Self);
-  f := FFileStream;
-  FFileStream := Nil;
-  f.Free;
+  FreeAndNil(FFileStream);
   l := FLogDataList.LockList;
   l := FLogDataList.LockList;
   try
   try
     for i := 0 to l.Count - 1 do begin
     for i := 0 to l.Count - 1 do begin
@@ -114,7 +112,7 @@ begin
   finally
   finally
     FLogDataList.UnlockList;
     FLogDataList.UnlockList;
   end;
   end;
-  FLogDataList.Free;
+  FreeAndNil(FLogDataList);
   inherited;
   inherited;
 end;
 end;
 
 

+ 1 - 1
Units/PascalCoin/UMiner.pas

@@ -174,7 +174,7 @@ end;
 destructor TMinerThread.Destroy;
 destructor TMinerThread.Destroy;
 begin
 begin
   DeleteCriticalSection(Flock);
   DeleteCriticalSection(Flock);
-  FOperations.Free;
+  FreeAndNil(FOperations);
   inherited;
   inherited;
 end;
 end;
 
 

File diff suppressed because it is too large
+ 308 - 156
Units/PascalCoin/UNetProtocol.pas


+ 42 - 14
Units/PascalCoin/UNode.pas

@@ -144,7 +144,7 @@ begin
   finally
   finally
     Result.MinerUnLockOperations(True);
     Result.MinerUnLockOperations(True);
   end;
   end;
-  FMinerThreads.Add(Result,'TNode.AddMiner');
+  FMinerThreads.Add(Result);
 end;
 end;
 
 
 function TNode.AddNewBlockChain(SenderMiner: TMinerThread; SenderConnection: TNetConnection; NewBlockOperations: TPCOperationsComp;
 function TNode.AddNewBlockChain(SenderMiner: TMinerThread; SenderConnection: TNetConnection; NewBlockOperations: TPCOperationsComp;
@@ -170,11 +170,11 @@ begin
   try
   try
     ms := TMemoryStream.Create;
     ms := TMemoryStream.Create;
     try
     try
-      FOperations.SaveToStream(false,false,ms);
+      FOperations.SaveBlockToStream(false,ms);
       Result := Bank.AddNewBlockChainBlock(NewBlockOperations,newBlockAccount,errors);
       Result := Bank.AddNewBlockChainBlock(NewBlockOperations,newBlockAccount,errors);
       FOperations.Clear(true);
       FOperations.Clear(true);
       ms.Position:=0;
       ms.Position:=0;
-      If Not FOperations.LoadFromStream(false,false,ms,errors) then begin
+      If Not FOperations.LoadBlockFromStream(ms,errors) then begin
         TLog.NewLog(lterror,Classname,'Error recovering operations to sanitize: '+errors);
         TLog.NewLog(lterror,Classname,'Error recovering operations to sanitize: '+errors);
       end;
       end;
     finally
     finally
@@ -437,23 +437,25 @@ begin
     step := 'Desactivating server';
     step := 'Desactivating server';
     FNetServer.Active := false;
     FNetServer.Active := false;
 
 
+    Sleep(1000);
+
     step := 'Deleting miners';
     step := 'Deleting miners';
     while (MinersCount>0) do DeleteMiner(0);
     while (MinersCount>0) do DeleteMiner(0);
 
 
     step := 'Destroying NetServer';
     step := 'Destroying NetServer';
-    FNetServer.Free;
+    FreeAndNil(FNetServer);
     step := 'Destroying MinerThreads';
     step := 'Destroying MinerThreads';
-    FMinerThreads.Free;
+    FreeAndNil(FMinerThreads);
 
 
     step := 'Destroying NotifyList';
     step := 'Destroying NotifyList';
-    FNotifyList.Free;
+    FreeAndNil(FNotifyList);
     step := 'Destroying Operations';
     step := 'Destroying Operations';
-    FOperations.Free;
+    FreeAndNil(FOperations);
     step := 'Assigning NIL to node var';
     step := 'Assigning NIL to node var';
     if _Node=Self then _Node := Nil;
     if _Node=Self then _Node := Nil;
 
 
     step := 'Destroying Bank';
     step := 'Destroying Bank';
-    FBank.Free;
+    FreeAndNil(FBank);
 
 
     step := 'inherited';
     step := 'inherited';
     inherited;
     inherited;
@@ -647,8 +649,8 @@ begin
   if Assigned(FNode) then FNode.FNotifyList.Remove(Self);
   if Assigned(FNode) then FNode.FNotifyList.Remove(Self);
   FThreadSafeNodeNotifyEvent.FNodeNotifyEvents := Nil;
   FThreadSafeNodeNotifyEvent.FNodeNotifyEvents := Nil;
   FThreadSafeNodeNotifyEvent.Terminate;
   FThreadSafeNodeNotifyEvent.Terminate;
-  FPendingNotificationsList.Free;
-  FMessages.Free;
+  FreeAndNil(FPendingNotificationsList);
+  FreeAndNil(FMessages);
   inherited;
   inherited;
 end;
 end;
 
 
@@ -690,7 +692,7 @@ procedure TThreadSafeNodeNotifyEvent.BCExecute;
 begin
 begin
   while (not Terminated) AND (Assigned(FNodeNotifyEvents)) do begin
   while (not Terminated) AND (Assigned(FNodeNotifyEvents)) do begin
     if (FNotifyOperationsChanged) Or (FNotifyBlocksChanged) Or (FNodeNotifyEvents.FMessages.Count>0) then Synchronize(SynchronizedProcess);
     if (FNotifyOperationsChanged) Or (FNotifyBlocksChanged) Or (FNodeNotifyEvents.FMessages.Count>0) then Synchronize(SynchronizedProcess);
-    Sleep(1);
+    Sleep(100);
   end;
   end;
 end;
 end;
 
 
@@ -722,16 +724,31 @@ end;
 
 
 procedure TThreadNodeNotifyNewBlock.BCExecute;
 procedure TThreadNodeNotifyNewBlock.BCExecute;
 begin
 begin
+  if TNetData.NetData.ConnectionLock(Self,FNetConnection) then begin
+    try
+      TLog.NewLog(ltdebug,ClassName,'Sending new block found to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
+      FNetConnection.Send_NewBlockFound;
+      if TNode.Node.Operations.OperationsHashTree.OperationsCount>0 then begin
+         TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(TNode.Node.Operations.OperationsHashTree.OperationsCount)+' sanitized operations to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
+         FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
+      end;
+    finally
+      TNetData.NetData.ConnectionUnlock(FNetConnection);
+    end;
+  end;
+  {
   If Not TNetData.NetData.ConnectionExistsAndActive(FNetConnection) then begin
   If Not TNetData.NetData.ConnectionExistsAndActive(FNetConnection) then begin
     TLog.NewLog(ltdebug,Classname,'Connection not active');
     TLog.NewLog(ltdebug,Classname,'Connection not active');
     exit;
     exit;
   end;
   end;
+  FNetConnection.WhenPossible_Send_NewBlockFound;
   TLog.NewLog(ltdebug,ClassName,'Sending new block found to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
   TLog.NewLog(ltdebug,ClassName,'Sending new block found to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
   FNetConnection.Send_NewBlockFound;
   FNetConnection.Send_NewBlockFound;
   if TNode.Node.Operations.OperationsHashTree.OperationsCount>0 then begin
   if TNode.Node.Operations.OperationsHashTree.OperationsCount>0 then begin
      TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(TNode.Node.Operations.OperationsHashTree.OperationsCount)+' sanitized operations to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
      TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(TNode.Node.Operations.OperationsHashTree.OperationsCount)+' sanitized operations to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
      FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
      FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
   end;
   end;
+  }
 end;
 end;
 
 
 constructor TThreadNodeNotifyNewBlock.Create(NetConnection: TNetConnection);
 constructor TThreadNodeNotifyNewBlock.Create(NetConnection: TNetConnection);
@@ -745,13 +762,24 @@ end;
 
 
 procedure TThreadNodeNotifyOperations.BCExecute;
 procedure TThreadNodeNotifyOperations.BCExecute;
 begin
 begin
-  If Not TNetData.NetData.ConnectionExistsAndActive(FNetConnection) then begin
+  if TNetData.NetData.ConnectionLock(Self, FNetConnection) then begin
+    try
+      if FOperationsHashTree.OperationsCount<=0 then exit;
+      TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(FOperationsHashTree.OperationsCount)+' Operations to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
+      FNetConnection.Send_AddOperations(FOperationsHashTree);
+    finally
+      TNetData.NetData.ConnectionUnlock(FNetConnection);
+    end;
+  end;
+
+{  If Not TNetData.NetData.ConnectionExistsAndActive(FNetConnection) then begin
     TLog.NewLog(ltdebug,Classname,'Connection not active');
     TLog.NewLog(ltdebug,Classname,'Connection not active');
     exit;
     exit;
   end;
   end;
   if FOperationsHashTree.OperationsCount<=0 then exit;
   if FOperationsHashTree.OperationsCount<=0 then exit;
   TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(FOperationsHashTree.OperationsCount)+' Operations to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
   TLog.NewLog(ltdebug,ClassName,'Sending '+inttostr(FOperationsHashTree.OperationsCount)+' Operations to '+FNetConnection.Client.RemoteHost+':'+FNetConnection.Client.RemotePort);
   FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
   FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
+  }
 end;
 end;
 
 
 constructor TThreadNodeNotifyOperations.Create(NetConnection: TNetConnection;
 constructor TThreadNodeNotifyOperations.Create(NetConnection: TNetConnection;
@@ -766,12 +794,12 @@ end;
 
 
 destructor TThreadNodeNotifyOperations.Destroy;
 destructor TThreadNodeNotifyOperations.Destroy;
 begin
 begin
-  FOperationsHashTree.Free;
+  FreeAndNil(FOperationsHashTree);
   inherited;
   inherited;
 end;
 end;
 
 
 initialization
 initialization
   _Node := Nil;
   _Node := Nil;
 finalization
 finalization
-  _Node.Free;
+  FreeAndNil(_Node);
 end.
 end.

+ 49 - 9
Units/PascalCoin/UThread.pas

@@ -24,6 +24,7 @@ Type
   TPCThread = Class(TThread)
   TPCThread = Class(TThread)
   private
   private
     FDebugStep: String;
     FDebugStep: String;
+    FStartTickCount : Cardinal;
   protected
   protected
     procedure DoTerminate; override;
     procedure DoTerminate; override;
     procedure Execute; override;
     procedure Execute; override;
@@ -34,6 +35,8 @@ Type
     Class function GetThread(index : Integer) : TPCThread;
     Class function GetThread(index : Integer) : TPCThread;
     Class function TerminateAllThreads : Integer;
     Class function TerminateAllThreads : Integer;
     Class Procedure ProtectEnterCriticalSection(Const Sender : TObject; var Lock : TRTLCriticalSection);
     Class Procedure ProtectEnterCriticalSection(Const Sender : TObject; var Lock : TRTLCriticalSection);
+    Class Function TryProtectEnterCriticalSection(Const Sender : TObject; MaxWaitMilliseconds : Cardinal; var Lock : TRTLCriticalSection) : Boolean;
+    Class Procedure ThreadsListInfo(list: TStrings);
     Property DebugStep : String read FDebugStep write FDebugStep;
     Property DebugStep : String read FDebugStep write FDebugStep;
   End;
   End;
 
 
@@ -44,7 +47,7 @@ Type
   public
   public
     constructor Create;
     constructor Create;
     destructor Destroy; override;
     destructor Destroy; override;
-    procedure Add(Item: Pointer; Const Subject : String);
+    procedure Add(Item: Pointer);
     procedure Clear;
     procedure Clear;
     procedure Remove(Item: Pointer); inline;
     procedure Remove(Item: Pointer); inline;
     function LockList: TList;
     function LockList: TList;
@@ -59,7 +62,7 @@ uses
 
 
 { TPCThread }
 { TPCThread }
 
 
-Var _threads,_aux : TPCThreadList;
+Var _threads : TPCThreadList;
 
 
 procedure TPCThread.DoTerminate;
 procedure TPCThread.DoTerminate;
 begin
 begin
@@ -68,9 +71,11 @@ end;
 
 
 procedure TPCThread.Execute;
 procedure TPCThread.Execute;
 Var l : TList;
 Var l : TList;
+  i : Integer;
 begin
 begin
+  FStartTickCount := GetTickCount;
   FDebugStep := '';
   FDebugStep := '';
-  _threads.Add(Self,'TPCThread.Execute');
+  _threads.Add(Self);
   try
   try
 //    TLog.NewLog(ltdebug,Classname,'Starting Thread');
 //    TLog.NewLog(ltdebug,Classname,'Starting Thread');
     Try
     Try
@@ -89,7 +94,8 @@ begin
     if (Assigned(_threads)) then begin
     if (Assigned(_threads)) then begin
       l := _threads.LockList;
       l := _threads.LockList;
       Try
       Try
-        l.Remove(Self);
+        i := l.Remove(Self);
+        TLog.NewLog(ltdebug,Classname,'Finalizing Thread in pos '+inttostr(i+1)+'/'+inttostr(l.Count+1)+' working time: '+FormatFloat('0.000',(GetTickCount-FStartTickCount) / 1000)+' sec');
       Finally
       Finally
         _threads.UnlockList;
         _threads.UnlockList;
       End;
       End;
@@ -167,9 +173,45 @@ begin
   end;
   end;
 end;
 end;
 
 
+class procedure TPCThread.ThreadsListInfo(list: TStrings);
+Var l : TList;
+  i : Integer;
+begin
+  l := _threads.LockList;
+  try
+    list.BeginUpdate;
+    list.Clear;
+    for i := 0 to l.Count - 1 do begin
+      list.Add(Format('%.2d/%.2d <%s> Time:%s sec - Step: %s',[i+1,l.Count,TPCThread(l[i]).ClassName,FormatFloat('0.000',(GetTickCount-TPCThread(l[i]).FStartTickCount) / 1000),TPCThread(l[i]).DebugStep] ));
+    end;
+    list.EndUpdate;
+  finally
+    _threads.UnlockList;
+  end;
+end;
+
+class function TPCThread.TryProtectEnterCriticalSection(const Sender: TObject;
+  MaxWaitMilliseconds: Cardinal; var Lock: TRTLCriticalSection): Boolean;
+Var tc : Cardinal;
+  s : String;
+begin
+  if MaxWaitMilliseconds>60000 then MaxWaitMilliseconds := 60000;
+  tc := GetTickCount;
+  Repeat
+    Result := TryEnterCriticalSection(Lock);
+    if Not Result then sleep(1);
+  Until (Result) Or (GetTickCount > (tc + MaxWaitMilliseconds));
+  if Not Result then begin
+    s := Format('Cannot Protect a critical section by %s after %d milis - LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',
+      [Sender.ClassName,MaxWaitMilliseconds,
+       Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]);
+    TLog.NewLog(lterror,Classname,s);
+  end;
+end;
+
 { TPCThreadList }
 { TPCThreadList }
 
 
-procedure TPCThreadList.Add(Item: Pointer; Const Subject : String);
+procedure TPCThreadList.Add(Item: Pointer);
 begin
 begin
   LockList;
   LockList;
   Try
   Try
@@ -199,7 +241,7 @@ destructor TPCThreadList.Destroy;
 begin
 begin
   LockList;
   LockList;
   try
   try
-    FList.Free;
+    FreeAndNil(FList);
     inherited Destroy;
     inherited Destroy;
   finally
   finally
     UnlockList;
     UnlockList;
@@ -231,7 +273,5 @@ end;
 initialization
 initialization
   _threads := TPCThreadList.Create;
   _threads := TPCThreadList.Create;
 finalization
 finalization
-  _aux := _threads;
-  _threads := Nil;
-  _aux.Free;
+  FreeAndNil(_threads);
 end.
 end.

Some files were not shown because too many files changed in this diff