From 6d8f2536d527b525c563cd3066fe2dc8ec98e9c9 Mon Sep 17 00:00:00 2001 From: PascalCoin Date: Wed, 19 Feb 2020 09:51:48 +0100 Subject: [PATCH 1/6] Fix freeze bug on GUI when updating accounts grid --- src/gui-classic/UGridUtils.pas | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/gui-classic/UGridUtils.pas b/src/gui-classic/UGridUtils.pas index 53f5334f0..087148534 100644 --- a/src/gui-classic/UGridUtils.pas +++ b/src/gui-classic/UGridUtils.pas @@ -97,7 +97,7 @@ interface procedure SetNode(const Value: TNode); function GetNode: TNode; procedure SetAllowMultiSelect(const Value: Boolean); - procedure TerminateAccountGridUpdateThread; + procedure TerminateAccountGridUpdateThread(AWaitUntilTerminated : Boolean); procedure SetAccountsGridFilter(const Value: TAccountsGridFilter); function GetAccountsCount: Integer; procedure SetAccountsGridDatasource(const Value: TAccountsGridDatasource); @@ -343,8 +343,9 @@ procedure TAccountsGridUpdateThread.BCExecute; end; Finally FisProcessing := False; - if Not Terminated then + if Not Terminated then begin Synchronize(SynchronizedOnTerminated); + end; End; end; @@ -447,7 +448,7 @@ constructor TAccountsGrid.Create(AOwner: TComponent); destructor TAccountsGrid.Destroy; begin - TerminateAccountGridUpdateThread; + TerminateAccountGridUpdateThread(True); FNodeNotifyEvents.Free; FAccountsList.Free; inherited; @@ -853,12 +854,18 @@ procedure TAccountsGrid.SetNode(const Value: TNode); UpdateData; end; -procedure TAccountsGrid.TerminateAccountGridUpdateThread; +procedure TAccountsGrid.TerminateAccountGridUpdateThread(AWaitUntilTerminated : Boolean); +var LTmp : TAccountsGridUpdateThread; begin - if Assigned(FAccountsGridUpdateThread) then begin - FAccountsGridUpdateThread.Terminate; - FAccountsGridUpdateThread.WaitFor; - FreeAndNil(FAccountsGridUpdateThread); + LTmp := FAccountsGridUpdateThread; + FAccountsGridUpdateThread := Nil; + if Assigned(Ltmp) then begin + if Not AWaitUntilTerminated then LTmp.FreeOnTerminate := True; + LTmp.Terminate; + if AWaitUntilTerminated then begin + LTmp.WaitFor; + FreeAndNil(LTmp); + end; end; end; @@ -892,7 +899,7 @@ procedure TAccountsGrid.UpdateData; if Assigned(Node) then begin case FAccountsGridDatasource of acds_NodeFiltered: begin - TerminateAccountGridUpdateThread; + TerminateAccountGridUpdateThread(False); FAccountsBalance := 0; FAccountsGridUpdateThread := TAccountsGridUpdateThread.Create(Self,AccountsGridFilter); end; From af79454036f0ba0a9bf9d5591e27c7e3e5d6281f Mon Sep 17 00:00:00 2001 From: PascalCoin Date: Thu, 12 Mar 2020 12:59:26 +0100 Subject: [PATCH 2/6] Allow assume old protocols PoW are valid (testing purpose only) --- src/config.inc | 7 ++++++- src/core/UAccounts.pas | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/config.inc b/src/config.inc index 72df9d45a..c39b763af 100644 --- a/src/config.inc +++ b/src/config.inc @@ -57,6 +57,11 @@ // This will allow check safebox names list. Warning: This will slow app {.$DEFINE Check_Safebox_Names_Consistency} + + // This will assume that PoW on old protocols are true and will not check, usefull after enough time to increase validation speed. + // Warning: Use only on versions after enough time since last protocol upgrade and non main-node versions + {.$DEFINE ASSUME_VALID_POW_OLD_PROTOCOLS} + { ******************************************************************** Don't touch more code, it will addapt based on your preferences @@ -66,7 +71,7 @@ ERROR: You must select ONLY ONE option: PRODUCTION or TESTNET {$ENDIF}{$ELSE}{$DEFINE PRODUCTION}{$ENDIF} -{$IF (not Defined(Use_OpenSSL)) or (not Defined(Use_CryptoLib4Pascal))} +{$IF (not Defined(Use_OpenSSL)) and (not Defined(Use_CryptoLib4Pascal))} {$DEFINE Use_OpenSSL} {$UNDEF Use_CryptoLib4Pascal} {$ENDIF} diff --git a/src/core/UAccounts.pas b/src/core/UAccounts.pas index e81a34c48..0305fa44e 100644 --- a/src/core/UAccounts.pas +++ b/src/core/UAccounts.pas @@ -828,6 +828,10 @@ class function TPascalCoinProtocol.AllowUseHardcodedRandomHashTable( LInternalHardcodedSha256 : TRawBytes; begin Result := False; + {$IFDEF ASSUME_VALID_POW_OLD_PROTOCOLS} + // In this case will not use Hardcoded RandomHash Table + Exit; + {$ENDIF} If Not FileExists(AHardcodedFileName) then begin TLog.NewLog(ltdebug,ClassName,Format('Hardcoded RandomHash from file not found:%s', [AHardcodedFileName] )); @@ -3383,7 +3387,11 @@ function TPCSafeBox.LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; // For TESTNET increase speed purposes, will only check latests blocks if ((iblock + (CT_BankToDiskEveryNBlocks * 10)) >= sbHeader.blockscount) then begin {$ENDIF} + {$IFDEF ASSUME_VALID_POW_OLD_PROTOCOLS} + LAddToMultiThreadOperationsBlockValidator := (LUseMultiThreadOperationsBlockValidator) and (LBlock.blockchainInfo.protocol_version>=CT_PROTOCOL_5) and (Assigned(LPCOperationsBlockValidator)); + {$ELSE} LAddToMultiThreadOperationsBlockValidator := (LUseMultiThreadOperationsBlockValidator) and (LBlock.blockchainInfo.protocol_version>=CT_PROTOCOL_4) and (Assigned(LPCOperationsBlockValidator)); + {$ENDIF} If not IsValidNewOperationsBlock(LBlock.blockchainInfo,False,Not LAddToMultiThreadOperationsBlockValidator,aux_errors) then begin errors := errors + ' > ' + aux_errors; exit; @@ -4121,11 +4129,18 @@ class function TPCSafeBox.IsValidOperationBlock(const newOperationBlock: TOperat end; // proof_of_work: {$IFnDEF TESTING_NO_POW_CHECK} + {$IFDEF ASSUME_VALID_POW_OLD_PROTOCOLS} + if (newOperationBlock.protocol_version>=CT_PROTOCOL_5) then begin + {$ENDIF} TPascalCoinProtocol.CalcProofOfWork(newOperationBlock,pow); if (Not TBaseType.Equals(pow,newOperationBlock.proof_of_work)) then begin errors := 'Proof of work is bad calculated '+TCrypto.ToHexaString(newOperationBlock.proof_of_work)+' <> Good: '+TCrypto.ToHexaString(pow); exit; end; + {$IFDEF ASSUME_VALID_POW_OLD_PROTOCOLS} + end; + {$ENDIF} + {$ENDIF} Result := true; end; From e2013e64dc42f20b0161d00d50e6cccc303ff71f Mon Sep 17 00:00:00 2001 From: PascalCoin Date: Thu, 12 Mar 2020 13:04:16 +0100 Subject: [PATCH 3/6] TPCTemporalFileStream that fixes "out of memory" bug when downloading Safebox --- src/core/UNetProtocol.pas | 25 ++++++--- src/core/UPCTemporalFileStream.pas | 81 ++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 src/core/UPCTemporalFileStream.pas diff --git a/src/core/UNetProtocol.pas b/src/core/UNetProtocol.pas index 7d2b1d1e3..709c3c3c7 100644 --- a/src/core/UNetProtocol.pas +++ b/src/core/UNetProtocol.pas @@ -509,7 +509,8 @@ implementation uses UConst, ULog, UNode, UTime, UPCEncryption, UChunk, - UPCOperationsBlockValidator, UPCOperationsSignatureValidator; + UPCOperationsBlockValidator, UPCOperationsSignatureValidator, + UPCTemporalFileStream; Const CT_NetTransferType : Array[TNetTransferType] of String = ('Unknown','Request','Response','Autosend'); @@ -1855,8 +1856,10 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; safeBoxHeader : TPCSafeBoxHeader; errors : String; i : Integer; + LFirstSafebox : Boolean; Begin Result := False; + LFirstSafebox := TNode.Node.Bank.SafeBox.BlocksCount = 0; safeboxStream.Size:=0; safeboxStream.Position:=0; // Will try to download penultimate saved safebox @@ -1876,7 +1879,8 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; for i:=0 to ((_blockcount-1) DIV 10000) do begin // Bug v3.0.1 and minors FNewBlockChainFromClientStatus := Format('Receiving new safebox with %d blocks (step %d/%d) from %s', [_blockcount,i+1,((_blockcount-1) DIV 10000)+1,Connection.ClientRemoteAddr]); - receiveChunk := TMemoryStream.Create; + if LFirstSafebox then receiveChunk := TMemoryStream.Create + else receiveChunk := TPCTemporalFileStream.Create('CHUNK_'+IntToStr(i)+'_'); if (Not DownloadSafeBoxChunk(_blockcount,safebox_last_operation_block.initial_safe_box_hash,(i*10000),((i+1)*10000)-1,receiveChunk,safeBoxHeader,errors)) then begin receiveChunk.Free; TLog.NewLog(ltError,CT_LogSender,errors); @@ -1886,8 +1890,9 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; chunks[High(chunks)].safeBoxHeader := safeBoxHeader; chunks[High(chunks)].chunkStream := receiveChunk; end; + TLog.NewLog(ltDebug,CT_LogSender,Format('Concatening %d chunks',[Length(chunks)])); // Will concat safeboxs: - chunk1 := TMemoryStream.Create; + chunk1 := TPCTemporalFileStream.Create('CONCAT_CHUNKS_'); try if (length(chunks)=1) then begin safeboxStream.CopyFrom(chunks[0].chunkStream,0); @@ -1895,6 +1900,9 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; chunk1.CopyFrom(chunks[0].chunkStream,0); end; for i:=1 to high(chunks) do begin + FNewBlockChainFromClientStatus := Format('Concatening downloaded safebox (step %d/%d) from %s', + [i,High(chunks),Connection.ClientRemoteAddr]); + TLog.NewLog(ltDebug,CT_LogSender,Format('Concatening chunk %d/%d',[i,High(chunks)])); safeboxStream.Size:=0; chunk1.Position:=0; chunks[i].chunkStream.Position:=0; @@ -1905,6 +1913,7 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; chunk1.Size := 0; chunk1.CopyFrom(safeboxStream,0); end; + FNewBlockChainFromClientStatus := Format('Downloaded safebox with %d chunks from %s',[High(chunks),Connection.ClientRemoteAddr]); finally chunk1.Free; end; @@ -1924,7 +1933,7 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; request_id : Cardinal; Begin Result := False; - receiveData := TMemoryStream.Create; + receiveData := TPCTemporalFileStream.Create('SAFEBOX_'); try if Not DownloadSafeboxStream(receiveData,op) then Exit; // Now receiveData is the ALL safebox @@ -1953,7 +1962,7 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; end; procedure DownloadNewBlockchain(start_block : Int64; IsMyBlockChainOk : Boolean); - var safeboxStream : TMemoryStream; + var safeboxStream : TStream; newTmpBank : TPCBank; safebox_last_operation_block : TOperationBlock; opComp : TPCOperationsComp; @@ -1971,7 +1980,7 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; if (download_new_safebox) then begin TLog.NewLog(ltinfo,ClassName,Format('Will download new safebox. My blocks:%d Remote blocks:%d Equal Block:%d (MaxFutureBlocksToDownloadNewSafebox:%d)',[TNode.Node.Bank.BlocksCount,Connection.RemoteOperationBlock.block+1,start_block-1,MinFutureBlocksToDownloadNewSafebox])); // Will try to download safebox - safeboxStream := TMemoryStream.Create; + safeboxStream := TPCTemporalFileStream.Create('NEW_SAFEBOX_'); Try if Not DownloadSafeboxStream(safeboxStream,safebox_last_operation_block) then Exit; safeboxStream.Position := 0; @@ -2046,6 +2055,7 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; var rid : Cardinal; my_op, client_op : TOperationBlock; errors : String; + LTickCount : TTickCount; begin // Protection against discovering servers... if FIsDiscoveringServers then begin @@ -2056,6 +2066,7 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; if (Not Assigned(TNode.Node.Bank.StorageClass)) then Exit; // + LTickCount := TPlatform.GetTickCount; if Not FLockGettingNewBlockChainFromClient.TryEnter then begin TLog.NewLog(ltdebug,CT_LogSender,'Is getting new blockchain from client...'); exit; @@ -2116,8 +2127,8 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; DownloadNewBlockchain(my_op.block+1,True); end; Finally - TLog.NewLog(ltdebug,CT_LogSender,'Finalizing'); FLockGettingNewBlockChainFromClient.Release; + TLog.NewLog(ltdebug,CT_LogSender,Format('Finalizing process in %d milis',[TPlatform.GetElapsedMilliseconds(LTickCount)])); end; end; diff --git a/src/core/UPCTemporalFileStream.pas b/src/core/UPCTemporalFileStream.pas new file mode 100644 index 000000000..e965f4d4b --- /dev/null +++ b/src/core/UPCTemporalFileStream.pas @@ -0,0 +1,81 @@ +unit UPCTemporalFileStream; + +{ Copyright (c) 2020 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 the PascalCoin Project, an infinitely scalable + cryptocurrency. Find us here: + Web: https://www.pascalcoin.org + Source: https://github.com/PascalCoin/PascalCoin + + If you like it, consider a donation using Bitcoin: + 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk + + THIS LICENSE HEADER MUST NOT BE REMOVED. +} + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + Classes, {$IFnDEF FPC}Windows,{$ENDIF} SysUtils; +{$I ./../config.inc} + +Type + { TPCTemporalFileStream } + + TPCTemporalFileStream = Class(TFileStream) + private + FTemporalFileName : String; + protected + public + Constructor Create(const AInitialName : String); reintroduce; + Destructor Destroy; override; + End; + +implementation + +Uses ULog, UNode; + +{ TPCTemporalFileStream } + +constructor TPCTemporalFileStream.Create(const AInitialName : String); +var LFolder, LTime, LFileName : String; + i : Integer; +begin + FTemporalFileName:= ''; + LFolder := TNode.GetPascalCoinDataFolder+PathDelim+'Temp'; + ForceDirectories(LFolder); + i := 0; + repeat + LTime := FormatDateTime('yyyymmddhhnnsszzz',Now); + if i>0 then begin + Sleep(1); + LFileName := LFolder + PathDelim + AInitialName + LTime +'_'+ IntToStr(i) + '.tmp'; + end else begin + LFileName := LFolder + PathDelim + AInitialName + LTime + '.tmp'; + end; + inc(i); + until (Not (FileExists(LFileName)) or (i>5000)); + TLog.NewLog(ltdebug,ClassName,Format('Creating a new Temporal file Stream: %s',[LFileName])); + inherited Create(LFileName,fmCreate+fmShareDenyWrite); + FTemporalFileName:=LFileName; +end; + +destructor TPCTemporalFileStream.Destroy; +var LSize : Integer; +begin + LSize := Size; + inherited Destroy; + if FTemporalFileName<>'' then begin + TLog.NewLog(ltdebug,ClassName,Format('Deleting a Temporal file Stream (%d bytes): %s',[LSize, FTemporalFileName])); + DeleteFile(FTemporalFileName); + end; +end; + +end. From 7e380f859c7b0495453c0248b64aec6d9ac7de55 Mon Sep 17 00:00:00 2001 From: PascalCoin Date: Thu, 12 Mar 2020 13:04:50 +0100 Subject: [PATCH 4/6] Set Version to 5.3 --- src/core/UConst.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/UConst.pas b/src/core/UConst.pas index 73f28877d..408c0dc1e 100644 --- a/src/core/UConst.pas +++ b/src/core/UConst.pas @@ -195,7 +195,7 @@ interface CT_OpSubtype_Data_Signer = 103; CT_OpSubtype_Data_Receiver = 104; - CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.2'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.2'{$ELSE}{$ENDIF}{$ENDIF}; + CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.3'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.3'{$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' {$ELSE}'pascaltestnet1.dynamic-dns.net;pascaltestnet2.dynamic-dns.net;pascaltestnet1.dns1.us;pascaltestnet2.dns1.us'{$ENDIF}; From 0424a4fe2f872fb2fbe26bec307b60279d65bdba Mon Sep 17 00:00:00 2001 From: PascalCoin Date: Thu, 12 Mar 2020 13:31:28 +0100 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d78823e8..4f097d413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## Build 5.3.0 - 2020-03-12 +- Fixed "out of memory" error when downloading Safebox +- Fixed freeze bug on GUI when updating accounts grid +- Minor improvements for testing + ## Build 5.2.0 - 2020-02-11 - Mandatory upgrade due fixes some important security bugs - Fixed CryptoLib4Pascal multithreading bug From 5616943bc38b052f6b97fcfce7719495668ccaac Mon Sep 17 00:00:00 2001 From: PascalCoin Date: Thu, 12 Mar 2020 23:11:51 +0100 Subject: [PATCH 6/6] Fixed FPC bug in "TFileStream.position"<>0 when setting size=0 --- src/core/UNetProtocol.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/UNetProtocol.pas b/src/core/UNetProtocol.pas index 709c3c3c7..8f51a8df6 100644 --- a/src/core/UNetProtocol.pas +++ b/src/core/UNetProtocol.pas @@ -1904,6 +1904,7 @@ procedure TNetData.GetNewBlockChainFromClient(Connection: TNetConnection; [i,High(chunks),Connection.ClientRemoteAddr]); TLog.NewLog(ltDebug,CT_LogSender,Format('Concatening chunk %d/%d',[i,High(chunks)])); safeboxStream.Size:=0; + safeboxStream.Position := 0; // Added caused by FPC 3.0.4 bug that does not update position auto when setting size=0 at a TFileStream chunk1.Position:=0; chunks[i].chunkStream.Position:=0; If Not TPCSafeBox.ConcatSafeBoxStream(chunk1,chunks[i].chunkStream,safeboxStream,errors) then begin