Browse Source

Merge pull request #20 from PascalCoinDev/master

Upgrade to 5.2
Pascal Coin 5 years ago
parent
commit
a7049b41ea

+ 10 - 0
CHANGELOG.md

@@ -1,5 +1,15 @@
 # Changelog
 # Changelog
 
 
+## Build 5.2.0 (PENDING)
+- Fixed important bug caused by bad calculated "more work" blockchain
+  - Previous "more work" (introduced on build 1.5.0.0 2017-02-15) was calculated by SUM(compact_target), but compact_target is a linear value (not exponential)
+  - Current "more work" will be equals to "aggregated hashrate" that is SUM(CompactTargetToHashRate(compact_target)) where "hashrate" is exponential
+  - This important bug was found by Herman Schoenfeld ([email protected])
+- NAT limited to 7 seconds by default as proposed by Herman Schoenfeld ([email protected]) in order to minimize a warp timestamp attack. This value can be configured.
+- Fix invalid "balance" rounded decimals value caused by FPC (daemon or Linux versions)
+- Improvements on hashlib4pascal library by Ugochukwu Mmaduekwe <https://github.com/Xor-el>
+- Minor improvements and fixed bugs
+
 ## Build 5.1.0 - 2019-11-25
 ## Build 5.1.0 - 2019-11-25
 - Fixed FastPropagation bug when Operations are not on Mempool and needs to obtain from a node with different version (V4 vs V5)
 - Fixed FastPropagation bug when Operations are not on Mempool and needs to obtain from a node with different version (V4 vs V5)
 - Fixed TOpChangeAccountInfo bug when changing Account.Data (not available on V4, V5 must not propagate while on V4 protocol)
 - Fixed TOpChangeAccountInfo bug when changing Account.Data (not available on V4, V5 must not propagate while on V4 protocol)

+ 70 - 2
src/core/UAccounts.pas

@@ -289,6 +289,7 @@ Type
     FSafeBoxHash : TRawBytes;
     FSafeBoxHash : TRawBytes;
     FLock: TPCCriticalSection; // Thread safe
     FLock: TPCCriticalSection; // Thread safe
     FWorkSum : UInt64;
     FWorkSum : UInt64;
+    FAggregatedHashrate : TBigNum;
     FCurrentProtocol: Integer;
     FCurrentProtocol: Integer;
     // Snapshots utility new on V3
     // Snapshots utility new on V3
     FSnapshots : TList<Pointer>; // Will save a Snapshots lists in order to rollback Safebox to a previous block state
     FSnapshots : TList<Pointer>; // Will save a Snapshots lists in order to rollback Safebox to a previous block state
@@ -372,6 +373,9 @@ Type
     Function HasSnapshotForBlock(block_number : Cardinal) : Boolean;
     Function HasSnapshotForBlock(block_number : Cardinal) : Boolean;
     Property OrderedAccountKeysList : TOrderedAccountKeysList read FOrderedAccountKeysList;
     Property OrderedAccountKeysList : TOrderedAccountKeysList read FOrderedAccountKeysList;
     property BufferBlocksHash: TBytesBuffer32Safebox read FBufferBlocksHash; // Warning: For testing purposes, do not use this property! TODO delete or put in protected mode
     property BufferBlocksHash: TBytesBuffer32Safebox read FBufferBlocksHash; // Warning: For testing purposes, do not use this property! TODO delete or put in protected mode
+
+    Property AggregatedHashrate : TBigNum read FAggregatedHashrate;
+    procedure GetAggregatedHashrateOnBlock(ABlockNumber : Cardinal; const AAggregatedHashrate : TBigNum);
   End;
   End;
 
 
 
 
@@ -1547,8 +1551,11 @@ begin
 end;
 end;
 
 
 class function TAccountComp.FormatMoneyDecimal(Money : Int64) : Currency;
 class function TAccountComp.FormatMoneyDecimal(Money : Int64) : Currency;
+var Ltmp : Double;
 begin
 begin
-  Result := RoundTo( Money / 10000.0, -4);
+  Ltmp := Money;
+  Ltmp := Ltmp / 10000.0;
+  Result := RoundTo( Ltmp , -4);
 end;
 end;
 
 
 class function TAccountComp.GetECInfoTxt(const EC_OpenSSL_NID: Word): String;
 class function TAccountComp.GetECInfoTxt(const EC_OpenSSL_NID: Word): String;
@@ -2216,12 +2223,13 @@ Type
     oldTotalFee: Int64;
     oldTotalFee: Int64;
     oldSafeBoxHash : TRawBytes;
     oldSafeBoxHash : TRawBytes;
     oldWorkSum : UInt64;
     oldWorkSum : UInt64;
+    oldAggregatedHashrate : TBigNum;
     oldCurrentProtocol: Integer;
     oldCurrentProtocol: Integer;
   end;
   end;
   PSafeboxSnapshot = ^TSafeboxSnapshot;
   PSafeboxSnapshot = ^TSafeboxSnapshot;
 
 
 Const
 Const
-  CT_TSafeboxSnapshot_NUL : TSafeboxSnapshot = (nBlockNumber : 0; oldBlocks : Nil; newBlocks : Nil; namesDeleted : Nil; namesAdded : Nil;oldBufferBlocksHash:Nil;oldTotalBalance:0;oldTotalFee:0;oldSafeBoxHash:Nil;oldWorkSum:0;oldCurrentProtocol:0);
+  CT_TSafeboxSnapshot_NUL : TSafeboxSnapshot = (nBlockNumber : 0; oldBlocks : Nil; newBlocks : Nil; namesDeleted : Nil; namesAdded : Nil;oldBufferBlocksHash:Nil;oldTotalBalance:0;oldTotalFee:0;oldSafeBoxHash:Nil;oldWorkSum:0;oldAggregatedHashrate:Nil;oldCurrentProtocol:0);
 
 
 function TPCSafeBox.Account(account_number: Cardinal): TAccount;
 function TPCSafeBox.Account(account_number: Cardinal): TAccount;
 var
 var
@@ -2277,6 +2285,7 @@ var i, base_addr : Integer;
   //
   //
   acc_0_miner_reward,acc_4_dev_reward : Int64;
   acc_0_miner_reward,acc_4_dev_reward : Int64;
   acc_4_for_dev : Boolean;
   acc_4_for_dev : Boolean;
+  LBlockHashRate : TBigNum;
 begin
 begin
   Result := CT_BlockAccount_NUL;
   Result := CT_BlockAccount_NUL;
   Result.blockchainInfo := blockChain;
   Result.blockchainInfo := blockChain;
@@ -2325,6 +2334,13 @@ begin
   end;
   end;
   Inc(FWorkSum,Result.blockchainInfo.compact_target);
   Inc(FWorkSum,Result.blockchainInfo.compact_target);
   Result.AccumulatedWork := FWorkSum;
   Result.AccumulatedWork := FWorkSum;
+  // Add Aggregated Work based on HashRate
+  LBlockHashRate := TBigNum.TargetToHashRate( blockChain.compact_target );
+  Try
+    FAggregatedHashrate.Add( LBlockHashRate );
+  finally
+    LBlockHashRate.Free;
+  end;
   // Calc block hash
   // Calc block hash
   Result.block_hash := CalcBlockHash(Result,FCurrentProtocol);
   Result.block_hash := CalcBlockHash(Result,FCurrentProtocol);
   If Assigned(FPreviousSafeBox) then begin
   If Assigned(FPreviousSafeBox) then begin
@@ -2360,6 +2376,7 @@ begin
     Psnapshot^.oldTotalFee:=FTotalFee;
     Psnapshot^.oldTotalFee:=FTotalFee;
     Psnapshot^.oldSafeBoxHash := FSafeBoxHash;
     Psnapshot^.oldSafeBoxHash := FSafeBoxHash;
     Psnapshot^.oldWorkSum := FWorkSum;
     Psnapshot^.oldWorkSum := FWorkSum;
+    Psnapshot^.oldAggregatedHashrate := FAggregatedHashrate.Copy;
     Psnapshot^.oldCurrentProtocol:= FCurrentProtocol;
     Psnapshot^.oldCurrentProtocol:= FCurrentProtocol;
     FSnapshots.Add(Psnapshot);
     FSnapshots.Add(Psnapshot);
     FModifiedBlocksPreviousState := TOrderedBlockAccountList.Create;
     FModifiedBlocksPreviousState := TOrderedBlockAccountList.Create;
@@ -2378,6 +2395,7 @@ begin
         FreeAndNil( Psnapshot^.namesAdded );
         FreeAndNil( Psnapshot^.namesAdded );
         FreeAndNil( Psnapshot^.namesDeleted );
         FreeAndNil( Psnapshot^.namesDeleted );
         FreeAndNil( Psnapshot^.oldBufferBlocksHash );
         FreeAndNil( Psnapshot^.oldBufferBlocksHash );
+        FreeAndNil( Psnapshot^.oldAggregatedHashrate );
         Psnapshot^.oldSafeBoxHash := Nil;
         Psnapshot^.oldSafeBoxHash := Nil;
         Dispose(Psnapshot);
         Dispose(Psnapshot);
       end;
       end;
@@ -2675,6 +2693,7 @@ begin
       FreeAndNil(Psnapshot^.namesAdded);
       FreeAndNil(Psnapshot^.namesAdded);
       FreeAndNil(Psnapshot^.namesDeleted);
       FreeAndNil(Psnapshot^.namesDeleted);
       FreeAndNil(Psnapshot^.oldBufferBlocksHash);
       FreeAndNil(Psnapshot^.oldBufferBlocksHash);
+      FreeAndNil(Psnapshot^.oldAggregatedHashrate);
       Psnapshot^.oldSafeBoxHash := Nil;
       Psnapshot^.oldSafeBoxHash := Nil;
       Dispose(Psnapshot);
       Dispose(Psnapshot);
     end;
     end;
@@ -2689,6 +2708,7 @@ begin
     FTotalFee := 0;
     FTotalFee := 0;
     FSafeBoxHash := CalcSafeBoxHash;
     FSafeBoxHash := CalcSafeBoxHash;
     FWorkSum := 0;
     FWorkSum := 0;
+    FAggregatedHashrate.Value := 0;
     FCurrentProtocol := CT_PROTOCOL_1;
     FCurrentProtocol := CT_PROTOCOL_1;
     FModifiedBlocksSeparatedChain.Clear;
     FModifiedBlocksSeparatedChain.Clear;
     FModifiedBlocksFinalState.Clear;
     FModifiedBlocksFinalState.Clear;
@@ -2744,6 +2764,7 @@ begin
       FBufferBlocksHash.CopyFrom(accounts.FBufferBlocksHash);
       FBufferBlocksHash.CopyFrom(accounts.FBufferBlocksHash);
       FSafeBoxHash := Copy(accounts.FSafeBoxHash);
       FSafeBoxHash := Copy(accounts.FSafeBoxHash);
       FWorkSum := accounts.FWorkSum;
       FWorkSum := accounts.FWorkSum;
+      FAggregatedHashrate.RawValue := accounts.FAggregatedHashrate.RawValue;
       FCurrentProtocol := accounts.FCurrentProtocol;
       FCurrentProtocol := accounts.FCurrentProtocol;
     finally
     finally
       accounts.EndThreadSave;
       accounts.EndThreadSave;
@@ -2755,6 +2776,7 @@ end;
 
 
 constructor TPCSafeBox.Create;
 constructor TPCSafeBox.Create;
 begin
 begin
+  FAggregatedHashrate := TBigNum.Create(0);
   FMaxSafeboxSnapshots:=CT_DEFAULT_MaxSafeboxSnapshots;
   FMaxSafeboxSnapshots:=CT_DEFAULT_MaxSafeboxSnapshots;
   FLock := TPCCriticalSection.Create('TPCSafeBox_Lock');
   FLock := TPCCriticalSection.Create('TPCSafeBox_Lock');
   FBlockAccountsList := TList<Pointer>.Create;
   FBlockAccountsList := TList<Pointer>.Create;
@@ -2801,6 +2823,7 @@ begin
     FPreviousSafeboxOriginBlock:=-1;
     FPreviousSafeboxOriginBlock:=-1;
   end;
   end;
   FreeAndNil(FBufferBlocksHash);
   FreeAndNil(FBufferBlocksHash);
+  FreeAndNil(FAggregatedHashrate);
   inherited;
   inherited;
 end;
 end;
 
 
@@ -2837,6 +2860,7 @@ begin
         FTotalFee := Psnapshot^.oldTotalFee;
         FTotalFee := Psnapshot^.oldTotalFee;
         FSafeBoxHash := Psnapshot^.oldSafeBoxHash;
         FSafeBoxHash := Psnapshot^.oldSafeBoxHash;
         FWorkSum := Psnapshot^.oldWorkSum;
         FWorkSum := Psnapshot^.oldWorkSum;
+        FAggregatedHashrate.RawValue := Psnapshot^.oldAggregatedHashrate.RawValue;
         FCurrentProtocol := Psnapshot^.oldCurrentProtocol;
         FCurrentProtocol := Psnapshot^.oldCurrentProtocol;
       finally
       finally
         APreviousSafeBox.EndThreadSave;
         APreviousSafeBox.EndThreadSave;
@@ -2961,6 +2985,9 @@ begin
       If (FPreviousSafeBox.WorkSum<>FWorkSum) then begin
       If (FPreviousSafeBox.WorkSum<>FWorkSum) then begin
         errors := errors+'> Invalid WorkSum!';
         errors := errors+'> Invalid WorkSum!';
       end;
       end;
+      If (FPreviousSafeBox.FAggregatedHashrate.CompareTo(FAggregatedHashrate)<>0) then begin
+        errors := errors+'> Invalid Aggregated Hashrate!';
+      end;
       If (FPreviousSafeBox.FCurrentProtocol<>FCurrentProtocol) then begin
       If (FPreviousSafeBox.FCurrentProtocol<>FCurrentProtocol) then begin
         errors := errors+'> Invalid Protocol!';
         errors := errors+'> Invalid Protocol!';
       end;
       end;
@@ -3092,6 +3119,7 @@ begin
       Psnapshot^.namesAdded.Free;
       Psnapshot^.namesAdded.Free;
       Psnapshot^.namesDeleted.Free;
       Psnapshot^.namesDeleted.Free;
       Psnapshot^.oldBufferBlocksHash.Free;
       Psnapshot^.oldBufferBlocksHash.Free;
+      Psnapshot^.oldAggregatedHashrate.Free;
       Psnapshot^.oldSafeBoxHash := Nil;
       Psnapshot^.oldSafeBoxHash := Nil;
       Dispose(Psnapshot);
       Dispose(Psnapshot);
     end;
     end;
@@ -3106,6 +3134,7 @@ begin
     FTotalFee := Psnapshot^.oldTotalFee;
     FTotalFee := Psnapshot^.oldTotalFee;
     FSafeBoxHash := Psnapshot^.oldSafeBoxHash;
     FSafeBoxHash := Psnapshot^.oldSafeBoxHash;
     FWorkSum := Psnapshot^.oldWorkSum;
     FWorkSum := Psnapshot^.oldWorkSum;
+    FAggregatedHashrate.RawValue := Psnapshot^.oldAggregatedHashrate.RawValue;
     FCurrentProtocol := Psnapshot^.oldCurrentProtocol;
     FCurrentProtocol := Psnapshot^.oldCurrentProtocol;
     // Clear data
     // Clear data
     FAddedNamesSincePreviousSafebox.Clear;
     FAddedNamesSincePreviousSafebox.Clear;
@@ -3217,6 +3246,7 @@ Var
   LUseMultiThreadOperationsBlockValidator, LAddToMultiThreadOperationsBlockValidator : Boolean;
   LUseMultiThreadOperationsBlockValidator, LAddToMultiThreadOperationsBlockValidator : Boolean;
   LPCOperationsBlockValidator : TPCOperationsBlockValidator;
   LPCOperationsBlockValidator : TPCOperationsBlockValidator;
   LValidatedOPOk, LValidatedOPError, LValidatedOPPending : Integer;
   LValidatedOPOk, LValidatedOPError, LValidatedOPPending : Integer;
+  LBlockHashRate : TBigNum;
 begin
 begin
   LPCOperationsBlockValidator := Nil;
   LPCOperationsBlockValidator := Nil;
   if checkAll then begin
   if checkAll then begin
@@ -3410,6 +3440,12 @@ begin
         FBufferBlocksHash.Replace( j, P^.block_hash[0], 32 );
         FBufferBlocksHash.Replace( j, P^.block_hash[0], 32 );
         ALastReadBlock := LBlock;
         ALastReadBlock := LBlock;
         Inc(FWorkSum,LBlock.blockchainInfo.compact_target);
         Inc(FWorkSum,LBlock.blockchainInfo.compact_target);
+        LBlockHashRate := TBigNum.TargetToHashRate( LBlock.blockchainInfo.compact_target );
+        Try
+          FAggregatedHashrate.Add( LBlockHashRate );
+        finally
+          LBlockHashRate.Free;
+        end;
         // Upgrade to Protocol 4,5... step:
         // Upgrade to Protocol 4,5... step:
         if (LBlock.blockchainInfo.protocol_version>FCurrentProtocol) then begin
         if (LBlock.blockchainInfo.protocol_version>FCurrentProtocol) then begin
           if (LBlock.blockchainInfo.protocol_version = CT_PROTOCOL_4) then begin
           if (LBlock.blockchainInfo.protocol_version = CT_PROTOCOL_4) then begin
@@ -4148,6 +4184,38 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TPCSafeBox.GetAggregatedHashrateOnBlock(ABlockNumber: Cardinal; const AAggregatedHashrate: TBigNum);
+var i : Integer;
+  LHashRate : TBigNum;
+begin
+  AAggregatedHashrate.Value := 0; // Set to zero
+  if ABlockNumber>=BlocksCount then raise Exception.Create(Format('BlockNumber %d out of range (%d / %d)',[ABlockNumber,0,BlocksCount]));
+
+  if (BlocksCount DIV 2) < ABlockNumber then begin
+    // decrease mode
+    AAggregatedHashrate.RawValue := FAggregatedHashrate.RawValue;
+    for i := Integer(BlocksCount)-1 downto (ABlockNumber+1) do begin
+      LHashRate := TBigNum.TargetToHashRate( GetBlockInfo(i).compact_target );
+      try
+        AAggregatedHashrate.Sub( LHashRate );
+      finally
+        LHashRate.Free;
+      end;
+    end;
+  end else begin
+    // Increase mode
+    for i := 0 to ABlockNumber do begin
+      LHashRate := TBigNum.TargetToHashRate( GetBlockInfo(i).compact_target );
+      try
+        AAggregatedHashrate.Add( LHashRate );
+      finally
+        LHashRate.Free;
+      end;
+    end;
+  end;
+
+end;
+
 function TPCSafeBox.GetBlockInfo(ABlockNumber: Cardinal): TOperationBlock;
 function TPCSafeBox.GetBlockInfo(ABlockNumber: Cardinal): TOperationBlock;
 begin
 begin
   Result := GetBlock(ABlockNumber).blockchainInfo;
   Result := GetBlock(ABlockNumber).blockchainInfo;

+ 55 - 5
src/core/UBlockChain.pas

@@ -548,6 +548,7 @@ Type
     procedure AssignTo(Dest: TPersistent); Override;
     procedure AssignTo(Dest: TPersistent); Override;
     function GetActualTargetSecondsAverage(BackBlocks : Cardinal): Real;
     function GetActualTargetSecondsAverage(BackBlocks : Cardinal): Real;
     function GetTargetSecondsAverage(FromBlock,BackBlocks : Cardinal): Real;
     function GetTargetSecondsAverage(FromBlock,BackBlocks : Cardinal): Real;
+    function GetTargetSecondsMedian(AFromBlock: Cardinal; ABackBlocks : Integer): Real;
     function LoadBankFromStream(Stream : TStream; useSecureLoad : Boolean; checkSafeboxHash : TRawBytes; previousCheckedSafebox : TPCSafebox; progressNotify : TProgressNotify; var errors : String) : Boolean;
     function LoadBankFromStream(Stream : TStream; useSecureLoad : Boolean; checkSafeboxHash : TRawBytes; previousCheckedSafebox : TPCSafebox; progressNotify : TProgressNotify; var errors : String) : Boolean;
     Procedure Clear;
     Procedure Clear;
     Function LoadOperations(Operations : TPCOperationsComp; Block : Cardinal) : Boolean;
     Function LoadOperations(Operations : TPCOperationsComp; Block : Cardinal) : Boolean;
@@ -1090,17 +1091,17 @@ end;
 function TPCBank.GetTargetSecondsAverage(FromBlock, BackBlocks: Cardinal): Real;
 function TPCBank.GetTargetSecondsAverage(FromBlock, BackBlocks: Cardinal): Real;
 Var ts1, ts2: Int64;
 Var ts1, ts2: Int64;
 begin
 begin
-  If FromBlock>=BlocksCount then begin
+  If (FromBlock>=BlocksCount) or (BackBlocks<1) then begin
     Result := 0;
     Result := 0;
     exit;
     exit;
   end;
   end;
   if FromBlock>BackBlocks then begin
   if FromBlock>BackBlocks then begin
-    ts1 := SafeBox.GetBlockInfo(FromBlock-1).timestamp;
-    ts2 := SafeBox.GetBlockInfo(FromBlock-BackBlocks-1).timestamp;
+    ts1 := SafeBox.GetBlockInfo(FromBlock).timestamp;
+    ts2 := SafeBox.GetBlockInfo(FromBlock-BackBlocks).timestamp;
   end else if (FromBlock>1) then begin
   end else if (FromBlock>1) then begin
-    ts1 := SafeBox.GetBlockInfo(FromBlock-1).timestamp;
+    ts1 := SafeBox.GetBlockInfo(FromBlock).timestamp;
     ts2 := SafeBox.GetBlockInfo(0).timestamp;
     ts2 := SafeBox.GetBlockInfo(0).timestamp;
-    BackBlocks := FromBlock-1;
+    BackBlocks := FromBlock;
   end else begin
   end else begin
     Result := 0;
     Result := 0;
     exit;
     exit;
@@ -1108,6 +1109,55 @@ begin
   Result := (ts1 - ts2) / BackBlocks;
   Result := (ts1 - ts2) / BackBlocks;
 end;
 end;
 
 
+function TPCBank.GetTargetSecondsMedian(AFromBlock: Cardinal; ABackBlocks : Integer): Real;
+Var LOrd : TOrderedCardinalList;
+  i, LStart, LEnd : Integer;
+  LPreviousTimestamp, LCurrentTimestamp, c1, c2 : Cardinal;
+begin
+  { Will return median time based on each block time
+    AFromBlock = 50
+    ABackBlocks = 5
+
+    Will take 6 blocks (ABackBlocks + 1)  from 45 to 50
+
+    time_diff_46 = 46 - 45
+    time_diff_47 = 47 - 46
+    time_diff_48 = 48 - 47
+    time_diff_49 = 49 - 48
+    time_diff_50 = 50 - 49
+  }
+  Result := 0;
+  If (AFromBlock>=BlocksCount) or (ABackBlocks<=0) then begin
+    exit;
+  end;
+  LOrd := TOrderedCardinalList.Create;
+  try
+    LStart := Integer(AFromBlock) - Integer(ABackBlocks);
+    LEnd := Integer(AFromBlock);
+    if LStart<1 then LStart := 1; // Ensure we will get access to 0 as a previous Timestamp
+    LPreviousTimestamp := SafeBox.GetBlockInfo(LStart - 1).timestamp; // Get first previous timestamp
+    for i := LStart to LEnd do begin
+      LCurrentTimestamp := SafeBox.GetBlockInfo(i).timestamp;
+      LOrd.Add( LCurrentTimestamp - LPreviousTimestamp ); // Add to ordered list
+      LPreviousTimestamp := LCurrentTimestamp;
+    end;
+    // Capture median in an ordered list
+    if LOrd.Count>0 then begin
+      if (LOrd.Count MOD 2)=0 then begin
+        // even list, take 2 values
+        c1 := LOrd.Get( (LOrd.Count DIV 2)-1 );
+        c2 := LOrd.Get( (LOrd.Count DIV 2) );
+        Result := (c1 + c2) / 2.0;
+      end else begin
+        // odd list, take middle
+        Result := LOrd.Get( LOrd.Count DIV 2) / 1.0;
+      end
+    end;
+  finally
+    LOrd.Free;
+  end;
+end;
+
 function TPCBank.GetStorage: TStorage;
 function TPCBank.GetStorage: TStorage;
 begin
 begin
   if Not Assigned(FStorage) then begin
   if Not Assigned(FStorage) then begin

+ 3 - 3
src/core/UConst.pas

@@ -129,10 +129,10 @@ Const
 
 
   CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}$05000004{$ENDIF};
   CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}$05000004{$ENDIF};
 
 
-  CT_NetProtocol_Version: Word = 9; // TODO Need to upgrade to 10 after V5 Hardfork
+  CT_NetProtocol_Version: Word = 10;
   // IMPORTANT NOTE!!!
   // IMPORTANT NOTE!!!
   // NetProtocol_Available MUST BE always >= NetProtocol_version
   // NetProtocol_Available MUST BE always >= NetProtocol_version
-  CT_NetProtocol_Available: Word = {$IFDEF PRODUCTION}11{$ELSE}11{$ENDIF};
+  CT_NetProtocol_Available: Word = {$IFDEF PRODUCTION}12{$ELSE}12{$ENDIF};
 
 
   CT_MaxAccountOperationsPerBlockWithoutFee = 1;
   CT_MaxAccountOperationsPerBlockWithoutFee = 1;
 
 
@@ -195,7 +195,7 @@ Const
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Receiver              = 104;
   CT_OpSubtype_Data_Receiver              = 104;
 
 
-  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.1'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.1'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.2'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.2'{$ELSE}{$ENDIF}{$ENDIF};
 
 
   CT_Discover_IPs = {$IFDEF PRODUCTION}'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.dynamic-dns.net;pascalcoin2.dynamic-dns.net;pascalcoin1.dns1.us;pascalcoin2.dns1.us;pascalcoin1.dns2.us;pascalcoin2.dns2.us'
   CT_Discover_IPs = {$IFDEF PRODUCTION}'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.dynamic-dns.net;pascalcoin2.dynamic-dns.net;pascalcoin1.dns1.us;pascalcoin2.dns1.us;pascalcoin1.dns2.us;pascalcoin2.dns2.us'
                     {$ELSE}'pascaltestnet1.dynamic-dns.net;pascaltestnet2.dynamic-dns.net;pascaltestnet1.dns1.us;pascaltestnet2.dns1.us'{$ENDIF};
                     {$ELSE}'pascaltestnet1.dynamic-dns.net;pascaltestnet2.dynamic-dns.net;pascaltestnet1.dns1.us;pascaltestnet2.dns1.us'{$ENDIF};

+ 13 - 1
src/core/UCrypto.pas

@@ -134,7 +134,8 @@ Type
     Function Multiply(int : Int64) : TBigNum; overload;
     Function Multiply(int : Int64) : TBigNum; overload;
     Function LShift(nbits : Integer) : TBigNum;
     Function LShift(nbits : Integer) : TBigNum;
     Function RShift(nbits : Integer) : TBigNum;
     Function RShift(nbits : Integer) : TBigNum;
-    Function CompareTo(BN : TBigNum) : Integer;
+    Function CompareTo(BN : TBigNum) : Integer; overload;
+    Function CompareTo(int : Int64) : Integer; overload;
     Function Divide(BN : TBigNum) : TBigNum; overload;
     Function Divide(BN : TBigNum) : TBigNum; overload;
     Function Divide(int : Int64) : TBigNum; overload;
     Function Divide(int : Int64) : TBigNum; overload;
     Procedure Divide(dividend, remainder : TBigNum); overload;
     Procedure Divide(dividend, remainder : TBigNum); overload;
@@ -863,6 +864,17 @@ begin
   {$ENDIF}
   {$ENDIF}
 end;
 end;
 
 
+function TBigNum.CompareTo(int: Int64): Integer;
+var LBigNum : TBigNum;
+begin
+  LBigNum := TBigNum.Create(int);
+  try
+    Result := CompareTo( LBigNum );
+  finally
+    LBigNum.Free;
+  end;
+end;
+
 function TBigNum.Copy: TBigNum;
 function TBigNum.Copy: TBigNum;
 begin
 begin
   Result := TBigNum.Create(0);
   Result := TBigNum.Create(0);

+ 108 - 47
src/core/UNetProtocol.pas

@@ -80,6 +80,8 @@ Const
   CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS = 10000;
   CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS = 10000;
   CT_MAX_SAFEBOXCHUNK_BLOCKS = 30000;
   CT_MAX_SAFEBOXCHUNK_BLOCKS = 30000;
 
 
+  CT_MIN_NetProtocol_Use_Aggregated_Hashrate = 12;
+
 Type
 Type
   {
   {
   Net Protocol:
   Net Protocol:
@@ -234,8 +236,11 @@ Type
     Constructor Create(NetData : TNetData);
     Constructor Create(NetData : TNetData);
   End;
   End;
 
 
+  { TNetworkAdjustedTime }
+
   TNetworkAdjustedTime = Class
   TNetworkAdjustedTime = Class
   private
   private
+    FOffsetLimit: Integer;
     FTimesList : TPCThreadList<Pointer>;
     FTimesList : TPCThreadList<Pointer>;
     FTimeOffset : Integer;
     FTimeOffset : Integer;
     FTotalCounter : Integer;
     FTotalCounter : Integer;
@@ -250,6 +255,7 @@ Type
     function GetAdjustedTime : Cardinal;
     function GetAdjustedTime : Cardinal;
     property TimeOffset : Integer read FTimeOffset;
     property TimeOffset : Integer read FTimeOffset;
     function GetMaxAllowedTimestampForNewBlock : Cardinal;
     function GetMaxAllowedTimestampForNewBlock : Cardinal;
+    property OffsetLimit : Integer read FOffsetLimit write FOffsetLimit;
   end;
   end;
 
 
   TProcessReservedAreaMessage = procedure (netData : TNetData; senderConnection : TNetConnection; const HeaderData : TNetHeaderData; receivedData : TStream; responseData : TStream) of object;
   TProcessReservedAreaMessage = procedure (netData : TNetData; senderConnection : TNetConnection; const HeaderData : TNetHeaderData; receivedData : TStream; responseData : TStream) of object;
@@ -369,6 +375,7 @@ Type
     FTcpIpClient : TNetTcpIpClient;
     FTcpIpClient : TNetTcpIpClient;
     FRemoteOperationBlock : TOperationBlock;
     FRemoteOperationBlock : TOperationBlock;
     FRemoteAccumulatedWork : UInt64;
     FRemoteAccumulatedWork : UInt64;
+    FRemoteAggregatedHashrate : TBigNum;
     FLastHelloTS : TTickCount;
     FLastHelloTS : TTickCount;
     FLastDataReceivedTS : TTickCount;
     FLastDataReceivedTS : TTickCount;
     FLastDataSendedTS : TTickCount;
     FLastDataSendedTS : TTickCount;
@@ -1647,6 +1654,7 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
         BlocksList := TList<TPCOperationsComp>.Create;
         BlocksList := TList<TPCOperationsComp>.Create;
         try
         try
           finished := NOT Do_GetOperationsBlock(Bank,start,start + 100,30000,false,BlocksList);
           finished := NOT Do_GetOperationsBlock(Bank,start,start + 100,30000,false,BlocksList);
+          finished := (finished) or (BlocksList.Count<=0);
           i := 0;
           i := 0;
           while (i<BlocksList.Count) And (Not finished) do begin
           while (i<BlocksList.Count) And (Not finished) do begin
             OpComp := TPCOperationsComp(BlocksList[i]);
             OpComp := TPCOperationsComp(BlocksList[i]);
@@ -1682,15 +1690,10 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
           BlocksList.Free;
           BlocksList.Free;
         end;
         end;
         start := Bank.BlocksCount;
         start := Bank.BlocksCount;
-      until (Bank.BlocksCount=Connection.FRemoteOperationBlock.block+1) Or (finished)
-        // Allow to do not download ALL new blockchain in a separate folder, only needed blocks!
-        Or (Bank.SafeBox.WorkSum > (TNode.Node.Bank.SafeBox.WorkSum + $FFFFFFFF) );
-      // New Build 1.5 more work vs more high
-      // work = SUM(target) of all previous blocks (Int64)
-      // -----------------------------
-      // Before of version 1.5 was: "if Bank.BlocksCount>TNode.Node.Bank.BlocksCount then ..."
-      // Starting on version 1.5 is: "if Bank.WORK > MyBank.WORK then ..."
-      if Bank.SafeBox.WorkSum > TNode.Node.Bank.SafeBox.WorkSum then begin
+      until (Bank.BlocksCount>=Connection.FRemoteOperationBlock.block+1) Or (finished);
+      // New Build 5.2 more aggregated hashrate
+      // More work equals to SUM( Hashrate ) of all previous blocks > my SUM( Hashsrate )
+      if Bank.SafeBox.AggregatedHashrate.CompareTo( TNode.Node.Bank.SafeBox.AggregatedHashrate ) > 0 then begin
         oldBlockchainOperations := TOperationsHashTree.Create;
         oldBlockchainOperations := TOperationsHashTree.Create;
         try
         try
           TNode.Node.DisableNewBlocks;
           TNode.Node.DisableNewBlocks;
@@ -1759,12 +1762,26 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
         finally
         finally
           oldBlockchainOperations.Free;
           oldBlockchainOperations.Free;
         end;
         end;
-      end else begin
-        if (Not IsAScam) And (Connection.FRemoteAccumulatedWork > TNode.Node.Bank.SafeBox.WorkSum) then begin
-          // Possible scammer!
+      end else if (Not IsAScam) then begin // If it was as Scam, then was disconnected previously
+        if (Connection.FRemoteAccumulatedWork > Bank.SafeBox.WorkSum) then begin
+          // Possible scammer because obtained is lower than claimed!
           Connection.DisconnectInvalidClient(false,Format('Possible scammer! Says blocks:%d Work:%d - Obtained blocks:%d work:%d',
           Connection.DisconnectInvalidClient(false,Format('Possible scammer! Says blocks:%d Work:%d - Obtained blocks:%d work:%d',
             [Connection.FRemoteOperationBlock.block+1,Connection.FRemoteAccumulatedWork,
             [Connection.FRemoteOperationBlock.block+1,Connection.FRemoteAccumulatedWork,
              Bank.BlocksCount,Bank.SafeBox.WorkSum]));
              Bank.BlocksCount,Bank.SafeBox.WorkSum]));
+        end else if (Connection.FRemoteAggregatedHashrate.CompareTo( Bank.SafeBox.AggregatedHashrate )>0) then begin
+          // Possible scammer because obtained Hashrate is lower than claimed!
+          Connection.DisconnectInvalidClient(false,Format('Possible scammer! Says blocks:%d Aggregated HashRate:%s - Obtained blocks:%d HashRate:%s',
+            [Connection.FRemoteOperationBlock.block+1,Connection.FRemoteAggregatedHashrate.ToDecimal,
+             Bank.BlocksCount,Bank.SafeBox.AggregatedHashrate.ToDecimal]));
+        end else begin
+          TLog.NewLog(ltinfo,CT_LogSender, Format('Nothing made! Says blocks:%d Aggregated HashRate:%s - Obtained blocks:%d HashRate:%s Current blocks:%d HashRate:%s',
+            [Connection.FRemoteOperationBlock.block+1,
+             Connection.FRemoteAggregatedHashrate.ToDecimal,
+             Bank.BlocksCount,Bank.SafeBox.AggregatedHashrate.ToDecimal,
+             TNode.Node.Bank.SafeBox.BlocksCount,
+             TNode.Node.Bank.SafeBox.AggregatedHashrate.ToDecimal
+             ]));
+
         end;
         end;
       end;
       end;
     finally
     finally
@@ -2521,6 +2538,7 @@ end;
 constructor TNetConnection.Create(AOwner: TComponent);
 constructor TNetConnection.Create(AOwner: TComponent);
 begin
 begin
   inherited;
   inherited;
+  FRemoteAggregatedHashrate := TBigNum.Create;
   FIsConnecting:=False;
   FIsConnecting:=False;
   FIsDownloadingBlocks := false;
   FIsDownloadingBlocks := false;
   FHasReceivedData := false;
   FHasReceivedData := false;
@@ -2571,6 +2589,7 @@ begin
     FreeAndNil(FBufferLock);
     FreeAndNil(FBufferLock);
     FreeAndNil(FBufferReceivedOperationsHash);
     FreeAndNil(FBufferReceivedOperationsHash);
     FreeAndNil(FBufferToSendOperations);
     FreeAndNil(FBufferToSendOperations);
+    FreeAndNil(FRemoteAggregatedHashrate);
     inherited;
     inherited;
   End;
   End;
 end;
 end;
@@ -3504,6 +3523,7 @@ var op, myLastOp : TPCOperationsComp;
     connection_ts : Cardinal;
     connection_ts : Cardinal;
    Duplicate : TNetConnection;
    Duplicate : TNetConnection;
    RawAccountKey : TRawBytes;
    RawAccountKey : TRawBytes;
+   LRawAggregatedHashrate : TRawBytes;
    other_version : String;
    other_version : String;
    isFirstHello : Boolean;
    isFirstHello : Boolean;
    lastTimestampDiff : Integer;
    lastTimestampDiff : Integer;
@@ -3578,12 +3598,21 @@ Begin
           ClientAppVersion := other_version;
           ClientAppVersion := other_version;
           if (DataBuffer.Size-DataBuffer.Position>=SizeOf(FRemoteAccumulatedWork)) then begin
           if (DataBuffer.Size-DataBuffer.Position>=SizeOf(FRemoteAccumulatedWork)) then begin
             DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
             DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
-            TLog.NewLog(ltdebug,ClassName,'Received HELLO with height: '+inttostr(op.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork)+ ' Remote block: '+TPCOperationsComp.OperationBlockToText(FRemoteOperationBlock));
           end;
           end;
         end;
         end;
-        //
+        if HeaderData.protocol.protocol_available>=CT_MIN_NetProtocol_Use_Aggregated_Hashrate then begin
+          // Read Aggregated Hashrate value
+          if TStreamOp.ReadAnsiString(DataBuffer,LRawAggregatedHashrate)>=0 then begin
+            FRemoteAggregatedHashrate.RawValue := LRawAggregatedHashrate;
+            FRemoteAccumulatedWork := 0;
+          end;
+        end;
+        TLog.NewLog(ltdebug,ClassName,'Received HELLO with height: '+inttostr(op.OperationBlock.block)+' Accumulated work|hashrate '+IntToStr(FRemoteAccumulatedWork)+'|'+FRemoteAggregatedHashrate.ToDecimal+' Remote block: '+TPCOperationsComp.OperationBlockToText(FRemoteOperationBlock));
+        // Detect if is a higher work blockchain
         if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) Or
         if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) Or
-          ((FRemoteAccumulatedWork=0) And (TNetData.NetData.FMaxRemoteOperationBlock.block<FRemoteOperationBlock.block)) then begin
+          ((FRemoteAccumulatedWork=0) And (TNetData.NetData.FMaxRemoteOperationBlock.block<FRemoteOperationBlock.block)) Or
+          ((FRemoteAggregatedHashrate.CompareTo(TNode.Node.Bank.SafeBox.AggregatedHashrate)>0))
+          then begin
           TNetData.NetData.FMaxRemoteOperationBlock := FRemoteOperationBlock;
           TNetData.NetData.FMaxRemoteOperationBlock := FRemoteOperationBlock;
           if TPCThread.ThreadClassFound(TThreadGetNewBlockChainFromClient,nil)<0 then begin
           if TPCThread.ThreadClassFound(TThreadGetNewBlockChainFromClient,nil)<0 then begin
             TThreadGetNewBlockChainFromClient.Create;
             TThreadGetNewBlockChainFromClient.Create;
@@ -3831,6 +3860,7 @@ var operationsComp : TPCOperationsComp;
     Result := True;
     Result := True;
   end;
   end;
 var c : Cardinal;
 var c : Cardinal;
+  LRawAggregatedHashrate : TRawBytes;
 begin
 begin
   errors := '';
   errors := '';
   DoDisconnect := true;
   DoDisconnect := true;
@@ -3847,14 +3877,24 @@ begin
         exit;
         exit;
       end else begin
       end else begin
         DoDisconnect := false;
         DoDisconnect := false;
-        DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
+        if AHeaderData.protocol.protocol_available>=CT_MIN_NetProtocol_Use_Aggregated_Hashrate then begin
+          TStreamOp.ReadAnsiString(DataBuffer,LRawAggregatedHashrate);
+          FRemoteAggregatedHashrate.RawValue := LRawAggregatedHashrate;
+          FRemoteAccumulatedWork := 0; // No needed
+        end else begin
+          DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
+          FRemoteAggregatedHashrate.Value:=0;
+        end;
         if operationsComp.IsOnlyOperationBlock then begin
         if operationsComp.IsOnlyOperationBlock then begin
-          TLog.NewLog(ltdebug,ClassName,'Received NEW FAST PROPAGATION BLOCK with height: '+inttostr(operationsComp.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork)+' from '+ClientRemoteAddr);
+          TLog.NewLog(ltdebug,ClassName,'Received NEW FAST PROPAGATION BLOCK with height: '+inttostr(operationsComp.OperationBlock.block)+' Accumulated values '+IntToStr(FRemoteAccumulatedWork)+' '+FRemoteAggregatedHashrate.ToDecimal+' from '+ClientRemoteAddr);
         end else begin
         end else begin
-          TLog.NewLog(ltdebug,ClassName,'Received NEW BLOCK with height: '+inttostr(operationsComp.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork)+' from '+ClientRemoteAddr);
+          TLog.NewLog(ltdebug,ClassName,'Received NEW BLOCK with height: '+inttostr(operationsComp.OperationBlock.block)+' Accumulated values '+IntToStr(FRemoteAccumulatedWork)+' '+FRemoteAggregatedHashrate.ToDecimal+' from '+ClientRemoteAddr);
         end;
         end;
         FRemoteOperationBlock := operationsComp.OperationBlock;
         FRemoteOperationBlock := operationsComp.OperationBlock;
-        if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
+        if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum)
+           or
+           (FRemoteAggregatedHashrate.CompareTo( TNode.Node.Bank.SafeBox.AggregatedHashrate ) > 0)
+          then begin
           if (operationsComp.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
           if (operationsComp.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
             // New block candidate:
             // New block candidate:
             if (operationsComp.IsOnlyOperationBlock) then begin
             if (operationsComp.IsOnlyOperationBlock) then begin
@@ -4409,6 +4449,8 @@ var data : TStream;
   nsarr : TNodeServerAddressArray;
   nsarr : TNodeServerAddressArray;
   w : Word;
   w : Word;
   currunixtimestamp : Cardinal;
   currunixtimestamp : Cardinal;
+  LRawAggregatedHashrate : TRawBytes;
+  LUInt64 : UInt64;
 begin
 begin
   Result := false;
   Result := false;
   if Not Connected then exit;
   if Not Connected then exit;
@@ -4441,9 +4483,17 @@ begin
     end;
     end;
     // Send client version
     // Send client version
     TStreamOp.WriteAnsiString(data,TEncoding.ASCII.GetBytes(TNode.NodeVersion));
     TStreamOp.WriteAnsiString(data,TEncoding.ASCII.GetBytes(TNode.NodeVersion));
-    // Build 1.5 send accumulated work
-    data.Write(TNode.Node.Bank.SafeBox.WorkSum,SizeOf(TNode.Node.Bank.SafeBox.WorkSum));
-    //
+    // Send Aggregated Hashsrate based on network protocol available version
+    if FNetProtocolVersion.protocol_available>=CT_MIN_NetProtocol_Use_Aggregated_Hashrate then begin
+      LUInt64:=0;
+      data.Write(LUInt64,SizeOf(LUInt64));
+      LRawAggregatedHashrate := TNode.Node.Bank.SafeBox.AggregatedHashrate.RawValue;
+      TStreamOp.WriteAnsiString(data,LRawAggregatedHashrate);
+    end else begin
+      // If version older than 5.2 then send previous WorkSum value instead of AggregatedHashate
+      data.Write(TNode.Node.Bank.SafeBox.WorkSum,SizeOf(TNode.Node.Bank.SafeBox.WorkSum));
+    end;
+
     Send(NetTranferType,CT_NetOp_Hello,0,request_id,data);
     Send(NetTranferType,CT_NetOp_Hello,0,request_id,data);
     Result := Client.Connected;
     Result := Client.Connected;
     FLastHelloTS := TPlatform.GetTickCount;
     FLastHelloTS := TPlatform.GetTickCount;
@@ -4477,6 +4527,7 @@ var data : TStream;
   c : Cardinal;
   c : Cardinal;
   i : Integer;
   i : Integer;
   opRef : TOpReference;
   opRef : TOpReference;
+  LRawAggregatedHashrate : TRawBytes;
 begin
 begin
   Result := false;
   Result := false;
   if Not Connected then exit;
   if Not Connected then exit;
@@ -4505,7 +4556,14 @@ begin
       // Will send a FAST PROPAGATION BLOCK as described at PIP-0015
       // Will send a FAST PROPAGATION BLOCK as described at PIP-0015
       netOp := CT_NetOp_NewBlock_Fast_Propagation;
       netOp := CT_NetOp_NewBlock_Fast_Propagation;
       NewBlock.SaveBlockToStream(netOp = CT_NetOp_NewBlock_Fast_Propagation,data); // Will save all only if not FAST PROPAGATION
       NewBlock.SaveBlockToStream(netOp = CT_NetOp_NewBlock_Fast_Propagation,data); // Will save all only if not FAST PROPAGATION
-      data.Write(TNode.Node.Bank.SafeBox.WorkSum,SizeOf(TNode.Node.Bank.SafeBox.WorkSum));
+      // Send Aggregated Hashsrate based on network protocol available version
+      if FNetProtocolVersion.protocol_available>=CT_MIN_NetProtocol_Use_Aggregated_Hashrate then begin
+        LRawAggregatedHashrate := TNode.Node.Bank.SafeBox.AggregatedHashrate.RawValue;
+        TStreamOp.WriteAnsiString(data,LRawAggregatedHashrate);
+      end else begin
+        // If version older than 5.2 then send previous WorkSum value instead of AggregatedHashate
+        data.Write(TNode.Node.Bank.SafeBox.WorkSum,SizeOf(TNode.Node.Bank.SafeBox.WorkSum));
+      end;
       if (netOp = CT_NetOp_NewBlock_Fast_Propagation) then begin
       if (netOp = CT_NetOp_NewBlock_Fast_Propagation) then begin
         // Fill with OpReference data:
         // Fill with OpReference data:
         c := NewBlock.OperationsHashTree.OperationsCount;
         c := NewBlock.OperationsHashTree.OperationsCount;
@@ -4773,57 +4831,54 @@ end;
 
 
 procedure TThreadGetNewBlockChainFromClient.BCExecute;
 procedure TThreadGetNewBlockChainFromClient.BCExecute;
 Var i,j : Integer;
 Var i,j : Integer;
-  maxWork : UInt64;
+  LMaxAggregatedTarget : UInt64;
   candidates : TList<TNetConnection>;
   candidates : TList<TNetConnection>;
   lop : TOperationBlock;
   lop : TOperationBlock;
   nc : TNetConnection;
   nc : TNetConnection;
+  LMaxAggregatedHashrate : TBigNum;
 begin
 begin
   if Not TNode.Node.UpdateBlockchain then Exit;
   if Not TNode.Node.UpdateBlockchain then Exit;
 
 
   // Search better candidates:
   // Search better candidates:
   candidates := TList<TNetConnection>.Create;
   candidates := TList<TNetConnection>.Create;
+  LMaxAggregatedHashrate := TBigNum.Create(0);
   try
   try
     lop := CT_OperationBlock_NUL;
     lop := CT_OperationBlock_NUL;
     TNetData.NetData.FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
     TNetData.NetData.FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
     // First round: Find by most work
     // First round: Find by most work
-    maxWork := 0;
+    LMaxAggregatedTarget := 0;
     j := TNetData.NetData.ConnectionsCountAll;
     j := TNetData.NetData.ConnectionsCountAll;
     nc := Nil;
     nc := Nil;
     for i := 0 to j - 1 do begin
     for i := 0 to j - 1 do begin
       if TNetData.NetData.GetConnection(i,nc) then begin
       if TNetData.NetData.GetConnection(i,nc) then begin
-        if (nc.FRemoteAccumulatedWork>maxWork) And (nc.FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
-          maxWork := nc.FRemoteAccumulatedWork;
-        end;
         // Preventing downloading
         // Preventing downloading
         if nc.FIsDownloadingBlocks then exit;
         if nc.FIsDownloadingBlocks then exit;
+        //
+        if (nc.FRemoteAggregatedHashrate.CompareTo( LMaxAggregatedHashrate )>0) and (nc.FRemoteAggregatedHashrate.CompareTo( TNode.Node.Bank.SafeBox.AggregatedHashrate )>0) then begin
+          LMaxAggregatedHashrate.RawValue := nc.FRemoteAggregatedHashrate.RawValue;
+        end;
+        if (nc.FRemoteAccumulatedWork>LMaxAggregatedTarget) And (nc.FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
+          LMaxAggregatedTarget := nc.FRemoteAccumulatedWork;
+        end;
       end;
       end;
     end;
     end;
-    if (maxWork>0) then begin
+    if (LMaxAggregatedHashrate.CompareTo( 1 ) > 0) then begin
+      // Search by Aggregated Hashrate
       for i := 0 to j - 1 do begin
       for i := 0 to j - 1 do begin
         If TNetData.NetData.GetConnection(i,nc) then begin
         If TNetData.NetData.GetConnection(i,nc) then begin
-          if (nc.FRemoteAccumulatedWork>=maxWork) then begin
+          if (nc.FRemoteAggregatedHashrate.CompareTo(LMaxAggregatedHashrate)>=0) then begin
             candidates.Add(nc);
             candidates.Add(nc);
             lop := nc.FRemoteOperationBlock;
             lop := nc.FRemoteOperationBlock;
           end;
           end;
         end;
         end;
       end;
       end;
-    end;
-    // Second round: Find by most height
-    if candidates.Count=0 then begin
+    end else if (LMaxAggregatedTarget>0) then begin
+      // Not found searching by Aggregated Hashrate, searching by Aggregated Target
       for i := 0 to j - 1 do begin
       for i := 0 to j - 1 do begin
-        if (TNetData.NetData.GetConnection(i,nc)) then begin
-          if (nc.FRemoteOperationBlock.block>=TNode.Node.Bank.BlocksCount) And
-             (nc.FRemoteOperationBlock.block>=lop.block) then begin
-             lop := nc.FRemoteOperationBlock;
-          end;
-        end;
-      end;
-      if (lop.block>0) then begin
-        for i := 0 to j - 1 do begin
-          If (TNetData.NetData.GetConnection(i,nc)) then begin
-            if (nc.FRemoteOperationBlock.block>=lop.block) then begin
-               candidates.Add(nc);
-            end;
+        If TNetData.NetData.GetConnection(i,nc) then begin
+          if (nc.FRemoteAccumulatedWork>=LMaxAggregatedTarget) then begin
+            candidates.Add(nc);
+            lop := nc.FRemoteOperationBlock;
           end;
           end;
         end;
         end;
       end;
       end;
@@ -4834,9 +4889,10 @@ begin
       i := 0;
       i := 0;
       if (candidates.Count>1) then i := Random(candidates.Count); // i = 0..count-1
       if (candidates.Count>1) then i := Random(candidates.Count); // i = 0..count-1
       nc := TNetConnection(candidates[i]);
       nc := TNetConnection(candidates[i]);
-      TNetData.NetData.GetNewBlockChainFromClient(nc,Format('Candidate block: %d sum: %d',[nc.FRemoteOperationBlock.block,nc.FRemoteAccumulatedWork]));
+      TNetData.NetData.GetNewBlockChainFromClient(nc,Format('Candidate block: %d Aggregated: %d %s',[nc.FRemoteOperationBlock.block,nc.FRemoteAccumulatedWork,nc.FRemoteAggregatedHashrate.ToDecimal]));
     end;
     end;
   finally
   finally
+    LMaxAggregatedHashrate.Free;
     candidates.Free;
     candidates.Free;
   end;
   end;
 end;
 end;
@@ -5015,6 +5071,7 @@ begin
   FTimesList := TPCThreadList<Pointer>.Create('TNetworkAdjustedTime_TimesList');
   FTimesList := TPCThreadList<Pointer>.Create('TNetworkAdjustedTime_TimesList');
   FTimeOffset := 0;
   FTimeOffset := 0;
   FTotalCounter := 0;
   FTotalCounter := 0;
+  FOffsetLimit:= CT_MaxFutureBlockTimestampOffset DIV 2; // <0 equals to NO LIMIT, otherwise limited to value
 end;
 end;
 
 
 destructor TNetworkAdjustedTime.Destroy;
 destructor TNetworkAdjustedTime.Destroy;
@@ -5160,6 +5217,10 @@ begin
   end else begin
   end else begin
     FTimeOffset := PNetworkAdjustedTimeReg(list[list.Count DIV 2])^.timeOffset;
     FTimeOffset := PNetworkAdjustedTimeReg(list[list.Count DIV 2])^.timeOffset;
   end;
   end;
+  if (FOffsetLimit>=0) and (Abs(FTimeOffset)>Abs(FOffsetLimit)) then begin
+    if FTimeOffset>=0 then FTimeOffset := Abs(FOffsetLimit)
+    else FTimeOffset := Abs(FOffsetLimit)*(-1);
+  end;
   if (last<>FTimeOffset) then begin
   if (last<>FTimeOffset) then begin
     s := '';
     s := '';
     for i := 0 to list.Count - 1 do begin
     for i := 0 to list.Count - 1 do begin

+ 5 - 4
src/core/UPoolMinerThreads.pas

@@ -47,7 +47,7 @@ Type
 
 
   TCustomMinerDeviceThreadClass = Class of TCustomMinerDeviceThread;
   TCustomMinerDeviceThreadClass = Class of TCustomMinerDeviceThread;
 
 
-  TOnFoundNonce = Procedure(Sender : TCustomMinerDeviceThread; Timestamp, nOnce : Cardinal) of object;
+  TOnFoundNonce = Procedure(Sender : TCustomMinerDeviceThread; const AUsedMinerValuesForWork : TMinerValuesForWork; ATimestamp, AnOnce : Cardinal; const APoW : TRawBytes) of object;
 
 
   { TPoolMinerThread }
   { TPoolMinerThread }
 
 
@@ -531,7 +531,7 @@ begin
   if (TBaseType.BinStrComp(LHash,usedMinerValuesForWork.target_pow)<=0) then begin
   if (TBaseType.BinStrComp(LHash,usedMinerValuesForWork.target_pow)<=0) then begin
     inc(FGlobaDeviceStats.WinsCount);
     inc(FGlobaDeviceStats.WinsCount);
     FPoolMinerThread.OnMinerNewBlockFound(self,usedMinerValuesForWork,Timestamp,nOnce,LHash);
     FPoolMinerThread.OnMinerNewBlockFound(self,usedMinerValuesForWork,Timestamp,nOnce,LHash);
-    If Assigned(FOnFoundNOnce) then FOnFoundNOnce(Self,Timestamp,nOnce);
+    If Assigned(FOnFoundNOnce) then FOnFoundNOnce(Self,usedMinerValuesForWork,Timestamp,nOnce,LHash);
   end else begin
   end else begin
     inc(FGlobaDeviceStats.Invalids);
     inc(FGlobaDeviceStats.Invalids);
     if LUseRandomHash then
     if LUseRandomHash then
@@ -681,7 +681,7 @@ end;
 procedure TCPUDeviceThread.BCExecute;
 procedure TCPUDeviceThread.BCExecute;
 begin
 begin
   while not terminated do begin
   while not terminated do begin
-    sleep(1);
+    sleep(10);
   end;
   end;
   FCPUs:=0;
   FCPUs:=0;
   CheckCPUs;
   CheckCPUs;
@@ -863,7 +863,7 @@ begin
             if FCurrentMinerValuesForWork.version < CT_PROTOCOL_5 then
             if FCurrentMinerValuesForWork.version < CT_PROTOCOL_5 then
               roundsToDo := 20
               roundsToDo := 20
             else
             else
-              roundsToDo := 200;
+              roundsToDo := 200+Random(200);
           end else begin
           end else begin
             roundsToDo := 10000;
             roundsToDo := 10000;
           end;
           end;
@@ -1012,6 +1012,7 @@ begin
   FResetNOnce:=True;
   FResetNOnce:=True;
   FJobNum := 0;
   FJobNum := 0;
   inherited Create(false);
   inherited Create(false);
+  Priority := tpHigher;
 end;
 end;
 
 
 destructor TCPUOpenSSLMinerThread.Destroy;
 destructor TCPUOpenSSLMinerThread.Destroy;

+ 13 - 12
src/pascalcoin_miner.pp

@@ -40,7 +40,7 @@ type
     procedure OnConnectionStateChanged(Sender : TObject);
     procedure OnConnectionStateChanged(Sender : TObject);
     procedure OnDeviceStateChanged(Sender : TObject);
     procedure OnDeviceStateChanged(Sender : TObject);
     procedure OnMinerValuesChanged(Sender : TObject);
     procedure OnMinerValuesChanged(Sender : TObject);
-    procedure OnFoundNOnce(Sender : TCustomMinerDeviceThread; Timestamp, nOnce : Cardinal);
+    procedure OnFoundNOnce(Sender : TCustomMinerDeviceThread; const AUsedMinerValuesForWork : TMinerValuesForWork; ATimestamp, AnOnce : Cardinal; const APoW : TRawBytes);
     procedure WriteLine(nline : Integer; txt : String);
     procedure WriteLine(nline : Integer; txt : String);
     procedure OnInThreadNewLog(logtype : TLogType; Time : TDateTime; ThreadID : TThreadID; Const sender, logtext : AnsiString);
     procedure OnInThreadNewLog(logtype : TLogType; Time : TDateTime; ThreadID : TThreadID; Const sender, logtext : AnsiString);
   protected
   protected
@@ -142,10 +142,10 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TPascalMinerApp.OnFoundNOnce(Sender: TCustomMinerDeviceThread; Timestamp, nOnce: Cardinal);
+procedure TPascalMinerApp.OnFoundNOnce(Sender : TCustomMinerDeviceThread; const AUsedMinerValuesForWork : TMinerValuesForWork; ATimestamp, AnOnce : Cardinal; const APoW : TRawBytes);
 begin
 begin
-  WriteLine(CT_Line_LastFound + FDeviceThreads.Count,FormatDateTime('hh:nn:ss',now)+' Block:'+IntToStr(Sender.MinerValuesForWork.block)+' NOnce:'+Inttostr(nOnce)+
-    ' Timestamp:'+inttostr(Timestamp)+' Miner:'+Sender.MinerValuesForWork.payload_start.ToPrintable);
+  WriteLine(CT_Line_LastFound + FDeviceThreads.Count,FormatDateTime('hh:nn:ss',now)+' Block:'+IntToStr(Sender.MinerValuesForWork.block)+' NOnce:'+Inttostr(AnOnce)+
+    ' Timestamp:'+inttostr(ATimestamp)+' Miner:'+Sender.MinerValuesForWork.payload_start.ToPrintable);
 end;
 end;
 
 
 procedure TPascalMinerApp.WriteLine(nline: Integer; txt: String);
 procedure TPascalMinerApp.WriteLine(nline: Integer; txt: String);
@@ -238,6 +238,15 @@ var
         Terminate;
         Terminate;
         exit;
         exit;
       end;
       end;
+
+      If Not FileExists(ExtractFileDir(ExeName)+PathDelim+CT_OpenCL_FileName) then begin
+        Writeln('**********************');
+        Writeln('OpenCL file not found!');
+        Writeln('File: ',CT_OpenCL_FileName);
+        Terminate;
+        Exit;
+      end;
+
       strl := TStringList.Create;
       strl := TStringList.Create;
       try
       try
         if (d<0) then begin
         if (d<0) then begin
@@ -438,14 +447,6 @@ begin
       Exit;
       Exit;
     end;
     end;
 
 
-    If Not FileExists(ExtractFileDir(ExeName)+PathDelim+CT_OpenCL_FileName) then begin
-      Writeln('**********************');
-      Writeln('OpenCL file not found!');
-      Writeln('File: ',CT_OpenCL_FileName);
-      Exit;
-    end;
-
-
     If HasOption('s','server') then begin
     If HasOption('s','server') then begin
       s := Trim(GetOptionValue('s','server'));
       s := Trim(GetOptionValue('s','server'));
       if (s='') then s := 'localhost:'+inttostr(CT_JSONRPCMinerServer_Port);
       if (s='') then s := 'localhost:'+inttostr(CT_JSONRPCMinerServer_Port);