Browse Source

Preparing 1.0.6

Changes for preventing some memory leaks and also to be nearly compiled
with Lazarus
PascalCoin 9 years ago
parent
commit
042c232270

+ 3 - 1
PascalCoinWallet.dpr

@@ -28,7 +28,9 @@ uses
   UFRMNewPrivateKeyType in 'Units\Forms\UFRMNewPrivateKeyType.pas' {FRMNewPrivateKeyType},
   UFRMNewPrivateKeyType in 'Units\Forms\UFRMNewPrivateKeyType.pas' {FRMNewPrivateKeyType},
   UAES in 'Units\Utils\UAES.pas',
   UAES in 'Units\Utils\UAES.pas',
   UFRMPayloadDecoder in 'Units\Forms\UFRMPayloadDecoder.pas' {FRMPayloadDecoder},
   UFRMPayloadDecoder in 'Units\Forms\UFRMPayloadDecoder.pas' {FRMPayloadDecoder},
-  UFRMNodesIp in 'Units\Forms\UFRMNodesIp.pas' {FRMNodesIp};
+  UFRMNodesIp in 'Units\Forms\UFRMNodesIp.pas' {FRMNodesIp},
+  UDBGridUtils in 'Units\Utils\UDBGridUtils.pas',
+  UTCPIP in 'Units\PascalCoin\UTCPIP.pas';
 
 
 {$R *.res}
 {$R *.res}
 
 

BIN
PascalCoinWallet.res


+ 1 - 1
Units/Forms/UFRMNodesIp.pas

@@ -29,7 +29,7 @@ type
 implementation
 implementation
 
 
 uses
 uses
-  UNetProtocol, UFRMWallet, UNode;
+  UNetProtocol, UNode, UConst;
 
 
 {$R *.dfm}
 {$R *.dfm}
 
 

+ 1 - 1
Units/Forms/UFRMPascalCoinWalletConfig.pas

@@ -66,7 +66,7 @@ type
 
 
 implementation
 implementation
 
 
-uses UConst, UAccounts, UFRMWallet, ULog, UCrypto;
+uses UConst, UAccounts, ULog, UCrypto, UMiner;
 
 
 {$R *.dfm}
 {$R *.dfm}
 
 

+ 37 - 1
Units/Forms/UFRMWallet.dfm

@@ -381,6 +381,10 @@ object FRMWallet: TFRMWallet
     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
@@ -586,6 +590,10 @@ object FRMWallet: TFRMWallet
         TabOrder = 2
         TabOrder = 2
         object tsAccountOperations: TTabSheet
         object tsAccountOperations: TTabSheet
           Caption = 'Operations of selected Account'
           Caption = 'Operations of selected Account'
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object dgAccountOperations: TDrawGrid
           object dgAccountOperations: TDrawGrid
             Left = 0
             Left = 0
             Top = 0
             Top = 0
@@ -605,6 +613,10 @@ object FRMWallet: TFRMWallet
         object tsMultiSelectAccounts: TTabSheet
         object tsMultiSelectAccounts: TTabSheet
           Caption = 'Selected accounts for massive operations'
           Caption = 'Selected accounts for massive operations'
           ImageIndex = 1
           ImageIndex = 1
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object dgSelectedAccounts: TDrawGrid
           object dgSelectedAccounts: TDrawGrid
             Left = 41
             Left = 41
             Top = 31
             Top = 31
@@ -788,6 +800,10 @@ object FRMWallet: TFRMWallet
     object tsPendingOperations: TTabSheet
     object tsPendingOperations: TTabSheet
       Caption = 'Pending Operations'
       Caption = 'Pending Operations'
       ImageIndex = 5
       ImageIndex = 5
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object dgPendingOperations: TDrawGrid
       object dgPendingOperations: TDrawGrid
         Left = 0
         Left = 0
         Top = 86
         Top = 86
@@ -835,6 +851,10 @@ object FRMWallet: TFRMWallet
     object tsBlockChain: TTabSheet
     object tsBlockChain: TTabSheet
       Caption = 'BlockChain Explorer'
       Caption = 'BlockChain Explorer'
       ImageIndex = 1
       ImageIndex = 1
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object Panel2: TPanel
       object Panel2: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -918,6 +938,10 @@ object FRMWallet: TFRMWallet
     object tsOperations: TTabSheet
     object tsOperations: TTabSheet
       Caption = 'Operations Explorer'
       Caption = 'Operations Explorer'
       ImageIndex = 1
       ImageIndex = 1
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object Panel1: TPanel
       object Panel1: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -1018,6 +1042,10 @@ object FRMWallet: TFRMWallet
     object tsLogs: TTabSheet
     object tsLogs: TTabSheet
       Caption = 'Logs'
       Caption = 'Logs'
       ImageIndex = 2
       ImageIndex = 2
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object pnlTopLogs: TPanel
       object pnlTopLogs: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -1047,6 +1075,10 @@ object FRMWallet: TFRMWallet
     object tsNodeStats: TTabSheet
     object tsNodeStats: TTabSheet
       Caption = 'Node Stats'
       Caption = 'Node Stats'
       ImageIndex = 3
       ImageIndex = 3
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       DesignSize = (
       DesignSize = (
         891
         891
         420)
         420)
@@ -1104,6 +1136,10 @@ 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)
@@ -1332,7 +1368,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Left = 105
     Top = 180
     Top = 180
     Bitmap = {
     Bitmap = {
-      494C010102000800000110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C010102000800080110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 8 - 8
Units/Forms/UFRMWallet.pas

@@ -19,7 +19,7 @@ uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, pngimage, ExtCtrls, ComCtrls, UWalletKeys, ShlObj, ADOInt, StdCtrls,
   Dialogs, pngimage, ExtCtrls, ComCtrls, UWalletKeys, ShlObj, ADOInt, StdCtrls,
   ULog, DB, ADODB, Grids, DBGrids, DBCGrids, UAppParams,
   ULog, DB, ADODB, Grids, DBGrids, DBCGrids, UAppParams,
-  UBlockChain, UNode, DBCtrls, UGridUtils, UMiner, UAccounts, Menus, ImgList,
+  UBlockChain, UNode, DBCtrls, UGridUtils, UDBGridUtils, UMiner, UAccounts, Menus, ImgList,
   AppEvnts, UNetProtocol, UCrypto, Buttons;
   AppEvnts, UNetProtocol, UCrypto, Buttons;
 
 
 Const
 Const
@@ -469,7 +469,7 @@ begin
         nc := TNetConnection(lbNetconnections.Items.Objects[i]);
         nc := TNetConnection(lbNetconnections.Items.Objects[i]);
         if TNetData.NetData.ConnectionExistsAndActive(nc) then begin
         if TNetData.NetData.ConnectionExistsAndActive(nc) then begin
           FNode.SendNodeMessage(nc,m,errors);
           FNode.SendNodeMessage(nc,m,errors);
-          memoMessages.Lines.Add(DateTimeToStr(now)+' Sent to '+nc.Client.RemoteHost+':'+nc.Client.RemotePort+' > '+m);
+          memoMessages.Lines.Add(DateTimeToStr(now)+' Sent to '+nc.ClientRemoteAddr+' > '+m);
         end;
         end;
       end;
       end;
     end;
     end;
@@ -477,7 +477,7 @@ begin
     nc := TNetConnection(lbNetconnections.Items.Objects[lbNetconnections.ItemIndex]);
     nc := TNetConnection(lbNetconnections.Items.Objects[lbNetconnections.ItemIndex]);
     if TNetData.NetData.ConnectionExistsAndActive(nc) then begin
     if TNetData.NetData.ConnectionExistsAndActive(nc) then begin
       FNode.SendNodeMessage(nc,m,errors);
       FNode.SendNodeMessage(nc,m,errors);
-      memoMessages.Lines.Add(DateTimeToStr(now)+' Sent to '+nc.Client.RemoteHost+':'+nc.Client.RemotePort+' > '+m);
+      memoMessages.Lines.Add(DateTimeToStr(now)+' Sent to '+nc.ClientRemoteAddr+' > '+m);
     end;
     end;
   end;
   end;
 
 
@@ -1339,11 +1339,11 @@ Var s : String;
 begin
 begin
   inc(FMessagesUnreadCount);
   inc(FMessagesUnreadCount);
   if Assigned(NetConnection) then begin
   if Assigned(NetConnection) then begin
-    s := DateTimeToStr(now)+' Message received from '+NetConnection.Client.RemoteHost+':'+NetConnection.Client.RemotePort;
-    memoMessages.Lines.Add(DateTimeToStr(now)+' Message received from '+NetConnection.Client.RemoteHost+':'+NetConnection.Client.RemotePort+' Length '+inttostr(Length(MessageData))+' bytes');
+    s := DateTimeToStr(now)+' Message received from '+NetConnection.ClientRemoteAddr;
+    memoMessages.Lines.Add(DateTimeToStr(now)+' Message received from '+NetConnection.ClientRemoteAddr+' Length '+inttostr(Length(MessageData))+' bytes');
     memoMessages.Lines.Add('RECEIVED> '+MessageData);
     memoMessages.Lines.Add('RECEIVED> '+MessageData);
     if FAppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false) then begin
     if FAppParams.ParamByName[CT_PARAM_ShowModalMessages].GetAsBoolean(false) then begin
-      s := DateTimeToStr(now)+' Message from '+NetConnection.Client.RemoteHost+':'+NetConnection.Client.RemotePort+#10+
+      s := DateTimeToStr(now)+' Message from '+NetConnection.ClientRemoteAddr+#10+
          'Length '+inttostr(length(MessageData))+' bytes'+#10+#10;
          'Length '+inttostr(length(MessageData))+' bytes'+#10+#10;
       if TCrypto.IsHumanReadable(MessageData) then begin
       if TCrypto.IsHumanReadable(MessageData) then begin
          s := s + MessageData;
          s := s + MessageData;
@@ -1612,11 +1612,11 @@ begin
         if NC.Connected then begin
         if NC.Connected then begin
           if NC is TNetServerClient then begin
           if NC is TNetServerClient then begin
             if Not NC.IsMyselfServer then begin
             if Not NC.IsMyselfServer then begin
-              lbNetConnections.Items.AddObject(Format('Client: IP:%s:%s',[NC.Client.RemoteHost,NC.Client.RemotePort]),NC);
+              lbNetConnections.Items.AddObject(Format('Client: IP:%s',[NC.ClientRemoteAddr]),NC);
             end;
             end;
           end else begin
           end else begin
             if Not NC.IsMyselfServer then begin
             if Not NC.IsMyselfServer then begin
-              lbNetConnections.Items.AddObject(Format('Server: IP:%s:%s',[NC.Client.RemoteHost,NC.Client.RemotePort]),NC);
+              lbNetConnections.Items.AddObject(Format('Server: IP:%s',[NC.ClientRemoteAddr]),NC);
             end;
             end;
           end;
           end;
         end;
         end;

+ 5 - 5
Units/PascalCoin/UAccounts.pas

@@ -16,7 +16,7 @@ unit UAccounts;
 interface
 interface
 
 
 uses
 uses
-  Classes, UConst, Windows, UCrypto;
+  Classes, UConst, Windows, UCrypto, SyncObjs;
 
 
 Type
 Type
   TAccountKey = TECDSA_Public;
   TAccountKey = TECDSA_Public;
@@ -105,7 +105,7 @@ Type
     FTotalBalance: Int64;
     FTotalBalance: Int64;
     FTotalFee: Int64;
     FTotalFee: Int64;
     FSafeBoxHash : TRawBytes;
     FSafeBoxHash : TRawBytes;
-    FLock: TRTLCriticalSection; // Thread safe
+    FLock: TCriticalSection; // Thread safe
     FIsLocked : Boolean;
     FIsLocked : Boolean;
     Procedure SetAccount(account_number : Cardinal; newAccountkey: TAccountKey; newBalance: UInt64; newN_operation: Cardinal);
     Procedure SetAccount(account_number : Cardinal; newAccountkey: TAccountKey; newBalance: UInt64; newN_operation: Cardinal);
     Procedure AccountKeyListAddAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
     Procedure AccountKeyListAddAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
@@ -728,7 +728,7 @@ end;
 
 
 constructor TPCSafeBox.Create;
 constructor TPCSafeBox.Create;
 begin
 begin
-  InitializeCriticalSection(FLock);
+  FLock := TCriticalSection.Create;
   FIsLocked := false;
   FIsLocked := false;
   FBlockAccountsList := TList.Create;
   FBlockAccountsList := TList.Create;
   FListOfOrderedAccountKeysList := TList.Create;
   FListOfOrderedAccountKeysList := TList.Create;
@@ -744,7 +744,7 @@ begin
   end;
   end;
   FreeAndNil(FBlockAccountsList);
   FreeAndNil(FBlockAccountsList);
   FreeAndNil(FListOfOrderedAccountKeysList);
   FreeAndNil(FListOfOrderedAccountKeysList);
-  DeleteCriticalSection(Flock);
+  FLock.Free;
   inherited;
   inherited;
 end;
 end;
 
 
@@ -752,7 +752,7 @@ procedure TPCSafeBox.EndThreadSave;
 begin
 begin
   if Not FIsLocked then raise Exception.Create('Is not locked');
   if Not FIsLocked then raise Exception.Create('Is not locked');
   FIsLocked := False;
   FIsLocked := False;
-  LeaveCriticalSection(FLock);
+  FLock.Release;
 end;
 end;
 
 
 function TPCSafeBox.LoadFromStream(Stream : TStream; var LastReadBlock : TBlockAccount; var errors : AnsiString) : Boolean;
 function TPCSafeBox.LoadFromStream(Stream : TStream; var LastReadBlock : TBlockAccount; var errors : AnsiString) : Boolean;

+ 60 - 75
Units/PascalCoin/UBlockChain.pas

@@ -16,7 +16,7 @@
 interface
 interface
 
 
 uses
 uses
-  Classes, UCrypto, UAccounts, Windows, ULog, UThread;
+  Classes, UCrypto, UAccounts, Windows, ULog, UThread, SyncObjs;
 
 
 
 
 Type
 Type
@@ -249,25 +249,28 @@ Type
   private
   private
     FOrphan: TOrphan;
     FOrphan: TOrphan;
     FBank : TPCBank;
     FBank : TPCBank;
+    FReadOnly: Boolean;
     procedure SetBank(const Value: TPCBank);
     procedure SetBank(const Value: TPCBank);
   protected
   protected
     procedure SetOrphan(const Value: TOrphan); virtual;
     procedure SetOrphan(const Value: TOrphan); virtual;
+    procedure SetReadOnly(const Value: Boolean); virtual;
     Function DoLoadBlockChain(Operations : TPCOperationsComp; Block : Cardinal) : Boolean; virtual; abstract;
     Function DoLoadBlockChain(Operations : TPCOperationsComp; Block : Cardinal) : Boolean; virtual; abstract;
     Function DoSaveBlockChain(Operations : TPCOperationsComp) : Boolean; virtual; abstract;
     Function DoSaveBlockChain(Operations : TPCOperationsComp) : Boolean; virtual; abstract;
-    Function DoMoveBlockChain(StartBlock : Cardinal; Const DestOrphan : TOrphan) : Boolean; virtual; abstract;
+    Function DoMoveBlockChain(StartBlock : Cardinal; Const DestOrphan : TOrphan; DestStorage : TStorage) : Boolean; virtual; abstract;
     Function DoSaveBank : Boolean; virtual; abstract;
     Function DoSaveBank : Boolean; virtual; abstract;
     Function DoRestoreBank(max_block : Int64) : Boolean; virtual; abstract;
     Function DoRestoreBank(max_block : Int64) : Boolean; virtual; abstract;
-    Procedure DoDeleteBlockChainBlocks(StartingDeleteBlock : Cardinal; Orphan : TOrphan); virtual; abstract;
+    Procedure DoDeleteBlockChainBlocks(StartingDeleteBlock : Cardinal); virtual; abstract;
     Function BlockExists(Block : Cardinal) : Boolean; virtual; abstract;
     Function BlockExists(Block : Cardinal) : Boolean; virtual; abstract;
   public
   public
     Function LoadBlockChainBlock(Operations : TPCOperationsComp; Block : Cardinal) : Boolean;
     Function LoadBlockChainBlock(Operations : TPCOperationsComp; Block : Cardinal) : Boolean;
     Function SaveBlockChainBlock(Operations : TPCOperationsComp) : Boolean;
     Function SaveBlockChainBlock(Operations : TPCOperationsComp) : Boolean;
-    Function MoveBlockChainBlocks(StartBlock : Cardinal; Const DestOrphan : TOrphan) : Boolean;
-    Procedure DeleteBlockChainBlocks(StartingDeleteBlock : Cardinal; Orphan : TOrphan);
+    Function MoveBlockChainBlocks(StartBlock : Cardinal; Const DestOrphan : TOrphan; DestStorage : TStorage) : Boolean;
+    Procedure DeleteBlockChainBlocks(StartingDeleteBlock : Cardinal);
     Function SaveBank : Boolean;
     Function SaveBank : Boolean;
     Function RestoreBank(max_block : Int64) : Boolean;
     Function RestoreBank(max_block : Int64) : Boolean;
     Constructor Create(AOwner : TComponent); Override;
     Constructor Create(AOwner : TComponent); Override;
     Property Orphan : TOrphan read FOrphan write SetOrphan;
     Property Orphan : TOrphan read FOrphan write SetOrphan;
+    Property ReadOnly : Boolean read FReadOnly write SetReadOnly;
     Property Bank : TPCBank read FBank write SetBank;
     Property Bank : TPCBank read FBank write SetBank;
     Procedure CopyConfiguration(Const CopyFrom : TStorage); virtual;
     Procedure CopyConfiguration(Const CopyFrom : TStorage); virtual;
   End;
   End;
@@ -284,7 +287,7 @@ Type
     FActualTargetHash: TRawBytes;
     FActualTargetHash: TRawBytes;
     FIsRestoringFromFile: Boolean;
     FIsRestoringFromFile: Boolean;
     FOnLog: TPCBankLog;
     FOnLog: TPCBankLog;
-    FBankLock: TRTLCriticalSection;
+    FBankLock: TCriticalSection;
     FNotifyList : TList;
     FNotifyList : TList;
     FStorageClass: TStorageClass;
     FStorageClass: TStorageClass;
     function GetStorage: TStorage;
     function GetStorage: TStorage;
@@ -380,10 +383,12 @@ begin
           exit;
           exit;
         end;
         end;
       end else begin
       end else begin
-        // Check if valid Zero block
-        if Not (AnsiSameText(TCrypto.ToHexaString(Operations.OperationBlock.proof_of_work),CT_Zero_Block_Proof_of_work_in_Hexa)) then begin
-          errors := 'Zero block not valid, Proof of Work invalid: '+TCrypto.ToHexaString(Operations.OperationBlock.proof_of_work)+'<>'+CT_Zero_Block_Proof_of_work_in_Hexa;
-          exit;
+        if (CT_Zero_Block_Proof_of_work_in_Hexa<>'') then begin
+          // Check if valid Zero block
+          if Not (AnsiSameText(TCrypto.ToHexaString(Operations.OperationBlock.proof_of_work),CT_Zero_Block_Proof_of_work_in_Hexa)) then begin
+            errors := 'Zero block not valid, Proof of Work invalid: '+TCrypto.ToHexaString(Operations.OperationBlock.proof_of_work)+'<>'+CT_Zero_Block_Proof_of_work_in_Hexa;
+            exit;
+          end;
         end;
         end;
       end;
       end;
       if (Operations.OperationBlock.compact_target <> GetActualCompactTargetHash) then begin
       if (Operations.OperationBlock.compact_target <> GetActualCompactTargetHash) then begin
@@ -440,7 +445,7 @@ begin
         NewLog(Operations, lterror, 'Invalid new block '+inttostr(Operations.OperationBlock.block)+': ' + errors);
         NewLog(Operations, lterror, 'Invalid new block '+inttostr(Operations.OperationBlock.block)+': ' + errors);
     End;
     End;
   Finally
   Finally
-    LeaveCriticalSection(FBankLock);
+    FBankLock.Release;
   End;
   End;
   if Result then begin
   if Result then begin
     for i := 0 to FNotifyList.Count - 1 do begin
     for i := 0 to FNotifyList.Count - 1 do begin
@@ -488,7 +493,7 @@ begin
   inherited;
   inherited;
   FStorage := Nil;
   FStorage := Nil;
   FStorageClass := Nil;
   FStorageClass := Nil;
-  InitializeCriticalSection(FBankLock);
+  FBankLock := TCriticalSection.Create;
   FIsRestoringFromFile := False;
   FIsRestoringFromFile := False;
   FOnLog := Nil;
   FOnLog := Nil;
   FSafeBox := TPCSafeBox.Create;
   FSafeBox := TPCSafeBox.Create;
@@ -502,7 +507,7 @@ var step : String;
 begin
 begin
   Try
   Try
     step := 'Deleting critical section';
     step := 'Deleting critical section';
-    DeleteCriticalSection(FBankLock);
+    FBankLock.Free;
     step := 'Clear';
     step := 'Clear';
     Clear;
     Clear;
     step := 'Destroying LastBlockCache';
     step := 'Destroying LastBlockCache';
@@ -554,7 +559,7 @@ begin
             if Storage.LoadBlockChainBlock(Operations,BlocksCount) then begin
             if Storage.LoadBlockChainBlock(Operations,BlocksCount) then begin
               if Not AddNewBlockChainBlock(Operations,newBlock,errors) then begin
               if Not AddNewBlockChainBlock(Operations,newBlock,errors) then begin
                 NewLog(Operations, lterror,'Error restoring block: ' + Inttostr(BlocksCount)+ ' Errors: ' + errors);
                 NewLog(Operations, lterror,'Error restoring block: ' + Inttostr(BlocksCount)+ ' Errors: ' + errors);
-                Storage.DeleteBlockChainBlocks(BlocksCount,Storage.Orphan);
+                Storage.DeleteBlockChainBlocks(BlocksCount);
                 break;
                 break;
               end else begin
               end else begin
                 Storage.SaveBank;
                 Storage.SaveBank;
@@ -570,7 +575,7 @@ begin
       FIsRestoringFromFile := False;
       FIsRestoringFromFile := False;
     end;
     end;
   finally
   finally
-    LeaveCriticalSection(FBankLock);
+    FBankLock.Release;
   end;
   end;
 end;
 end;
 
 
@@ -602,23 +607,6 @@ begin
     FActualTargetHash := GetNewTarget(tsTeorical, tsReal,TargetFromCompact(FLastOperationBlock.compact_target));
     FActualTargetHash := GetNewTarget(tsTeorical, tsReal,TargetFromCompact(FLastOperationBlock.compact_target));
   end;
   end;
   Result := FActualTargetHash;
   Result := FActualTargetHash;
-
-  exit;
-
-  if (BlocksCount <= CT_CalcNewTargetBlocksAverage) then begin
-    // Important: CT_MinCompactTarget is applied for blocks 0 until ((CT_CalcNewDifficulty*2)-1)
-    FActualTargetHash := TargetFromCompact(CT_MinCompactTarget);
-  end else begin
-    if (BlocksCount MOD CT_CalcNewTargetBlocksAverage) = 0 then begin
-      // Calc new target!
-      ts1 := SafeBox.Block(BlocksCount-1).timestamp;
-      ts2 := SafeBox.Block(BlocksCount-CT_CalcNewTargetBlocksAverage-1).timestamp;
-      tsTeorical := (CT_CalcNewTargetBlocksAverage * CT_NewLineSecondsAvg);
-      tsReal := (ts1 - ts2);
-      FActualTargetHash := GetNewTarget(tsTeorical, tsReal,TargetFromCompact(FLastOperationBlock.compact_target));
-    end;
-  end;
-  Result := FActualTargetHash;
 end;
 end;
 
 
 function TPCBank.GetActualTargetSecondsAverage(BackBlocks: Cardinal): Real;
 function TPCBank.GetActualTargetSecondsAverage(BackBlocks: Cardinal): Real;
@@ -751,7 +739,7 @@ begin
       // Initialize new target hash:
       // Initialize new target hash:
       FActualTargetHash := GetActualTargetHash;
       FActualTargetHash := GetActualTargetHash;
     finally
     finally
-      LeaveCriticalSection(FBankLock);
+      FBankLock.Release;
     end;
     end;
     for i := 0 to FNotifyList.Count - 1 do begin
     for i := 0 to FNotifyList.Count - 1 do begin
       TPCBankNotify(FNotifyList.Items[i]).NotifyNewBlock;
       TPCBankNotify(FNotifyList.Items[i]).NotifyNewBlock;
@@ -771,7 +759,7 @@ begin
       Result := Storage.LoadBlockChainBlock(Operations,Block);
       Result := Storage.LoadBlockChainBlock(Operations,Block);
     end;
     end;
   finally
   finally
-    LeaveCriticalSection(FBankLock);
+    FBankLock.Release;
   end;
   end;
 end;
 end;
 
 
@@ -1270,34 +1258,30 @@ begin
   Stream.Read(c, 4);
   Stream.Read(c, 4);
   // c = operations count
   // c = operations count
   for i := 1 to c do begin
   for i := 1 to c do begin
-    bcop := Nil;
-    try
-      errors := 'Invalid operation structure ' + inttostr(i) + '/' + inttostr(c);
-      if Stream.Size - Stream.Position < 4 then exit;
-      Stream.Read(OpType, 4);
-      j := IndexOfOperationClassByOpType(OpType);
-      if j >= 0 then
-        OpClass := _OperationsClass[j]
-      else
-        OpClass := Nil;
-      if Not Assigned(OpClass) then begin
-        errors := errors + ' optype not valid:' + InttoHex(OpType, 4);
-        exit;
-      end;
-      errors := errors + ' Operation:'+OpClass.ClassName;
-      bcop := OpClass.Create;
+    errors := 'Invalid operation structure ' + inttostr(i) + '/' + inttostr(c);
+    if Stream.Size - Stream.Position < 4 then exit;
+    Stream.Read(OpType, 4);
+    j := IndexOfOperationClassByOpType(OpType);
+    if j >= 0 then
+      OpClass := _OperationsClass[j]
+    else
+      OpClass := Nil;
+    if Not Assigned(OpClass) then begin
+      errors := errors + ' optype not valid:' + InttoHex(OpType, 4);
+      exit;
+    end;
+    errors := 'Invalid operation ' + inttostr(i) + '/' + inttostr(c)+' Class:'+OpClass.ClassName;
+    bcop := OpClass.Create;
+    Try
       if not bcop.LoadFromStream(Stream) then begin
       if not bcop.LoadFromStream(Stream) then begin
-        bcop.Free;
         exit;
         exit;
       end;
       end;
       if Not AddOperation(false,bcop, errors2) then begin
       if Not AddOperation(false,bcop, errors2) then begin
         errors := errors + ' '+errors2+' '+bcop.ToString;
         errors := errors + ' '+errors2+' '+bcop.ToString;
-        bcop.Free;
         exit;
         exit;
       end;
       end;
-    Except
+    Finally
       FreeAndNil(bcop);
       FreeAndNil(bcop);
-      raise ;
     end;
     end;
   end;
   end;
   // Validation control:
   // Validation control:
@@ -1640,31 +1624,19 @@ end;
 procedure TOperationsHashTree.CopyFromHashTree(Sender: TOperationsHashTree);
 procedure TOperationsHashTree.CopyFromHashTree(Sender: TOperationsHashTree);
 Var i : Integer;
 Var i : Integer;
   lme, lsender : TList;
   lme, lsender : TList;
-  opsender,op : TPCOperation;
-  ms : TMemoryStream;
+  opsender : TPCOperation;
 begin
 begin
   if (Sender = Self) then begin
   if (Sender = Self) then begin
     exit;
     exit;
   end;
   end;
-
   ClearHastThree;
   ClearHastThree;
   lme := FHashTreeOperations.LockList;
   lme := FHashTreeOperations.LockList;
   lsender := Sender.FHashTreeOperations.LockList;
   lsender := Sender.FHashTreeOperations.LockList;
   try
   try
-    ms := TMemoryStream.Create;
-    Try
-      for i := 0 to lsender.Count - 1 do begin
-        opsender := lsender[i];
-        op := TPCOperation(opsender.NewInstance);
-        ms.Size:=0;
-        opsender.SaveToStream(ms);
-        ms.Position:=0;
-        op.LoadFromStream(ms);
-        InternalAddOperationToHashTree(lme,op);
-      end;
-    Finally
-      ms.Free;
-    End;
+    for i := 0 to lsender.Count - 1 do begin
+      opsender := lsender[i];
+      InternalAddOperationToHashTree(lme,opsender);
+    end;
   finally
   finally
     FHashTreeOperations.UnlockList;
     FHashTreeOperations.UnlockList;
     Sender.FHashTreeOperations.UnlockList;
     Sender.FHashTreeOperations.UnlockList;
@@ -1681,6 +1653,7 @@ destructor TOperationsHashTree.Destroy;
 begin
 begin
   ClearHastThree;
   ClearHastThree;
   FreeAndNil(FHashTreeOperations);
   FreeAndNil(FHashTreeOperations);
+  SetLength(FHashTree,0);
   inherited;
   inherited;
 end;
 end;
 
 
@@ -1761,11 +1734,13 @@ constructor TStorage.Create(AOwner: TComponent);
 begin
 begin
   inherited;
   inherited;
   FOrphan := '';
   FOrphan := '';
+  FReadOnly := false;
 end;
 end;
 
 
-procedure TStorage.DeleteBlockChainBlocks(StartingDeleteBlock: Cardinal; Orphan: TOrphan);
+procedure TStorage.DeleteBlockChainBlocks(StartingDeleteBlock: Cardinal);
 begin
 begin
-  DoDeleteBlockChainBlocks(StartingDeleteBlock,Orphan);
+  if ReadOnly then raise Exception.Create('Cannot delete blocks because is ReadOnly');
+  DoDeleteBlockChainBlocks(StartingDeleteBlock);
 end;
 end;
 
 
 function TStorage.LoadBlockChainBlock(Operations: TPCOperationsComp; Block: Cardinal): Boolean;
 function TStorage.LoadBlockChainBlock(Operations: TPCOperationsComp; Block: Cardinal): Boolean;
@@ -1773,9 +1748,12 @@ begin
    Result := DoLoadBlockChain(Operations,Block);
    Result := DoLoadBlockChain(Operations,Block);
 end;
 end;
 
 
-function TStorage.MoveBlockChainBlocks(StartBlock: Cardinal; const DestOrphan: TOrphan): Boolean;
+function TStorage.MoveBlockChainBlocks(StartBlock: Cardinal; const DestOrphan: TOrphan; DestStorage : TStorage): Boolean;
 begin
 begin
-  Result := DoMoveBlockChain(StartBlock,DestOrphan);
+  if Assigned(DestStorage) then begin
+    if DestStorage.ReadOnly then raise Exception.Create('Cannot move blocks because is ReadOnly');
+  end else if ReadOnly then raise Exception.Create('Cannot move blocks from myself because is ReadOnly');
+  Result := DoMoveBlockChain(StartBlock,DestOrphan,DestStorage);
 end;
 end;
 
 
 function TStorage.RestoreBank(max_block: Int64): Boolean;
 function TStorage.RestoreBank(max_block: Int64): Boolean;
@@ -1788,6 +1766,7 @@ begin
   Result := true;
   Result := true;
   if (Bank.BlocksCount MOD CT_BankToDiskEveryNBlocks)<>0 then exit; // No bank!
   if (Bank.BlocksCount MOD CT_BankToDiskEveryNBlocks)<>0 then exit; // No bank!
   Try
   Try
+    if ReadOnly then raise Exception.Create('Cannot save because is ReadOnly');
     Result := DoSaveBank;
     Result := DoSaveBank;
   Except
   Except
     On E:Exception do begin
     On E:Exception do begin
@@ -1800,6 +1779,7 @@ end;
 function TStorage.SaveBlockChainblock(Operations: TPCOperationsComp): Boolean;
 function TStorage.SaveBlockChainblock(Operations: TPCOperationsComp): Boolean;
 begin
 begin
   Try
   Try
+    if ReadOnly then raise Exception.Create('Cannot save because is ReadOnly');
     Result := DoSaveBlockChain(Operations);
     Result := DoSaveBlockChain(Operations);
   Except
   Except
     On E:Exception do begin
     On E:Exception do begin
@@ -1819,6 +1799,11 @@ begin
   FOrphan := Value;
   FOrphan := Value;
 end;
 end;
 
 
+procedure TStorage.SetReadOnly(const Value: Boolean);
+begin
+  FReadOnly := Value;
+end;
+
 { TPCOperation }
 { TPCOperation }
 
 
 class function TPCOperation.IsReadablePayload(const Payload: TRawBytes): Boolean;
 class function TPCOperation.IsReadablePayload(const Payload: TRawBytes): Boolean;

+ 29 - 8
Units/PascalCoin/UConst.pas

@@ -23,30 +23,31 @@ Const
     '(c) Albert Molina - Genesis block at same time than BitCoin Block 424720 Hash 000000000000000001cc41ff7846264718ef0a15f97f532a98277bd5f6820b89';
     '(c) Albert Molina - Genesis block at same time than BitCoin Block 424720 Hash 000000000000000001cc41ff7846264718ef0a15f97f532a98277bd5f6820b89';
 
 
   CT_Zero_Block_Proof_of_work_in_Hexa =
   CT_Zero_Block_Proof_of_work_in_Hexa =
-    '00000003A29C32E84A539ADE24397D41D30116A6FAFEC17B7D9CED68A4238C92';
+    {$IFDEF PRODUCTION}'00000003A29C32E84A539ADE24397D41D30116A6FAFEC17B7D9CED68A4238C92'{$ELSE}{$IFDEF TESTNET}''{$ENDIF}{$ENDIF};
 
 
 
 
-  CT_NetServer_Port = 4004;
+  CT_NetServer_Port = {$IFDEF PRODUCTION}4004{$ELSE}{$IFDEF TESTNET}4104{$ENDIF}{$ENDIF};
   CT_AccountsPerBlock = 5;
   CT_AccountsPerBlock = 5;
 
 
-  CT_NewLineSecondsAvg: Cardinal = 300; // 60*5=300 seconds -> 5 minutes avg
+  CT_NewLineSecondsAvg: Cardinal = {$IFDEF PRODUCTION}300{$ELSE}{$IFDEF TESTNET}30{$ENDIF}{$ENDIF};
+    // 60*5=300 seconds -> 5 minutes avg
     //   -> 1 day = 86400 seconds -> 1 year = 31536000 seconds (aprox)
     //   -> 1 day = 86400 seconds -> 1 year = 31536000 seconds (aprox)
     //   Each year = 105120 new blocks (aprox)
     //   Each year = 105120 new blocks (aprox)
     //   -> *5 accounts per block = 525600 new accounts each year (aprox)
     //   -> *5 accounts per block = 525600 new accounts each year (aprox)
 
 
   CT_FirstReward: UInt64 = 1000000; // 4 decimals... First reward = 100,0000
   CT_FirstReward: UInt64 = 1000000; // 4 decimals... First reward = 100,0000
   CT_MinReward: UInt64 = 10000; // 4 decimals... Min reward = 1,0000
   CT_MinReward: UInt64 = 10000; // 4 decimals... Min reward = 1,0000
-  CT_NewLineRewardDecrease: Cardinal = 420480; // Avg 4 year
+  CT_NewLineRewardDecrease: Cardinal = {$IFDEF PRODUCTION}420480{$ELSE}{$IFDEF TESTNET}600{$ENDIF}{$ENDIF}; // Avg 4 year
 
 
   CT_WaitNewBlocksBeforeTransaction = 100;
   CT_WaitNewBlocksBeforeTransaction = 100;
 
 
-  CT_RecoverFoundsWaitInactiveCount = 420480;  // After 4 years... if an account has no operations, money will be a reward for a miner!
+  CT_RecoverFoundsWaitInactiveCount = {$IFDEF PRODUCTION}420480{$ELSE}{$IFDEF TESTNET}500{$ENDIF}{$ENDIF};  // After 4 years... if an account has no operations, money will be a reward for a miner!
 
 
   CT_MaxTransactionAmount = 1000000000000;
   CT_MaxTransactionAmount = 1000000000000;
   CT_MaxTransactionFee = 100000000;
   CT_MaxTransactionFee = 100000000;
   CT_MaxWalletAmount = 10000000000000;
   CT_MaxWalletAmount = 10000000000000;
   //
   //
-  CT_MinCompactTarget: Cardinal = $19000000; // First compact target of block 0
+  CT_MinCompactTarget: Cardinal = {$IFDEF PRODUCTION}$19000000{$ELSE}{$IFDEF TESTNET}$16000000{$ENDIF}{$ENDIF}; // First compact target of block 0
 
 
   CT_CalcNewTargetBlocksAverage: Cardinal = 100;
   CT_CalcNewTargetBlocksAverage: Cardinal = 100;
   CT_MaxBlock : Cardinal = $FFFFFFFF;
   CT_MaxBlock : Cardinal = $FFFFFFFF;
@@ -78,12 +79,32 @@ Const
   CT_Op_Changekey = $02;
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
   CT_Op_Recover = $03;
 
 
-  CT_ClientAppVersion : AnsiString = '1.0.5';
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.0.5'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ENDIF}{$ENDIF};
 
 
-  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 =  {$IFDEF PRODUCTION}'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.ddns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us'{$ELSE}{$IFDEF TESTNET}''{$ENDIF}{$ENDIF};
 
 
   CT_TRUE_FALSE : Array[Boolean] Of AnsiString = ('FALSE','TRUE');
   CT_TRUE_FALSE : Array[Boolean] Of AnsiString = ('FALSE','TRUE');
 
 
+  // App Params
+  CT_PARAM_GridAccountsStream = 'GridAccountsStream';
+  CT_PARAM_GridAccountsPos = 'GridAccountsPos';
+  CT_PARAM_DefaultFee = 'DefaultFee';
+  CT_PARAM_InternetServerPort = 'InternetServerPort';
+  CT_PARAM_AutomaticMineWhenConnectedToNodes = 'AutomaticMineWhenConnectedToNodes';
+  CT_PARAM_MinerPrivateKeyType = 'MinerPrivateKeyType';
+  CT_PARAM_MinerPrivateKeySelectedPublicKey = 'MinerPrivateKeySelectedPublicKey';
+  CT_PARAM_SaveLogFiles = 'SaveLogFiles';
+  CT_PARAM_SaveDebugLogs = 'SaveDebugLogs';
+  CT_PARAM_ShowLogs = 'ShowLogs';
+  CT_PARAM_MinerName = 'MinerName';
+  CT_PARAM_FirstTime = 'FirstTime';
+  CT_PARAM_ShowModalMessages = 'ShowModalMessages';
+  CT_PARAM_MaxCPUs = 'MaxCPUs';
+  CT_PARAM_PeerCache = 'PeerCache';
+  CT_PARAM_TryToConnectOnlyWithThisFixedServers = 'TryToConnectOnlyWithFixedServers';
+
+
+
 implementation
 implementation
 
 
 end.
 end.

+ 8 - 6
Units/PascalCoin/UCrypto.pas

@@ -345,7 +345,6 @@ end;
 
 
 class function TCrypto.DoSha256(p: PAnsiChar; plength: Cardinal): TRawBytes;
 class function TCrypto.DoSha256(p: PAnsiChar; plength: Cardinal): TRawBytes;
 Var PS : PAnsiChar;
 Var PS : PAnsiChar;
-  PC : PAnsiChar;
 begin
 begin
   SetLength(Result,32);
   SetLength(Result,32);
   PS := @Result[1];
   PS := @Result[1];
@@ -358,7 +357,6 @@ begin
   SetLength(Result,32);
   SetLength(Result,32);
   PS := @Result[1];
   PS := @Result[1];
   SHA256(PAnsiChar(TheMessage),Length(TheMessage),PS);
   SHA256(PAnsiChar(TheMessage),Length(TheMessage),PS);
-  exit;
 end;
 end;
 
 
 class function TCrypto.ECDSASign(Key: PEC_KEY; const digest: AnsiString): TECDSA_SIG;
 class function TCrypto.ECDSASign(Key: PEC_KEY; const digest: AnsiString): TECDSA_SIG;
@@ -626,10 +624,14 @@ Var n : TBigNum;
   ctx : PBN_CTX;
   ctx : PBN_CTX;
 begin
 begin
   n := TBigNum.Create(int);
   n := TBigNum.Create(int);
-  ctx := BN_CTX_new;
-  if BN_mul(FBN,FBN,n.FBN,ctx)<>1 then raise ECryptoException.Create('Error on multiply');
-  BN_CTX_free(ctx);
-  Result := Self;
+  Try
+    ctx := BN_CTX_new;
+    if BN_mul(FBN,FBN,n.FBN,ctx)<>1 then raise ECryptoException.Create('Error on multiply');
+    Result := Self;
+  Finally
+    BN_CTX_free(ctx);
+    n.Free;
+  End;
 end;
 end;
 
 
 function TBigNum.RShift(nbits: Integer): TBigNum;
 function TBigNum.RShift(nbits: Integer): TBigNum;

+ 4 - 4
Units/PascalCoin/UDBStorage.pas

@@ -123,8 +123,8 @@ Type
   protected
   protected
     Function DoLoadBlockChain(Operations : TPCOperationsComp; Block : Cardinal) : Boolean; override;
     Function DoLoadBlockChain(Operations : TPCOperationsComp; Block : Cardinal) : Boolean; override;
     Function DoSaveBlockChain(Operations : TPCOperationsComp) : Boolean; override;
     Function DoSaveBlockChain(Operations : TPCOperationsComp) : Boolean; override;
-    Function DoMoveBlockChain(Start_Block : Cardinal; Const DestOrphan : TOrphan) : Boolean; override;
-    Procedure DoDeleteBlockChainBlocks(StartingDeleteBlock : Cardinal; Orphan : TOrphan); override;
+    Function DoMoveBlockChain(Start_Block : Cardinal; Const DestOrphan : TOrphan; DestStorage : TStorage) : Boolean; override;
+    Procedure DoDeleteBlockChainBlocks(StartingDeleteBlock : Cardinal); override;
     Function DoSaveBank : Boolean; override;
     Function DoSaveBank : Boolean; override;
     Function DoRestoreBank(max_block : Int64) : Boolean; override;
     Function DoRestoreBank(max_block : Int64) : Boolean; override;
     Function BlockExists(Block : Cardinal) : Boolean; override;
     Function BlockExists(Block : Cardinal) : Boolean; override;
@@ -297,7 +297,7 @@ begin
   inherited;
   inherited;
 end;
 end;
 
 
-procedure TDBStorage.DoDeleteBlockChainBlocks(StartingDeleteBlock: Cardinal; Orphan: TOrphan);
+procedure TDBStorage.DoDeleteBlockChainBlocks(StartingDeleteBlock: Cardinal);
 Var ds : TADOQuery;
 Var ds : TADOQuery;
   whereorphan : AnsiString;
   whereorphan : AnsiString;
 begin
 begin
@@ -366,7 +366,7 @@ begin
   End;
   End;
 end;
 end;
 
 
-function TDBStorage.DoMoveBlockChain(Start_Block: Cardinal; const DestOrphan: TOrphan): Boolean;
+function TDBStorage.DoMoveBlockChain(Start_Block: Cardinal; const DestOrphan: TOrphan; DestStorage : TStorage): Boolean;
 Var whereorphan : AnsiString;
 Var whereorphan : AnsiString;
   setvalue : AnsiString;
   setvalue : AnsiString;
 begin
 begin

+ 459 - 160
Units/PascalCoin/UFileStorage.pas

@@ -16,152 +16,232 @@ unit UFileStorage;
 interface
 interface
 
 
 uses
 uses
-  Classes, UBlockChain;
+  Classes, UBlockChain, Windows, SyncObjs;
 
 
 Type
 Type
+  TBlockHeader = Record
+    BlockNumber : Cardinal;
+    StreamBlockRelStartPos : Int64;
+    BlockSize : Cardinal;
+  end; // 16 bytes
+
   TFileStorage = Class(TStorage)
   TFileStorage = Class(TStorage)
   private
   private
-    FBaseDataFolder : AnsiString;
-    FIsRestoring : Boolean;
+    FStorageLock : TCriticalSection;
+    FBlockChainStream : TFileStream;
+    FStreamFirstBlockNumber : Cardinal;
+    FBlockHeadersFirstBytePosition : Array of Int64;
+    FDatabaseFolder: AnsiString;
+    Function StreamReadBlockHeader(Stream: TStream; StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock, Block: Cardinal; var BlockHeader : TBlockHeader): Boolean;
+    Function StreamBlockRead(Stream : TStream; StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock, Block : Cardinal; Operations : TPCOperationsComp) : Boolean;
+    Function StreamBlockSave(Stream : TStream; StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock : Cardinal; Operations : TPCOperationsComp) : Boolean;
     Function GetFolder(Const AOrphan : TOrphan): AnsiString;
     Function GetFolder(Const AOrphan : TOrphan): AnsiString;
+    Function GetBlockHeaderFirstBytePosition(Stream : TStream; Block : Cardinal; var StreamBlockHeaderStartPos : Int64; var BlockHeaderFirstBlock : Cardinal) : Boolean;
+    Function GetBlockHeaderFixedSize : Int64;
+    procedure SetDatabaseFolder(const Value: AnsiString);
+    Procedure ClearStream;
   protected
   protected
+    procedure SetReadOnly(const Value: Boolean); override;
+    procedure SetOrphan(const Value: TOrphan); override;
     Function DoLoadBlockChain(Operations : TPCOperationsComp; Block : Cardinal) : Boolean; override;
     Function DoLoadBlockChain(Operations : TPCOperationsComp; Block : Cardinal) : Boolean; override;
     Function DoSaveBlockChain(Operations : TPCOperationsComp) : Boolean; override;
     Function DoSaveBlockChain(Operations : TPCOperationsComp) : Boolean; override;
-    Function DoMoveBlockChain(Start_Block : Cardinal; Const DestOrphan : TOrphan) : Boolean; override;
+    Function DoMoveBlockChain(Start_Block : Cardinal; Const DestOrphan : TOrphan; DestStorage : TStorage) : Boolean; override;
     Function DoSaveBank : Boolean; override;
     Function DoSaveBank : Boolean; override;
     Function DoRestoreBank(max_block : Int64) : Boolean; override;
     Function DoRestoreBank(max_block : Int64) : Boolean; override;
-    Procedure DoDeleteBlockChainBlocks(StartingDeleteBlock : Cardinal; Orphan : TOrphan); override;
+    Procedure DoDeleteBlockChainBlocks(StartingDeleteBlock : Cardinal); override;
     Function BlockExists(Block : Cardinal) : Boolean; override;
     Function BlockExists(Block : Cardinal) : Boolean; override;
+    Function LockBlockChainStream : TFileStream;
+    Procedure UnlockBlockChainStream;
   public
   public
     Constructor Create(AOwner : TComponent); Override;
     Constructor Create(AOwner : TComponent); Override;
-    Class Function GetBlockChainFileName(Const BaseDataFolder : AnsiString; block : Cardinal) : AnsiString;
+    Destructor Destroy; Override;
     Class Function GetBankFileName(Const BaseDataFolder : AnsiString; block : Cardinal) : AnsiString;
     Class Function GetBankFileName(Const BaseDataFolder : AnsiString; block : Cardinal) : AnsiString;
+    Property DatabaseFolder : AnsiString read FDatabaseFolder write SetDatabaseFolder;
+    Procedure CopyConfiguration(Const CopyFrom : TStorage); override;
   End;
   End;
 
 
 implementation
 implementation
 
 
-uses
-  SysUtils, ULog, Forms, UConst;
+Uses ULog, SysUtils, UThread;
 
 
 { TFileStorage }
 { TFileStorage }
 
 
-procedure _CopyFile(const FileName, DestName: string);
-var CopyBuffer   : Pointer; { buffer for copying }
-  BytesCopied  : Longint;
-  Source, Dest : Integer; { handles }
-  Destination  : TFileName; { holder for expanded destination name }
-const ChunkSize  : Longint = 8192; { copy in 8K chunks }
+Const CT_TBlockHeader_NUL : TBlockHeader = (BlockNumber:0;StreamBlockRelStartPos:0;BlockSize:0);
+
+  CT_GroupBlockSize = 1000;
+  CT_SizeOfBlockHeader = 16;
+  {
+  BlockChain file storage:
+
+  BlockHeader 0 -> From Block 0 to (CT_GroupBlockSize-1)
+    Foreach Block:
+      BlockNumber : 4 bytes
+      StreamBlockRelStartPos : 8 bytes  -> Start pos relative to End of BlockHeader
+      BlockSizeH : 4 bytes
+      -- Total size of BlockHeader: (4+8+4) * (CT_GroupBlockSize) = 16 * CT_GroupBlockSize
+    -- Note: If BlockHeader starts at pos X, it ends at pos X + (16*CT_GroupBlockSize)
+  Block 0
+    BlockSizeC: 4 bytes
+    Data: BlockSizeC bytes
+  Block 1
+    ...
+  Block CT_GroupBlockSize-1
+
+  BlockHeader 1 -> From Block CT_GroupBlockSize to ((CT_GroupBlockSize*2)-1)
+    (Same as BlockHeader 1)
+  Block CT_GroupBlockSize
+    ...
+  Block ((CT_GroupBlockSize*2)-1)
+
+  ...
+  BlockHeader X -> From (CT_GroupBlockSize*X) to ((CT_GroupBlockSize*(X+1))-1)
+  ...
+
+  }
+
+function TFileStorage.BlockExists(Block: Cardinal): Boolean;
+Var  StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock : Cardinal;
+  stream : TStream;
+  BlockHeader : TBlockHeader;
 begin
 begin
-  Destination := DestName;
-  GetMem(CopyBuffer, ChunkSize); { allocate the buffer }
+  Result := false;
+  stream := LockBlockChainStream;
   try
   try
-   Source := FileOpen(FileName, fmShareDenyWrite); { open source file }
-   if (Source<0) then raise EFOpenError.CreateFmt('Error: Can''t open file!', [FileName]);
-   try
-     Dest := FileCreate(Destination); { create output file; overwrite existing }
-     if (Dest<0) then raise EFCreateError.CreateFmt('Error: Can''t create file!', [Destination]);
-     try
-       repeat
-         BytesCopied := FileRead(Source, CopyBuffer^, ChunkSize); { read chunk }
-         if BytesCopied > 0  {if we read anything... }
-            then FileWrite(Dest, CopyBuffer^, BytesCopied); { ...write chunk }
-       until BytesCopied < ChunkSize; { until we run out of chunks }
-     finally
-       FileClose(Dest); { close the destination file }
-     end;
-   finally
-     FileClose(Source); { close the source file }
-   end;
+    if Not GetBlockHeaderFirstBytePosition(stream,Block,StreamBlockHeaderStartPos,BlockHeaderFirstBlock) then exit;
+    if not StreamReadBlockHeader(stream,StreamBlockHeaderStartPos,BlockHeaderFirstBlock,Block,BlockHeader) then exit;
+    Result := (BlockHeader.BlockNumber = Block) And
+        (((BlockHeader.BlockNumber MOD CT_GroupBlockSize)=0) OR (BlockHeader.StreamBlockRelStartPos>0)) And
+        (BlockHeader.BlockSize>0);
   finally
   finally
-   FreeMem(CopyBuffer, ChunkSize); { free the buffer }
+    UnlockBlockChainStream;
   end;
   end;
 end;
 end;
 
 
-function TFileStorage.BlockExists(Block: Cardinal): Boolean;
+procedure TFileStorage.ClearStream;
 begin
 begin
-  Result := FileExists(GetBlockChainFileName(GetFolder(Orphan),Block));
+  FreeAndNil(FBlockChainStream);
+  FStreamFirstBlockNumber := 0;
+  SetLength(FBlockHeadersFirstBytePosition,0);
+end;
+
+procedure TFileStorage.CopyConfiguration(const CopyFrom: TStorage);
+begin
+  inherited;
+  if CopyFrom is TFileStorage then begin
+    DatabaseFolder := TFileStorage(CopyFrom).DatabaseFolder;
+  end;
 end;
 end;
 
 
 constructor TFileStorage.Create(AOwner: TComponent);
 constructor TFileStorage.Create(AOwner: TComponent);
 begin
 begin
-  FIsRestoring := false;
-  FBaseDataFolder := '';
   inherited;
   inherited;
+  FDatabaseFolder := '';
+  FBlockChainStream := Nil;
+  SetLength(FBlockHeadersFirstBytePosition,0);
+  FStreamFirstBlockNumber := 0;
+  FStorageLock := TCriticalSection.Create;
 end;
 end;
 
 
-procedure TFileStorage.DoDeleteBlockChainBlocks(StartingDeleteBlock: Cardinal; Orphan: TOrphan);
-Var bfn : AnsiString;
+destructor TFileStorage.Destroy;
 begin
 begin
-  while (BlockExists(StartingDeleteBlock)) do begin
-    DeleteFile(GetBlockChainFileName(GetFolder(Orphan),StartingDeleteBlock));
-    inc(StartingDeleteBlock);
-    bfn := GetBankFileName(GetFolder(Orphan),StartingDeleteBlock);
-    if FileExists(bfn) then begin
-      DeleteFile(bfn);
+  inherited;
+  ClearStream;
+  FreeAndNil(FStorageLock);
+end;
+
+procedure TFileStorage.DoDeleteBlockChainBlocks(StartingDeleteBlock: Cardinal);
+Var stream : TStream;
+  StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock : Cardinal;
+  _Header : TBlockHeader;
+  _intBlockIndex : Cardinal;
+  p : Int64;
+  Procedure GrowUntilPos(newPos : Int64; DeleteDataStartingAtCurrentPos : Boolean);
+  Var b : Byte;
+  begin
+    b := 0;
+    if Not DeleteDataStartingAtCurrentPos then begin
+      Stream.Position := Stream.Size;
     end;
     end;
+    While (Stream.Position<newPos) do begin
+      Stream.Write(b,1);
+    end;
+    Stream.Position := newPos;
   end;
   end;
+begin
+  stream := LockBlockChainStream;
+  Try
+    if Not GetBlockHeaderFirstBytePosition(stream,StartingDeleteBlock,StreamBlockHeaderStartPos,BlockHeaderFirstBlock) then exit;
+    If Not StreamReadBlockHeader(Stream,StreamBlockHeaderStartPos,BlockHeaderFirstBlock,StartingDeleteBlock,_Header) then exit;
+    _intBlockIndex := (_Header.BlockNumber-BlockHeaderFirstBlock);
+    p := Int64(_intBlockIndex) * Int64(CT_SizeOfBlockHeader);
+    // Write null data until end of header
+    GrowUntilPos(StreamBlockHeaderStartPos + GetBlockHeaderFixedSize,true);
+    // End Stream at _Header
+    Stream.Size := Stream.Position + _Header.StreamBlockRelStartPos-1;
+  Finally
+    UnlockBlockChainStream;
+  End;
 end;
 end;
 
 
 function TFileStorage.DoLoadBlockChain(Operations: TPCOperationsComp; Block: Cardinal): Boolean;
 function TFileStorage.DoLoadBlockChain(Operations: TPCOperationsComp; Block: Cardinal): Boolean;
-Var filename : AnsiString;
-  fs : TFileStream;
-  e : AnsiString;
+Var stream : TStream;
+  StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock : Cardinal;
 begin
 begin
-  Result := false;
-  filename :=  GetBlockChainFileName(GetFolder(Orphan),Block);
-  if Not FileExists(filename) then begin
-    TLog.NewLog(lterror,Classname,'Operations ('+inttostr(Block)+') file not found: '+filename);
-    exit;
-  end;
-  fs := TFileStream.Create(filename, fmOpenRead);
-  try
-    If Operations.LoadBlockFromStream(fs, e) then result := true
-    else begin
-      TLog.NewLog(lterror,Classname,'Error reading file: '+filename+' Errors: '+e);
-    end;
-  finally
-    fs.Free;
-  end;
+  Result := False;
+  stream := LockBlockChainStream;
+  Try
+    if Not GetBlockHeaderFirstBytePosition(stream,Block,StreamBlockHeaderStartPos,BlockHeaderFirstBlock) then exit;
+    Result := StreamBlockRead(stream,StreamBlockHeaderStartPos,BlockHeaderFirstBlock,Block,Operations);
+  Finally
+    UnlockBlockChainStream;
+  End;
 end;
 end;
 
 
-function TFileStorage.DoMoveBlockChain(Start_Block: Cardinal; const DestOrphan: TOrphan): Boolean;
-Var fn,destfn,bankfilename : AnsiString;
-  i : Cardinal;
+function TFileStorage.DoMoveBlockChain(Start_Block: Cardinal; const DestOrphan: TOrphan; DestStorage : TStorage): Boolean;
+Var db : TFileStorage;
+  i : Integer;
+  ops : TPCOperationsComp;
+  b : Cardinal;
 begin
 begin
-  if Bank.BlocksCount<Start_Block then exit;
-  TLog.NewLog(ltInfo,Classname,'Moving operations ('+inttostr(start_block)+' to '+inttostr(Bank.BlocksCount)+' from '+GetFolder('')+' to '+GetFolder(DestOrphan));
-  for i := start_block to Bank.BlocksCount - 1 do begin
-    fn := GetBlockChainFileName(GetFolder(Orphan),i);
-    destfn := GetBlockChainFileName(GetFolder(DestOrphan),i);
-    if FileExists(destfn) then TLog.NewLog(lterror,Classname,'File exists '+fn);
-    if Not FileExists(fn) then TLog.NewLog(lterror,Classname,'File not exists '+fn)
-    else _CopyFile(fn,destfn);
-    // Delete banks:
-    bankfilename := GetBankFileName(GetFolder(Orphan),i);
-    if (bankfilename<>'') then begin
-      if not DeleteFile(bankfilename) then begin
-        TLog.NewLog(lterror,Classname,'Cannot delete old bank file: '+bankfilename);
+  Try
+    if (Assigned(DestStorage)) And (DestStorage is TFileStorage) then db := TFileStorage(DestStorage)
+    else db := Nil;
+    try
+      if Not assigned(db) then begin
+        db := TFileStorage.Create(Nil);
+        db.DatabaseFolder := Self.DatabaseFolder;
+        db.Bank := Self.Bank;
+        db.Orphan := DestOrphan;
+        db.FStreamFirstBlockNumber := Start_Block;
       end;
       end;
-    end;
-  end;
-end;
-
-function TFileStorage.DoRestoreBank(max_block: Int64): Boolean;
-  function LoadOperationsFromFile(blockcount : Cardinal; Operations : TPCOperationsComp; var errors : AnsiString) : Boolean;
-  var filename : AnsiString;
-    fs : TFileStream;
-  Begin
-    Result := false;
-    filename := GetBlockChainFileName(GetFolder(Orphan),blockcount);
-    if FileExists(filename) then begin
-      fs := TFileStream.Create(filename, fmOpenRead);
+      if db is TFileStorage then TFileStorage(db).LockBlockChainStream;
       try
       try
-          Result := Operations.LoadBlockFromStream(fs, errors);
+        ops := TPCOperationsComp.Create(Nil);
+        try
+          b := Start_Block;
+          while LoadBlockChainBlock(ops,b) do begin
+            inc(b);
+            db.SaveBlockChainBlock(ops);
+          end;
+          TLog.NewLog(ltdebug,Classname,'Moved blockchain from "'+Orphan+'" to "'+DestOrphan+'" from block '+inttostr(Start_Block)+' to '+inttostr(b-1));
+        finally
+          ops.Free;
+        end;
       finally
       finally
-        fs.Free;
+        if db is TFileStorage then TFileStorage(db).UnlockBlockChainStream;
       end;
       end;
-    end else errors := 'File operations (Block: '+inttostr(blockcount)+') not exists:'+filename;
+    Finally
+      If Not Assigned(DestStorage) then db.Free;
+    End;
+  Except
+    On E:Exception do begin
+      TLog.NewLog(lterror,ClassName,'Error at DoMoveBlockChain: ('+E.ClassName+') '+E.Message);
+      Raise;
+    end;
   End;
   End;
+end;
+
+function TFileStorage.DoRestoreBank(max_block: Int64): Boolean;
 var
 var
     sr: TSearchRec;
     sr: TSearchRec;
     FileAttrs,errcode: Integer;
     FileAttrs,errcode: Integer;
@@ -172,47 +252,48 @@ var
     c,lastc : Cardinal;
     c,lastc : Cardinal;
     operations : TPCOperationsComp;
     operations : TPCOperationsComp;
 begin
 begin
-  FileAttrs := faArchive;
-  folder := GetFolder(Orphan);
-  filename := '';
-  operations := TPCOperationsComp.Create(Nil);
-  try
-    if SysUtils.FindFirst(folder+'\bank*.bank', FileAttrs, sr) = 0 then begin
-      lastc := 0;
-      repeat
-        if (sr.Attr and FileAttrs) = sr.Attr then begin
-          auxfn := ChangeFileExt(sr.Name,'');
-          val(copy(auxfn,5,length(auxfn)),c,errcode);
-          if (errcode=0) And ((c<=max_block)) then begin
-            if LoadOperationsFromFile(c,operations,errors) then begin
-              if (filename='') then begin
-                filename := sr.Name;
-                lastc := c;
-              end else if (lastc<c) then begin
-                filename := sr.Name;
-                lastc := c;
-              end;
-            end else begin
-              TLog.NewLog(lterror,ClassName,'Found a bank in file:'+filename+' but not operations:'+errors);
+  LockBlockChainStream;
+  Try
+    FileAttrs := faArchive;
+    folder := GetFolder(Orphan);
+    filename := '';
+    operations := TPCOperationsComp.Create(Nil);
+    try
+      if SysUtils.FindFirst(folder+'\bank*.bank', FileAttrs, sr) = 0 then begin
+        lastc := 0;
+        repeat
+          if (sr.Attr and FileAttrs) = FileAttrs then begin
+            auxfn := ChangeFileExt(sr.Name,'');
+            val(copy(auxfn,5,length(auxfn)),c,errcode);
+            if (errcode=0) And ((c<=max_block)) then begin
+                if (filename='') then begin
+                  filename := sr.Name;
+                  lastc := c;
+                end else if (lastc<c) then begin
+                  filename := sr.Name;
+                  lastc := c;
+                end;
             end;
             end;
           end;
           end;
+        until FindNext(sr) <> 0;
+        FindClose(sr);
+      end;
+      if (filename<>'') then begin
+        fs := TFileStream.Create(folder+'\'+filename,fmOpenRead);
+        try
+          if not Bank.LoadBankFromStream(fs,errors) then begin
+            TLog.NewLog(lterror,ClassName,'Error reading bank from file: '+filename+ ' Error: '+errors);
+          end;
+        finally
+          fs.Free;
         end;
         end;
-      until FindNext(sr) <> 0;
-      FindClose(sr);
-    end;
-    if (filename<>'') then begin
-      fs := TFileStream.Create(folder+'\'+filename,fmOpenRead);
-      try
-        if not Bank.LoadBankFromStream(fs,errors) then begin
-          TLog.NewLog(lterror,ClassName,'Error reading bank from file: '+filename+ ' Error: '+errors);
-        end;
-      finally
-        fs.Free;
       end;
       end;
+    finally
+      operations.Free;
     end;
     end;
-  finally
-    operations.Free;
-  end;
+  Finally
+    UnlockBlockChainStream;
+  End;
 end;
 end;
 
 
 function TFileStorage.DoSaveBank: Boolean;
 function TFileStorage.DoSaveBank: Boolean;
@@ -233,54 +314,272 @@ begin
 end;
 end;
 
 
 function TFileStorage.DoSaveBlockChain(Operations: TPCOperationsComp): Boolean;
 function TFileStorage.DoSaveBlockChain(Operations: TPCOperationsComp): Boolean;
-Var
-  fs: TFileStream;
-  bankfilename,folder: AnsiString;
+Var stream : TStream;
+  StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock : Cardinal;
 begin
 begin
-  folder := GetFolder(Orphan);
-  If Not ForceDirectories(folder) then exit;
-  if Not FIsRestoring then begin
-    fs := TFileStream.Create(GetBlockChainFileName(folder,Operations.OperationBlock.block), fmCreate);
-    try
-      fs.Size := 0;
-      Operations.SaveBlockToStream(false,fs);
-    finally
-      fs.Free;
+  Result := False;
+  stream := LockBlockChainStream;
+  Try
+    if (Length(FBlockHeadersFirstBytePosition)=0) then begin
+      // Is saving first block on the stream?
+      if (Stream.Size=0) then begin
+        // Yes! Positioning
+        FStreamFirstBlockNumber := Operations.OperationBlock.block;
+      end;
+      TLog.NewLog(ltdebug,Classname,Format('Saving Block %d on a newer stream, stream first position=%d',[Operations.OperationBlock.block,FStreamFirstBlockNumber]));
     end;
     end;
-  end;
-  Result := true;
+    if Not GetBlockHeaderFirstBytePosition(stream,Operations.OperationBlock.block,StreamBlockHeaderStartPos,BlockHeaderFirstBlock) then exit;
+    Result := StreamBlockSave(stream,StreamBlockHeaderStartPos,BlockHeaderFirstBlock,Operations);
+  Finally
+    UnlockBlockChainStream;
+  End;
   SaveBank;
   SaveBank;
 end;
 end;
 
 
-class function TFileStorage.GetBankFileName(const BaseDataFolder: AnsiString; block: Cardinal): AnsiString;
+class function TFileStorage.GetBankFileName(const BaseDataFolder: AnsiString;
+  block: Cardinal): AnsiString;
 Var c : Cardinal;
 Var c : Cardinal;
   folder : AnsiString;
   folder : AnsiString;
 begin
 begin
   Result := '';
   Result := '';
-  if (Block MOD CT_BankToDiskEveryNBlocks)<>0 then exit; // No bank!
   If not ForceDirectories(BaseDataFolder) then exit;
   If not ForceDirectories(BaseDataFolder) then exit;
   Result := BaseDataFolder + '\bank'+Format('%.6d',[Block])+'.bank';
   Result := BaseDataFolder + '\bank'+Format('%.6d',[Block])+'.bank';
 end;
 end;
 
 
-class function TFileStorage.GetBlockChainFileName(const BaseDataFolder: AnsiString; block: Cardinal): AnsiString;
-Var c : Cardinal;
-  folder : AnsiString;
+function TFileStorage.GetBlockHeaderFirstBytePosition(Stream : TStream; Block: Cardinal; var StreamBlockHeaderStartPos: Int64; var BlockHeaderFirstBlock: Cardinal): Boolean;
+var iPos,start : Cardinal;
+  bh : TBlockHeader;
 begin
 begin
-  Result := '';
-  c := block DIV 1000;
-  folder := BaseDataFolder+'\block'+Format('%.4d',[c]);
-  If not ForceDirectories(folder) then exit;
-  Result :=  folder+'\op'+Format('%.6d',[block])+ '.bco';
+  Result := false;
+  if Block<FStreamFirstBlockNumber then begin
+    TLog.NewLog(lterror,Classname,Format('Block %d is lower than Stream First block %d',[Block,FStreamFirstBlockNumber]));
+    exit;
+  end;
+  iPos := (Block-FStreamFirstBlockNumber) DIV CT_GroupBlockSize;
+  if iPos>High(FBlockHeadersFirstBytePosition) then Begin
+    if Length(FBlockHeadersFirstBytePosition)>0 then begin
+      start := High(FBlockHeadersFirstBytePosition);
+    end else begin
+      // Initialize and start at 0
+      SetLength(FBlockHeadersFirstBytePosition,1);
+      FBlockHeadersFirstBytePosition[0] := 0;
+      start := 0;
+    end;
+    while (start<iPos) do begin
+      // Read last start position
+      if (Stream.Size<(FBlockHeadersFirstBytePosition[start] + GetBlockHeaderFixedSize)) then begin
+        // This position not exists... This is a Fatal error due must find previos block!
+        TLog.NewLog(ltError,Classname,Format('Stream size %d is lower than BlockHeader[%d] position %d + BlockHeaderSize %d',
+          [Stream.size,start,FBlockHeadersFirstBytePosition[start],GetBlockHeaderFixedSize]));
+        exit;
+      end;
+      Stream.Position := FBlockHeadersFirstBytePosition[start] + GetBlockHeaderFixedSize - CT_SizeOfBlockHeader;
+      // Read last Header
+      Stream.Read(bh.BlockNumber,SizeOf(bh.BlockNumber));
+      Stream.Read(bh.StreamBlockRelStartPos,SizeOf(bh.StreamBlockRelStartPos));
+      Stream.Read(bh.BlockSize,sizeof(bh.BlockSize));
+      SetLength(FBlockHeadersFirstBytePosition,length(FBlockHeadersFirstBytePosition)+1);
+      FBlockHeadersFirstBytePosition[High(FBlockHeadersFirstBytePosition)] := Stream.Position + bh.StreamBlockRelStartPos + bh.BlockSize;
+      inc(start);
+    end;
+  End;
+  StreamBlockHeaderStartPos := FBlockHeadersFirstBytePosition[high(FBlockHeadersFirstBytePosition)];
+  BlockHeaderFirstBlock := FStreamFirstBlockNumber + (iPos * CT_GroupBlockSize);
+  Result := true;
 end;
 end;
 
 
+function TFileStorage.GetBlockHeaderFixedSize: Int64;
+begin
+  Result := (CT_GroupBlockSize* CT_SizeOfBlockHeader);
+end;
 
 
 function TFileStorage.GetFolder(const AOrphan: TOrphan): AnsiString;
 function TFileStorage.GetFolder(const AOrphan: TOrphan): AnsiString;
 begin
 begin
-  if FBaseDataFolder = '' then begin
-    FBaseDataFolder := ExtractFileDir(Application.ExeName)+'\'+ChangeFileExt(ExtractFileName(Application.ExeName),'')+ '\BCOperations';
+  if FDatabaseFolder = '' then raise Exception.Create('No Database Folder');
+  if AOrphan<>'' then Result := FDatabaseFolder + '\'+AOrphan
+  else Result := FDatabaseFolder;
+  if not ForceDirectories(Result) then raise Exception.Create('Cannot create database folder: '+Result);
+end;
+
+function TFileStorage.LockBlockChainStream: TFileStream;
+Var fn : TFileName;
+  fm : Word;
+begin
+  TPCThread.ProtectEnterCriticalSection(Self,FStorageLock);
+  Try
+    if Not Assigned(FBlockChainStream) then begin
+      fn := GetFolder(Orphan)+'\BlockChainStream.blocks';
+      if ReadOnly then begin
+        if FileExists(fn) then fm := fmOpenRead+fmShareDenyNone
+        else raise Exception.Create('DBFileStorage not exists for open ReadOnly: '+fn);
+      end else begin
+        if FileExists(fn) then fm := fmOpenReadWrite+fmShareDenyNone  // XXXXXXXXX Sure not to use fmShareDenyWrite ???
+        else fm := fmCreate+fmShareDenyNone  // XXXXXXXXX Sure not to use fmShareDenyWrite too ???
+      end;
+      FBlockChainStream := TFileStream.Create(fn,fm);
+      // Read Headers:
+      SetLength(FBlockHeadersFirstBytePosition,0);
+    end;
+  Except
+    FStorageLock.Release;
+    Raise;
+  End;
+  Result := FBlockChainStream;
+end;
+
+procedure TFileStorage.SetDatabaseFolder(const Value: AnsiString);
+begin
+  if FDatabaseFolder=Value then exit;
+  FDatabaseFolder := Value;
+  FreeAndNil(FBlockChainStream);
+  SetLength(FBlockHeadersFirstBytePosition,0);
+end;
+
+procedure TFileStorage.SetOrphan(const Value: TOrphan);
+begin
+  inherited;
+  ClearStream;
+end;
+
+procedure TFileStorage.SetReadOnly(const Value: Boolean);
+begin
+  inherited;
+  ClearStream;
+end;
+
+function TFileStorage.StreamBlockRead(Stream : TStream; StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock, Block : Cardinal; Operations : TPCOperationsComp) : Boolean;
+Var p : Int64;
+  errors : AnsiString;
+  streamFirstBlock,
+  _BlockSizeC,
+  _intBlockIndex : Cardinal;
+  _Header : TBlockHeader;
+  _ops : TStream;
+begin
+  Result := StreamReadBlockHeader(Stream,StreamBlockHeaderStartPos,BlockHeaderFirstBlock,Block,_Header);
+  if Not Result then exit;
+  // Calculating block position
+  p := (StreamBlockHeaderStartPos + GetBlockHeaderFixedSize) +
+     (_Header.StreamBlockRelStartPos);
+  if Stream.Size<(p + _Header.BlockSize) then begin
+    TLog.NewLog(ltError,Classname,Format(
+      'Invalid stream size. Block %d need to be at relative %d after %d = %d BlockSize:%d (Size %d)',
+      [Block,_Header.StreamBlockRelStartPos,(StreamBlockHeaderStartPos + GetBlockHeaderFixedSize),p,_Header.BlockSize,Stream.Size]));
+    exit;
+  end;
+  Stream.Position := p;
+  // Read the block
+  // Reading size
+  Stream.Read(_BlockSizeC,sizeof(_BlockSizeC));
+  if (_BlockSizeC>(_Header.BlockSize+sizeof(_BlockSizeC))) then begin
+    TLog.NewLog(lterror,Classname,Format('Corruption at stream Block size. Block %d SizeH:%d SizeC:%d',[Block,
+      _Header.BlockSize,_BlockSizeC]));
+    exit;
+  end;
+  // Reading Block
+  _ops := TMemoryStream.Create;
+  try
+    _ops.CopyFrom(Stream,_BlockSizeC);
+    _ops.Position := 0;
+    If Not Operations.LoadBlockFromStream(_ops,errors) then begin
+      TLog.NewLog(lterror,Classname,'Error reading OperationBlock '+inttostr(Block)+' from stream. Errors: '+errors);
+      exit;
+    end;
+    Result := true;
+  Finally
+    _ops.Free;
+  end;
+end;
+
+
+function TFileStorage.StreamBlockSave(Stream : TStream; StreamBlockHeaderStartPos : Int64; BlockHeaderFirstBlock : Cardinal; Operations : TPCOperationsComp) : Boolean;
+  Procedure GrowUntilPos(newPos : Int64; DeleteDataStartingAtCurrentPos : Boolean);
+  Var b : Byte;
+  begin
+    b := 0;
+    if Not DeleteDataStartingAtCurrentPos then begin
+      Stream.Position := Stream.Size;
+    end;
+    While (Stream.Position<newPos) do begin
+      Stream.Write(b,1);
+    end;
+    Stream.Position := newPos;
+  end;
+Var p : Int64;
+  c : Cardinal;
+  _Header, _HeaderPrevious : TBlockHeader;
+  _intBlockIndex : Cardinal;
+  _ops : TStream;
+begin
+  Result := false;
+  _Header := CT_TBlockHeader_NUL;
+  _Header.BlockNumber := Operations.OperationBlock.block;
+  if BlockHeaderFirstBlock>_Header.BlockNumber then raise Exception.Create('Dev error 20160917-3')
+  else if BlockHeaderFirstBlock<_Header.BlockNumber then begin
+    Result := StreamReadBlockHeader(Stream,StreamBlockHeaderStartPos,BlockHeaderFirstBlock,_Header.BlockNumber-1,_HeaderPrevious);
+    if not Result then begin
+      raise Exception.Create('Cannot found header of previous block '+inttostr(Operations.OperationBlock.block));
+    end;
+    _Header.StreamBlockRelStartPos := _HeaderPrevious.StreamBlockRelStartPos + _HeaderPrevious.BlockSize;
+  end else begin
+    // First block of the stream
+    _Header.StreamBlockRelStartPos := 0;
+  end;
+  _ops := TMemoryStream.Create;
+  Try
+    Operations.SaveBlockToStream(false,_ops);
+    _Header.BlockSize := _ops.Size;
+    // Positioning until Header Position to save Header data
+    _intBlockIndex := (_Header.BlockNumber-BlockHeaderFirstBlock);
+    p := Int64(_intBlockIndex) * Int64(CT_SizeOfBlockHeader);
+    GrowUntilPos(StreamBlockHeaderStartPos + p,false);
+    // Save Header
+    Stream.Write(_Header.BlockNumber,sizeof(_Header.BlockNumber));
+    Stream.Write(_Header.StreamBlockRelStartPos,sizeof(_Header.StreamBlockRelStartPos));
+    c := _Header.BlockSize + sizeof(c);
+    Stream.Write(c,sizeof(_Header.BlockSize));
+    // Positioning until Header end
+    GrowUntilPos(StreamBlockHeaderStartPos + GetBlockHeaderFixedSize,true);
+    // And now positioning until Data:
+    GrowUntilPos(StreamBlockHeaderStartPos + GetBlockHeaderFixedSize + _Header.StreamBlockRelStartPos, false );
+    // Save stream size
+    Stream.Write(_Header.BlockSize,sizeof(_Header.BlockSize));
+    // Save Data
+    _ops.Position := 0;
+    Stream.CopyFrom(_ops,_ops.Size);
+  Finally
+    _ops.Free;
   end;
   end;
-  if AOrphan<>'' then Result := FBaseDataFolder + '\'+AOrphan
-  else Result := FBaseDataFolder;
+end;
+
+function TFileStorage.StreamReadBlockHeader(Stream: TStream;
+  StreamBlockHeaderStartPos: Int64; BlockHeaderFirstBlock, Block: Cardinal;
+  var BlockHeader: TBlockHeader): Boolean;
+Var p : Int64;
+  errors : AnsiString;
+  streamFirstBlock : Cardinal;
+  _intBlockIndex : Cardinal;
+  _Blocks : Cardinal;
+begin
+  Result := false;
+  BlockHeader := CT_TBlockHeader_NUL;
+  if (BlockHeaderFirstBlock>Block) then raise Exception.Create('Dev error 20160917-1');
+  if (BlockHeaderFirstBlock+CT_GroupBlockSize)<Block then raise Exception.Create('Dev error 20160917-2');
+  if Stream.Size< (StreamBlockHeaderStartPos + (GetBlockHeaderFixedSize)) then begin
+    TLog.NewLog(ltError,Classname,'Invalid stream size');
+    exit;
+  end;
+  Stream.Position := StreamBlockHeaderStartPos + (CT_SizeOfBlockHeader*(Block-BlockHeaderFirstBlock));
+  // Reading block header
+  If Stream.Read(BlockHeader.BlockNumber,sizeof(BlockHeader.BlockNumber))<sizeof(BlockHeader.BlockNumber) then exit;
+  If Stream.Read(BlockHeader.StreamBlockRelStartPos,sizeof(BlockHeader.StreamBlockRelStartPos))<sizeof(BlockHeader.StreamBlockRelStartPos) then exit;
+  If Stream.Read(BlockHeader.BlockSize,sizeof(BlockHeader.BlockSize))<sizeof(BlockHeader.BlockSize) then exit;
+  Result := (BlockHeader.BlockNumber = Block);
+end;
+
+procedure TFileStorage.UnlockBlockChainStream;
+begin
+  FStorageLock.Release;
 end;
 end;
 
 
 end.
 end.

+ 7 - 5
Units/PascalCoin/UMiner.pas

@@ -18,6 +18,8 @@ interface
 Uses UBlockChain, Classes, SyncObjs, Windows, UAccounts, UThread;
 Uses UBlockChain, Classes, SyncObjs, Windows, UAccounts, UThread;
 
 
 Type
 Type
+  TMinerPrivateKey = (mpk_NewEachTime, mpk_Random, mpk_Selected);
+
   TMinerThread = Class;
   TMinerThread = Class;
 
 
   TMinerNewAccountFound = procedure(sender : TMinerThread; Operations : TPCOperationsComp) of object;
   TMinerNewAccountFound = procedure(sender : TMinerThread; Operations : TPCOperationsComp) of object;
@@ -26,7 +28,7 @@ Type
   TMinerThread = Class(TPCThread)
   TMinerThread = Class(TPCThread)
   private
   private
     FOperations : TPCOperationsComp;
     FOperations : TPCOperationsComp;
-    FLock: TRTLCriticalSection;
+    FLock: TCriticalSection;
     FPlayCount : Int64;
     FPlayCount : Int64;
     FTotalActiveTime : Int64;
     FTotalActiveTime : Int64;
     FLastStartTickCount : Cardinal;
     FLastStartTickCount : Cardinal;
@@ -100,7 +102,7 @@ begin
   FPaused := true;
   FPaused := true;
   FPlayCount := 0;
   FPlayCount := 0;
   FAccountKey := minerAccountKey;
   FAccountKey := minerAccountKey;
-  InitializeCriticalSection(FLock);
+  FLock := TCriticalSection.Create;
   FOperations := TPCOperationsComp.Create(nil);
   FOperations := TPCOperationsComp.Create(nil);
   FOperations.Bank := Bank;
   FOperations.Bank := Bank;
   FOperations.AccountKey := AccountKey;
   FOperations.AccountKey := AccountKey;
@@ -145,7 +147,7 @@ begin
 
 
         end;
         end;
       finally
       finally
-        LeaveCriticalSection(FLock);
+        FLock.Release;
       end;
       end;
       if (winner) then begin
       if (winner) then begin
         Try
         Try
@@ -173,7 +175,7 @@ end;
 
 
 destructor TMinerThread.Destroy;
 destructor TMinerThread.Destroy;
 begin
 begin
-  DeleteCriticalSection(Flock);
+  FreeAndNil(FLock);
   FreeAndNil(FOperations);
   FreeAndNil(FOperations);
   inherited;
   inherited;
 end;
 end;
@@ -193,7 +195,7 @@ end;
 
 
 procedure TMinerThread.MinerUnLockOperations(IsNewBlock : Boolean);
 procedure TMinerThread.MinerUnLockOperations(IsNewBlock : Boolean);
 begin
 begin
-  LeaveCriticalSection(FLock);
+  FLock.Release;
   if IsNewBlock then CheckIfCanRecoverBlocks;
   if IsNewBlock then CheckIfCanRecoverBlocks;
 end;
 end;
 
 

+ 62 - 190
Units/PascalCoin/UNetProtocol.pas

@@ -15,12 +15,11 @@ unit UNetProtocol;
 
 
 interface
 interface
 
 
-Uses UBlockChain, Classes, SysUtils, UAccounts, UThread, Sockets, ExtCtrls,
-  UCrypto,
-  Windows;
+Uses UBlockChain, Classes, SysUtils, UAccounts, UThread, ExtCtrls,
+  UCrypto, UTCPIP, SyncObjs, Windows;
 
 
 Const
 Const
-  CT_MagicNetIdentification = $0A043580; // Unix timestamp 168048000 ... It's Albert birthdate!
+  CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}{$IFDEF TESTNET}$8035040A{$ENDIF}{$ENDIF}; // Unix timestamp 168048000 ... It's Albert birthdate!
   CT_MagicRequest = $0001;
   CT_MagicRequest = $0001;
   CT_MagicResponse = $0002;
   CT_MagicResponse = $0002;
   CT_MagicAutoSend = $0003;
   CT_MagicAutoSend = $0003;
@@ -53,8 +52,6 @@ Type
   Max size: (depends on last 4 bytes) = 22..(2^32)-1
   Max size: (depends on last 4 bytes) = 22..(2^32)-1
   }
   }
 
 
-  TNetTcpIpClient = TCustomIpClient;
-
   TNetTransferType = (ntp_unknown, ntp_request, ntp_response, ntp_autosend);
   TNetTransferType = (ntp_unknown, ntp_request, ntp_response, ntp_autosend);
 
 
   TNetProtocolVersion = Record
   TNetProtocolVersion = Record
@@ -225,11 +222,10 @@ Type
   private
   private
     FTcpIpClient : TNetTcpIpClient;
     FTcpIpClient : TNetTcpIpClient;
     FRemoteOperationBlock : TOperationBlock;
     FRemoteOperationBlock : TOperationBlock;
-    FSocketError : Integer;
     FLastDataReceivedTS : Cardinal;
     FLastDataReceivedTS : Cardinal;
     FLastDataSendedTS : Cardinal;
     FLastDataSendedTS : Cardinal;
     FClientBufferRead : TStream;
     FClientBufferRead : TStream;
-    FNetLock : TRTLCriticalSection;
+    FNetLock : TCriticalSection;
     FIsWaitingForResponse : Boolean;
     FIsWaitingForResponse : Boolean;
     FLastKnownTimestampDiff : Int64;
     FLastKnownTimestampDiff : Int64;
     FIsMyselfServer : Boolean;
     FIsMyselfServer : Boolean;
@@ -243,13 +239,8 @@ Type
     FIsDownloadingBlocks : Boolean;
     FIsDownloadingBlocks : Boolean;
     function GetConnected: Boolean;
     function GetConnected: Boolean;
     procedure SetConnected(const Value: Boolean);
     procedure SetConnected(const Value: Boolean);
-    procedure TcpClient_OnError(Sender: TObject; SocketError: Integer);
     procedure TcpClient_OnConnect(Sender: TObject);
     procedure TcpClient_OnConnect(Sender: TObject);
     procedure TcpClient_OnDisconnect(Sender: TObject);
     procedure TcpClient_OnDisconnect(Sender: TObject);
-    procedure TcpClient_OnReceive(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer);
-    procedure TcpClient_OnSend(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer);
-    procedure TcpClient_OnCreateHandle(Sender : TObject);
-    procedure TcpClient_OnDestroyHandle(Sender : TObject);
     Function DoSendAndWaitForResponse(operation: Word; RequestId: Integer; SendDataBuffer, ReceiveDataBuffer: TStream; MaxWaitTime : Cardinal; var HeaderData : TNetHeaderData) : Boolean;
     Function DoSendAndWaitForResponse(operation: Word; RequestId: Integer; SendDataBuffer, ReceiveDataBuffer: TStream; MaxWaitTime : Cardinal; var HeaderData : TNetHeaderData) : Boolean;
     procedure DoProcessBuffer;
     procedure DoProcessBuffer;
     Procedure DoProcess_Hello(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_Hello(HeaderData : TNetHeaderData; DataBuffer: TStream);
@@ -318,27 +309,12 @@ Type
 
 
   TNetServerClient = Class(TNetConnection);
   TNetServerClient = Class(TNetConnection);
 
 
-  TNetServer = Class(TComponent)
+  TNetServer = Class(TNetTcpIpServer)
   private
   private
-    // Build 1.0.4 Changing FNetClients from TList to TPCThreadList
-    FNetClients : TPCThreadList;  // When a connection is established to a new client, a TNetConnection is created (p2p)
-    FTCPServer : TTcpServer;
-    FPort: Word;
-    function GetActive: Boolean;
-    procedure SetActive(const Value: Boolean);
-    procedure OnTcpServerCreateHandle(Sender : TObject);
-    procedure OnTcpServerDestroyHandle(Sender : TObject);
-    procedure OnTcpServerListening(Sender : TObject);
-    procedure OnTcpServerAccept(Sender: TObject; ClientSocket: TCustomIpClient);
-    procedure OnTcpServerGetThread(Sender: TObject; var ClientSocketThread: TClientSocketThread);
-    procedure SetPort(const Value: Word);
   protected
   protected
-    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
+    Procedure OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient); override;
+    procedure SetActive(const Value: Boolean); override;
   public
   public
-    Constructor Create(AOwner : TComponent); override;
-    Destructor Destroy; override;
-    Property Active : Boolean read GetActive write SetActive;
-    Property Port : Word read FPort Write SetPort;
   End;
   End;
 
 
   TThreadDiscoverConnection = Class(TPCThread)
   TThreadDiscoverConnection = Class(TPCThread)
@@ -534,7 +510,7 @@ begin
   try
   try
     for i := 0 to l.Count - 1 do begin
     for i := 0 to l.Count - 1 do begin
       if TObject(l[i])=ObjectPointer then begin
       if TObject(l[i])=ObjectPointer then begin
-        LeaveCriticalSection(TNetConnection(l[i]).FNetLock);
+        TNetConnection(l[i]).FNetLock.Release;
         exit;
         exit;
       end;
       end;
     end;
     end;
@@ -934,19 +910,20 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
     TLog.NewLog(ltdebug,CT_LogSender,Format('GetNewBank(new_start_block:%d)',[start_block]));
     TLog.NewLog(ltdebug,CT_LogSender,Format('GetNewBank(new_start_block:%d)',[start_block]));
     Bank := TPCBank.Create(Nil);
     Bank := TPCBank.Create(Nil);
     try
     try
-
       Bank.StorageClass := TNode.Node.Bank.StorageClass;
       Bank.StorageClass := TNode.Node.Bank.StorageClass;
       Bank.Storage.Orphan := TNode.Node.Bank.Storage.Orphan;
       Bank.Storage.Orphan := TNode.Node.Bank.Storage.Orphan;
+      Bank.Storage.ReadOnly := true;
       Bank.Storage.CopyConfiguration(TNode.Node.Bank.Storage);
       Bank.Storage.CopyConfiguration(TNode.Node.Bank.Storage);
       if start_block>=0 then begin
       if start_block>=0 then begin
         // Restore a part
         // Restore a part
-        Bank.DiskRestoreFromOperations(start_block);
-        start := start_block + 1;
+        Bank.DiskRestoreFromOperations(start_block-1);
+        start := start_block;
       end else begin
       end else begin
         start := 0;
         start := 0;
         start_block := 0;
         start_block := 0;
       end;
       end;
       Bank.Storage.Orphan := FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now));
       Bank.Storage.Orphan := FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now));
+      Bank.Storage.ReadOnly := false;
       // Receive new blocks:
       // Receive new blocks:
       finished := false;
       finished := false;
       repeat
       repeat
@@ -983,12 +960,17 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
         start := Bank.BlocksCount;
         start := Bank.BlocksCount;
       until (Bank.BlocksCount=Connection.FRemoteOperationBlock.block+1) Or (finished);
       until (Bank.BlocksCount=Connection.FRemoteOperationBlock.block+1) Or (finished);
       if Bank.BlocksCount>TNode.Node.Bank.BlocksCount then begin
       if Bank.BlocksCount>TNode.Node.Bank.BlocksCount then begin
-        // I'm an orphan blockchain...
-        TLog.NewLog(ltinfo,CT_LogSender,'New valid blockchain found. My block count='+inttostr(TNode.Node.Bank.BlocksCount)+
-          ' found='+inttostr(Bank.BlocksCount)+' starting at block '+inttostr(start_block));
-        TNode.Node.Bank.Storage.MoveBlockChainBlocks(start_block,Inttostr(start_block)+'_'+FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now)));
-        Bank.Storage.MoveBlockChainBlocks(start_block,TNode.Node.Bank.Storage.Orphan);
-        TNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
+        TNode.Node.DisableNewBlocks;
+        Try
+          // I'm an orphan blockchain...
+          TLog.NewLog(ltinfo,CT_LogSender,'New valid blockchain found. My block count='+inttostr(TNode.Node.Bank.BlocksCount)+
+            ' found='+inttostr(Bank.BlocksCount)+' starting at block '+inttostr(start_block));
+          TNode.Node.Bank.Storage.MoveBlockChainBlocks(start_block,Inttostr(start_block)+'_'+FormatDateTime('yyyymmddhhnnss',DateTime2UnivDateTime(now)),Nil);
+          Bank.Storage.MoveBlockChainBlocks(start_block,TNode.Node.Bank.Storage.Orphan,TNode.Node.Bank.Storage);
+          TNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
+        Finally
+          TNode.Node.EnableNewBlocks;
+        End;
       end;
       end;
     finally
     finally
       Bank.Free;
       Bank.Free;
@@ -1284,83 +1266,34 @@ end;
 
 
 { TNetServer }
 { TNetServer }
 
 
-constructor TNetServer.Create(AOwner: TComponent);
-begin
-  FNetClients := TPCThreadList.Create;
-  inherited;
-  FPort := CT_NetServer_Port;
-  FTCPServer := TTcpServer.Create(Self);
-  FTCPServer.LocalPort := Inttostr(CT_NetServer_Port);
-  FTCPServer.OnAccept := OnTcpServerAccept;
-  FTCPServer.OnGetThread := OnTcpServerGetThread;
-  FTCPServer.OnListening := OnTcpServerListening;
-  FTCPServer.OnCreateHandle := OnTcpServerCreateHandle;
-  FTCPServer.OnDestroyHandle := OnTcpServerDestroyHandle;
-  // New on Build 1.0.4: Prior where limited to 10... causing a queue list
-  // and CPU usage for nothing (TCPServer issue).
-  FTCPServer.ServerSocketThread.ThreadCacheSize := CT_MaxClientsConnected;
-end;
-
-destructor TNetServer.Destroy;
-begin
-  FreeAndNil(FTCPServer);
-  inherited;
-  FreeAndNil(FNetClients);
-end;
-
-function TNetServer.GetActive: Boolean;
-begin
-  Result := FTCPServer.Active;
-end;
-
-procedure TNetServer.Notification(AComponent: TComponent; Operation: TOperation);
-var i : Integer;
-  l : TList;
-begin
-  inherited;
-  if (Operation=opRemove) then begin
-    if Not Assigned(FNetClients) then exit;
-    l := FNetClients.LockList;
-    Try
-      i := l.IndexOf(AComponent);
-      if (i>=0) then begin
-        l.Delete(i);
-        TLog.NewLog(ltdebug,ClassName,'TNetConnection destroyed. Remaining: '+Inttostr(l.Count));
-      end;
-    Finally
-      FNetClients.UnlockList;
-    End;
-  end;
-end;
-
-procedure TNetServer.OnTcpServerAccept(Sender: TObject; ClientSocket: TCustomIpClient);
+procedure TNetServer.OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient);
+//procedure TNetServer.OnTcpServerAccept(Sender: TObject; ClientSocket: TCustomIpClient);
 Var n : TNetServerClient;
 Var n : TNetServerClient;
   DebugStep : String;
   DebugStep : String;
 begin
 begin
   DebugStep := '';
   DebugStep := '';
   Try
   Try
-    if Not ClientSocket.Connected then exit;
+    if Not Client.Connected then exit;
     // NOTE: I'm in a separate thread
     // NOTE: I'm in a separate thread
     // While in this function the ClientSocket connection will be active, when finishes the ClientSocket will be destroyed
     // While in this function the ClientSocket connection will be active, when finishes the ClientSocket will be destroyed
-    TLog.NewLog(ltInfo,Classname,'Starting ClientSocket accept '+ClientSocket.RemoteHost+':'+ClientSocket.RemotePort);
-    n := TNetServerClient.Create(Self);
+    TLog.NewLog(ltInfo,Classname,'Starting ClientSocket accept '+Client.ClientRemoteAddr);
+    n := TNetServerClient.Create(Nil);
     Try
     Try
       DebugStep := 'Assigning client';
       DebugStep := 'Assigning client';
-      n.SetClient(ClientSocket);
+      n.SetClient(Client);
       TNetData.NetData.IncStatistics(1,1,0,0,0,0);
       TNetData.NetData.IncStatistics(1,1,0,0,0,0);
       TNetData.NetData.CleanBlackList;
       TNetData.NetData.CleanBlackList;
       DebugStep := 'Checking blacklisted';
       DebugStep := 'Checking blacklisted';
-      if (TNetData.NetData.IsBlackListed(ClientSocket.RemoteHost,0)) then begin
+      if (TNetData.NetData.IsBlackListed(Client.RemoteHost,0)) then begin
         // Invalid!
         // Invalid!
-        TLog.NewLog(ltinfo,Classname,'Refusing Blacklist ip: '+ClientSocket.RemoteHost+':'+ClientSocket.RemotePort);
-        n.SendError(ntp_autosend,CT_NetOp_Error, 0,CT_NetError_IPBlackListed,'Your IP is blacklisted:'+ClientSocket.RemoteHost+':'+ClientSocket.RemotePort);
+        TLog.NewLog(ltinfo,Classname,'Refusing Blacklist ip: '+Client.ClientRemoteAddr);
+        n.SendError(ntp_autosend,CT_NetOp_Error, 0,CT_NetError_IPBlackListed,'Your IP is blacklisted:'+Client.ClientRemoteAddr);
         // Wait some time before close connection
         // Wait some time before close connection
         sleep(5000);
         sleep(5000);
       end else begin
       end else begin
         DebugStep := 'Adding client';
         DebugStep := 'Adding client';
-        FNetClients.Add(n);
         DebugStep := '   ';
         DebugStep := '   ';
-        while (n.Connected) And (FTCPServer.Active) do begin
+        while (n.Connected) And (Active) do begin
           DebugStep[1] := '1';
           DebugStep[1] := '1';
           n.DoProcessBuffer;
           n.DoProcessBuffer;
           DebugStep[1] := '2';
           DebugStep[1] := '2';
@@ -1375,7 +1308,7 @@ begin
         n.Connected := false;
         n.Connected := false;
         sleep(10);
         sleep(10);
         DebugStep := 'Assigning old client';
         DebugStep := 'Assigning old client';
-        n.SetClient( TTcpClient.Create(Nil) );
+        n.SetClient( TNetTcpIpClient.Create(Nil) );
       Finally
       Finally
         DebugStep := 'Freeing NetServerClient';
         DebugStep := 'Freeing NetServerClient';
         n.Free;
         n.Free;
@@ -1388,55 +1321,27 @@ begin
   End;
   End;
 end;
 end;
 
 
-procedure TNetServer.OnTcpServerCreateHandle(Sender: TObject);
-begin
-//  TLog.NewLog(ltdebug,Classname,'ServerCreateHandle');
-end;
-
-procedure TNetServer.OnTcpServerDestroyHandle(Sender: TObject);
-begin
-//  TLog.NewLog(ltdebug,Classname,'ServerDestroyHandle');
-end;
-
-procedure TNetServer.OnTcpServerGetThread(Sender: TObject; var ClientSocketThread: TClientSocketThread);
-begin
-//  TLog.NewLog(ltdebug,Classname,'ClientSocket Get Thread');
-end;
-
-procedure TNetServer.OnTcpServerListening(Sender: TObject);
-begin
-  TLog.NewLog(ltinfo,Classname,'Server listening');
-end;
-
 procedure TNetServer.SetActive(const Value: Boolean);
 procedure TNetServer.SetActive(const Value: Boolean);
 begin
 begin
   if Value then begin
   if Value then begin
-    TLog.NewLog(ltinfo,Classname,'Activating server on port '+FTCPServer.LocalPort);
+    TLog.NewLog(ltinfo,Classname,'Activating server on port '+IntToStr(Port));
   end else begin
   end else begin
     TLog.NewLog(ltinfo,Classname,'Closing server');
     TLog.NewLog(ltinfo,Classname,'Closing server');
   end;
   end;
-  FTCPServer.Active := Value;
-  if FTCPServer.Active then begin
+  inherited;
+  if Active then begin
     TNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
     TNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
   end else begin
   end else begin
     TNetData.NetData.DisconnectClients;
     TNetData.NetData.DisconnectClients;
   end;
   end;
 end;
 end;
 
 
-procedure TNetServer.SetPort(const Value: Word);
-begin
-  if FPort=Value then exit;
-  Active := false;
-  FPort := Value;
-  FTCPServer.LocalPort := Inttostr(Value);
-end;
-
 { TNetConnection }
 { TNetConnection }
 
 
 function TNetConnection.ClientRemoteAddr: AnsiString;
 function TNetConnection.ClientRemoteAddr: AnsiString;
 begin
 begin
   If Assigned(FTcpIpClient) then begin
   If Assigned(FTcpIpClient) then begin
-    Result := Client.RemoteHost+':'+Client.RemotePort;
+    Result := FtcpIpClient.ClientRemoteAddr
   end else Result := 'NIL';
   end else Result := 'NIL';
 end;
 end;
 
 
@@ -1458,7 +1363,7 @@ begin
 
 
   Client.RemoteHost := ServerIP;
   Client.RemoteHost := ServerIP;
   if ServerPort<=0 then ServerPort := CT_NetServer_Port;
   if ServerPort<=0 then ServerPort := CT_NetServer_Port;
-  Client.RemotePort := Inttostr(ServerPort);
+  Client.RemotePort := ServerPort;
   TLog.NewLog(ltDebug,Classname,'Trying to connect to a server at: '+ClientRemoteAddr);
   TLog.NewLog(ltDebug,Classname,'Trying to connect to a server at: '+ClientRemoteAddr);
   TNetData.NetData.NotifyNetConnectionUpdated;
   TNetData.NetData.NotifyNetConnectionUpdated;
   Result := Client.Connect;
   Result := Client.Connect;
@@ -1486,13 +1391,12 @@ begin
   FLastKnownTimestampDiff := 0;
   FLastKnownTimestampDiff := 0;
   FIsWaitingForResponse := false;
   FIsWaitingForResponse := false;
   FClientBufferRead := TMemoryStream.Create;
   FClientBufferRead := TMemoryStream.Create;
-  InitializeCriticalSection(FNetLock);
+  FNetLock := TCriticalSection.Create;
   FLastDataReceivedTS := 0;
   FLastDataReceivedTS := 0;
   FLastDataSendedTS := 0;
   FLastDataSendedTS := 0;
   FTcpIpClient := Nil;
   FTcpIpClient := Nil;
   FRemoteOperationBlock := CT_OperationBlock_NUL;
   FRemoteOperationBlock := CT_OperationBlock_NUL;
-  FSocketError := 0;
-  SetClient( TTcpClient.Create(Nil) );
+  SetClient( TNetTcpIpClient.Create(Nil) );
   TNetData.NetData.FNetConnections.Add(Self);
   TNetData.NetData.FNetConnections.Add(Self);
   TNetData.NetData.NotifyNetConnectionUpdated;
   TNetData.NetData.NotifyNetConnectionUpdated;
 end;
 end;
@@ -1522,7 +1426,7 @@ begin
   Try
   Try
     TNetData.NetData.NotifyNetConnectionUpdated;
     TNetData.NetData.NotifyNetConnectionUpdated;
   Finally
   Finally
-    DeleteCriticalSection(FNetLock);
+    FreeAndNil(FNetLock);
     FreeAndNil(FClientBufferRead);
     FreeAndNil(FClientBufferRead);
     inherited;
     inherited;
     FreeAndNil(FTcpIpClient);
     FreeAndNil(FTcpIpClient);
@@ -1548,14 +1452,14 @@ begin
   if include_in_list then begin
   if include_in_list then begin
     l := TNetData.NetData.FBlackList.LockList;
     l := TNetData.NetData.FBlackList.LockList;
     try
     try
-      i := TNetData.NetData.IndexOfNetClient(l,Client.RemoteHost,StrToIntDef( Client.RemotePort,CT_NetServer_Port));
+      i := TNetData.NetData.IndexOfNetClient(l,Client.RemoteHost,Client.RemotePort);
       if i<0 then begin
       if i<0 then begin
         new(P);
         new(P);
         P^ := CT_TNodeServerAddress_NUL;
         P^ := CT_TNodeServerAddress_NUL;
         l.Add(P);
         l.Add(P);
       end else P := l[i];
       end else P := l[i];
       P^.ip := Client.RemoteHost;
       P^.ip := Client.RemoteHost;
-      P^.port := StrToIntDef( Client.RemotePort,CT_NetServer_Port);
+      P^.port := Client.RemotePort;
       P^.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
       P^.last_connection := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
       P^.its_myself := ItsMyself;
       P^.its_myself := ItsMyself;
       P^.BlackListText := Why;
       P^.BlackListText := Why;
@@ -1566,7 +1470,7 @@ begin
   if ItsMyself then begin
   if ItsMyself then begin
     l := TNetData.NetData.FNodeServers.LockList;
     l := TNetData.NetData.FNodeServers.LockList;
     try
     try
-      i := TNetData.NetData.IndexOfNetClient(l,Client.RemoteHost,StrToIntDef( Client.RemotePort,CT_NetServer_Port));
+      i := TNetData.NetData.IndexOfNetClient(l,Client.RemoteHost,Client.RemotePort);
       if i>=0 then begin
       if i>=0 then begin
         P := l[i];
         P := l[i];
         P^.its_myself := true;
         P^.its_myself := true;
@@ -1605,7 +1509,7 @@ begin
           DebugStep := 'Is waiting for response, nothing';
           DebugStep := 'Is waiting for response, nothing';
         end;
         end;
       Finally
       Finally
-        LeaveCriticalSection(FNetLock);
+        FNetLock.Release;
       End;
       End;
     finally
     finally
       ms.Free;
       ms.Free;
@@ -1922,7 +1826,7 @@ procedure TNetConnection.DoProcess_Hello(HeaderData: TNetHeaderData; DataBuffer:
       end;
       end;
       if showmessage then begin
       if showmessage then begin
         TNode.Node.NotifyNetClientMessage(Nil,'Detected a different time in an other node... check that your PC time and timezone is correct or you will be Blacklisted! '+
         TNode.Node.NotifyNetClientMessage(Nil,'Detected a different time in an other node... check that your PC time and timezone is correct or you will be Blacklisted! '+
-          'Your time: '+TimeToStr(now)+' - '+Client.RemoteHost+':'+Client.RemotePort+' time: '+TimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(connection_ts)))+' Difference: '+inttostr(FLastKnownTimestampDiff)+' seconds. '+
+          'Your time: '+TimeToStr(now)+' - '+Client.ClientRemoteAddr+' time: '+TimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(connection_ts)))+' Difference: '+inttostr(FLastKnownTimestampDiff)+' seconds. '+
           '(If this message appears on each connection, then you have a bad configured time, if not, do nothing)' );
           '(If this message appears on each connection, then you have a bad configured time, if not, do nothing)' );
       end;
       end;
     end else begin
     end else begin
@@ -2134,7 +2038,7 @@ begin
     exit;
     exit;
   end;
   end;
   If Not Assigned(FTcpIpClient) then exit;
   If Not Assigned(FTcpIpClient) then exit;
-  if Not Client.Active then exit;
+  if Not Client.Connected then exit;
   TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
   TPCThread.ProtectEnterCriticalSection(Self,FNetLock);
   Try
   Try
     was_waiting_for_response := RequestId>0;
     was_waiting_for_response := RequestId>0;
@@ -2143,12 +2047,11 @@ begin
         FIsWaitingForResponse := true;
         FIsWaitingForResponse := true;
         Send(ntp_request,operation,0,RequestId,SendDataBuffer);
         Send(ntp_request,operation,0,RequestId,SendDataBuffer);
       end;
       end;
-      FSocketError := 0;
       tc := GetTickCount;
       tc := GetTickCount;
       Repeat
       Repeat
         if Not Client.WaitForData(100) then begin
         if Not Client.WaitForData(100) then begin
-          If FSocketError<>0 then begin
-            TLog.NewLog(ltdebug,classname,'Broken connection by error '+Inttostr(FSocketError)+' to '+ClientRemoteAddr);
+          If Client.SocketError<>0 then begin
+            TLog.NewLog(ltdebug,classname,'Broken connection by error '+Inttostr(Client.SocketError)+' to '+ClientRemoteAddr);
             Connected := false;
             Connected := false;
             exit;
             exit;
           end;
           end;
@@ -2211,7 +2114,7 @@ begin
       if was_waiting_for_response then FIsWaitingForResponse := false;
       if was_waiting_for_response then FIsWaitingForResponse := false;
     end;
     end;
   Finally
   Finally
-    LeaveCriticalSection(FNetLock);
+    FNetLock.Release;
   End;
   End;
 end;
 end;
 
 
@@ -2259,7 +2162,7 @@ begin
     tc := GetTickCount;
     tc := GetTickCount;
     repeat
     repeat
       If not Connected then exit;
       If not Connected then exit;
-      if Not Client.active then exit;
+      if Not Client.Connected then exit;
       last_bytes_read := 0;
       last_bytes_read := 0;
       FClientBufferRead.Position := 0;
       FClientBufferRead.Position := 0;
       Result := TNetData.ExtractHeaderInfo(FClientBufferRead,HeaderData,BufferData,IsValidHeaderButNeedMoreData);
       Result := TNetData.ExtractHeaderInfo(FClientBufferRead,HeaderData,BufferData,IsValidHeaderButNeedMoreData);
@@ -2317,17 +2220,17 @@ begin
     until (Result) Or ((GetTickCount > (tc+MaxWaitMiliseconds)) And (last_bytes_read=0));
     until (Result) Or ((GetTickCount > (tc+MaxWaitMiliseconds)) And (last_bytes_read=0));
   finally
   finally
     Try
     Try
-      if (Connected) And (Client.Active) then begin
+      if (Connected) then begin
         if (Not Result) And (FClientBufferRead.Size>0) And (Not IsValidHeaderButNeedMoreData) then begin
         if (Not Result) And (FClientBufferRead.Size>0) And (Not IsValidHeaderButNeedMoreData) then begin
           deletedBytes := FClientBufferRead.Size;
           deletedBytes := FClientBufferRead.Size;
-          TLog.NewLog(lterror,ClassName,Format('Deleting %d bytes from TcpClient buffer of %s:%s after max %d miliseconds. Passed: %d',
-            [deletedBytes, Client.RemoteHost,Client.RemotePort,MaxWaitMiliseconds,GetTickCount-tc]));
+          TLog.NewLog(lterror,ClassName,Format('Deleting %d bytes from TcpClient buffer of %s after max %d miliseconds. Passed: %d',
+            [deletedBytes, Client.ClientRemoteAddr,MaxWaitMiliseconds,GetTickCount-tc]));
           FClientBufferRead.Size:=0;
           FClientBufferRead.Size:=0;
           DisconnectInvalidClient(false,'Invalid data received in buffer ('+inttostr(deletedBytes)+' bytes)');
           DisconnectInvalidClient(false,'Invalid data received in buffer ('+inttostr(deletedBytes)+' bytes)');
         end;
         end;
       end;
       end;
     Finally
     Finally
-      LeaveCriticalSection(FNetLock);
+      FNetLock.Release;
     End;
     End;
   end;
   end;
   if (Result) And (HeaderData.header_type=ntp_response) then begin
   if (Result) And (HeaderData.header_type=ntp_response) then begin
@@ -2399,7 +2302,7 @@ begin
       FLastDataSendedTS := GetTickCount;
       FLastDataSendedTS := GetTickCount;
       TNetData.NetData.IncStatistics(0,0,0,0,0,Buffer.Size);
       TNetData.NetData.IncStatistics(0,0,0,0,0,Buffer.Size);
     Finally
     Finally
-      LeaveCriticalSection(FNetLock);
+      FNetLock.Release;
     End;
     End;
   finally
   finally
     Buffer.Free;
     Buffer.Free;
@@ -2536,7 +2439,7 @@ begin
     end;
     end;
     //
     //
     Send(NetTranferType,CT_NetOp_Hello,0,request_id,data);
     Send(NetTranferType,CT_NetOp_Hello,0,request_id,data);
-    Result := Client.Active;
+    Result := Client.Connected;
   finally
   finally
     data.Free;
     data.Free;
   end;
   end;
@@ -2613,12 +2516,7 @@ begin
   if Assigned(FTcpIpClient) then begin
   if Assigned(FTcpIpClient) then begin
     FTcpIpClient.FreeNotification(Self);
     FTcpIpClient.FreeNotification(Self);
     FTcpIpClient.OnConnect := TcpClient_OnConnect;
     FTcpIpClient.OnConnect := TcpClient_OnConnect;
-    FTcpIpClient.OnCreateHandle := TcpClient_OnCreateHandle;
-    FTcpIpClient.OnDestroyHandle := TcpClient_OnDestroyHandle;
-    FTcpIpClient.OnError := TcpClient_OnError;
     FTcpIpClient.OnDisconnect := TcpClient_OnDisconnect;
     FTcpIpClient.OnDisconnect := TcpClient_OnDisconnect;
-    FTcpIpClient.OnReceive := TcpClient_OnReceive;
-    FTcpIpClient.OnSend := TcpClient_OnSend;
   end;
   end;
   TNetData.NetData.NotifyNetConnectionUpdated;
   TNetData.NetData.NotifyNetConnectionUpdated;
 end;
 end;
@@ -2626,7 +2524,7 @@ end;
 procedure TNetConnection.SetConnected(const Value: Boolean);
 procedure TNetConnection.SetConnected(const Value: Boolean);
 begin
 begin
   if (Value = GetConnected) then exit;
   if (Value = GetConnected) then exit;
-  if Value then ConnectTo(Client.RemoteHost,StrToIntDef(Client.RemotePort,CT_NetServer_Port))
+  if Value then ConnectTo(Client.RemoteHost,Client.RemotePort)
   else Client.Disconnect;
   else Client.Disconnect;
 end;
 end;
 
 
@@ -2637,16 +2535,6 @@ begin
   TNetData.NetData.NotifyNetConnectionUpdated;
   TNetData.NetData.NotifyNetConnectionUpdated;
 end;
 end;
 
 
-procedure TNetConnection.TcpClient_OnCreateHandle(Sender: TObject);
-begin
-  //
-end;
-
-procedure TNetConnection.TcpClient_OnDestroyHandle(Sender: TObject);
-begin
-  //
-end;
-
 procedure TNetConnection.TcpClient_OnDisconnect(Sender: TObject);
 procedure TNetConnection.TcpClient_OnDisconnect(Sender: TObject);
 begin
 begin
   if self is TNetServerClient then TNetData.NetData.IncStatistics(-1,-1,0,0,0,0)
   if self is TNetServerClient then TNetData.NetData.IncStatistics(-1,-1,0,0,0,0)
@@ -2658,29 +2546,13 @@ begin
   TNetData.NetData.NotifyNetConnectionUpdated;
   TNetData.NetData.NotifyNetConnectionUpdated;
 end;
 end;
 
 
-procedure TNetConnection.TcpClient_OnError(Sender: TObject; SocketError: Integer);
-begin
-  FSocketError := SocketError;
-  TLog.NewLog(ltdebug,Classname,'Error '+inttohex(SocketError,8)+' with connection to '+ClientRemoteAddr);
-end;
-
-procedure TNetConnection.TcpClient_OnReceive(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer);
-begin
-  //
-end;
-
-procedure TNetConnection.TcpClient_OnSend(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer);
-begin
-  //
-end;
-
 { TNetClientThread }
 { TNetClientThread }
 
 
 procedure TNetClientThread.BCExecute;
 procedure TNetClientThread.BCExecute;
 Var clientIp : AnsiString;
 Var clientIp : AnsiString;
 begin
 begin
   debugstep := 'Initiating...';
   debugstep := 'Initiating...';
-  clientIp := FNetClient.Client.RemoteHost+':'+FNetClient.Client.RemotePort;
+  clientIp := FNetClient.ClientRemoteAddr;
   debugstep := 'Chenking terminated';
   debugstep := 'Chenking terminated';
   while (Not Terminated) do begin
   while (Not Terminated) do begin
     debugstep := 'Check connection '+clientIp;
     debugstep := 'Check connection '+clientIp;
@@ -2946,7 +2818,7 @@ begin
   DebugStep := 'Locking NetClient if exists';
   DebugStep := 'Locking NetClient if exists';
   If TNetData.NetData.ConnectionLock(Self,FNetClient) then begin
   If TNetData.NetData.ConnectionLock(Self,FNetClient) then begin
     try
     try
-      DebugStep := 'Destroying NetClient';
+      DebugStep := 'Destroying NetClient '+FNetClient.ClientRemoteAddr;
       FreeAndNil(FNetClient);
       FreeAndNil(FNetClient);
     finally
     finally
       // Not Necessary because on Freeing then Lock is deleted.
       // Not Necessary because on Freeing then Lock is deleted.
@@ -2958,7 +2830,7 @@ end;
 constructor TNetClientDestroyThread.Create(NetClient: TNetClient);
 constructor TNetClientDestroyThread.Create(NetClient: TNetClient);
 begin
 begin
   FNetClient := NetClient;
   FNetClient := NetClient;
-  TLog.NewLog(ltdebug,Classname,'Start destroying NetClient: '+NetClient.Client.RemoteHost+':'+NetClient.Client.RemotePort);
+  TLog.NewLog(ltdebug,Classname,'Start destroying NetClient: '+NetClient.ClientRemoteAddr);
   inherited Create(true);
   inherited Create(true);
   FreeOnTerminate := true;
   FreeOnTerminate := true;
   Suspended := false;
   Suspended := false;

+ 57 - 117
Units/PascalCoin/UNode.pas

@@ -26,12 +26,12 @@ unit UNode;
 interface
 interface
 
 
 uses
 uses
-  Classes, UBlockChain, UNetProtocol, UMiner, UAccounts, UCrypto, Windows, UThread;
+  Classes, UBlockChain, UNetProtocol, UMiner, UAccounts, UCrypto, Windows, UThread, SyncObjs;
 
 
 Type
 Type
   TNode = Class(TComponent)
   TNode = Class(TComponent)
   private
   private
-    FLockNodeOperations : TRTLCriticalSection;
+    FLockNodeOperations : TCriticalSection;
     FNotifyList : TList;
     FNotifyList : TList;
     FBank : TPCBank;
     FBank : TPCBank;
     FOperations : TPCOperationsComp;
     FOperations : TPCOperationsComp;
@@ -39,9 +39,8 @@ Type
     FMinerThreads : TPCThreadList;
     FMinerThreads : TPCThreadList;
     FBCBankNotify : TPCBankNotify;
     FBCBankNotify : TPCBankNotify;
     FPeerCache : AnsiString;
     FPeerCache : AnsiString;
+    FDisabledsNewBlocksCount : Integer;
     Procedure OnBankNewBlock(Sender : TObject);
     Procedure OnBankNewBlock(Sender : TObject);
-    Procedure StartLocking(MaxWaitMilliseconds : Cardinal);
-    Procedure EndLocking;
     Procedure OnMinerThreadTerminate(Sender : TObject);
     Procedure OnMinerThreadTerminate(Sender : TObject);
   protected
   protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
@@ -72,6 +71,8 @@ Type
     Function IsBlockChainValid(var WhyNot : AnsiString) : Boolean;
     Function IsBlockChainValid(var WhyNot : AnsiString) : Boolean;
     Function IsReady(Var CurrentProcess : AnsiString) : Boolean;
     Function IsReady(Var CurrentProcess : AnsiString) : Boolean;
     Property PeerCache : AnsiString read FPeerCache write FPeerCache;
     Property PeerCache : AnsiString read FPeerCache write FPeerCache;
+    Procedure DisableNewBlocks;
+    Procedure EnableNewBlocks;
   End;
   End;
 
 
   TNodeNotifyEvents = Class;
   TNodeNotifyEvents = Class;
@@ -157,18 +158,21 @@ Var i : Integer;
   ms : TMemoryStream;
   ms : TMemoryStream;
   mtl : TList;
   mtl : TList;
   netConnectionsList : TList;
   netConnectionsList : TList;
+  s : String;
 begin
 begin
   Result := false;
   Result := false;
+  if FDisabledsNewBlocksCount>0 then begin
+    TLog.NewLog(ltinfo,Classname,Format('Cannot Add new BlockChain due is adding disabled - Miner:%s Connection:%s NewBlock:%s',[Inttohex(Integer(SenderMiner),8),
+    Inttohex(Integer(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock)]));
+    exit;
+  end;
   TLog.NewLog(ltdebug,Classname,Format('AddNewBlockChain Miner:%s Connection:%s NewBlock:%s',[Inttohex(Integer(SenderMiner),8),
   TLog.NewLog(ltdebug,Classname,Format('AddNewBlockChain Miner:%s Connection:%s NewBlock:%s',[Inttohex(Integer(SenderMiner),8),
     Inttohex(Integer(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock)]));
     Inttohex(Integer(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock)]));
-  Try
-    StartLocking(2000);
-  Except
-    On E: Exception do begin
-      TLog.NewLog(lterror,Classname,'Fatal Error at AddNewBlockChain: '+e.Message);
-      if TThread.CurrentThread.ThreadID=MainThreadID then raise else exit;
-    end;
-  End;
+  If Not TPCThread.TryProtectEnterCriticalSection(Self,2000,FLockNodeOperations) then begin
+    s := 'Cannot AddNewBlockChain due blocking lock operations node';
+    TLog.NewLog(lterror,Classname,s);
+    if TThread.CurrentThread.ThreadID=MainThreadID then raise Exception.Create(s) else exit;
+  end;
   try
   try
     ms := TMemoryStream.Create;
     ms := TMemoryStream.Create;
     try
     try
@@ -245,7 +249,7 @@ begin
       end;
       end;
     end;
     end;
   finally
   finally
-    EndLocking;
+    FLockNodeOperations.Release;
     TLog.NewLog(ltdebug,Classname,Format('Finalizing AddNewBlockChain Miner:%s Connection:%s NewBlock:%s',[Inttohex(Integer(SenderMiner),8),
     TLog.NewLog(ltdebug,Classname,Format('Finalizing AddNewBlockChain Miner:%s Connection:%s NewBlock:%s',[Inttohex(Integer(SenderMiner),8),
       Inttohex(Integer(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock) ]));
       Inttohex(Integer(SenderConnection),8),TPCOperationsComp.OperationBlockToText(NewBlockOperations.OperationBlock) ]));
   End;
   End;
@@ -276,18 +280,21 @@ Var
   e : AnsiString;
   e : AnsiString;
   mtl : TList;
   mtl : TList;
   netConnectionsList : TList;
   netConnectionsList : TList;
+  s : String;
 begin
 begin
   Result := -1;
   Result := -1;
+  if FDisabledsNewBlocksCount>0 then begin
+    errors := Format('Cannot Add Operations due is adding disabled - OpCount:%d',[Operations.OperationsCount]);
+    TLog.NewLog(ltinfo,Classname,errors);
+    exit;
+  end;
   TLog.NewLog(ltdebug,Classname,Format('AddOperations Connection:%s Operations:%d',[
   TLog.NewLog(ltdebug,Classname,Format('AddOperations Connection:%s Operations:%d',[
     Inttohex(Integer(SenderConnection),8),Operations.OperationsCount]));
     Inttohex(Integer(SenderConnection),8),Operations.OperationsCount]));
-  Try
-    StartLocking(4000);
-  Except
-    On E: Exception do begin
-      TLog.NewLog(lterror,Classname,'Fatal Error at AddOperations: '+e.Message);
-      if TThread.CurrentThread.ThreadID=MainThreadID then raise else exit;
-    end;
-  End;
+  if Not TPCThread.TryProtectEnterCriticalSection(Self,4000,FLockNodeOperations) then begin
+    s := 'Cannot AddOperations due blocking lock operations node';
+    TLog.NewLog(lterror,Classname,s);
+    if TThread.CurrentThread.ThreadID=MainThreadID then raise Exception.Create(s) else exit;
+  end;
   try
   try
     Result := 0;
     Result := 0;
     errors := '';
     errors := '';
@@ -336,9 +343,9 @@ begin
       valids_operations.Free;
       valids_operations.Free;
     end;
     end;
   finally
   finally
-    EndLocking;
-    TLog.NewLog(ltdebug,Classname,Format('Finalizing AddOperations Connection:%s Operations:%d LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
-      Inttohex(Integer(SenderConnection),8),Operations.OperationsCount,FLockNodeOperations.LockCount,FLockNodeOperations.RecursionCount,FLockNodeOperations.LockSemaphore,IntToHex(FLockNodeOperations.OwningThread,8) ]));
+    FLockNodeOperations.Release;
+    TLog.NewLog(ltdebug,Classname,Format('Finalizing AddOperations Connection:%s Operations:%d',[
+      Inttohex(Integer(SenderConnection),8),Operations.OperationsCount ]));
   end;
   end;
   // Notify it!
   // Notify it!
   for i := 0 to FNotifyList.Count-1 do begin
   for i := 0 to FNotifyList.Count-1 do begin
@@ -347,55 +354,13 @@ begin
 end;
 end;
 
 
 procedure TNode.AutoDiscoverNodes(Const ips : AnsiString);
 procedure TNode.AutoDiscoverNodes(Const ips : AnsiString);
-{  Function GetIp(var ips_string : AnsiString; var nsa : TNodeServerAddress) : Boolean;
-  Const CT_IP_CHARS = ['a'..'z','A'..'Z','0'..'9','.','-','_'];
-  var i : Integer;
-    port : AnsiString;
-  begin
-    nsa := CT_TNodeServerAddress_NUL;
-    Result := false;
-    if length(trim(ips_string))=0 then begin
-      ips_string := '';
-      exit;
-    end;
-    i := 1;
-    while (i<length(ips_string)) AND (NOT (ips_string[i] IN CT_IP_CHARS)) do inc(i);
-    if (i>1) then ips_string := copy(ips_string,i,length(ips_string));
-    //
-    i := 1;
-    while (i<=length(ips_string)) and (ips_string[i] in CT_IP_CHARS) do inc(i);
-    nsa.ip := copy(ips_string,1,i-1);
-    if (i<=length(ips_string)) and (ips_string[i]=':') then begin
-      inc(i);
-      port := '';
-      while (i<=length(ips_string)) and (ips_string[i] in ['0'..'9']) do begin
-        port := port + ips_string[i];
-        inc(i);
-      end;
-      nsa.port := StrToIntDef(port,0);
-    end;
-    ips_string := copy(ips_string,i+1,length(ips_string));
-    if nsa.port=0 then nsa.port := CT_NetServer_Port;
-    Result := (trim(nsa.ip)<>'');
-  end;}
 Var i,j : Integer;
 Var i,j : Integer;
-{  ips_string : AnsiString;
-  nsa : TNodeServerAddress;}
   nsarr : TNodeServerAddressArray;
   nsarr : TNodeServerAddressArray;
 begin
 begin
   DecodeIpStringToNodeServerAddressArray(ips+';'+PeerCache,nsarr);
   DecodeIpStringToNodeServerAddressArray(ips+';'+PeerCache,nsarr);
   for i := low(nsarr) to high(nsarr) do begin
   for i := low(nsarr) to high(nsarr) do begin
     TNetData.NetData.AddServer(nsarr[i]);
     TNetData.NetData.AddServer(nsarr[i]);
   end;
   end;
-
-{  ips_string := ips+';'+PeerCache;
-  repeat
-    If GetIp(ips_string,nsa) then begin
-      TNetData.NetData.AddServer(nsa);
-    end;
-  until (ips_string='');
-  //
-}
   j := (CT_MaxServersConnected -  TNetData.NetData.ConnectionsCount(true));
   j := (CT_MaxServersConnected -  TNetData.NetData.ConnectionsCount(true));
   if j<=0 then exit;
   if j<=0 then exit;
   TNetData.NetData.DiscoverServers;
   TNetData.NetData.DiscoverServers;
@@ -405,14 +370,13 @@ constructor TNode.Create(AOwner: TComponent);
 begin
 begin
   if Assigned(_Node) then raise Exception.Create('Duplicate nodes protection');
   if Assigned(_Node) then raise Exception.Create('Duplicate nodes protection');
   inherited;
   inherited;
-  InitializeCriticalSection(FLockNodeOperations);
-  TLog.NewLog(ltdebug,Classname,Format('Initialize LockOperations LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
-    FLockNodeOperations.LockCount,FLockNodeOperations.RecursionCount,FLockNodeOperations.LockSemaphore,IntToHex(FLockNodeOperations.OwningThread,8) ]));
+  FDisabledsNewBlocksCount := 0;
+  FLockNodeOperations := TCriticalSection.Create;
   FBank := TPCBank.Create(Self);
   FBank := TPCBank.Create(Self);
   FBCBankNotify := TPCBankNotify.Create(Self);
   FBCBankNotify := TPCBankNotify.Create(Self);
   FBCBankNotify.Bank := FBank;
   FBCBankNotify.Bank := FBank;
   FBCBankNotify.OnNewBlock := OnBankNewBlock;
   FBCBankNotify.OnNewBlock := OnBankNewBlock;
-  FNetServer := TNetServer.Create(Self);
+  FNetServer := TNetServer.Create;
   FMinerThreads := TPCThreadList.Create;
   FMinerThreads := TPCThreadList.Create;
   FOperations := TPCOperationsComp.Create(Self);
   FOperations := TPCOperationsComp.Create(Self);
   FOperations.bank := FBank;
   FOperations.bank := FBank;
@@ -490,7 +454,7 @@ begin
   TLog.NewLog(ltinfo,Classname,'Destroying Node - START');
   TLog.NewLog(ltinfo,Classname,'Destroying Node - START');
   Try
   Try
     step := 'Deleting critical section';
     step := 'Deleting critical section';
-    DeleteCriticalSection(FLockNodeOperations);
+    FreeAndNil(FLockNodeOperations);
 
 
     step := 'Desactivating server';
     step := 'Desactivating server';
     FNetServer.Active := false;
     FNetServer.Active := false;
@@ -526,6 +490,17 @@ begin
   TLog.NewLog(ltinfo,Classname,'Destroying Node - END');
   TLog.NewLog(ltinfo,Classname,'Destroying Node - END');
 end;
 end;
 
 
+procedure TNode.DisableNewBlocks;
+begin
+  inc(FDisabledsNewBlocksCount);
+end;
+
+procedure TNode.EnableNewBlocks;
+begin
+  if FDisabledsNewBlocksCount=0 then raise Exception.Create('Dev error 20160924-1');
+  dec(FDisabledsNewBlocksCount);
+end;
+
 class function TNode.EncodeNodeServerAddressArrayToIpString(
 class function TNode.EncodeNodeServerAddressArrayToIpString(
   const NodeServerAddressArray: TNodeServerAddressArray): AnsiString;
   const NodeServerAddressArray: TNodeServerAddressArray): AnsiString;
 var i : Integer;
 var i : Integer;
@@ -540,11 +515,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TNode.EndLocking;
-begin
-  LeaveCriticalSection(FLockNodeOperations);
-end;
-
 function TNode.IsBlockChainValid(var WhyNot : AnsiString): Boolean;
 function TNode.IsBlockChainValid(var WhyNot : AnsiString): Boolean;
 Var unixtimediff : Integer;
 Var unixtimediff : Integer;
 begin
 begin
@@ -650,17 +620,15 @@ function TNode.SendNodeMessage(Target: TNetConnection; TheMessage: AnsiString; v
 Var i : Integer;
 Var i : Integer;
   nc : TNetConnection;
   nc : TNetConnection;
   netConnectionsList : TList;
   netConnectionsList : TList;
+  s : String;
 begin
 begin
-  Try
-    StartLocking(4000);
-  Except
-    On E: Exception do begin
-      TLog.NewLog(lterror,Classname,'Fatal Error at SendNodeMessage: '+e.Message);
-      if TThread.CurrentThread.ThreadID=MainThreadID then raise else exit;
-    end;
-  End;
+  Result := false;
+  if Not TPCThread.TryProtectEnterCriticalSection(Self,4000,FLockNodeOperations) then begin
+    s := 'Cannot Send node message due blocking lock operations node';
+    TLog.NewLog(lterror,Classname,s);
+    if TThread.CurrentThread.ThreadID=MainThreadID then raise Exception.Create(s) else exit;
+  end;
   try
   try
-    Result := false;
     errors := '';
     errors := '';
     if assigned(Target) then begin
     if assigned(Target) then begin
       Target.Send_Message(TheMessage);
       Target.Send_Message(TheMessage);
@@ -677,26 +645,7 @@ begin
     end;
     end;
     result := true;
     result := true;
   finally
   finally
-    EndLocking;
-  end;
-end;
-
-procedure TNode.StartLocking(MaxWaitMilliseconds : Cardinal);
-Var tc : Cardinal;
-  s : String;
-  IsLocked : Boolean;
-begin
-  if MaxWaitMilliseconds>60000 then MaxWaitMilliseconds := 60000;
-  tc := GetTickCount;
-  Repeat
-    IsLocked := TryEnterCriticalSection(FLockNodeOperations);
-    if Not IsLocked then sleep(1);
-  Until (IsLocked) Or (GetTickCount > (tc + MaxWaitMilliseconds));
-  if Not IsLocked then begin
-    s := Format('Cannot lock operations node - LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
-      FLockNodeOperations.LockCount,FLockNodeOperations.RecursionCount,FLockNodeOperations.LockSemaphore,IntToHex(FLockNodeOperations.OwningThread,8) ]);
-    TLog.NewLog(lterror,Classname,s);
-    raise Exception.Create(s);
+    FLockNodeOperations.Release;
   end;
   end;
 end;
 end;
 
 
@@ -798,10 +747,10 @@ procedure TThreadNodeNotifyNewBlock.BCExecute;
 begin
 begin
   if TNetData.NetData.ConnectionLock(Self,FNetConnection) then begin
   if TNetData.NetData.ConnectionLock(Self,FNetConnection) then begin
     try
     try
-      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.ClientRemoteAddr);
       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.ClientRemoteAddr);
          FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
          FNetConnection.Send_AddOperations(TNode.Node.Operations.OperationsHashTree);
       end;
       end;
     finally
     finally
@@ -824,21 +773,12 @@ begin
   if TNetData.NetData.ConnectionLock(Self, FNetConnection) then begin
   if TNetData.NetData.ConnectionLock(Self, FNetConnection) then begin
     try
     try
       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.ClientRemoteAddr);
       FNetConnection.Send_AddOperations(FOperationsHashTree);
       FNetConnection.Send_AddOperations(FOperationsHashTree);
     finally
     finally
       TNetData.NetData.ConnectionUnlock(FNetConnection);
       TNetData.NetData.ConnectionUnlock(FNetConnection);
     end;
     end;
   end;
   end;
-
-{  If Not TNetData.NetData.ConnectionExistsAndActive(FNetConnection) then begin
-    TLog.NewLog(ltdebug,Classname,'Connection not active');
-    exit;
-  end;
-  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(TNode.Node.Operations.OperationsHashTree);
-  }
 end;
 end;
 
 
 constructor TThreadNodeNotifyOperations.Create(NetConnection: TNetConnection;
 constructor TThreadNodeNotifyOperations.Create(NetConnection: TNetConnection;

+ 1 - 0
Units/PascalCoin/UOpTransaction.pas

@@ -222,6 +222,7 @@ begin
     trans.sign.s:='';
     trans.sign.s:='';
     Result := false;
     Result := false;
   End;
   End;
+  SetLength(s,0);
 end;
 end;
 
 
 function TOpTransaction.GetOperationBufferToHash: TRawBytes;
 function TOpTransaction.GetOperationBufferToHash: TRawBytes;

+ 323 - 0
Units/PascalCoin/UTCPIP.pas

@@ -0,0 +1,323 @@
+unit UTCPIP;
+
+{ Copyright (c) 2016 by Albert Molina
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  This unit is a part of Pascal Coin, a P2P crypto currency without need of
+  historical operations.
+
+  If you like it, consider a donation using BitCoin:
+  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
+
+  }
+
+interface
+
+{$IFDEF FPC}
+  {$mode objfpc}
+{$ENDIF}
+
+{$DEFINE DelphiSockets}
+
+uses
+  {$IFDEF UNIX}
+ cthreads,
+ {$ENDIF}
+  Classes, Sysutils,
+  UThread,Sockets;
+
+type
+  TNetTcpIpClient = Class(TComponent)
+  private
+    {$IFDEF DelphiSockets}
+    FTcpIpClient : TCustomIpClient;
+    FOnConnect: TNotifyEvent;
+    FOnDisconnect: TNotifyEvent;
+    FSocketError: Integer;
+    {$ENDIF}
+    function GetConnected: Boolean;
+    function GetRemoteHost: AnsiString;
+    function GetRemotePort: Word;
+    procedure SetRemoteHost(const Value: AnsiString);
+    procedure SetRemotePort(const Value: Word);
+    procedure SetOnConnect(const Value: TNotifyEvent);
+    procedure SetOnDisconnect(const Value: TNotifyEvent);
+    procedure SetSocketError(const Value: Integer);
+    {$IFDEF DelphiSockets}
+    procedure TCustomIpClient_OnError(Sender: TObject; ASocketError: Integer);
+    {$ENDIF}
+  public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy; override;
+    Function ClientRemoteAddr : AnsiString;
+    Property RemoteHost : AnsiString read GetRemoteHost Write SetRemoteHost;
+    Property RemotePort : Word read GetRemotePort write SetRemotePort;
+    Property Connected : Boolean read GetConnected;
+    Procedure Disconnect;
+    Function Connect : Boolean;
+    //
+    Function WaitForData(WaitMilliseconds : Integer) : Boolean;
+    function ReceiveBuf(var Buf; BufSize: Integer): Integer;
+    Function SendStream(Stream : TStream) : Int64;
+    //
+    Property OnConnect : TNotifyEvent read FOnConnect write SetOnConnect;
+    Property OnDisconnect : TNotifyEvent read FOnDisconnect write SetOnDisconnect;
+    Function BytesReceived : Int64;
+    Function BytesSent : Int64;
+    Property SocketError : Integer read FSocketError write SetSocketError;
+  End;
+
+  TNetTcpIpServer = Class(TObject)
+  private
+    {$IFDEF DelphiSockets}
+    FTcpIpServer : TTcpServer;
+    FTcpIpClient : TCustomIpClient;
+    {$ENDIF}
+    FNetClients : TPCThreadList;
+    function GetActive: Boolean;
+    procedure SetPort(const Value: Word);  // When a connection is established to a new client, a TNetConnection is created (p2p)
+    {$IFDEF DelphiSockets}
+    procedure OnTcpServerAccept(Sender: TObject; ClientSocket: TCustomIpClient);
+    function GetPort: Word;
+    {$ENDIF}
+  protected
+    Procedure OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient); virtual;
+    procedure SetActive(const Value: Boolean); virtual;
+  public
+    Constructor Create;
+    Destructor Destroy; override;
+    Property Active : Boolean read GetActive write SetActive;
+    Property Port : Word read GetPort Write SetPort;
+  End;
+
+
+implementation
+
+uses UConst, ULog;
+
+{ TNetTcpIpClient }
+
+function TNetTcpIpClient.BytesReceived: Int64;
+begin
+  {$IFDEF DelphiSockets}
+  Result := FTcpIpClient.BytesReceived;
+  {$ENDIF}
+end;
+
+function TNetTcpIpClient.BytesSent: Int64;
+begin
+  {$IFDEF DelphiSockets}
+  Result := FTcpIpClient.BytesSent;
+  {$ENDIF}
+end;
+
+function TNetTcpIpClient.ClientRemoteAddr: AnsiString;
+begin
+  If Assigned(FTcpIpClient) then begin
+    {$IFDEF DelphiSockets}
+    Result := FTcpIpClient.RemoteHost+':'+FTcpIpClient.RemotePort;
+    {$ENDIF}
+  end else Result := 'NIL';
+end;
+
+function TNetTcpIpClient.Connect: Boolean;
+begin
+  {$IFDEF DelphiSockets}
+  Result := FTcpIpClient.Connect;
+  {$ENDIF}
+end;
+
+constructor TNetTcpIpClient.Create(AOwner : TComponent);
+begin
+  inherited;
+  FTcpIpClient := Nil;
+  FSocketError := 0;
+  {$IFDEF DelphiSockets}
+  FTcpIpClient := TTcpClient.Create(Nil);
+  FTcpIpClient.OnConnect := OnConnect;
+  FTcpIpClient.OnDisconnect := OnDisconnect;
+  FTcpIpClient.OnError := TCustomIpClient_OnError;
+  {$ENDIF}
+end;
+
+destructor TNetTcpIpClient.Destroy;
+begin
+  Disconnect;
+  inherited;
+  FreeAndNil(FTcpIpClient);
+end;
+
+procedure TNetTcpIpClient.Disconnect;
+begin
+  {$IFDEF DelphiSockets}
+  FTcpIpClient.Disconnect;
+  FTcpIpClient.OnConnect := Nil;
+  FTcpIpClient.OnDisconnect := Nil;
+  FTcpIpClient.OnError := Nil;
+  {$ENDIF}
+end;
+
+function TNetTcpIpClient.GetConnected: Boolean;
+begin
+  {$IFDEF DelphiSockets}
+  Result := FTcpIpClient.Connected;
+  {$ENDIF}
+end;
+
+function TNetTcpIpClient.GetRemoteHost: AnsiString;
+begin
+  {$IFDEF DelphiSockets}
+  Result := FTcpIpClient.RemoteHost;
+  {$ENDIF}
+end;
+
+function TNetTcpIpClient.GetRemotePort: Word;
+begin
+  {$IFDEF DelphiSockets}
+  Result := StrToIntDef(FTcpIpClient.RemotePort,0);
+  {$ENDIF}
+end;
+
+function TNetTcpIpClient.ReceiveBuf(var Buf; BufSize: Integer): Integer;
+begin
+  {$IFDEF DelphiSockets}
+  Result := FTcpIpClient.ReceiveBuf(Buf,BufSize);
+  {$ENDIF}
+end;
+
+function TNetTcpIpClient.SendStream(Stream: TStream): Int64;
+Var sp : Int64;
+begin
+  {$IFDEF DelphiSockets}
+  sp := Stream.Position;
+  FTcpIpClient.SendStream(Stream);
+  Result := Stream.Position - sp;
+  {$ENDIF}
+end;
+
+procedure TNetTcpIpClient.SetOnConnect(const Value: TNotifyEvent);
+begin
+  FOnConnect := Value;
+  {$IFDEF DelphiSockets}
+  FTcpIpClient.OnConnect := OnConnect;
+  {$ENDIF}
+end;
+
+procedure TNetTcpIpClient.SetOnDisconnect(const Value: TNotifyEvent);
+begin
+  FOnDisconnect := Value;
+  {$IFDEF DelphiSockets}
+  FTcpIpClient.OnDisconnect := OnDisconnect;
+  {$ENDIF}
+end;
+
+procedure TNetTcpIpClient.SetRemoteHost(const Value: AnsiString);
+begin
+  {$IFDEF DelphiSockets}
+  FTcpIpClient.RemoteHost := Value;
+  {$ENDIF}
+end;
+
+procedure TNetTcpIpClient.SetRemotePort(const Value: Word);
+begin
+  {$IFDEF DelphiSockets}
+  FTcpIpClient.RemotePort := IntToStr(Value);
+  {$ENDIF}
+end;
+
+procedure TNetTcpIpClient.SetSocketError(const Value: Integer);
+begin
+  FSocketError := Value;
+  if Value<>0 then
+    TLog.NewLog(ltdebug,Classname,'Error '+inttohex(SocketError,8)+' with connection to '+ClientRemoteAddr);
+end;
+
+{$IFDEF DelphiSockets}
+procedure TNetTcpIpClient.TCustomIpClient_OnError(Sender: TObject; ASocketError: Integer);
+begin
+  SocketError := ASocketError;
+end;
+{$ENDIF}
+
+function TNetTcpIpClient.WaitForData(WaitMilliseconds: Integer): Boolean;
+begin
+  {$IFDEF DelphiSockets}
+  Result := FTcpIpClient.WaitForData(WaitMilliseconds);
+  {$ENDIF}
+end;
+
+{ TNetTcpIpServer }
+
+constructor TNetTcpIpServer.Create;
+begin
+  {$IFDEF DelphiSockets}
+  FTcpIpServer := TTcpServer.Create(Nil);
+  FTcpIpServer.OnAccept := OnTcpServerAccept;
+  FTcpIpServer.ServerSocketThread.ThreadCacheSize := CT_MaxClientsConnected;
+  {$ENDIF}
+end;
+
+destructor TNetTcpIpServer.Destroy;
+begin
+  Active := false;
+  {$IFDEF DelphiSockets}
+  FreeAndNil(FTcpIpServer);
+  {$ENDIF}
+  inherited;
+  FreeAndNil(FNetClients);
+end;
+
+function TNetTcpIpServer.GetActive: Boolean;
+begin
+  {$IFDEF DelphiSockets}
+  Result := FTcpIpServer.Active;
+  {$ENDIF}
+end;
+
+function TNetTcpIpServer.GetPort: Word;
+begin
+  {$IFDEF DelphiSockets}
+  Result := StrToIntDef(FTcpIpServer.LocalPort,0);
+  {$ENDIF}
+end;
+
+procedure TNetTcpIpServer.OnNewIncommingConnection(Sender: TObject; Client: TNetTcpIpClient);
+begin
+  //
+end;
+
+{$IFDEF DelphiSockets}
+procedure TNetTcpIpServer.OnTcpServerAccept(Sender: TObject; ClientSocket: TCustomIpClient);
+Var n : TNetTcpIpClient;
+  oldSocket : TCustomIpClient;
+begin
+  n := TNetTcpIpClient.Create(Nil);
+  Try
+    oldSocket := n.FTcpIpClient;
+    n.FTcpIpClient := ClientSocket;
+    OnNewIncommingConnection(Sender,n);
+  Finally
+    n.FTcpIpClient := oldSocket;
+    FreeAndNil(n);
+  End;
+end;
+{$ENDIF}
+
+procedure TNetTcpIpServer.SetActive(const Value: Boolean);
+begin
+  {$IFDEF DelphiSockets}
+  FTcpIpServer.Active := Value;
+  {$ENDIF}
+end;
+
+procedure TNetTcpIpServer.SetPort(const Value: Word);
+begin
+  {$IFDEF DelphiSockets}
+  FTcpIpServer.LocalPort := IntToStr(Value);
+  {$ENDIF}
+end;
+
+
+end.

+ 13 - 14
Units/PascalCoin/UThread.pas

@@ -34,8 +34,8 @@ Type
     Class function ThreadCount : Integer;
     Class function ThreadCount : Integer;
     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 Function TryProtectEnterCriticalSection(Const Sender : TObject; MaxWaitMilliseconds : Cardinal; var Lock : TRTLCriticalSection) : Boolean;
+    Class Procedure ProtectEnterCriticalSection(Const Sender : TObject; var Lock : TCriticalSection);
+    Class Function TryProtectEnterCriticalSection(Const Sender : TObject; MaxWaitMilliseconds : Cardinal; var Lock : TCriticalSection) : Boolean;
     Class Procedure ThreadsListInfo(list: TStrings);
     Class Procedure ThreadsListInfo(list: TStrings);
     Property DebugStep : String read FDebugStep write FDebugStep;
     Property DebugStep : String read FDebugStep write FDebugStep;
   End;
   End;
@@ -43,7 +43,7 @@ Type
   TPCThreadList = class
   TPCThreadList = class
   private
   private
     FList: TList;
     FList: TList;
-    FLock: TRTLCriticalSection;
+    FLock: TCriticalSection;
   public
   public
     constructor Create;
     constructor Create;
     destructor Destroy; override;
     destructor Destroy; override;
@@ -116,12 +116,12 @@ begin
   end;
   end;
 end;
 end;
 
 
-class procedure TPCThread.ProtectEnterCriticalSection(Const Sender : TObject; var Lock: TRTLCriticalSection);
+class procedure TPCThread.ProtectEnterCriticalSection(Const Sender : TObject; var Lock: TCriticalSection);
 begin
 begin
-  if Not TryEnterCriticalSection(Lock) then begin
+  if Not Lock.TryEnter then begin
 //    TLog.NewLog(ltdebug,Sender.Classname,Format('Locked critical section (WAIT): LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
 //    TLog.NewLog(ltdebug,Sender.Classname,Format('Locked critical section (WAIT): LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
 //      Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
 //      Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
-    EnterCriticalSection(Lock);
+    Lock.Acquire;
 //    TLog.NewLog(ltdebug,Sender.Classname,Format('UnLocked critical section (ENTER): LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
 //    TLog.NewLog(ltdebug,Sender.Classname,Format('UnLocked critical section (ENTER): LockCount:%d RecursionCount:%d Semaphore:%d LockOwnerThread:%s',[
 //      Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
 //      Lock.LockCount,Lock.RecursionCount,Lock.LockSemaphore,IntToHex(Lock.OwningThread,8) ]));
   end;
   end;
@@ -191,20 +191,19 @@ begin
 end;
 end;
 
 
 class function TPCThread.TryProtectEnterCriticalSection(const Sender: TObject;
 class function TPCThread.TryProtectEnterCriticalSection(const Sender: TObject;
-  MaxWaitMilliseconds: Cardinal; var Lock: TRTLCriticalSection): Boolean;
+  MaxWaitMilliseconds: Cardinal; var Lock: TCriticalSection): Boolean;
 Var tc : Cardinal;
 Var tc : Cardinal;
   s : String;
   s : String;
 begin
 begin
   if MaxWaitMilliseconds>60000 then MaxWaitMilliseconds := 60000;
   if MaxWaitMilliseconds>60000 then MaxWaitMilliseconds := 60000;
   tc := GetTickCount;
   tc := GetTickCount;
   Repeat
   Repeat
-    Result := TryEnterCriticalSection(Lock);
+    Result := Lock.TryEnter;
     if Not Result then sleep(1);
     if Not Result then sleep(1);
   Until (Result) Or (GetTickCount > (tc + MaxWaitMilliseconds));
   Until (Result) Or (GetTickCount > (tc + MaxWaitMilliseconds));
   if Not Result then begin
   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) ]);
+    s := Format('Cannot Protect a critical section by %s after %d milis',
+      [Sender.ClassName,MaxWaitMilliseconds]);
     TLog.NewLog(lterror,Classname,s);
     TLog.NewLog(lterror,Classname,s);
   end;
   end;
 end;
 end;
@@ -233,7 +232,7 @@ end;
 
 
 constructor TPCThreadList.Create;
 constructor TPCThreadList.Create;
 begin
 begin
-  InitializeCriticalSection(FLock);
+  FLock := TCriticalSection.Create;
   FList := TList.Create;
   FList := TList.Create;
 end;
 end;
 
 
@@ -245,7 +244,7 @@ begin
     inherited Destroy;
     inherited Destroy;
   finally
   finally
     UnlockList;
     UnlockList;
-    DeleteCriticalSection(FLock);
+    FLock.Free;
   end;
   end;
 end;
 end;
 
 
@@ -267,7 +266,7 @@ end;
 
 
 procedure TPCThreadList.UnlockList;
 procedure TPCThreadList.UnlockList;
 begin
 begin
-  LeaveCriticalSection(FLock);
+  FLock.Release;
 end;
 end;
 
 
 initialization
 initialization

+ 1486 - 0
Units/Utils/UDBGridUtils.pas

@@ -0,0 +1,1486 @@
+unit UDBGridUtils;
+
+{ Copyright (c) 2016 by Albert Molina
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  This unit is a part of Pascal Coin, a P2P crypto currency without need of
+  historical operations.
+
+  If you like it, consider a donation using BitCoin:
+  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
+
+  ABOUT THIS UNIT:
+
+  This units works with UDBStorage.pas unit.
+  So, is to use in Windows version due UDBStorage works with Access database
+
+  }
+
+interface
+
+uses
+  Classes, Grids, Windows, UNode, UAccounts, UBlockChain, UDBStorage, DBGrids, DB, ADODB,
+  UWalletKeys, UAppParams;
+
+Type
+  // TAccountsGrid implements a visual integration of TDrawGrid
+  // to show accounts information
+  TAccountColumnType = (act_account_number,act_account_key,act_balance,act_updated,act_n_operation,act_updated_state);
+  TAccountColumn = Record
+    ColumnType : TAccountColumnType;
+    width : Integer;
+  End;
+
+  TAccountsGrid = Class(TComponent)
+  private
+    FAccountsBalance : Int64;
+    FAccountsList : TOrderedCardinalList;
+    FColumns : Array of TAccountColumn;
+    FDrawGrid : TDrawGrid;
+    FNodeNotifyEvents : TNodeNotifyEvents;
+    FShowAllAccounts: Boolean;
+    FOnUpdated: TNotifyEvent;
+    FAccountsCount: Integer;
+    procedure SetDrawGrid(const Value: TDrawGrid);
+    Procedure InitGrid;
+    Procedure OnNodeNewOperation(Sender : TObject);
+    procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
+    procedure SetNode(const Value: TNode);
+    function GetNode: TNode;
+    procedure SetShowAllAccounts(const Value: Boolean);
+  protected
+    procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
+  public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy; override;
+    Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
+    Function LockAccountsList : TOrderedCardinalList;
+    Procedure UnlockAccountsList;
+    Property Node : TNode read GetNode write SetNode;
+    Function AccountNumber(GridRow : Integer) : Int64;
+    Procedure SaveToStream(Stream : TStream);
+    Procedure LoadFromStream(Stream : TStream);
+    Property ShowAllAccounts : Boolean read FShowAllAccounts write SetShowAllAccounts;
+    Property AccountsBalance : Int64 read FAccountsBalance;
+    Property AccountsCount : Integer read FAccountsCount;
+    Function MoveRowToAccount(nAccount : Cardinal) : Boolean;
+    Property OnUpdated : TNotifyEvent read FOnUpdated write FOnUpdated;
+  End;
+
+  TOperationsGrid = Class(TComponent)
+  private
+    FDrawGrid: TDrawGrid;
+    FAccountNumber: Int64;
+    FOperationsResume : TOperationsResumeList;
+    FNodeNotifyEvents : TNodeNotifyEvents;
+    FPendingOperations: Boolean;
+    Procedure OnNodeNewOperation(Sender : TObject);
+    Procedure OnNodeNewAccount(Sender : TObject);
+    Procedure InitGrid;
+    procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
+    procedure SetDrawGrid(const Value: TDrawGrid);
+    procedure SetAccountNumber(const Value: Int64);
+    procedure SetNode(const Value: TNode);
+    function GetNode: TNode;
+    procedure SetPendingOperations(const Value: Boolean);
+  protected
+    procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
+  public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy; override;
+    Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
+    Property PendingOperations : Boolean read FPendingOperations write SetPendingOperations;
+    Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
+    Property Node : TNode read GetNode write SetNode;
+    Procedure UpdateAccountOperations;
+    Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
+  End;
+
+  TOperationsDBGrid = Class(TComponent)
+  private
+    FDisableds : Integer;
+    FQrySQL : TAdoQuery;
+    FDBGrid: TDBGrid;
+    FAccountNumber: Int64;
+    FNodeNotifyEvents : TNodeNotifyEvents;
+    FDataSource : TDataSource;
+    FDateEnd: TDate;
+    FBlockStart: Int64;
+    FDateStart: TDate;
+    FBlockEnd: Int64;
+    FNeedRefreshSQL : Boolean;
+    function GetNode: TNode;
+    procedure SetAccountNumber(const Value: Int64);
+    procedure SetDBGrid(const Value: TDBGrid);
+    procedure SetNode(const Value: TNode);
+    Procedure OnGridDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
+    procedure SetAdoConnection(const Value: TADOConnection);
+    function GetAdoConnection: TADOConnection;
+    Procedure OnQryCalcFields(DataSet: TDataSet);
+    Procedure OnNodeNewAccount(Sender : TObject);
+    procedure SetBlockEnd(const Value: Int64);
+    procedure SetBlockStart(const Value: Int64);
+    procedure SetDateEnd(const Value: TDate);
+    procedure SetDateStart(const Value: TDate);
+  protected
+    procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
+  published
+  public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy; override;
+    Property DBGrid : TDBGrid read FDBGrid write SetDBGrid;
+    Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
+    Property BlockStart : Int64 read FBlockStart write SetBlockStart;
+    Property BlockEnd : Int64 read FBlockEnd write SetBlockEnd;
+    Procedure SetBlocks(bstart,bend : Int64);
+    Property DateStart : TDate read FDateStart write SetDateStart;
+    Property DateEnd : TDate read FDateEnd write SetDateEnd;
+    Procedure SetDates(dStart,dEnd : TDate);
+    Property Node : TNode read GetNode write SetNode;
+    Procedure RefreshData;
+    Property AdoConnection : TADOConnection read GetAdoConnection write SetAdoConnection;
+    Procedure Disable;
+    Procedure Enable;
+    Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
+  End;
+
+  TBlockChainDBGrid = Class(TComponent)
+  private
+    FDisableds : Integer;
+    FQrySQL : TAdoQuery;
+    FDBGrid: TDBGrid;
+    FNodeNotifyEvents : TNodeNotifyEvents;
+    FDataSource : TDataSource;
+    FDateEnd: TDate;
+    FBlockStart: Int64;
+    FDateStart: TDate;
+    FBlockEnd: Int64;
+    FAccountNumber: Int64;
+    FNeedRefreshSQL : Boolean;
+    function GetNode: TNode;
+    procedure SetDBGrid(const Value: TDBGrid);
+    procedure SetNode(const Value: TNode);
+    Procedure OnGridDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
+    procedure SetAdoConnection(const Value: TADOConnection);
+    function GetAdoConnection: TADOConnection;
+    Procedure OnQryCalcFields(DataSet: TDataSet);
+    Procedure OnNodeNewAccount(Sender : TObject);
+    procedure SetBlockEnd(const Value: Int64);
+    procedure SetBlockStart(const Value: Int64);
+    procedure SetDateEnd(const Value: TDate);
+    procedure SetDateStart(const Value: TDate);
+  protected
+    procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
+  published
+  public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor Destroy; override;
+    Property DBGrid : TDBGrid read FDBGrid write SetDBGrid;
+    Property BlockStart : Int64 read FBlockStart write SetBlockStart;
+    Property BlockEnd : Int64 read FBlockEnd write SetBlockEnd;
+    Procedure SetBlocks(bstart,bend : Int64);
+    Property DateStart : TDate read FDateStart write SetDateStart;
+    Property DateEnd : TDate read FDateEnd write SetDateEnd;
+    Procedure SetDates(dStart,dEnd : TDate);
+    Property Node : TNode read GetNode write SetNode;
+    Procedure RefreshData;
+    Property AdoConnection : TADOConnection read GetAdoConnection write SetAdoConnection;
+    Procedure Disable;
+    Procedure Enable;
+  End;
+
+implementation
+
+uses
+  Graphics, UCrypto, SysUtils, UTime, UOpTransaction, UConst,
+  UFRMPayloadDecoder, ULog;
+
+{ TAccountsGrid }
+
+Const CT_ColumnHeader : Array[TAccountColumnType] Of String =
+  ('Account N.','Key','Balance','Updated','N Oper.','State');
+
+function TAccountsGrid.AccountNumber(GridRow: Integer): Int64;
+begin
+  if GridRow<1 then Result := -1
+  else if FShowAllAccounts then begin
+    if Assigned(Node) then begin
+      Result := GridRow-1;
+    end else Result := -1;
+  end else if GridRow<=FAccountsList.Count then begin
+    Result := Integer(FAccountsList.Get(GridRow-1));
+  end else Result := -1;
+end;
+
+constructor TAccountsGrid.Create(AOwner: TComponent);
+Var i : Integer;
+begin
+  inherited;
+  FOnUpdated := Nil;
+  FAccountsBalance := 0;
+  FAccountsCount := 0;
+  FShowAllAccounts := false;
+  FAccountsList := TOrderedCardinalList.Create;
+  FDrawGrid := Nil;
+  SetLength(FColumns,4);
+  FColumns[0].ColumnType := act_account_number;
+  FColumns[0].width := 80;
+  FColumns[1].ColumnType := act_balance;
+  FColumns[1].width := 100;
+  FColumns[2].ColumnType := act_n_operation;
+  FColumns[2].width := 50;
+  FColumns[3].ColumnType := act_updated_state;
+  FColumns[3].width := 50;
+  FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
+  FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
+end;
+
+destructor TAccountsGrid.Destroy;
+begin
+  FNodeNotifyEvents.Free;
+  FAccountsList.Free;
+  inherited;
+end;
+
+function TAccountsGrid.GetNode: TNode;
+begin
+  Result := FNodeNotifyEvents.Node;
+end;
+
+procedure TAccountsGrid.InitGrid;
+Var i : Integer;
+  acc : TAccount;
+begin
+  FAccountsBalance := 0;
+  FAccountsCount := FAccountsList.Count;
+  if Not assigned(DrawGrid) then exit;
+  if FShowAllAccounts then begin
+    if Assigned(Node) then begin
+      if Node.Bank.AccountsCount<1 then DrawGrid.RowCount := 2
+      else DrawGrid.RowCount := Node.Bank.AccountsCount+1;
+      FAccountsBalance := Node.Bank.SafeBox.TotalBalance;
+    end else DrawGrid.RowCount := 2;
+  end else begin
+    if FAccountsList.Count<1 then DrawGrid.RowCount := 2
+    else DrawGrid.RowCount := FAccountsList.Count+1;
+    if Assigned(Node) then begin
+      for i := 0 to FAccountsList.Count - 1 do begin
+        acc := Node.Bank.SafeBox.Account( FAccountsList.Get(i) );
+        inc(FAccountsBalance, acc.balance);
+      end;
+    end;
+  end;
+  DrawGrid.FixedRows := 1;
+  if Length(FColumns)=0 then DrawGrid.ColCount := 1
+  else DrawGrid.ColCount := Length(FColumns);
+  DrawGrid.FixedCols := 0;
+  for i := low(FColumns) to high(FColumns) do begin
+    DrawGrid.ColWidths[i] := FColumns[i].width;
+  end;
+  FDrawGrid.DefaultRowHeight := 18;
+  DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
+    {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
+    {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
+    goThumbTracking, goFixedColClick, goFixedRowClick, goFixedHotTrack];
+  FDrawGrid.Invalidate;
+  if Assigned(FOnUpdated) then FOnUpdated(Self);
+end;
+
+procedure TAccountsGrid.LoadFromStream(Stream: TStream);
+Var c,i,j : Integer;
+begin
+  if Stream.Read(c,sizeof(c))<sizeof(c) then exit;
+  if c<=0 then exit;
+  SetLength(FColumns,c);
+  for i := 0 to c - 1 do begin
+    Stream.Read(j,sizeof(j));
+    if (j>=Integer(Low(TAccountColumnType))) And (j<=Integer(High(TAccountColumnType))) then begin
+      FColumns[i].ColumnType := TAccountColumnType(j);
+    end else FColumns[i].ColumnType := act_account_number;
+    Stream.Read(FColumns[i].width,sizeof(FColumns[i].width));
+  end;
+  Stream.Read(j,sizeof(j));
+  If Assigned(FDrawGrid) then FDrawGrid.Width := j;
+  Stream.Read(j,sizeof(j));
+  If Assigned(FDrawGrid) then FDrawGrid.Height := j;
+end;
+
+function TAccountsGrid.LockAccountsList: TOrderedCardinalList;
+begin
+  Result := FAccountsList;
+end;
+
+function TAccountsGrid.MoveRowToAccount(nAccount: Cardinal): Boolean;
+Var oal : TOrderedCardinalList;
+  idx : Integer;
+begin
+  Result := false;
+  if Not Assigned(FDrawGrid) then exit;
+  if Not Assigned(Node) then exit;
+  if FDrawGrid.RowCount<=1 then exit;
+  if FShowAllAccounts then begin
+    If (FDrawGrid.RowCount>nAccount+1) And (nAccount>=0) And (nAccount<Node.Bank.AccountsCount) then begin
+      FDrawGrid.Row := nAccount+1;
+      Result := true;
+    end else begin
+      FDrawGrid.Row := FDrawGrid.RowCount-1;
+    end;
+  end else begin
+    oal := LockAccountsList;
+    try
+      If oal.Find(nAccount,idx) then begin
+        If FDrawGrid.RowCount>idx+1 then begin
+          FDrawGrid.Row := idx+1;
+          Result := true;
+        end else begin
+          FDrawGrid.Row := FDrawGrid.RowCount-1;
+        end;
+      end else begin
+        If FDrawGrid.RowCount>idx+1 then begin
+          FDrawGrid.Row := idx+1;
+        end else begin
+          FDrawGrid.Row := FDrawGrid.RowCount-1;
+        end;
+      end;
+    finally
+      UnlockAccountsList;
+    end;
+  end;
+end;
+
+procedure TAccountsGrid.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited;
+  if Operation=opRemove then begin
+    if (AComponent=FDrawGrid) then begin
+      SetDrawGrid(Nil);
+    end;
+  end;
+end;
+
+procedure TAccountsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
+  Function FromColorToColor(colorstart,colordest : Integer; step,totalsteps : Integer) : Integer;
+  var sr,sg,sb,dr,dg,db : Byte;
+    i : Integer;
+  begin
+    i := colorstart;
+    sr := GetRValue(i);
+    sg := GetGValue(i);
+    sb := GetBValue(i);
+    i := colordest;
+    dr := GetRValue(i);
+    dg := GetGValue(i);
+    db := GetBValue(i);
+    sr := sr + (((dr-sr) DIV totalsteps)*step);
+    sg := sg + (((dg-sg) DIV totalsteps)*step);
+    sb := sb + (((db-sb) DIV totalsteps)*step);
+    Result :=RGB(sr,sg,sb);
+  end;
+Var C : TAccountColumn;
+  s : String;
+  n_acc : Int64;
+  account : TAccount;
+  ndiff : Cardinal;
+begin
+  if Not Assigned(Node) then exit;
+
+  if (ACol>=0) AND (ACol<length(FColumns)) then begin
+    C := FColumns[ACol];
+  end else begin
+    C.ColumnType := act_account_number;
+    C.width := -1;
+  end;
+  if (ARow=0) then begin
+    // Header
+    s := CT_ColumnHeader[C.ColumnType];
+    DrawGrid.Canvas.TextRect(Rect,s,[tfCenter,tfVerticalCenter]);
+  end else begin
+    n_acc := AccountNumber(ARow);
+    if (n_acc>=0) then begin
+      if (n_acc>=Node.Bank.AccountsCount) then account := CT_Account_NUL
+      else account := Node.Operations.SafeBoxTransaction.Account(n_acc);
+      ndiff := Node.Bank.BlocksCount - account.updated_block;
+      if (gdSelected in State) then
+        If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
+        else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
+      else DrawGrid.Canvas.Brush.Color := clWindow;
+      DrawGrid.Canvas.FillRect(Rect);
+      InflateRect(Rect,-2,-1);
+      case C.ColumnType of
+        act_account_number : Begin
+          s := TAccountComp.AccountNumberToAccountTxtNumber(n_acc);
+          DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+        End;
+        act_account_key : Begin
+          s := Tcrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountkey));
+          DrawGrid.Canvas.TextRect(Rect,s,[tfLeft,tfVerticalCenter,tfSingleLine]);
+        End;
+        act_balance : Begin
+          if ndiff=0 then begin
+            // Pending operation... showing final balance
+            DrawGrid.Canvas.Font.Color := clBlue;
+            s := '('+TAccountComp.FormatMoney(account.balance)+')';
+          end else begin
+            s := TAccountComp.FormatMoney(account.balance);
+            if account.balance>0 then DrawGrid.Canvas.Font.Color := ClGreen
+            else if account.balance=0 then DrawGrid.Canvas.Font.Color := clGrayText
+            else DrawGrid.Canvas.Font.Color := clRed;
+          end;
+          DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+        End;
+        act_updated : Begin
+          s := Inttostr(account.updated_block);
+          DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+        End;
+        act_n_operation : Begin
+          s := InttoStr(account.n_operation);
+          DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+        End;
+        act_updated_state : Begin
+          if TAccountComp.IsAccountBlockedByProtocol(account.account,Node.Bank.BlocksCount) then begin
+            DrawGrid.Canvas.Brush.Color := clRed;
+            DrawGrid.Canvas.Ellipse(Rect.Left+1,Rect.Top+1,Rect.Right-1,Rect.Bottom-1);
+          end else if ndiff=0 then begin
+            DrawGrid.Canvas.Brush.Color := RGB(255,128,0);
+            DrawGrid.Canvas.Ellipse(Rect.Left+1,Rect.Top+1,Rect.Right-1,Rect.Bottom-1);
+          end else if ndiff<=8 then begin
+            DrawGrid.Canvas.Brush.Color := FromColorToColor(RGB(253,250,115),ColorToRGB(clGreen),ndiff-1,8-1);
+            DrawGrid.Canvas.Ellipse(Rect.Left+1,Rect.Top+1,Rect.Right-1,Rect.Bottom-1);
+          end else begin
+            DrawGrid.Canvas.Brush.Color := clGreen;
+            DrawGrid.Canvas.Ellipse(Rect.Left+1,Rect.Top+1,Rect.Right-1,Rect.Bottom-1);
+          end;
+        End;
+      else
+        s := '(???)';
+        DrawGrid.Canvas.TextRect(Rect,s,[tfCenter,tfVerticalCenter,tfSingleLine]);
+      end;
+    end;
+  end;
+end;
+
+procedure TAccountsGrid.OnNodeNewOperation(Sender: TObject);
+begin
+  If Assigned(FDrawGrid) then FDrawGrid.Invalidate;
+end;
+
+procedure TAccountsGrid.SaveToStream(Stream: TStream);
+Var c,i,j : Integer;
+begin
+  c := Length(FColumns);
+  Stream.Write(c,sizeof(c));
+  for i := 0 to c - 1 do begin
+    j := Integer(FColumns[i].ColumnType);
+    Stream.Write(j,sizeof(j));
+    if Assigned(FDrawGrid) then begin
+      FColumns[i].width := FDrawGrid.ColWidths[i];
+    end;
+    Stream.Write(FColumns[i].width,sizeof(FColumns[i].width));
+  end;
+  j := FDrawGrid.Width;
+  Stream.Write(j,sizeof(j));
+  j := FDrawGrid.Height;
+  Stream.Write(j,sizeof(j));
+end;
+
+procedure TAccountsGrid.SetDrawGrid(const Value: TDrawGrid);
+begin
+  if FDrawGrid=Value then exit;
+  FDrawGrid := Value;
+  if Assigned(Value) then begin
+    Value.FreeNotification(self);
+    FDrawGrid.OnDrawCell := OnGridDrawCell;
+    InitGrid;
+  end;
+end;
+
+procedure TAccountsGrid.SetNode(const Value: TNode);
+begin
+  if GetNode=Value then exit;
+  FNodeNotifyEvents.Node := Value;
+  InitGrid;
+end;
+
+procedure TAccountsGrid.SetShowAllAccounts(const Value: Boolean);
+begin
+  if FShowAllAccounts=Value then exit;
+  FShowAllAccounts := Value;
+  InitGrid;
+end;
+
+procedure TAccountsGrid.UnlockAccountsList;
+begin
+  InitGrid;
+end;
+
+{ TOperationsGrid }
+
+constructor TOperationsGrid.Create(AOwner: TComponent);
+begin
+  FAccountNumber := 0;
+  FDrawGrid := Nil;
+  FOperationsResume := TOperationsResumeList.Create;
+  FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
+  FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
+  FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
+  inherited;
+end;
+
+destructor TOperationsGrid.Destroy;
+begin
+  FOperationsResume.Free;
+  FNodeNotifyEvents.Free;
+  inherited;
+end;
+
+function TOperationsGrid.GetNode: TNode;
+begin
+  Result := FNodeNotifyEvents.Node;
+end;
+
+procedure TOperationsGrid.InitGrid;
+begin
+  if Not Assigned(FDrawGrid) then exit;
+  if FOperationsResume.Count>0 then FDrawGrid.RowCount := FOperationsResume.Count+1
+  else FDrawGrid.RowCount := 2;
+  DrawGrid.FixedRows := 1;
+  DrawGrid.DefaultDrawing := true;
+  DrawGrid.FixedCols := 0;
+  DrawGrid.ColCount := 8;
+  DrawGrid.ColWidths[0] := 110; // Time
+  DrawGrid.ColWidths[1] := 50; // Block
+  DrawGrid.ColWidths[2] := 60; // Account
+  DrawGrid.ColWidths[3] := 150; // OpType
+  DrawGrid.ColWidths[4] := 70; // Amount
+  DrawGrid.ColWidths[5] := 60; // Operation Fee
+  DrawGrid.ColWidths[6] := 70; // Balance
+  DrawGrid.ColWidths[7] := 500; // Payload
+  FDrawGrid.DefaultRowHeight := 18;
+  FDrawGrid.Invalidate;
+  DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
+    {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
+    {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
+    goThumbTracking, goFixedColClick, goFixedRowClick, goFixedHotTrack];
+end;
+
+procedure TOperationsGrid.Notification(AComponent: TComponent; Operation: TOperation);
+begin
+  inherited;
+  if Operation=opRemove then begin
+    if (AComponent=FDrawGrid) then begin
+      SetDrawGrid(Nil);
+    end;
+  end;
+end;
+
+procedure TOperationsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
+Var s : String;
+  opr : TOperationResume;
+begin
+  opr := CT_TOperationResume_NUL;
+  Try
+  if (ARow=0) then begin
+    // Header
+    case ACol of
+      0 : s := 'Time';
+      1 : s := 'Block';
+      2 : s := 'Account';
+      3 : s := 'Operation';
+      4 : s := 'Amount';
+      5 : s := 'Fee';
+      6 : s := 'Balance';
+      7 : s := 'Payload';
+    else s:= '';
+    end;
+    DrawGrid.Canvas.TextRect(Rect,s,[tfCenter,tfVerticalCenter]);
+  end else begin
+    if (gdSelected in State) then
+      If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
+      else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
+    else DrawGrid.Canvas.Brush.Color := clWindow;
+    DrawGrid.Canvas.FillRect(Rect);
+    InflateRect(Rect,-2,-1);
+    if (ARow<=FOperationsResume.Count) then begin
+      opr := FOperationsResume.OperationResume[ARow-1];
+      if ACol=0 then begin
+        if opr.time=0 then s := '(Pending)'
+        else s := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime(opr.time)));
+        DrawGrid.Canvas.TextRect(Rect,s,[tfleft,tfVerticalCenter,tfSingleLine]);
+      end else if ACol=1 then begin
+        s := Inttostr(opr.Block);
+        DrawGrid.Canvas.TextRect(Rect,s,[tfleft,tfVerticalCenter,tfSingleLine]);
+      end else if ACol=2 then begin
+        s := TAccountComp.AccountNumberToAccountTxtNumber(opr.AffectedAccount);
+        DrawGrid.Canvas.TextRect(Rect,s,[tfleft,tfVerticalCenter,tfSingleLine]);
+      end else if ACol=3 then begin
+        s := opr.OperationTxt;
+        DrawGrid.Canvas.TextRect(Rect,s,[tfleft,tfVerticalCenter,tfSingleLine]);
+      end else if ACol=4 then begin
+        s := TAccountComp.FormatMoney(opr.Amount);
+        if opr.Amount>0 then DrawGrid.Canvas.Font.Color := ClGreen
+        else if opr.Amount=0 then DrawGrid.Canvas.Font.Color := clGrayText
+        else DrawGrid.Canvas.Font.Color := clRed;
+        DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+      end else if ACol=5 then begin
+        s := TAccountComp.FormatMoney(opr.Fee);
+        if opr.Fee>0 then DrawGrid.Canvas.Font.Color := ClGreen
+        else if opr.Fee=0 then DrawGrid.Canvas.Font.Color := clGrayText
+        else DrawGrid.Canvas.Font.Color := clRed;
+        DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+      end else if ACol=6 then begin
+        if opr.time=0 then begin
+          // Pending operation... showing final balance
+          DrawGrid.Canvas.Font.Color := clBlue;
+          s := '('+TAccountComp.FormatMoney(opr.Balance)+')';
+        end else begin
+          s := TAccountComp.FormatMoney(opr.Balance);
+          if opr.Balance>0 then DrawGrid.Canvas.Font.Color := ClGreen
+          else if opr.Balance=0 then DrawGrid.Canvas.Font.Color := clGrayText
+          else DrawGrid.Canvas.Font.Color := clRed;
+        end;
+        DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+      end else if ACol=7 then begin
+        s := opr.PrintablePayload;
+        DrawGrid.Canvas.TextRect(Rect,s,[tfLeft,tfVerticalCenter,tfSingleLine]);
+      end else begin
+        s := '(???)';
+        DrawGrid.Canvas.TextRect(Rect,s,[tfCenter,tfVerticalCenter,tfSingleLine]);
+      end;
+    end;
+  end;
+  Except
+    On E:Exception do begin
+      TLog.NewLog(lterror,Classname,Format('Error at OnGridDrawCell row %d col %d Block %d - %s',[ARow,ACol,opr.Block,E.Message]));
+    end;
+  End;
+end;
+
+procedure TOperationsGrid.OnNodeNewAccount(Sender: TObject);
+begin
+  UpdateAccountOperations;
+end;
+
+procedure TOperationsGrid.OnNodeNewOperation(Sender: TObject);
+Var Op : TPCOperation;
+  l : TList;
+begin
+  if AccountNumber<0 then UpdateAccountOperations
+  else begin
+    Op := TPCOperation(Sender);
+    l := TList.Create;
+    Try
+      Op.AffectedAccounts(l);
+      if l.IndexOf(TObject(Integer(AccountNumber)))>=0 then UpdateAccountOperations;
+    Finally
+      l.Free;
+    End;
+  end;
+end;
+
+procedure TOperationsGrid.SetAccountNumber(const Value: Int64);
+begin
+  if FAccountNumber=Value then exit;
+  FAccountNumber := Value;
+  if FAccountNumber>=0 then FPendingOperations := false;
+  UpdateAccountOperations;
+end;
+
+procedure TOperationsGrid.SetDrawGrid(const Value: TDrawGrid);
+begin
+  if FDrawGrid=Value then exit;
+  FDrawGrid := Value;
+  if Assigned(Value) then begin
+    Value.FreeNotification(self);
+    FDrawGrid.OnDrawCell := OnGridDrawCell;
+    InitGrid;
+  end;
+end;
+
+procedure TOperationsGrid.SetNode(const Value: TNode);
+begin
+  if GetNode=Value then exit;
+  FNodeNotifyEvents.Node := Value;
+  UpdateAccountOperations; // New Build 1.0.3
+end;
+
+procedure TOperationsGrid.SetPendingOperations(const Value: Boolean);
+begin
+  FPendingOperations := Value;
+  if FPendingOperations then  FAccountNumber := -1;
+  UpdateAccountOperations;
+end;
+
+procedure TOperationsGrid.ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
+Var i : Integer;
+  opr : TOperationResume;
+  FRM : TFRMPayloadDecoder;
+begin
+  if Not Assigned(FDrawGrid) then exit;
+  if (FDrawGrid.Row<=0) Or (FDrawGrid.Row>FOperationsResume.Count) then exit;
+  opr := FOperationsResume.OperationResume[FDrawGrid.Row-1];
+  FRM := TFRMPayloadDecoder.Create(FDrawGrid.Owner);
+  try
+    FRM.Init(opr.Block,opr.time,opr.OperationTxt,opr.OriginalPayload,WalletKeys,AppParams);
+    FRM.ShowModal;
+  finally
+    FRM.Free;
+  end;
+end;
+
+procedure TOperationsGrid.UpdateAccountOperations;
+Var list : TList;
+  i,j : Integer;
+  OPR : TOperationResume;
+  Op : TPCOperation;
+begin
+  FOperationsResume.Clear;
+  Try
+    if Not Assigned(Node) then exit;
+    if FPendingOperations then begin
+      for i := Node.Operations.Count - 1 downto 0 do begin
+        Op := Node.Operations.OperationsHashTree.GetOperation(i);
+        If TDBStorage.OperationToOperationResume(Op,Op.SenderAccount,OPR) then begin
+          OPR.Block := Node.Operations.OperationBlock.block;
+          OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
+          FOperationsResume.Add(OPR);
+        end;
+      end;
+    end else begin
+      if AccountNumber<0 then begin
+        list := TList.Create;
+        try
+          for i := 0 to Node.Operations.Count-1 do begin
+            Op := Node.Operations.Operation[i];
+            If TDBStorage.OperationToOperationResume(Op,Op.SenderAccount,OPR) then begin
+              OPR.Block := Node.Operations.OperationBlock.block;
+              OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
+              FOperationsResume.Add(OPR);
+            end;
+          end;
+        finally
+          list.Free;
+        end;
+      end else begin
+        list := TList.Create;
+        Try
+          Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
+          for i := list.Count - 1 downto 0 do begin
+            Op := Node.Operations.OperationsHashTree.GetOperation(Integer(list[i]));
+            If TDBStorage.OperationToOperationResume(Op,AccountNumber,OPR) then begin
+              OPR.Block := Node.Operations.OperationBlock.block;
+              OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
+              FOperationsResume.Add(OPR);
+            end;
+          end;
+        Finally
+          list.Free;
+        End;
+        if Node.Bank.Storage is TDBStorage then begin
+          TDBStorage(Node.Bank.Storage).GetOperationsFromAccount(FOperationsResume,AccountNumber,0,200);
+        end;
+      end;
+    end;
+  Finally
+    InitGrid;
+  End;
+end;
+
+{ TOperationsDBGrid }
+
+Type TAuxDBGrid = Class(TDBGrid);
+
+constructor TOperationsDBGrid.Create(AOwner: TComponent);
+Var i : Integer;
+  fld : TField;
+begin
+  inherited;
+  FNeedRefreshSQL := false;
+  FDisableds := 0;
+  FDBGrid := Nil;
+  FQrySQL := TADOQuery.Create(Self);
+  FQrySQL.OnCalcFields := OnQryCalcFields;
+  FqrySQL.CursorLocation := clUseClient;
+  FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
+  FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
+  FDataSource := TDataSource.Create(Self);
+  FDataSource.DataSet := FQrySQL;
+  FAccountNumber := -1; // all
+  FBlockStart := -1;
+  FBlockEnd := -1;
+  FDateStart := 0;
+  FDateEnd := 0;
+  fld := TIntegerField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_block;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  //
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_s_timestamp;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  //
+  fld := TIntegerField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_optype;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  fld := TIntegerField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_optype_op;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  fld := TIntegerField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_account;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  fld := TIntegerField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_other_account;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  fld := TDateTimeField.Create(FQrySQL);
+  fld.FieldName := 'datetime';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := 'op_account';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+  TStringField(fld).Size := 100;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := 'operation';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+  TStringField(fld).Size := 100;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := 'payload_txt';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+  TStringField(fld).Size := 600;
+  //
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_s_amount;
+  fld.DataSet := FQrySQL;
+  fld := TLargeintField.Create(FQrySQL);
+  fld.FieldName := 'amount';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_s_fee;
+  fld.DataSet := FQrySQL;
+  fld := TLargeintField.Create(FQrySQL);
+  fld.FieldName := 'fee';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_s_balance;
+  fld.DataSet := FQrySQL;
+  fld := TLargeintField.Create(FQrySQL);
+  fld.FieldName := 'balance';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_Operations_rawpayload;
+  fld.DataSet := FQrySQL;
+  TStringField(fld).Size := 255;
+end;
+
+destructor TOperationsDBGrid.Destroy;
+begin
+  FNodeNotifyEvents.Free;
+  FDataSource.Free;
+  FQrySQL.Free;
+  inherited;
+end;
+
+procedure TOperationsDBGrid.Disable;
+begin
+  inc(FDisableds);
+end;
+
+procedure TOperationsDBGrid.Enable;
+begin
+  dec(FDisableds);
+  if FDisableds>0 then exit;
+  FDisableds := 0;
+  if FNeedRefreshSQL then RefreshData;
+end;
+
+function TOperationsDBGrid.GetAdoConnection: TADOConnection;
+begin
+  Result := FQrySQL.Connection;
+end;
+
+function TOperationsDBGrid.GetNode: TNode;
+begin
+  Result := FNodeNotifyEvents.Node;
+end;
+
+procedure TOperationsDBGrid.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited;
+  if Operation=opRemove then begin
+    if (AComponent=FDBGrid) then begin
+      SetDBGrid(Nil);
+    end;
+  end;
+end;
+
+procedure TOperationsDBGrid.OnGridDrawColumnCell(Sender: TObject;
+  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
+Var c : TCanvas;
+  s : String;
+  r : TRect;
+begin
+  c := TDBGrid(Sender).Canvas;
+  r := Rect;
+  if (gdSelected in State) then
+    If (gdFocused in State) then c.Brush.Color := clGradientActiveCaption
+    else c.Brush.Color := clGradientInactiveCaption
+  else c.Brush.Color := clWindow;
+  c.FillRect(Rect);
+  if SameText(Column.FieldName,'amount') Or
+     SameText(Column.FieldName,'fee') Or
+     SameText(Column.FieldName,'balance')
+      then begin
+    c.FillRect(Rect);
+    if Column.Field.AsLargeInt>0 then c.Font.Color := ClGreen
+    else if Column.Field.AsLargeInt=0 then c.Font.Color := clGrayText
+    else c.Font.Color := clRed;
+    s := TAccountComp.FormatMoney(Column.Field.AsLargeInt);
+    c.TextRect(r,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+  end else begin
+    TDBGrid(Sender).DefaultDrawColumnCell(Rect,DataCol,Column,State);
+  end;
+
+  if (gdFixed in State) and ([dgRowLines, dgColLines] * TDBGrid(Sender).Options =  [dgRowLines, dgColLines]) and
+     not (gdPressed in State) then
+  begin
+    InflateRect(r, 1, 1);
+    DrawEdge(c.Handle, r, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
+    DrawEdge(c.Handle, r, BDR_RAISEDINNER, BF_TOPLEFT);
+  end;
+  //
+end;
+
+procedure TOperationsDBGrid.OnNodeNewAccount(Sender: TObject);
+begin
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.OnQryCalcFields(DataSet: TDataSet);
+Var fld : TField;
+  raw : TRawBytes;
+  s : AnsiString;
+begin
+  fld := DataSet.FieldByName('datetime');
+  fld.AsDateTime :=  UnivDateTime2LocalDateTime(UnixToUnivDateTime( StrToIntDef( DataSet.FieldByName(CT_TblFld_Operations_s_timestamp).AsString, 0)));
+  fld := DataSet.FieldByName('op_account');
+  fld.AsString := TAccountComp.AccountNumberToAccountTxtNumber(DataSet.FieldByName(CT_TblFld_Operations_account).AsInteger);
+  fld := DataSet.FieldByName('payload_txt');
+  TDBStorage.DBStringFieldToRaw(DataSet.FieldByName(CT_TblFld_Operations_rawpayload),raw);
+  If TDBStorage.DBPayloadToReadableText(raw,s) then begin
+    fld.AsString := s;
+  end else begin
+    fld.AsString := TCrypto.ToHexaString(raw);
+  end;
+  //
+  fld := DataSet.FieldByName('amount');
+  TLargeintField(fld).Value := StrToInt64Def(Dataset.FieldByName(CT_TblFld_Operations_s_amount).AsString,0);
+  fld := DataSet.FieldByName('balance');
+  TLargeintField(fld).Value := StrToInt64Def(Dataset.FieldByName(CT_TblFld_Operations_s_balance).AsString,0);
+  fld := DataSet.FieldByName('fee');
+  TLargeintField(fld).Value := StrToInt64Def(Dataset.FieldByName(CT_TblFld_Operations_s_fee).AsString,0);
+
+  fld := DataSet.FieldByName('operation');
+          case dataset.FieldByName(CT_TblFld_Operations_optype).AsInteger of
+            0 : fld.AsString := 'Blockchain reward';
+            CT_Op_Transaction : begin
+              if dataset.FieldByName(CT_TblFld_Operations_optype_op).AsInteger=0 then begin
+                fld.AsString := 'Transaction Sent to '+TAccountComp.AccountNumberToAccountTxtNumber(dataset.FieldByName(CT_TblFld_Operations_other_account).AsLargeInt);
+              end else begin
+                fld.AsString := 'Transaction Received from '+TAccountComp.AccountNumberToAccountTxtNumber(dataset.FieldByName(CT_TblFld_Operations_other_account).AsLargeInt);
+              end;
+            end;
+            CT_Op_Changekey : Begin
+              fld.AsString := 'Change Key';
+            End;
+            CT_Op_Recover : begin
+              fld.AsString := 'Recover founds';
+            end;
+          else
+            fld.AsString := 'Unknown OpType:'+Inttostr(dataset.FieldByName(CT_TblFld_Operations_optype).AsInteger);
+          end;
+end;
+
+procedure TOperationsDBGrid.RefreshData;
+Var sql : AnsiString;
+begin
+  if FDisableds>0 then begin
+    FNeedRefreshSQL := true;
+    exit;
+  end;
+  FNeedRefreshSQL := false;
+  sql := TDBStorage.GetOperationsFromAccountSQL(AccountNumber,BlockStart,BlockEnd,DateStart,DateEnd, 0,50000);
+  If FQrySQL.Connection=Nil then exit;
+  if Node=Nil then exit;
+  if FDBGrid=Nil then exit;
+
+  FQrySQL.DisableControls;
+  try
+    FQrySQL.Close;
+    FQrySQL.SQL.Text := sql;
+    FQrySQL.Open;
+  finally
+    FQrySQL.EnableControls;
+  end;
+end;
+
+procedure TOperationsDBGrid.SetAccountNumber(const Value: Int64);
+begin
+  if FAccountNumber=Value then exit;
+  FAccountNumber := Value;
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.SetAdoConnection(const Value: TADOConnection);
+begin
+  FQrySQL.Connection := Value;
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.SetBlockEnd(const Value: Int64);
+begin
+  if FBlockEnd=Value then exit;
+  FBlockEnd := Value;
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.SetBlocks(bstart, bend: Int64);
+begin
+  FBlockStart := bstart;
+  FBlockEnd := bend;
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.SetBlockStart(const Value: Int64);
+begin
+  if FBlockStart=Value then exit;
+  FBlockStart := Value;
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.SetDateEnd(const Value: TDate);
+Var d,h,m,y : word;
+begin
+  if FDateEnd=Value then exit;
+  decodedate(value,y,m,d);
+  FDateEnd := EncodeDate(y,m,d);
+  if FDateStart>=FDateEnd then FDateStart := FDateEnd;
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.SetDates(dStart, dEnd: TDate);
+begin
+  Disable;
+  try
+    DateStart := dStart;
+    DateEnd := dEnd;
+  finally
+    Enable;
+  end;
+end;
+
+procedure TOperationsDBGrid.SetDateStart(const Value: TDate);
+Var d,h,m,y : word;
+begin
+  if FDateStart=Value then exit;
+  decodedate(value,y,m,d);
+  FDateStart := EncodeDate(y,m,d);
+  if FDateStart>=FDateEnd then FDateEnd := FDateStart;
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.SetDBGrid(const Value: TDBGrid);
+  Procedure AddColumn(fieldname,displayname : String; colwidth : integer);
+  Var c : TColumn;
+  begin
+    c := DBgrid.Columns.Add;
+    c.FieldName := fieldname;
+    c.Title.Caption := displayname;
+    c.Width := colwidth;
+    c.Title.Font.Style := [fsBold];
+    c.Title.Alignment := taCenter;
+  end;
+begin
+  if FDBGrid=Value then exit;
+  if Assigned(FDBGrid) then FDBGrid.DataSource := Nil;
+  FDBGrid := Value;
+  if Assigned(Value) then begin
+    Value.FreeNotification(self);
+    Value.DataSource := FDataSource;
+    Value.ReadOnly := true;
+    FDBGrid.OnDrawColumnCell := OnGridDrawColumnCell;
+    FDBGrid.DefaultDrawing := false;
+    FDBGrid.Columns.Clear;
+    AddColumn(CT_TblFld_Operations_block,'Block',50);
+    AddColumn('datetime','Date/Time',120);
+    AddColumn('op_account','Account',70);
+    AddColumn('operation','Operation',150);
+    AddColumn('amount','Amount',80);
+    AddColumn('fee','Fee',60);
+    AddColumn('balance','Balance',80);
+    AddColumn('payload_txt','Payload',280);
+    RefreshData;
+  end;
+end;
+
+procedure TOperationsDBGrid.SetNode(const Value: TNode);
+begin
+  FNodeNotifyEvents.Node:= value;
+  RefreshData;
+end;
+
+procedure TOperationsDBGrid.ShowModalDecoder(WalletKeys: TWalletKeys; AppParams: TAppParams);
+Var FRM : TFRMPayloadDecoder;
+  raw : TRawBytes;
+begin
+  if Not Assigned(FDBGrid) Or Not Assigned(FQrySQL) then exit;
+  If FQrySQL.Eof then exit;
+  FRM := TFRMPayloadDecoder.Create(FDBGrid.Owner);
+  try
+    TDBStorage.DBStringFieldToRaw(FQrySQL.FieldByName(CT_TblFld_Operations_rawpayload),raw);
+    FRM.Init(FQrySQL.FieldByName(CT_TblFld_Operations_block).AsInteger,
+      StrToIntDef( FQrySQL.FieldByName(CT_TblFld_Operations_s_timestamp).AsString,0),
+      FQrySQL.FieldByName('operation').AsString,
+      raw,WalletKeys,AppParams);
+    FRM.ShowModal;
+  finally
+    FRM.Free;
+  end;
+end;
+
+{ TBlockChainDBGrid }
+
+constructor TBlockChainDBGrid.Create(AOwner: TComponent);
+Var fld : TField;
+begin
+  inherited;
+  FNeedRefreshSQL := False;
+  FBlockStart := -1;
+  FBlockEnd := -1;
+  FDateEnd := 0;
+  FDateStart := 0;
+  FDisableds := 0;
+  FQrySQL := TADOQuery.Create(Self);
+  FQrySQL.OnCalcFields := OnQryCalcFields;
+  FqrySQL.CursorLocation := clUseClient;
+  FDBGrid := Nil;
+  FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
+  FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
+  FDataSource := TDataSource.Create(Self);
+  FDataSource.DataSet := FQrySQL;
+  fld := TIntegerField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_block;
+  fld.DataSet := FQrySQL;
+  fld.Visible := true;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_s_timestamp;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_s_reward;
+  fld.DataSet := FQrySQL;
+  fld.Visible := true;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_s_fee;
+  fld.DataSet := FQrySQL;
+  fld.Visible := true;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_s_compact_target;
+  fld.DataSet := FQrySQL;
+  fld.Visible := true;
+  fld := TIntegerField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_operations_count;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  fld := TDateTimeField.Create(FQrySQL);
+  fld.FieldName := 'datetime';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_proof_of_work;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  TStringField(fld).Size := 64;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_safe_box_hash;
+  fld.DataSet := FQrySQL;
+  fld.Visible := false;
+  TStringField(fld).Size := 64;
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := 'target';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+  TStringField(fld).Size := 8;
+
+  fld := TLargeintField.Create(FQrySQL);
+  fld.FieldName := 'reward';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+
+  fld := TLargeintField.Create(FQrySQL);
+  fld.FieldName := 'fee';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := CT_TblFld_BlockChain_rawpayload;
+  fld.DataSet := FQrySQL;
+  TStringField(fld).Size := 255;
+
+  fld := TStringField.Create(FQrySQL);
+  fld.FieldName := 'payload_decoded';
+  fld.Calculated := true;
+  fld.FieldKind := fkCalculated;
+  fld.DataSet := FQrySQL;
+  TStringField(fld).Size := 600;
+end;
+
+destructor TBlockChainDBGrid.Destroy;
+begin
+  SetDBGrid(Nil);
+  FNodeNotifyEvents.Free;
+  FDataSource.Free;
+  FQrySQL.Free;
+  inherited;
+end;
+
+procedure TBlockChainDBGrid.Disable;
+begin
+  Inc(FDisableds);
+end;
+
+procedure TBlockChainDBGrid.Enable;
+begin
+  if FDisableds<0 then exit;
+  Dec(FDisableds);
+  if FNeedRefreshSQL then RefreshData;
+end;
+
+function TBlockChainDBGrid.GetAdoConnection: TADOConnection;
+begin
+  Result := FQrySQL.Connection;
+end;
+
+function TBlockChainDBGrid.GetNode: TNode;
+begin
+  Result := FNodeNotifyEvents.Node;
+end;
+
+procedure TBlockChainDBGrid.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited;
+  if Operation=OpRemove then begin
+    if AComponent=FDBGrid then FDBGrid:=Nil;
+  end;
+end;
+
+procedure TBlockChainDBGrid.OnGridDrawColumnCell(Sender: TObject;
+  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
+Var c : TCanvas;
+  s : String;
+  r : TRect;
+begin
+  c := TDBGrid(Sender).Canvas;
+  r := Rect;
+  if (gdSelected in State) then
+    If (gdFocused in State) then c.Brush.Color := clGradientActiveCaption
+    else c.Brush.Color := clGradientInactiveCaption
+  else c.Brush.Color := clWindow;
+  c.FillRect(Rect);
+  if SameText(Column.FieldName,'reward') Or
+     SameText(Column.FieldName,'fee')
+      then begin
+    c.FillRect(Rect);
+    if Column.Field.AsLargeInt>0 then c.Font.Color := ClGreen
+    else if Column.Field.AsLargeInt=0 then c.Font.Color := clGrayText
+    else c.Font.Color := clRed;
+    s := TAccountComp.FormatMoney(Column.Field.AsLargeInt);
+    c.TextRect(r,s,[tfRight,tfVerticalCenter,tfSingleLine]);
+  end else begin
+    TDBGrid(Sender).DefaultDrawColumnCell(Rect,DataCol,Column,State);
+  end;
+
+  if (gdFixed in State) and ([dgRowLines, dgColLines] * TDBGrid(Sender).Options =  [dgRowLines, dgColLines]) and
+     not (gdPressed in State) then
+  begin
+    InflateRect(r, 1, 1);
+    DrawEdge(c.Handle, r, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
+    DrawEdge(c.Handle, r, BDR_RAISEDINNER, BF_TOPLEFT);
+  end;
+  //
+end;
+
+procedure TBlockChainDBGrid.OnNodeNewAccount(Sender: TObject);
+begin
+  RefreshData;
+end;
+
+procedure TBlockChainDBGrid.OnQryCalcFields(DataSet: TDataSet);
+Var fld : TField;
+  raw : TRawBytes;
+  s : AnsiString;
+begin
+  fld := DataSet.FieldByName('datetime');
+  fld.AsDateTime :=  UnivDateTime2LocalDateTime(UnixToUnivDateTime(StrToIntDef( DataSet.FieldByName(CT_TblFld_BlockChain_s_timestamp).AsString,0)));
+  fld := DataSet.FieldByName('target');
+  fld.AsString :=  IntToHex(StrToIntDef( DataSet.FieldByName(CT_TblFld_BlockChain_s_compact_target).AsString,0),8);
+  DataSet.FieldByName('reward').AsLargeInt := StrToIntDef(DataSet.FieldByName(CT_TblFld_BlockChain_s_reward).AsString,0);
+  DataSet.FieldByName('fee').AsLargeInt := StrToIntDef(DataSet.FieldByName(CT_TblFld_BlockChain_s_fee).AsString,0);
+  fld := DataSet.FieldByName('payload_decoded');
+  TDBStorage.DBStringFieldToRaw(DataSet.FieldByName(CT_TblFld_BlockChain_rawpayload),raw);
+  If TDBStorage.DBPayloadToReadableText(raw,s) then begin
+    fld.AsString := s;
+  end else begin
+    fld.AsString := TCrypto.ToHexaString(raw);
+  end;
+end;
+
+procedure TBlockChainDBGrid.RefreshData;
+Var sql : AnsiString;
+begin
+  if FDisableds>0 then begin
+    FNeedRefreshSQL := true;
+    exit;
+  end;
+  FNeedRefreshSQL := false;
+  sql := TDBStorage.GetBlockChainSQL(BlockStart,BlockEnd,DateStart,DateEnd, 0,300);
+  If FQrySQL.Connection=Nil then exit;
+  if Node=Nil then exit;
+  if FDBGrid=Nil then exit;
+
+  FQrySQL.DisableControls;
+  try
+    FQrySQL.Close;
+    FQrySQL.SQL.Text := sql;
+    FQrySQL.Open;
+  finally
+    FQrySQL.EnableControls;
+  end;
+end;
+
+procedure TBlockChainDBGrid.SetAdoConnection(const Value: TADOConnection);
+begin
+  FQrySQL.Connection := Value;
+  RefreshData;
+end;
+
+procedure TBlockChainDBGrid.SetBlockEnd(const Value: Int64);
+begin
+  if FBlockEnd=Value then exit;
+  FBlockEnd := Value;
+  RefreshData;
+end;
+
+procedure TBlockChainDBGrid.SetBlocks(bstart, bend: Int64);
+begin
+  disable;
+  Try
+    BlockStart := bstart;
+    BlockEnd := bEnd;
+  Finally
+    Enable;
+  End;
+end;
+
+procedure TBlockChainDBGrid.SetBlockStart(const Value: Int64);
+begin
+  if FBlockStart=Value then exit;
+  FBlockStart:=Value;
+  RefreshData;
+end;
+
+procedure TBlockChainDBGrid.SetDateEnd(const Value: TDate);
+begin
+  if FDateEnd=Value then exit;
+  FDateEnd := Value;
+  RefreshData;
+end;
+
+procedure TBlockChainDBGrid.SetDates(dStart, dEnd: TDate);
+begin
+  Disable;
+  Try
+    DateStart := dStart;
+    DateEnd := dEnd;
+  Finally
+    Enable;
+  End;
+end;
+
+procedure TBlockChainDBGrid.SetDateStart(const Value: TDate);
+begin
+  if FDateStart=Value then exit;
+  FDateStart := Value;
+  RefreshData;
+end;
+
+procedure TBlockChainDBGrid.SetDBGrid(const Value: TDBGrid);
+  Procedure AddColumn(fieldname,displayname : String; colwidth : integer);
+  Var c : TColumn;
+  begin
+    c := DBgrid.Columns.Add;
+    c.FieldName := fieldname;
+    c.Title.Caption := displayname;
+    c.Width := colwidth;
+    c.Title.Font.Style := [fsBold];
+    c.Title.Alignment := taCenter;
+  end;
+begin
+  if FDBGrid=Value then exit;
+  if Assigned(FDBGrid) then FDBGrid.DataSource := Nil;
+  FDBGrid := Value;
+  if Assigned(Value) then begin
+    Value.FreeNotification(self);
+    Value.DataSource := FDataSource;
+    Value.ReadOnly := true;
+    FDBGrid.OnDrawColumnCell := OnGridDrawColumnCell;
+    FDBGrid.DefaultDrawing := false;
+    FDBGrid.Columns.Clear;
+    AddColumn(CT_TblFld_BlockChain_block,'Block',60);
+    AddColumn('datetime','Date/Time',120);
+    AddColumn(CT_TblFld_BlockChain_operations_count,'Ops.',30);
+    AddColumn('reward','Reward',80);
+    AddColumn('fee','Fee',60);
+    AddColumn('target','Target',60);
+    AddColumn('payload_decoded','Miner Payload',150);
+    AddColumn(CT_TblFld_BlockChain_proof_of_work,'Proof of Work',400);
+    AddColumn(CT_TblFld_BlockChain_safe_box_hash,'Safe Box Hash',400);
+    RefreshData;
+  end;
+end;
+
+procedure TBlockChainDBGrid.SetNode(const Value: TNode);
+begin
+  FNodeNotifyEvents.Node := Value;
+  RefreshData;
+end;
+
+end.

+ 1 - 1
Units/Utils/UFolderHelper.pas

@@ -39,10 +39,10 @@ Type TFileVersionInfo = record
   strict private
   strict private
     class function GetFolder(const aCSIDL: Integer): string; static;
     class function GetFolder(const aCSIDL: Integer): string; static;
     class function GetAppDataFolder : string; static;
     class function GetAppDataFolder : string; static;
-    class function GetUserDataFolder : string; static;
   public
   public
     class function GetPascalCoinDataFolder : string; static;
     class function GetPascalCoinDataFolder : string; static;
     class Function GetTFileVersionInfo(Const FileName : String) : TFileVersionInfo; static;
     class Function GetTFileVersionInfo(Const FileName : String) : TFileVersionInfo; static;
+    class function GetUserDataFolder : string; static;
   end;
   end;
 
 
 implementation
 implementation

+ 2 - 1091
Units/Utils/UGridUtils.pas

@@ -16,8 +16,8 @@ unit UGridUtils;
 interface
 interface
 
 
 uses
 uses
-  Classes, Grids, Windows, UNode, UAccounts, UBlockChain, UDBStorage, DBGrids, DB, ADODB,
-  UWalletKeys, UAppParams;
+  Classes, Grids, Windows, UNode, UAccounts, UBlockChain,
+  UWalletKeys;
 
 
 Type
 Type
   // TAccountsGrid implements a visual integration of TDrawGrid
   // TAccountsGrid implements a visual integration of TDrawGrid
@@ -64,128 +64,6 @@ Type
     Property OnUpdated : TNotifyEvent read FOnUpdated write FOnUpdated;
     Property OnUpdated : TNotifyEvent read FOnUpdated write FOnUpdated;
   End;
   End;
 
 
-  TOperationsGrid = Class(TComponent)
-  private
-    FDrawGrid: TDrawGrid;
-    FAccountNumber: Int64;
-    FOperationsResume : TOperationsResumeList;
-    FNodeNotifyEvents : TNodeNotifyEvents;
-    FPendingOperations: Boolean;
-    Procedure OnNodeNewOperation(Sender : TObject);
-    Procedure OnNodeNewAccount(Sender : TObject);
-    Procedure InitGrid;
-    procedure OnGridDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
-    procedure SetDrawGrid(const Value: TDrawGrid);
-    procedure SetAccountNumber(const Value: Int64);
-    procedure SetNode(const Value: TNode);
-    function GetNode: TNode;
-    procedure SetPendingOperations(const Value: Boolean);
-  protected
-    procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
-  public
-    Constructor Create(AOwner : TComponent); override;
-    Destructor Destroy; override;
-    Property DrawGrid : TDrawGrid read FDrawGrid write SetDrawGrid;
-    Property PendingOperations : Boolean read FPendingOperations write SetPendingOperations;
-    Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
-    Property Node : TNode read GetNode write SetNode;
-    Procedure UpdateAccountOperations;
-    Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
-  End;
-
-  TOperationsDBGrid = Class(TComponent)
-  private
-    FDisableds : Integer;
-    FQrySQL : TAdoQuery;
-    FDBGrid: TDBGrid;
-    FAccountNumber: Int64;
-    FNodeNotifyEvents : TNodeNotifyEvents;
-    FDataSource : TDataSource;
-    FDateEnd: TDate;
-    FBlockStart: Int64;
-    FDateStart: TDate;
-    FBlockEnd: Int64;
-    FNeedRefreshSQL : Boolean;
-    function GetNode: TNode;
-    procedure SetAccountNumber(const Value: Int64);
-    procedure SetDBGrid(const Value: TDBGrid);
-    procedure SetNode(const Value: TNode);
-    Procedure OnGridDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
-    procedure SetAdoConnection(const Value: TADOConnection);
-    function GetAdoConnection: TADOConnection;
-    Procedure OnQryCalcFields(DataSet: TDataSet);
-    Procedure OnNodeNewAccount(Sender : TObject);
-    procedure SetBlockEnd(const Value: Int64);
-    procedure SetBlockStart(const Value: Int64);
-    procedure SetDateEnd(const Value: TDate);
-    procedure SetDateStart(const Value: TDate);
-  protected
-    procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
-  published
-  public
-    Constructor Create(AOwner : TComponent); override;
-    Destructor Destroy; override;
-    Property DBGrid : TDBGrid read FDBGrid write SetDBGrid;
-    Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
-    Property BlockStart : Int64 read FBlockStart write SetBlockStart;
-    Property BlockEnd : Int64 read FBlockEnd write SetBlockEnd;
-    Procedure SetBlocks(bstart,bend : Int64);
-    Property DateStart : TDate read FDateStart write SetDateStart;
-    Property DateEnd : TDate read FDateEnd write SetDateEnd;
-    Procedure SetDates(dStart,dEnd : TDate);
-    Property Node : TNode read GetNode write SetNode;
-    Procedure RefreshData;
-    Property AdoConnection : TADOConnection read GetAdoConnection write SetAdoConnection;
-    Procedure Disable;
-    Procedure Enable;
-    Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
-  End;
-
-  TBlockChainDBGrid = Class(TComponent)
-  private
-    FDisableds : Integer;
-    FQrySQL : TAdoQuery;
-    FDBGrid: TDBGrid;
-    FNodeNotifyEvents : TNodeNotifyEvents;
-    FDataSource : TDataSource;
-    FDateEnd: TDate;
-    FBlockStart: Int64;
-    FDateStart: TDate;
-    FBlockEnd: Int64;
-    FAccountNumber: Int64;
-    FNeedRefreshSQL : Boolean;
-    function GetNode: TNode;
-    procedure SetDBGrid(const Value: TDBGrid);
-    procedure SetNode(const Value: TNode);
-    Procedure OnGridDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
-    procedure SetAdoConnection(const Value: TADOConnection);
-    function GetAdoConnection: TADOConnection;
-    Procedure OnQryCalcFields(DataSet: TDataSet);
-    Procedure OnNodeNewAccount(Sender : TObject);
-    procedure SetBlockEnd(const Value: Int64);
-    procedure SetBlockStart(const Value: Int64);
-    procedure SetDateEnd(const Value: TDate);
-    procedure SetDateStart(const Value: TDate);
-  protected
-    procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
-  published
-  public
-    Constructor Create(AOwner : TComponent); override;
-    Destructor Destroy; override;
-    Property DBGrid : TDBGrid read FDBGrid write SetDBGrid;
-    Property BlockStart : Int64 read FBlockStart write SetBlockStart;
-    Property BlockEnd : Int64 read FBlockEnd write SetBlockEnd;
-    Procedure SetBlocks(bstart,bend : Int64);
-    Property DateStart : TDate read FDateStart write SetDateStart;
-    Property DateEnd : TDate read FDateEnd write SetDateEnd;
-    Procedure SetDates(dStart,dEnd : TDate);
-    Property Node : TNode read GetNode write SetNode;
-    Procedure RefreshData;
-    Property AdoConnection : TADOConnection read GetAdoConnection write SetAdoConnection;
-    Procedure Disable;
-    Procedure Enable;
-  End;
-
 implementation
 implementation
 
 
 uses
 uses
@@ -511,971 +389,4 @@ begin
   InitGrid;
   InitGrid;
 end;
 end;
 
 
-{ TOperationsGrid }
-
-constructor TOperationsGrid.Create(AOwner: TComponent);
-begin
-  FAccountNumber := 0;
-  FDrawGrid := Nil;
-  FOperationsResume := TOperationsResumeList.Create;
-  FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
-  FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
-  FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
-  inherited;
-end;
-
-destructor TOperationsGrid.Destroy;
-begin
-  FOperationsResume.Free;
-  FNodeNotifyEvents.Free;
-  inherited;
-end;
-
-function TOperationsGrid.GetNode: TNode;
-begin
-  Result := FNodeNotifyEvents.Node;
-end;
-
-procedure TOperationsGrid.InitGrid;
-begin
-  if Not Assigned(FDrawGrid) then exit;
-  if FOperationsResume.Count>0 then FDrawGrid.RowCount := FOperationsResume.Count+1
-  else FDrawGrid.RowCount := 2;
-  DrawGrid.FixedRows := 1;
-  DrawGrid.DefaultDrawing := true;
-  DrawGrid.FixedCols := 0;
-  DrawGrid.ColCount := 8;
-  DrawGrid.ColWidths[0] := 110; // Time
-  DrawGrid.ColWidths[1] := 50; // Block
-  DrawGrid.ColWidths[2] := 60; // Account
-  DrawGrid.ColWidths[3] := 150; // OpType
-  DrawGrid.ColWidths[4] := 70; // Amount
-  DrawGrid.ColWidths[5] := 60; // Operation Fee
-  DrawGrid.ColWidths[6] := 70; // Balance
-  DrawGrid.ColWidths[7] := 500; // Payload
-  FDrawGrid.DefaultRowHeight := 18;
-  FDrawGrid.Invalidate;
-  DrawGrid.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
-    {goRangeSelect, }goDrawFocusSelected, {goRowSizing, }goColSizing, {goRowMoving,}
-    {goColMoving, goEditing, }goTabs, goRowSelect, {goAlwaysShowEditor,}
-    goThumbTracking, goFixedColClick, goFixedRowClick, goFixedHotTrack];
-end;
-
-procedure TOperationsGrid.Notification(AComponent: TComponent; Operation: TOperation);
-begin
-  inherited;
-  if Operation=opRemove then begin
-    if (AComponent=FDrawGrid) then begin
-      SetDrawGrid(Nil);
-    end;
-  end;
-end;
-
-procedure TOperationsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
-Var s : String;
-  opr : TOperationResume;
-begin
-  opr := CT_TOperationResume_NUL;
-  Try
-  if (ARow=0) then begin
-    // Header
-    case ACol of
-      0 : s := 'Time';
-      1 : s := 'Block';
-      2 : s := 'Account';
-      3 : s := 'Operation';
-      4 : s := 'Amount';
-      5 : s := 'Fee';
-      6 : s := 'Balance';
-      7 : s := 'Payload';
-    else s:= '';
-    end;
-    DrawGrid.Canvas.TextRect(Rect,s,[tfCenter,tfVerticalCenter]);
-  end else begin
-    if (gdSelected in State) then
-      If (gdFocused in State) then DrawGrid.Canvas.Brush.Color := clGradientActiveCaption
-      else DrawGrid.Canvas.Brush.Color := clGradientInactiveCaption
-    else DrawGrid.Canvas.Brush.Color := clWindow;
-    DrawGrid.Canvas.FillRect(Rect);
-    InflateRect(Rect,-2,-1);
-    if (ARow<=FOperationsResume.Count) then begin
-      opr := FOperationsResume.OperationResume[ARow-1];
-      if ACol=0 then begin
-        if opr.time=0 then s := '(Pending)'
-        else s := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime(opr.time)));
-        DrawGrid.Canvas.TextRect(Rect,s,[tfleft,tfVerticalCenter,tfSingleLine]);
-      end else if ACol=1 then begin
-        s := Inttostr(opr.Block);
-        DrawGrid.Canvas.TextRect(Rect,s,[tfleft,tfVerticalCenter,tfSingleLine]);
-      end else if ACol=2 then begin
-        s := TAccountComp.AccountNumberToAccountTxtNumber(opr.AffectedAccount);
-        DrawGrid.Canvas.TextRect(Rect,s,[tfleft,tfVerticalCenter,tfSingleLine]);
-      end else if ACol=3 then begin
-        s := opr.OperationTxt;
-        DrawGrid.Canvas.TextRect(Rect,s,[tfleft,tfVerticalCenter,tfSingleLine]);
-      end else if ACol=4 then begin
-        s := TAccountComp.FormatMoney(opr.Amount);
-        if opr.Amount>0 then DrawGrid.Canvas.Font.Color := ClGreen
-        else if opr.Amount=0 then DrawGrid.Canvas.Font.Color := clGrayText
-        else DrawGrid.Canvas.Font.Color := clRed;
-        DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
-      end else if ACol=5 then begin
-        s := TAccountComp.FormatMoney(opr.Fee);
-        if opr.Fee>0 then DrawGrid.Canvas.Font.Color := ClGreen
-        else if opr.Fee=0 then DrawGrid.Canvas.Font.Color := clGrayText
-        else DrawGrid.Canvas.Font.Color := clRed;
-        DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
-      end else if ACol=6 then begin
-        if opr.time=0 then begin
-          // Pending operation... showing final balance
-          DrawGrid.Canvas.Font.Color := clBlue;
-          s := '('+TAccountComp.FormatMoney(opr.Balance)+')';
-        end else begin
-          s := TAccountComp.FormatMoney(opr.Balance);
-          if opr.Balance>0 then DrawGrid.Canvas.Font.Color := ClGreen
-          else if opr.Balance=0 then DrawGrid.Canvas.Font.Color := clGrayText
-          else DrawGrid.Canvas.Font.Color := clRed;
-        end;
-        DrawGrid.Canvas.TextRect(Rect,s,[tfRight,tfVerticalCenter,tfSingleLine]);
-      end else if ACol=7 then begin
-        s := opr.PrintablePayload;
-        DrawGrid.Canvas.TextRect(Rect,s,[tfLeft,tfVerticalCenter,tfSingleLine]);
-      end else begin
-        s := '(???)';
-        DrawGrid.Canvas.TextRect(Rect,s,[tfCenter,tfVerticalCenter,tfSingleLine]);
-      end;
-    end;
-  end;
-  Except
-    On E:Exception do begin
-      TLog.NewLog(lterror,Classname,Format('Error at OnGridDrawCell row %d col %d Block %d - %s',[ARow,ACol,opr.Block,E.Message]));
-    end;
-  End;
-end;
-
-procedure TOperationsGrid.OnNodeNewAccount(Sender: TObject);
-begin
-  UpdateAccountOperations;
-end;
-
-procedure TOperationsGrid.OnNodeNewOperation(Sender: TObject);
-Var Op : TPCOperation;
-  l : TList;
-begin
-  if AccountNumber<0 then UpdateAccountOperations
-  else begin
-    Op := TPCOperation(Sender);
-    l := TList.Create;
-    Try
-      Op.AffectedAccounts(l);
-      if l.IndexOf(TObject(Integer(AccountNumber)))>=0 then UpdateAccountOperations;
-    Finally
-      l.Free;
-    End;
-  end;
-end;
-
-procedure TOperationsGrid.SetAccountNumber(const Value: Int64);
-begin
-  if FAccountNumber=Value then exit;
-  FAccountNumber := Value;
-  if FAccountNumber>=0 then FPendingOperations := false;
-  UpdateAccountOperations;
-end;
-
-procedure TOperationsGrid.SetDrawGrid(const Value: TDrawGrid);
-begin
-  if FDrawGrid=Value then exit;
-  FDrawGrid := Value;
-  if Assigned(Value) then begin
-    Value.FreeNotification(self);
-    FDrawGrid.OnDrawCell := OnGridDrawCell;
-    InitGrid;
-  end;
-end;
-
-procedure TOperationsGrid.SetNode(const Value: TNode);
-begin
-  if GetNode=Value then exit;
-  FNodeNotifyEvents.Node := Value;
-  UpdateAccountOperations; // New Build 1.0.3
-end;
-
-procedure TOperationsGrid.SetPendingOperations(const Value: Boolean);
-begin
-  FPendingOperations := Value;
-  if FPendingOperations then  FAccountNumber := -1;
-  UpdateAccountOperations;
-end;
-
-procedure TOperationsGrid.ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
-Var i : Integer;
-  opr : TOperationResume;
-  FRM : TFRMPayloadDecoder;
-begin
-  if Not Assigned(FDrawGrid) then exit;
-  if (FDrawGrid.Row<=0) Or (FDrawGrid.Row>FOperationsResume.Count) then exit;
-  opr := FOperationsResume.OperationResume[FDrawGrid.Row-1];
-  FRM := TFRMPayloadDecoder.Create(FDrawGrid.Owner);
-  try
-    FRM.Init(opr.Block,opr.time,opr.OperationTxt,opr.OriginalPayload,WalletKeys,AppParams);
-    FRM.ShowModal;
-  finally
-    FRM.Free;
-  end;
-end;
-
-procedure TOperationsGrid.UpdateAccountOperations;
-Var list : TList;
-  i,j : Integer;
-  OPR : TOperationResume;
-  Op : TPCOperation;
-begin
-  FOperationsResume.Clear;
-  Try
-    if Not Assigned(Node) then exit;
-    if FPendingOperations then begin
-      for i := Node.Operations.Count - 1 downto 0 do begin
-        Op := Node.Operations.OperationsHashTree.GetOperation(i);
-        If TDBStorage.OperationToOperationResume(Op,Op.SenderAccount,OPR) then begin
-          OPR.Block := Node.Operations.OperationBlock.block;
-          OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
-          FOperationsResume.Add(OPR);
-        end;
-      end;
-    end else begin
-      if AccountNumber<0 then begin
-        list := TList.Create;
-        try
-          for i := 0 to Node.Operations.Count-1 do begin
-            Op := Node.Operations.Operation[i];
-            If TDBStorage.OperationToOperationResume(Op,Op.SenderAccount,OPR) then begin
-              OPR.Block := Node.Operations.OperationBlock.block;
-              OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
-              FOperationsResume.Add(OPR);
-            end;
-          end;
-        finally
-          list.Free;
-        end;
-      end else begin
-        list := TList.Create;
-        Try
-          Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
-          for i := list.Count - 1 downto 0 do begin
-            Op := Node.Operations.OperationsHashTree.GetOperation(Integer(list[i]));
-            If TDBStorage.OperationToOperationResume(Op,AccountNumber,OPR) then begin
-              OPR.Block := Node.Operations.OperationBlock.block;
-              OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
-              FOperationsResume.Add(OPR);
-            end;
-          end;
-        Finally
-          list.Free;
-        End;
-        if Node.Bank.Storage is TDBStorage then begin
-          TDBStorage(Node.Bank.Storage).GetOperationsFromAccount(FOperationsResume,AccountNumber,0,200);
-        end;
-      end;
-    end;
-  Finally
-    InitGrid;
-  End;
-end;
-
-{ TOperationsDBGrid }
-
-Type TAuxDBGrid = Class(TDBGrid);
-
-constructor TOperationsDBGrid.Create(AOwner: TComponent);
-Var i : Integer;
-  fld : TField;
-begin
-  inherited;
-  FNeedRefreshSQL := false;
-  FDisableds := 0;
-  FDBGrid := Nil;
-  FQrySQL := TADOQuery.Create(Self);
-  FQrySQL.OnCalcFields := OnQryCalcFields;
-  FqrySQL.CursorLocation := clUseClient;
-  FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
-  FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
-  FDataSource := TDataSource.Create(Self);
-  FDataSource.DataSet := FQrySQL;
-  FAccountNumber := -1; // all
-  FBlockStart := -1;
-  FBlockEnd := -1;
-  FDateStart := 0;
-  FDateEnd := 0;
-  fld := TIntegerField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_block;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  //
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_s_timestamp;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  //
-  fld := TIntegerField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_optype;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  fld := TIntegerField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_optype_op;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  fld := TIntegerField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_account;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  fld := TIntegerField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_other_account;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  fld := TDateTimeField.Create(FQrySQL);
-  fld.FieldName := 'datetime';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := 'op_account';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-  TStringField(fld).Size := 100;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := 'operation';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-  TStringField(fld).Size := 100;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := 'payload_txt';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-  TStringField(fld).Size := 600;
-  //
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_s_amount;
-  fld.DataSet := FQrySQL;
-  fld := TLargeintField.Create(FQrySQL);
-  fld.FieldName := 'amount';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_s_fee;
-  fld.DataSet := FQrySQL;
-  fld := TLargeintField.Create(FQrySQL);
-  fld.FieldName := 'fee';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_s_balance;
-  fld.DataSet := FQrySQL;
-  fld := TLargeintField.Create(FQrySQL);
-  fld.FieldName := 'balance';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_Operations_rawpayload;
-  fld.DataSet := FQrySQL;
-  TStringField(fld).Size := 255;
-end;
-
-destructor TOperationsDBGrid.Destroy;
-begin
-  FNodeNotifyEvents.Free;
-  FDataSource.Free;
-  FQrySQL.Free;
-  inherited;
-end;
-
-procedure TOperationsDBGrid.Disable;
-begin
-  inc(FDisableds);
-end;
-
-procedure TOperationsDBGrid.Enable;
-begin
-  dec(FDisableds);
-  if FDisableds>0 then exit;
-  FDisableds := 0;
-  if FNeedRefreshSQL then RefreshData;
-end;
-
-function TOperationsDBGrid.GetAdoConnection: TADOConnection;
-begin
-  Result := FQrySQL.Connection;
-end;
-
-function TOperationsDBGrid.GetNode: TNode;
-begin
-  Result := FNodeNotifyEvents.Node;
-end;
-
-procedure TOperationsDBGrid.Notification(AComponent: TComponent;
-  Operation: TOperation);
-begin
-  inherited;
-  if Operation=opRemove then begin
-    if (AComponent=FDBGrid) then begin
-      SetDBGrid(Nil);
-    end;
-  end;
-end;
-
-procedure TOperationsDBGrid.OnGridDrawColumnCell(Sender: TObject;
-  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
-Var c : TCanvas;
-  s : String;
-  r : TRect;
-begin
-  c := TDBGrid(Sender).Canvas;
-  r := Rect;
-  if (gdSelected in State) then
-    If (gdFocused in State) then c.Brush.Color := clGradientActiveCaption
-    else c.Brush.Color := clGradientInactiveCaption
-  else c.Brush.Color := clWindow;
-  c.FillRect(Rect);
-  if SameText(Column.FieldName,'amount') Or
-     SameText(Column.FieldName,'fee') Or
-     SameText(Column.FieldName,'balance')
-      then begin
-    c.FillRect(Rect);
-    if Column.Field.AsLargeInt>0 then c.Font.Color := ClGreen
-    else if Column.Field.AsLargeInt=0 then c.Font.Color := clGrayText
-    else c.Font.Color := clRed;
-    s := TAccountComp.FormatMoney(Column.Field.AsLargeInt);
-    c.TextRect(r,s,[tfRight,tfVerticalCenter,tfSingleLine]);
-  end else begin
-    TDBGrid(Sender).DefaultDrawColumnCell(Rect,DataCol,Column,State);
-  end;
-
-  if (gdFixed in State) and ([dgRowLines, dgColLines] * TDBGrid(Sender).Options =  [dgRowLines, dgColLines]) and
-     not (gdPressed in State) then
-  begin
-    InflateRect(r, 1, 1);
-    DrawEdge(c.Handle, r, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
-    DrawEdge(c.Handle, r, BDR_RAISEDINNER, BF_TOPLEFT);
-  end;
-  //
-end;
-
-procedure TOperationsDBGrid.OnNodeNewAccount(Sender: TObject);
-begin
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.OnQryCalcFields(DataSet: TDataSet);
-Var fld : TField;
-  raw : TRawBytes;
-  s : AnsiString;
-begin
-  fld := DataSet.FieldByName('datetime');
-  fld.AsDateTime :=  UnivDateTime2LocalDateTime(UnixToUnivDateTime( StrToIntDef( DataSet.FieldByName(CT_TblFld_Operations_s_timestamp).AsString, 0)));
-  fld := DataSet.FieldByName('op_account');
-  fld.AsString := TAccountComp.AccountNumberToAccountTxtNumber(DataSet.FieldByName(CT_TblFld_Operations_account).AsInteger);
-  fld := DataSet.FieldByName('payload_txt');
-  TDBStorage.DBStringFieldToRaw(DataSet.FieldByName(CT_TblFld_Operations_rawpayload),raw);
-  If TDBStorage.DBPayloadToReadableText(raw,s) then begin
-    fld.AsString := s;
-  end else begin
-    fld.AsString := TCrypto.ToHexaString(raw);
-  end;
-  //
-  fld := DataSet.FieldByName('amount');
-  TLargeintField(fld).Value := StrToInt64Def(Dataset.FieldByName(CT_TblFld_Operations_s_amount).AsString,0);
-  fld := DataSet.FieldByName('balance');
-  TLargeintField(fld).Value := StrToInt64Def(Dataset.FieldByName(CT_TblFld_Operations_s_balance).AsString,0);
-  fld := DataSet.FieldByName('fee');
-  TLargeintField(fld).Value := StrToInt64Def(Dataset.FieldByName(CT_TblFld_Operations_s_fee).AsString,0);
-
-  fld := DataSet.FieldByName('operation');
-          case dataset.FieldByName(CT_TblFld_Operations_optype).AsInteger of
-            0 : fld.AsString := 'Blockchain reward';
-            CT_Op_Transaction : begin
-              if dataset.FieldByName(CT_TblFld_Operations_optype_op).AsInteger=0 then begin
-                fld.AsString := 'Transaction Sent to '+TAccountComp.AccountNumberToAccountTxtNumber(dataset.FieldByName(CT_TblFld_Operations_other_account).AsLargeInt);
-              end else begin
-                fld.AsString := 'Transaction Received from '+TAccountComp.AccountNumberToAccountTxtNumber(dataset.FieldByName(CT_TblFld_Operations_other_account).AsLargeInt);
-              end;
-            end;
-            CT_Op_Changekey : Begin
-              fld.AsString := 'Change Key';
-            End;
-            CT_Op_Recover : begin
-              fld.AsString := 'Recover founds';
-            end;
-          else
-            fld.AsString := 'Unknown OpType:'+Inttostr(dataset.FieldByName(CT_TblFld_Operations_optype).AsInteger);
-          end;
-end;
-
-procedure TOperationsDBGrid.RefreshData;
-Var sql : AnsiString;
-begin
-  if FDisableds>0 then begin
-    FNeedRefreshSQL := true;
-    exit;
-  end;
-  FNeedRefreshSQL := false;
-  sql := TDBStorage.GetOperationsFromAccountSQL(AccountNumber,BlockStart,BlockEnd,DateStart,DateEnd, 0,50000);
-  If FQrySQL.Connection=Nil then exit;
-  if Node=Nil then exit;
-  if FDBGrid=Nil then exit;
-
-  FQrySQL.DisableControls;
-  try
-    FQrySQL.Close;
-    FQrySQL.SQL.Text := sql;
-    FQrySQL.Open;
-  finally
-    FQrySQL.EnableControls;
-  end;
-end;
-
-procedure TOperationsDBGrid.SetAccountNumber(const Value: Int64);
-begin
-  if FAccountNumber=Value then exit;
-  FAccountNumber := Value;
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.SetAdoConnection(const Value: TADOConnection);
-begin
-  FQrySQL.Connection := Value;
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.SetBlockEnd(const Value: Int64);
-begin
-  if FBlockEnd=Value then exit;
-  FBlockEnd := Value;
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.SetBlocks(bstart, bend: Int64);
-begin
-  FBlockStart := bstart;
-  FBlockEnd := bend;
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.SetBlockStart(const Value: Int64);
-begin
-  if FBlockStart=Value then exit;
-  FBlockStart := Value;
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.SetDateEnd(const Value: TDate);
-Var d,h,m,y : word;
-begin
-  if FDateEnd=Value then exit;
-  decodedate(value,y,m,d);
-  FDateEnd := EncodeDate(y,m,d);
-  if FDateStart>=FDateEnd then FDateStart := FDateEnd;
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.SetDates(dStart, dEnd: TDate);
-begin
-  Disable;
-  try
-    DateStart := dStart;
-    DateEnd := dEnd;
-  finally
-    Enable;
-  end;
-end;
-
-procedure TOperationsDBGrid.SetDateStart(const Value: TDate);
-Var d,h,m,y : word;
-begin
-  if FDateStart=Value then exit;
-  decodedate(value,y,m,d);
-  FDateStart := EncodeDate(y,m,d);
-  if FDateStart>=FDateEnd then FDateEnd := FDateStart;
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.SetDBGrid(const Value: TDBGrid);
-  Procedure AddColumn(fieldname,displayname : String; colwidth : integer);
-  Var c : TColumn;
-  begin
-    c := DBgrid.Columns.Add;
-    c.FieldName := fieldname;
-    c.Title.Caption := displayname;
-    c.Width := colwidth;
-    c.Title.Font.Style := [fsBold];
-    c.Title.Alignment := taCenter;
-  end;
-begin
-  if FDBGrid=Value then exit;
-  if Assigned(FDBGrid) then FDBGrid.DataSource := Nil;
-  FDBGrid := Value;
-  if Assigned(Value) then begin
-    Value.FreeNotification(self);
-    Value.DataSource := FDataSource;
-    Value.ReadOnly := true;
-    FDBGrid.OnDrawColumnCell := OnGridDrawColumnCell;
-    FDBGrid.DefaultDrawing := false;
-    FDBGrid.Columns.Clear;
-    AddColumn(CT_TblFld_Operations_block,'Block',50);
-    AddColumn('datetime','Date/Time',120);
-    AddColumn('op_account','Account',70);
-    AddColumn('operation','Operation',150);
-    AddColumn('amount','Amount',80);
-    AddColumn('fee','Fee',60);
-    AddColumn('balance','Balance',80);
-    AddColumn('payload_txt','Payload',280);
-    RefreshData;
-  end;
-end;
-
-procedure TOperationsDBGrid.SetNode(const Value: TNode);
-begin
-  FNodeNotifyEvents.Node:= value;
-  RefreshData;
-end;
-
-procedure TOperationsDBGrid.ShowModalDecoder(WalletKeys: TWalletKeys; AppParams: TAppParams);
-Var FRM : TFRMPayloadDecoder;
-  raw : TRawBytes;
-begin
-  if Not Assigned(FDBGrid) Or Not Assigned(FQrySQL) then exit;
-  If FQrySQL.Eof then exit;
-  FRM := TFRMPayloadDecoder.Create(FDBGrid.Owner);
-  try
-    TDBStorage.DBStringFieldToRaw(FQrySQL.FieldByName(CT_TblFld_Operations_rawpayload),raw);
-    FRM.Init(FQrySQL.FieldByName(CT_TblFld_Operations_block).AsInteger,
-      StrToIntDef( FQrySQL.FieldByName(CT_TblFld_Operations_s_timestamp).AsString,0),
-      FQrySQL.FieldByName('operation').AsString,
-      raw,WalletKeys,AppParams);
-    FRM.ShowModal;
-  finally
-    FRM.Free;
-  end;
-end;
-
-{ TBlockChainDBGrid }
-
-constructor TBlockChainDBGrid.Create(AOwner: TComponent);
-Var fld : TField;
-begin
-  inherited;
-  FNeedRefreshSQL := False;
-  FBlockStart := -1;
-  FBlockEnd := -1;
-  FDateEnd := 0;
-  FDateStart := 0;
-  FDisableds := 0;
-  FQrySQL := TADOQuery.Create(Self);
-  FQrySQL.OnCalcFields := OnQryCalcFields;
-  FqrySQL.CursorLocation := clUseClient;
-  FDBGrid := Nil;
-  FNodeNotifyEvents := TNodeNotifyEvents.Create(Self);
-  FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
-  FDataSource := TDataSource.Create(Self);
-  FDataSource.DataSet := FQrySQL;
-  fld := TIntegerField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_block;
-  fld.DataSet := FQrySQL;
-  fld.Visible := true;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_s_timestamp;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_s_reward;
-  fld.DataSet := FQrySQL;
-  fld.Visible := true;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_s_fee;
-  fld.DataSet := FQrySQL;
-  fld.Visible := true;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_s_compact_target;
-  fld.DataSet := FQrySQL;
-  fld.Visible := true;
-  fld := TIntegerField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_operations_count;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  fld := TDateTimeField.Create(FQrySQL);
-  fld.FieldName := 'datetime';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_proof_of_work;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  TStringField(fld).Size := 64;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_safe_box_hash;
-  fld.DataSet := FQrySQL;
-  fld.Visible := false;
-  TStringField(fld).Size := 64;
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := 'target';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-  TStringField(fld).Size := 8;
-
-  fld := TLargeintField.Create(FQrySQL);
-  fld.FieldName := 'reward';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-
-  fld := TLargeintField.Create(FQrySQL);
-  fld.FieldName := 'fee';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := CT_TblFld_BlockChain_rawpayload;
-  fld.DataSet := FQrySQL;
-  TStringField(fld).Size := 255;
-
-  fld := TStringField.Create(FQrySQL);
-  fld.FieldName := 'payload_decoded';
-  fld.Calculated := true;
-  fld.FieldKind := fkCalculated;
-  fld.DataSet := FQrySQL;
-  TStringField(fld).Size := 600;
-end;
-
-destructor TBlockChainDBGrid.Destroy;
-begin
-  SetDBGrid(Nil);
-  FNodeNotifyEvents.Free;
-  FDataSource.Free;
-  FQrySQL.Free;
-  inherited;
-end;
-
-procedure TBlockChainDBGrid.Disable;
-begin
-  Inc(FDisableds);
-end;
-
-procedure TBlockChainDBGrid.Enable;
-begin
-  if FDisableds<0 then exit;
-  Dec(FDisableds);
-  if FNeedRefreshSQL then RefreshData;
-end;
-
-function TBlockChainDBGrid.GetAdoConnection: TADOConnection;
-begin
-  Result := FQrySQL.Connection;
-end;
-
-function TBlockChainDBGrid.GetNode: TNode;
-begin
-  Result := FNodeNotifyEvents.Node;
-end;
-
-procedure TBlockChainDBGrid.Notification(AComponent: TComponent;
-  Operation: TOperation);
-begin
-  inherited;
-  if Operation=OpRemove then begin
-    if AComponent=FDBGrid then FDBGrid:=Nil;
-  end;
-end;
-
-procedure TBlockChainDBGrid.OnGridDrawColumnCell(Sender: TObject;
-  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
-Var c : TCanvas;
-  s : String;
-  r : TRect;
-begin
-  c := TDBGrid(Sender).Canvas;
-  r := Rect;
-  if (gdSelected in State) then
-    If (gdFocused in State) then c.Brush.Color := clGradientActiveCaption
-    else c.Brush.Color := clGradientInactiveCaption
-  else c.Brush.Color := clWindow;
-  c.FillRect(Rect);
-  if SameText(Column.FieldName,'reward') Or
-     SameText(Column.FieldName,'fee')
-      then begin
-    c.FillRect(Rect);
-    if Column.Field.AsLargeInt>0 then c.Font.Color := ClGreen
-    else if Column.Field.AsLargeInt=0 then c.Font.Color := clGrayText
-    else c.Font.Color := clRed;
-    s := TAccountComp.FormatMoney(Column.Field.AsLargeInt);
-    c.TextRect(r,s,[tfRight,tfVerticalCenter,tfSingleLine]);
-  end else begin
-    TDBGrid(Sender).DefaultDrawColumnCell(Rect,DataCol,Column,State);
-  end;
-
-  if (gdFixed in State) and ([dgRowLines, dgColLines] * TDBGrid(Sender).Options =  [dgRowLines, dgColLines]) and
-     not (gdPressed in State) then
-  begin
-    InflateRect(r, 1, 1);
-    DrawEdge(c.Handle, r, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
-    DrawEdge(c.Handle, r, BDR_RAISEDINNER, BF_TOPLEFT);
-  end;
-  //
-end;
-
-procedure TBlockChainDBGrid.OnNodeNewAccount(Sender: TObject);
-begin
-  RefreshData;
-end;
-
-procedure TBlockChainDBGrid.OnQryCalcFields(DataSet: TDataSet);
-Var fld : TField;
-  raw : TRawBytes;
-  s : AnsiString;
-begin
-  fld := DataSet.FieldByName('datetime');
-  fld.AsDateTime :=  UnivDateTime2LocalDateTime(UnixToUnivDateTime(StrToIntDef( DataSet.FieldByName(CT_TblFld_BlockChain_s_timestamp).AsString,0)));
-  fld := DataSet.FieldByName('target');
-  fld.AsString :=  IntToHex(StrToIntDef( DataSet.FieldByName(CT_TblFld_BlockChain_s_compact_target).AsString,0),8);
-  DataSet.FieldByName('reward').AsLargeInt := StrToIntDef(DataSet.FieldByName(CT_TblFld_BlockChain_s_reward).AsString,0);
-  DataSet.FieldByName('fee').AsLargeInt := StrToIntDef(DataSet.FieldByName(CT_TblFld_BlockChain_s_fee).AsString,0);
-  fld := DataSet.FieldByName('payload_decoded');
-  TDBStorage.DBStringFieldToRaw(DataSet.FieldByName(CT_TblFld_BlockChain_rawpayload),raw);
-  If TDBStorage.DBPayloadToReadableText(raw,s) then begin
-    fld.AsString := s;
-  end else begin
-    fld.AsString := TCrypto.ToHexaString(raw);
-  end;
-end;
-
-procedure TBlockChainDBGrid.RefreshData;
-Var sql : AnsiString;
-begin
-  if FDisableds>0 then begin
-    FNeedRefreshSQL := true;
-    exit;
-  end;
-  FNeedRefreshSQL := false;
-  sql := TDBStorage.GetBlockChainSQL(BlockStart,BlockEnd,DateStart,DateEnd, 0,300);
-  If FQrySQL.Connection=Nil then exit;
-  if Node=Nil then exit;
-  if FDBGrid=Nil then exit;
-
-  FQrySQL.DisableControls;
-  try
-    FQrySQL.Close;
-    FQrySQL.SQL.Text := sql;
-    FQrySQL.Open;
-  finally
-    FQrySQL.EnableControls;
-  end;
-end;
-
-procedure TBlockChainDBGrid.SetAdoConnection(const Value: TADOConnection);
-begin
-  FQrySQL.Connection := Value;
-  RefreshData;
-end;
-
-procedure TBlockChainDBGrid.SetBlockEnd(const Value: Int64);
-begin
-  if FBlockEnd=Value then exit;
-  FBlockEnd := Value;
-  RefreshData;
-end;
-
-procedure TBlockChainDBGrid.SetBlocks(bstart, bend: Int64);
-begin
-  disable;
-  Try
-    BlockStart := bstart;
-    BlockEnd := bEnd;
-  Finally
-    Enable;
-  End;
-end;
-
-procedure TBlockChainDBGrid.SetBlockStart(const Value: Int64);
-begin
-  if FBlockStart=Value then exit;
-  FBlockStart:=Value;
-  RefreshData;
-end;
-
-procedure TBlockChainDBGrid.SetDateEnd(const Value: TDate);
-begin
-  if FDateEnd=Value then exit;
-  FDateEnd := Value;
-  RefreshData;
-end;
-
-procedure TBlockChainDBGrid.SetDates(dStart, dEnd: TDate);
-begin
-  Disable;
-  Try
-    DateStart := dStart;
-    DateEnd := dEnd;
-  Finally
-    Enable;
-  End;
-end;
-
-procedure TBlockChainDBGrid.SetDateStart(const Value: TDate);
-begin
-  if FDateStart=Value then exit;
-  FDateStart := Value;
-  RefreshData;
-end;
-
-procedure TBlockChainDBGrid.SetDBGrid(const Value: TDBGrid);
-  Procedure AddColumn(fieldname,displayname : String; colwidth : integer);
-  Var c : TColumn;
-  begin
-    c := DBgrid.Columns.Add;
-    c.FieldName := fieldname;
-    c.Title.Caption := displayname;
-    c.Width := colwidth;
-    c.Title.Font.Style := [fsBold];
-    c.Title.Alignment := taCenter;
-  end;
-begin
-  if FDBGrid=Value then exit;
-  if Assigned(FDBGrid) then FDBGrid.DataSource := Nil;
-  FDBGrid := Value;
-  if Assigned(Value) then begin
-    Value.FreeNotification(self);
-    Value.DataSource := FDataSource;
-    Value.ReadOnly := true;
-    FDBGrid.OnDrawColumnCell := OnGridDrawColumnCell;
-    FDBGrid.DefaultDrawing := false;
-    FDBGrid.Columns.Clear;
-    AddColumn(CT_TblFld_BlockChain_block,'Block',60);
-    AddColumn('datetime','Date/Time',120);
-    AddColumn(CT_TblFld_BlockChain_operations_count,'Ops.',30);
-    AddColumn('reward','Reward',80);
-    AddColumn('fee','Fee',60);
-    AddColumn('target','Target',60);
-    AddColumn('payload_decoded','Miner Payload',150);
-    AddColumn(CT_TblFld_BlockChain_proof_of_work,'Proof of Work',400);
-    AddColumn(CT_TblFld_BlockChain_safe_box_hash,'Safe Box Hash',400);
-    RefreshData;
-  end;
-end;
-
-procedure TBlockChainDBGrid.SetNode(const Value: TNode);
-begin
-  FNodeNotifyEvents.Node := Value;
-  RefreshData;
-end;
-
 end.
 end.