Browse Source

Merge pull request #14 from PascalCoinDev/master

Improvements and new features (no hard fork)
Pascal Coin 5 years ago
parent
commit
b504fc6f22

+ 112 - 77
src/core/UAccounts.pas

@@ -156,6 +156,7 @@ Type
     Class Function IsAccountForSaleOrSwapAcceptingTransactions(const AAccount: TAccount; ACurrentBlock : Integer; ACurrentProtocol : Word; const APayload : TRawBytes) : Boolean;
     Class Function IsOperationRecipientSignable(const ASender, ATarget : TAccount; ACurrentBlock : Integer; ACurrentProtocol : Word) : Boolean;
     Class Function GetECInfoTxt(Const EC_OpenSSL_NID: Word) : String;
+    Class Function IsValidEC_OpenSSL_NID(ANID : Word) : Boolean;
     Class Procedure ValidsEC_OpenSSL_NID(list : TList<Word>);
     Class Function AccountKey2RawString(const account: TAccountKey): TRawBytes; overload;
     Class procedure AccountKey2RawString(const account: TAccountKey; var dest: TRawBytes); overload;
@@ -331,7 +332,7 @@ Type
     Class Function CalcBlockHash(const block : TBlockAccount; current_protocol : Word):TRawBytes;
     Class Function BlockAccountToText(Const block : TBlockAccount):String;
     Function LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; var LastReadBlock : TBlockAccount; var errors : String) : Boolean; overload;
-    Function LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; checkSafeboxHash : TRawBytes; progressNotify : TProgressNotify; previousCheckedSafebox : TPCSafebox; var LastReadBlock : TBlockAccount; var errors : String) : Boolean; overload;
+    Function LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; checkSafeboxHash : TRawBytes; progressNotify : TProgressNotify; previousCheckedSafebox : TPCSafebox; var ALastReadBlock : TBlockAccount; var errors : String) : Boolean; overload;
     Class Function LoadSafeBoxStreamHeader(Stream : TStream; var sbHeader : TPCSafeBoxHeader) : Boolean;
     Class Function SaveSafeBoxStreamHeader(Stream : TStream; protocol : Word; OffsetStartBlock, OffsetEndBlock, CurrentSafeBoxBlocksCount : Cardinal) : Boolean;
     Class Function MustSafeBoxBeSaved(BlocksCount : Cardinal) : Boolean;
@@ -348,10 +349,13 @@ Type
     Function GetActualCompactTargetHash(protocolVersion : Word): Cardinal;
     Function FindAccountByName(const aName : String) : Integer; overload;
     Function FindAccountByName(const aName : TRawBytes) : Integer; overload;
+    Function FindAccountsStartingByName(const AStartName : TRawBytes; const ARawList : TOrderedRawList; const AMax : Integer = 0) : Integer;
 
     Procedure Clear;
     Function Account(account_number : Cardinal) : TAccount;
-    Function Block(block_number : Cardinal) : TBlockAccount;
+    Function GetBlock(block_number : Cardinal) : TBlockAccount;
+    Function GetBlockInfo(ABlockNumber : Cardinal) : TOperationBlock;
+
     Function CalcSafeBoxHash : TRawBytes;
     Function CalcBlockHashRateInKhs(block_number : Cardinal; Previous_blocks_average : Cardinal) : Int64;
     Function CalcBlockHashRateInHs(block_number : Cardinal; Previous_blocks_average : Cardinal) : TBigNum;
@@ -593,7 +597,7 @@ var i,j,maxBlock : Integer;
 Begin
   For i:=0 to sb.FModifiedBlocksFinalState.Count-1 do begin
     bl_modified := sb.FModifiedBlocksFinalState.Get(i);
-    bl_my := sb.Block(bl_modified.blockchainInfo.block);
+    bl_my := sb.GetBlock(bl_modified.blockchainInfo.block);
     If Not TAccountComp.EqualBlockAccounts(bl_my,bl_modified) then begin
       Raise Exception.Create(Format('%s Integrity on modified (i)=%d for block number:%d',[title, i,bl_my.blockchainInfo.block]));
     end;
@@ -606,7 +610,7 @@ Begin
     maxBlock := sb.BlocksCount;
     auxH.SetLength(sb.BlocksCount*32);
     for i:=0 to sb.BlocksCount-1 do begin
-      bl_my := sb.Block(i);
+      bl_my := sb.GetBlock(i);
       for j:=Low(bl_my.accounts) to High(bl_my.accounts) do begin
         If (maxBlock < (bl_my.accounts[j].updated_on_block_passive_mode)) or (maxBlock < (bl_my.accounts[j].updated_on_block_active_mode)) then begin
           Raise Exception.Create(Format('%s Integrity on (i)=%d for block account:%d pasive updated on %d , active updated on %d ,maxBlock %d',[title, i,bl_my.accounts[j].account,bl_my.accounts[j].updated_on_block_passive_mode,bl_my.accounts[j].updated_on_block_active_mode,maxBlock]));
@@ -1641,13 +1645,7 @@ begin
   end else begin
     // V5 only will allow PRIVATE SALES or SWAPS while locked
     if (IsAccountForPublicSale(AAccount.accountInfo)) Then Exit; // Public sales not allowed
-    {$IFDEF TESTNET}
-    // TESTNET ONLY to allow a previous created blockchain
-    if (ACurrentBlock > 7000) and
-      (Not (IsAccountLocked(AAccount.accountInfo,ACurrentBlock))) then Exit; // Time lock expired
-    {$ELSE}
     if (Not (IsAccountLocked(AAccount.accountInfo,ACurrentBlock))) then Exit; // Time lock expired
-    {$ENDIF}
   end;
 
   if (AAccount.accountInfo.state in [as_ForSale, as_ForAtomicAccountSwap]) then begin
@@ -1794,6 +1792,12 @@ begin
   end;
 end;
 
+class function TAccountComp.IsValidEC_OpenSSL_NID(ANID: Word): Boolean;
+begin
+  Result := (ANID = CT_NID_secp256k1) or (ANID = CT_NID_secp384r1)
+    or (ANID = CT_NID_sect283k1) or (ANID = CT_NID_secp521r1);
+end;
+
 class function TAccountComp.IsNullAccountKey(const AAccountInfo : TAccountKey) : Boolean;
 begin
   Result := AAccountInfo.EC_OpenSSL_NID = CT_TECDSA_Public_Nul.EC_OpenSSL_NID;
@@ -2405,7 +2409,7 @@ begin
   end;
 end;
 
-function TPCSafeBox.Block(block_number: Cardinal): TBlockAccount;
+function TPCSafeBox.GetBlock(block_number: Cardinal): TBlockAccount;
 begin
   StartThreadSafe;
   try
@@ -2708,7 +2712,7 @@ begin
         end else lastOAKL := Nil;
         FBlockAccountsList.Capacity:=accounts.BlocksCount;
         for i := 0 to accounts.BlocksCount - 1 do begin
-          BA := accounts.Block(i);
+          BA := accounts.GetBlock(i);
           New(P);
           ToTMemBlockAccount(BA,P^);
           FBlockAccountsList.Add(P);
@@ -2879,7 +2883,7 @@ procedure TPCSafeBox.CommitToPrevious;
     //
     RedoAddedDeletedNames(Psnapshot^.namesAdded,Psnapshot^.namesDeleted);
     //
-    FPreviousSafeBox.AddNew(Block(Psnapshot^.nBlockNumber).blockchainInfo);
+    FPreviousSafeBox.AddNew(GetBlockInfo(Psnapshot^.nBlockNumber));
   end;
 
 Var errors : String;
@@ -3118,7 +3122,7 @@ begin
   FBufferBlocksHash.Clear;
   for block_number := 0 to BlocksCount - 1 do begin
     {$IFDEF uselowmem}
-    TBaseType.To32Bytes(CalcBlockHash( Block(block_number), CT_PROTOCOL_2),PBlockAccount(FBlockAccountsList.Items[block_number])^.block_hash);
+    TBaseType.To32Bytes(CalcBlockHash( GetBlock(block_number), CT_PROTOCOL_2),PBlockAccount(FBlockAccountsList.Items[block_number])^.block_hash);
     FBufferBlocksHash.Add( PBlockAccount(FBlockAccountsList.Items[block_number])^.block_hash[0], 32 );
     {$ELSE}
     PBlockAccount(FBlockAccountsList.Items[block_number])^.block_hash := CalcBlockHash( Block(block_number), CT_PROTOCOL_2);
@@ -3166,7 +3170,7 @@ begin
       LPtrBlockAccount^.accounts[i].updated_on_block_active_mode := LPtrBlockAccount^.accounts[i].updated_on_block_passive_mode;
     end;
     {$IFDEF uselowmem}
-    TBaseType.To32Bytes(CalcBlockHash( Block(LBlockNumber), CT_PROTOCOL_5),PBlockAccount(FBlockAccountsList.Items[LBlockNumber])^.block_hash);
+    TBaseType.To32Bytes(CalcBlockHash( GetBlock(LBlockNumber), CT_PROTOCOL_5),PBlockAccount(FBlockAccountsList.Items[LBlockNumber])^.block_hash);
     FBufferBlocksHash.Add( PBlockAccount(FBlockAccountsList.Items[LBlockNumber])^.block_hash[0], 32 );
     {$ELSE}
     PBlockAccount(FBlockAccountsList.Items[LBlockNumber])^.block_hash := CalcBlockHash( Block(LBlockNumber), CT_PROTOCOL_5);
@@ -3182,11 +3186,11 @@ begin
   FLock.Release;
 end;
 
-function TPCSafeBox.LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; checkSafeboxHash : TRawBytes; progressNotify : TProgressNotify; previousCheckedSafebox : TPCSafebox; var LastReadBlock : TBlockAccount; var errors : String) : Boolean;
+function TPCSafeBox.LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; checkSafeboxHash : TRawBytes; progressNotify : TProgressNotify; previousCheckedSafebox : TPCSafebox; var ALastReadBlock : TBlockAccount; var errors : String) : Boolean;
 Var
   iblock,iacc, LTempCardinal : Cardinal;
   raw, LPreviousProofOfWork : TRawBytes;
-  block : TBlockAccount;
+  LBlock : TBlockAccount;
   P : PBlockAccount;
   i,j : Integer;
   savedSBH : TRawBytes;
@@ -3194,7 +3198,7 @@ Var
   offsets : Array of Cardinal;
   sbHeader : TPCSafeBoxHeader;
   tc, LStartTickCount : TTickCount;
-  previous_Block : TBlockAccount;
+  LPrevious_Block_info : TOperationBlock;
   do_check_blockchain_info : Boolean;
   aux_errors : String;
   LUseMultiThreadOperationsBlockValidator, LAddToMultiThreadOperationsBlockValidator : Boolean;
@@ -3207,6 +3211,7 @@ begin
   end else LUseMultiThreadOperationsBlockValidator := False;
   If Assigned(FPreviousSafeBox) then Raise Exception.Create('Cannot loadSafeBoxFromStream on a Safebox in a Separate chain');
   if (previousCheckedSafebox = Self) then previousCheckedSafebox := Nil; // Protection
+  ALastReadBlock := CT_BlockAccount_NUL;
   tc := TPlatform.GetTickCount;
   StartThreadSafe;
   try
@@ -3270,62 +3275,62 @@ begin
           end;
         end;
 
-        block := CT_BlockAccount_NUL;
-        If Not TAccountComp.LoadTOperationBlockFromStream(Stream,block.blockchainInfo) then exit;
-        if block.blockchainInfo.block<>iBlock then exit;
-        for iacc := Low(block.accounts) to High(block.accounts) do begin
-          errors := 'Corrupted stream reading account '+inttostr(iacc+1)+'/'+inttostr(length(block.accounts))+' of block '+inttostr(iblock+1)+'/'+inttostr(sbHeader.blockscount);
-          if Stream.Read(block.accounts[iacc].account,4)<4 then exit;
+        LBlock := CT_BlockAccount_NUL;
+        If Not TAccountComp.LoadTOperationBlockFromStream(Stream,LBlock.blockchainInfo) then exit;
+        if LBlock.blockchainInfo.block<>iBlock then exit;
+        for iacc := Low(LBlock.accounts) to High(LBlock.accounts) do begin
+          errors := 'Corrupted stream reading account '+inttostr(iacc+1)+'/'+inttostr(length(LBlock.accounts))+' of block '+inttostr(iblock+1)+'/'+inttostr(sbHeader.blockscount);
+          if Stream.Read(LBlock.accounts[iacc].account,4)<4 then exit;
           if TStreamOp.ReadAnsiString(Stream,raw)<0 then exit;
-          block.accounts[iacc].accountInfo := TAccountComp.RawString2AccountInfo(raw);
-          if Stream.Read(block.accounts[iacc].balance,SizeOf(UInt64))<SizeOf(UInt64) then exit;
-          if Stream.Read(block.accounts[iacc].updated_on_block_passive_mode,4)<4 then exit;
+          LBlock.accounts[iacc].accountInfo := TAccountComp.RawString2AccountInfo(raw);
+          if Stream.Read(LBlock.accounts[iacc].balance,SizeOf(UInt64))<SizeOf(UInt64) then exit;
+          if Stream.Read(LBlock.accounts[iacc].updated_on_block_passive_mode,4)<4 then exit;
           if FCurrentProtocol>=CT_PROTOCOL_5 then begin
-            if Stream.Read(block.accounts[iacc].updated_on_block_active_mode,4)<4 then exit;
-          end else block.accounts[iacc].updated_on_block_active_mode := block.accounts[iacc].updated_on_block_passive_mode;
-          if Stream.Read(block.accounts[iacc].n_operation,4)<4 then exit;
+            if Stream.Read(LBlock.accounts[iacc].updated_on_block_active_mode,4)<4 then exit;
+          end else LBlock.accounts[iacc].updated_on_block_active_mode := LBlock.accounts[iacc].updated_on_block_passive_mode;
+          if Stream.Read(LBlock.accounts[iacc].n_operation,4)<4 then exit;
           If FCurrentProtocol>=CT_PROTOCOL_2 then begin
-            if TStreamOp.ReadAnsiString(Stream,block.accounts[iacc].name)<0 then exit;
-            if Stream.Read(block.accounts[iacc].account_type,2)<2 then exit;
+            if TStreamOp.ReadAnsiString(Stream,LBlock.accounts[iacc].name)<0 then exit;
+            if Stream.Read(LBlock.accounts[iacc].account_type,2)<2 then exit;
           end;
           if FCurrentProtocol>=CT_PROTOCOL_5 then begin
-            if TStreamOp.ReadAnsiString(Stream,block.accounts[iacc].account_data)<0 then Exit;
-            if (Length(block.accounts[iacc].account_data)>CT_MaxAccountDataSize) then Exit;
-            if TStreamOp.ReadAnsiString(Stream,block.accounts[iacc].account_seal)<0 then Exit;
+            if TStreamOp.ReadAnsiString(Stream,LBlock.accounts[iacc].account_data)<0 then Exit;
+            if (Length(LBlock.accounts[iacc].account_data)>CT_MaxAccountDataSize) then Exit;
+            if TStreamOp.ReadAnsiString(Stream,LBlock.accounts[iacc].account_seal)<0 then Exit;
           end else begin
             if Stream.Read(LTempCardinal,4)<4 then exit;
           end;
           //
           // check valid
-          If (Length(block.accounts[iacc].name)>0) then begin
-            if FOrderedByName.IndexOf(block.accounts[iacc].name)>=0 then begin
-              errors := errors + ' Duplicate name "'+block.accounts[iacc].name.ToPrintable+'"';
+          If (Length(LBlock.accounts[iacc].name)>0) then begin
+            if FOrderedByName.IndexOf(LBlock.accounts[iacc].name)>=0 then begin
+              errors := errors + ' Duplicate name "'+LBlock.accounts[iacc].name.ToPrintable+'"';
               Exit;
             end;
-            if Not TPCSafeBox.ValidAccountName(block.accounts[iacc].name,aux_errors) then begin
-              errors := errors + ' > Invalid name "'+block.accounts[iacc].name.ToPrintable+'": '+aux_errors;
+            if Not TPCSafeBox.ValidAccountName(LBlock.accounts[iacc].name,aux_errors) then begin
+              errors := errors + ' > Invalid name "'+LBlock.accounts[iacc].name.ToPrintable+'": '+aux_errors;
               Exit;
             end;
-            FOrderedByName.Add(block.accounts[iacc].name,block.accounts[iacc].account);
+            FOrderedByName.Add(LBlock.accounts[iacc].name,LBlock.accounts[iacc].account);
           end;
           If checkAll then begin
-            if not TAccountComp.IsValidAccountInfo(block.accounts[iacc].accountInfo,aux_errors) then begin
+            if not TAccountComp.IsValidAccountInfo(LBlock.accounts[iacc].accountInfo,aux_errors) then begin
               errors := errors + ' > '+aux_errors;
               Exit;
             end;
           end;
-          inc(FTotalBalance,Int64(block.accounts[iacc].balance));
+          inc(FTotalBalance,Int64(LBlock.accounts[iacc].balance));
         end;
         errors := 'Corrupted stream reading block '+inttostr(iblock+1)+'/'+inttostr(sbHeader.blockscount);
-        If TStreamOp.ReadAnsiString(Stream,block.block_hash)<0 then exit;
-        If Stream.Read(block.accumulatedWork,SizeOf(block.accumulatedWork)) < SizeOf(block.accumulatedWork) then exit;
+        If TStreamOp.ReadAnsiString(Stream,LBlock.block_hash)<0 then exit;
+        If Stream.Read(LBlock.accumulatedWork,SizeOf(LBlock.accumulatedWork)) < SizeOf(LBlock.accumulatedWork) then exit;
 
         if checkAll then begin
           if (Not do_check_blockchain_info) then begin
             // Only check if block not found on previous or different block
-            if previousCheckedSafebox.BlocksCount>block.blockchainInfo.block then begin
-              previous_Block := previousCheckedSafebox.Block( block.blockchainInfo.block );
-              do_check_blockchain_info := Not TAccountComp.EqualOperationBlocks(block.blockchainInfo,previous_Block.blockchainInfo);
+            if previousCheckedSafebox.BlocksCount>LBlock.blockchainInfo.block then begin
+              LPrevious_Block_info := previousCheckedSafebox.GetBlockInfo( LBlock.blockchainInfo.block );
+              do_check_blockchain_info := Not TAccountComp.EqualOperationBlocks(LBlock.blockchainInfo,LPrevious_Block_info);
             end else do_check_blockchain_info := True;
           end else do_check_blockchain_info := True;
           // Check is valid:
@@ -3335,13 +3340,13 @@ begin
               // For TESTNET increase speed purposes, will only check latests blocks
             if ((iblock + (CT_BankToDiskEveryNBlocks * 10)) >= sbHeader.blockscount) then begin
             {$ENDIF}
-              LAddToMultiThreadOperationsBlockValidator := (LUseMultiThreadOperationsBlockValidator) and (block.blockchainInfo.protocol_version>=CT_PROTOCOL_4) and (Assigned(LPCOperationsBlockValidator));
-              If not IsValidNewOperationsBlock(block.blockchainInfo,False,Not LAddToMultiThreadOperationsBlockValidator,aux_errors) then begin
+              LAddToMultiThreadOperationsBlockValidator := (LUseMultiThreadOperationsBlockValidator) and (LBlock.blockchainInfo.protocol_version>=CT_PROTOCOL_4) and (Assigned(LPCOperationsBlockValidator));
+              If not IsValidNewOperationsBlock(LBlock.blockchainInfo,False,Not LAddToMultiThreadOperationsBlockValidator,aux_errors) then begin
                 errors := errors + ' > ' + aux_errors;
                 exit;
               end;
               if (LAddToMultiThreadOperationsBlockValidator) then begin
-                LPCOperationsBlockValidator.AddToValidate(block.blockchainInfo);
+                LPCOperationsBlockValidator.AddToValidate(LBlock.blockchainInfo);
                 LPCOperationsBlockValidator.GetStatus(LValidatedOPOk, LValidatedOPError, LValidatedOPPending);
                 if LValidatedOPError>0 then begin
                   LPCOperationsBlockValidator.FillErrors(errors);
@@ -3354,54 +3359,54 @@ begin
           end;
 
           // STEP 2: Check if valid block hash
-          if (Not TBaseType.Equals(CalcBlockHash(block,FCurrentProtocol),block.block_hash)) then begin
+          if (Not TBaseType.Equals(CalcBlockHash(LBlock,FCurrentProtocol),LBlock.block_hash)) then begin
             errors := errors + ' > Invalid block hash '+inttostr(iblock+1)+'/'+inttostr(sbHeader.blockscount);
             exit;
           end;
           // STEP 3: Check accumulatedWork
           if (iblock>0) then begin
-            If (self.Block(iblock-1).accumulatedWork)+block.blockchainInfo.compact_target <> block.accumulatedWork then begin
+            If (ALastReadBlock.accumulatedWork)+LBlock.blockchainInfo.compact_target <> LBlock.accumulatedWork then begin
               errors := errors + ' > Invalid accumulatedWork';
               exit;
             end;
           end;
         end;
         // Checking previous_proof_of_work
-        if block.blockchainInfo.protocol_version>=CT_PROTOCOL_5 then begin
-          if (Not TBaseType.Equals(block.blockchainInfo.previous_proof_of_work,LPreviousProofOfWork)) then begin
+        if LBlock.blockchainInfo.protocol_version>=CT_PROTOCOL_5 then begin
+          if (Not TBaseType.Equals(LBlock.blockchainInfo.previous_proof_of_work,LPreviousProofOfWork)) then begin
             errors := errors + ' > previous_proof_of_work does not match!';
             Exit;
           end;
         end else begin
           // Ensure no value on "previous_proof_of_work" field
-          if (Length(block.blockchainInfo.previous_proof_of_work)>0)
-            and (Not TBaseType.Equals(block.blockchainInfo.previous_proof_of_work,LPreviousProofOfWork)) then begin
+          if (Length(LBlock.blockchainInfo.previous_proof_of_work)>0)
+            and (Not TBaseType.Equals(LBlock.blockchainInfo.previous_proof_of_work,LPreviousProofOfWork)) then begin
             errors := errors + ' > contains previous_proof_of_work on protocol<5 different than needed!';
             Exit;
           end;
         end;
         // Add
         New(P);
-        ToTMemBlockAccount(block,P^);
+        ToTMemBlockAccount(LBlock,P^);
         FBlockAccountsList.Add(P);
-        for j := low(block.accounts) to High(block.accounts) do begin
-          AccountKeyListAddAccounts(block.accounts[j].accountInfo.accountKey,[block.accounts[j].account]);
+        for j := low(LBlock.accounts) to High(LBlock.accounts) do begin
+          AccountKeyListAddAccounts(LBlock.accounts[j].accountInfo.accountKey,[LBlock.accounts[j].account]);
         end;
         // BufferBlocksHash fill with data
         j := (length(P^.block_hash)*(iBlock));
         FBufferBlocksHash.Replace( j, P^.block_hash[0], 32 );
-        LastReadBlock := block;
-        Inc(FWorkSum,block.blockchainInfo.compact_target);
+        ALastReadBlock := LBlock;
+        Inc(FWorkSum,LBlock.blockchainInfo.compact_target);
         // Upgrade to Protocol 4,5... step:
-        if (block.blockchainInfo.protocol_version>FCurrentProtocol) then begin
-          if (block.blockchainInfo.protocol_version = CT_PROTOCOL_4) then begin
+        if (LBlock.blockchainInfo.protocol_version>FCurrentProtocol) then begin
+          if (LBlock.blockchainInfo.protocol_version = CT_PROTOCOL_4) then begin
             FCurrentProtocol := CT_PROTOCOL_4;
-          end else if (block.blockchainInfo.protocol_version = CT_PROTOCOL_5) then begin
+          end else if (LBlock.blockchainInfo.protocol_version = CT_PROTOCOL_5) then begin
             FCurrentProtocol := CT_PROTOCOL_5;
           end;
         end;
         // Assign to previous
-        LPreviousProofOfWork := block.blockchainInfo.proof_of_work;
+        LPreviousProofOfWork := LBlock.blockchainInfo.proof_of_work;
       end;
         if Assigned(LPCOperationsBlockValidator) then begin
           repeat
@@ -3437,7 +3442,7 @@ begin
       end;
       // Check worksum value
       If sbHeader.blockscount>0 then begin
-        If (FWorkSum<>Self.Block(sbHeader.blockscount-1).accumulatedWork) then begin
+        If (FWorkSum<>ALastReadBlock.accumulatedWork) then begin
           errors := 'Invalid WorkSum value';
           exit;
         end;
@@ -3446,13 +3451,13 @@ begin
       FSafeBoxHash := CalcSafeBoxHash;
       // Checking saved SafeBoxHash
       If (Not TBaseType.Equals(FSafeBoxHash,savedSBH)) then begin
-        errors := 'Invalid SafeBoxHash value in stream '+TCrypto.ToHexaString(FSafeBoxHash)+'<>'+TCrypto.ToHexaString(savedSBH)+' Last block:'+IntToStr(LastReadBlock.blockchainInfo.block);
+        errors := 'Invalid SafeBoxHash value in stream '+TCrypto.ToHexaString(FSafeBoxHash)+'<>'+TCrypto.ToHexaString(savedSBH)+' Last block:'+IntToStr(ALastReadBlock.blockchainInfo.block);
         exit;
       end;
       // Check that checkSafeboxHash is as expected
       if (Length(checkSafeboxHash)>0) then begin
         if (Not TBaseType.Equals(checkSafeboxHash,FSafeBoxHash)) then begin
-          errors := 'Invalid SafeboxHash, does not match '+TCrypto.ToHexaString(FSafeBoxHash)+'<>'+TCrypto.ToHexaString(checkSafeboxHash)+' Last block:'+IntToStr(LastReadBlock.blockchainInfo.block);
+          errors := 'Invalid SafeboxHash, does not match '+TCrypto.ToHexaString(FSafeBoxHash)+'<>'+TCrypto.ToHexaString(checkSafeboxHash)+' Last block:'+IntToStr(ALastReadBlock.blockchainInfo.block);
           Exit;
         end;
       end;
@@ -3545,7 +3550,7 @@ var b : TBlockAccount;
   Stream : TStream;
   LCardinal : Cardinal;
 begin
-  b := Block(nblock);
+  b := GetBlock(nblock);
   if DestStream is TMemoryStream then Stream := DestStream
   else begin
     Stream := TMemoryStream.Create;
@@ -3621,7 +3626,7 @@ begin
     Stream.Position := posFinal;
     // Final zone: Save safeboxhash for next block
     If (ToBlock+1<BlocksCount) then begin
-      b := Block(ToBlock);
+      b := GetBlock(ToBlock);
       TStreamOp.WriteAnsiString(Stream,b.blockchainInfo.initial_safe_box_hash);
     end else begin
       TStreamOp.WriteAnsiString(Stream,FSafeBoxHash);
@@ -3890,7 +3895,7 @@ var target_hash, pow : TRawBytes;
 begin
   Result := False;
   errors := '';
-  If BlocksCount>0 then lastBlock := Block(BlocksCount-1).blockchainInfo
+  If BlocksCount>0 then lastBlock := GetBlockInfo(BlocksCount-1)
   else lastBlock := CT_OperationBlock_NUL;
   // Check block
   if (BlocksCount <> newOperationBlock.block) then begin
@@ -4093,10 +4098,10 @@ begin
   end else begin
     if BlocksCount > CT_CalcNewTargetBlocksAverage then CalcBack := CT_CalcNewTargetBlocksAverage
     else CalcBack := BlocksCount-1;
-    lastBlock := Block(BlocksCount-1).blockchainInfo;
+    lastBlock := GetBlockInfo(BlocksCount-1);
     // Calc new target!
     ts1 := lastBlock.timestamp;
-    ts2 := Block(BlocksCount-CalcBack-1).blockchainInfo.timestamp;
+    ts2 := GetBlockInfo(BlocksCount-CalcBack-1).timestamp;
     tsTeorical := (CalcBack * CT_NewLineSecondsAvg);
     tsReal := (ts1 - ts2);
     If (protocolVersion=CT_PROTOCOL_1) then begin
@@ -4104,7 +4109,7 @@ begin
     end else if (protocolVersion<=CT_PROTOCOL_5) then begin
       CalcBack := CalcBack DIV CT_CalcNewTargetLimitChange_SPLIT;
       If CalcBack=0 then CalcBack := 1;
-      ts2 := Block(BlocksCount-CalcBack-1).blockchainInfo.timestamp;
+      ts2 := GetBlockInfo(BlocksCount-CalcBack-1).timestamp;
       tsTeoricalStop := (CalcBack * CT_NewLineSecondsAvg);
       tsRealStop := (ts1 - ts2);
       { Protocol 2 change:
@@ -4131,6 +4136,11 @@ begin
   end;
 end;
 
+function TPCSafeBox.GetBlockInfo(ABlockNumber: Cardinal): TOperationBlock;
+begin
+  Result := GetBlock(ABlockNumber).blockchainInfo;
+end;
+
 function TPCSafeBox.GetActualCompactTargetHash(protocolVersion : Word): Cardinal;
 begin
   Result := TPascalCoinProtocol.TargetToCompact(GetActualTargetHash(protocolVersion),protocolVersion);
@@ -4195,6 +4205,31 @@ begin
   end;
 end;
 
+function TPCSafeBox.FindAccountsStartingByName(const AStartName: TRawBytes;
+  const ARawList: TOrderedRawList; const AMax: Integer = 0): Integer;
+var LIndex : Integer;
+begin
+  ARawList.Clear;
+  StartThreadSafe;
+  try
+
+    if FOrderedByName.Find(AStartName,LIndex) then begin
+      ARawList.Add( FOrderedByName.Get(LIndex), FOrderedByName.GetTag(LIndex) );
+      inc(LIndex);
+    end;
+    while (LIndex<FOrderedByName.Count) and (TBaseType.StartsWith(AStartName,FOrderedByName.Get(LIndex)))
+      and ((AMax<=0) or (AMax>ARawList.Count)) // AMax <=0 inifinte results
+      do begin
+      ARawList.Add( FOrderedByName.Get(LIndex), FOrderedByName.GetTag(LIndex) );
+      inc(LIndex);
+    end;
+
+    Result := ARawList.Count;
+  finally
+    EndThreadSave;
+  end;
+end;
+
 procedure TPCSafeBox.SearchBlockWhenOnSeparatedChain(blockNumber: Cardinal; out blockAccount: TBlockAccount);
   Function WasUpdatedBeforeOrigin : Boolean;
   var j, maxUB : Integer;
@@ -4217,7 +4252,7 @@ begin
     Exit;
   end else begin
     // Has not changed on my chain, must search on PreviousSafebox chain AT OriginStartPos
-    blockAccount := FPreviousSafeBox.Block(blockNumber);
+    blockAccount := FPreviousSafeBox.GetBlock(blockNumber);
     // Is valid?
     If WasUpdatedBeforeOrigin then Exit;
     //
@@ -4254,7 +4289,7 @@ begin
   iBlock := account_number DIV CT_AccountsPerBlock;
   iAccount := account_number MOD CT_AccountsPerBlock;
 
-  blockAccount := Block(iBlock);
+  blockAccount := GetBlock(iBlock);
   FModifiedBlocksPreviousState.AddIfNotExists(blockAccount);
   If Assigned(FPreviousSafeBox) then begin
     Pblock := Nil;

+ 24 - 6
src/core/UBaseTypes.pas

@@ -62,6 +62,8 @@ Type
     procedure FromString(const AValue : String); // Will store a RAW bytes assuming each char of the string is a byte -> ALERT: Do not use when the String contains chars encoded with multibyte character set!
     function Add(const ARawValue : TRawBytes) : TRawBytes; // Will concat a new RawBytes value to current value
     function IsEmpty : Boolean; // Will return TRUE when Length = 0
+    procedure FromStream(AStream : TStream); overload;
+    procedure FromStream(AStream : TStream; AStartPos, ALength : Integer); overload;
   end;
 
 
@@ -193,6 +195,18 @@ begin
   end else Result := '';
 end;
 
+procedure TRawBytesHelper.FromStream(AStream: TStream; AStartPos, ALength: Integer);
+begin
+  System.SetLength(Self,ALength);
+  AStream.Position := AStartPos;
+  AStream.Read(Self,ALength);
+end;
+
+procedure TRawBytesHelper.FromStream(AStream: TStream);
+begin
+  Self.FromStream(AStream,0,AStream.Size);
+end;
+
 procedure TRawBytesHelper.FromString(const AValue: String);
 var i : Integer;
 begin
@@ -443,20 +457,24 @@ begin
    Str2Len := Length(Str2);
    if ((Str1Len=0) and (Str2Len=0)) or (@Str1[Low(Str1)] = @Str2[Low(Str2)]) then
      Result := 0
-   else if (Str1Len < Str2Len) then
-     Result := -1
-   else if (Str1Len > Str2Len) then
-     Result := 1
    else begin
      Result := 0;
-     for i:= Low(Str1) to High(Str1) do begin
+     i := 0;
+     while (i<Length(Str1)) and (i<Length(Str2)) do begin
        if Str1[i] < Str2[i] then begin
          Result := -1;
          Break;
        end else if Str1[i] > Str2[i] then begin
          Result := 1;
          Break;
-       end
+       end;
+       inc(i);
+     end;
+     if (Result=0) then begin
+       if (Str1Len < Str2Len) then
+         Result := -1
+       else if (Str1Len > Str2Len) then
+         Result := 1;
      end;
    end;
 End;

+ 12 - 15
src/core/UBlockChain.pas

@@ -551,7 +551,7 @@ Type
     Procedure Clear;
     Function LoadOperations(Operations : TPCOperationsComp; Block : Cardinal) : Boolean;
     Property SafeBox : TPCSafeBox read FSafeBox;
-    Function AddNewBlockChainBlock(Operations: TPCOperationsComp; MaxAllowedTimestamp : Cardinal; var newBlock: TBlockAccount; var errors: String): Boolean;
+    Function AddNewBlockChainBlock(Operations: TPCOperationsComp; MaxAllowedTimestamp : Cardinal; var errors: String): Boolean;
     Procedure DiskRestoreFromOperations(max_block : Int64; restoreProgressNotify : TProgressNotify = Nil);
     Procedure UpdateValuesFromSafebox;
     Procedure NewLog(Operations: TPCOperationsComp; Logtype: TLogType; const Logtxt: String);
@@ -784,7 +784,7 @@ begin
   Result := FSafeBox.AccountsCount;
 end;
 
-function TPCBank.AddNewBlockChainBlock(Operations: TPCOperationsComp; MaxAllowedTimestamp : Cardinal; var newBlock: TBlockAccount; var errors: String): Boolean;
+function TPCBank.AddNewBlockChainBlock(Operations: TPCOperationsComp; MaxAllowedTimestamp : Cardinal; var errors: String): Boolean;
 Var i : Integer;
 begin
   TPCThread.ProtectEnterCriticalSection(Self,FBankLock);
@@ -810,8 +810,6 @@ begin
         exit;
       end;
 
-      newBlock := SafeBox.Block(SafeBox.BlocksCount-1);
-
       // Initialize values
       FLastOperationBlock := Operations.OperationBlock;
       // log it!
@@ -923,7 +921,6 @@ end;
 procedure TPCBank.DiskRestoreFromOperations(max_block : Int64; restoreProgressNotify : TProgressNotify = Nil);
 Var
   errors: String;
-  newBlock: TBlockAccount;
   n : Int64;
   tc, LStartProcessTC : TTickCount;
   LBlocks : TList<TPCOperationsComp>;
@@ -998,7 +995,7 @@ begin
             for i := 0 to LBlocks.Count-1 do begin
               inc(LProgressBlock);
               SetLength(errors,0);
-              if Not AddNewBlockChainBlock(LBlocks[i],0,newBlock,errors) then begin
+              if Not AddNewBlockChainBlock(LBlocks[i],0,errors) then begin
                 NewLog(LBlocks[i], lterror,'Error restoring block: ' + Inttostr(BlocksCount)+ ' Errors: ' + errors);
                 Storage.DeleteBlockChainBlocks(BlocksCount);
                 Exit;
@@ -1076,11 +1073,11 @@ function TPCBank.GetActualTargetSecondsAverage(BackBlocks: Cardinal): Real;
 Var ts1, ts2: Int64;
 begin
   if BlocksCount>BackBlocks then begin
-    ts1 := SafeBox.Block(BlocksCount-1).blockchainInfo.timestamp;
-    ts2 := SafeBox.Block(BlocksCount-BackBlocks-1).blockchainInfo.timestamp;
+    ts1 := SafeBox.GetBlockInfo(BlocksCount-1).timestamp;
+    ts2 := SafeBox.GetBlockInfo(BlocksCount-BackBlocks-1).timestamp;
   end else if (BlocksCount>1) then begin
-    ts1 := SafeBox.Block(BlocksCount-1).blockchainInfo.timestamp;
-    ts2 := SafeBox.Block(0).blockchainInfo.timestamp;
+    ts1 := SafeBox.GetBlockInfo(BlocksCount-1).timestamp;
+    ts2 := SafeBox.GetBlockInfo(0).timestamp;
     BackBlocks := BlocksCount-1;
   end else begin
     Result := 0;
@@ -1097,11 +1094,11 @@ begin
     exit;
   end;
   if FromBlock>BackBlocks then begin
-    ts1 := SafeBox.Block(FromBlock-1).blockchainInfo.timestamp;
-    ts2 := SafeBox.Block(FromBlock-BackBlocks-1).blockchainInfo.timestamp;
+    ts1 := SafeBox.GetBlockInfo(FromBlock-1).timestamp;
+    ts2 := SafeBox.GetBlockInfo(FromBlock-BackBlocks-1).timestamp;
   end else if (FromBlock>1) then begin
-    ts1 := SafeBox.Block(FromBlock-1).blockchainInfo.timestamp;
-    ts2 := SafeBox.Block(0).blockchainInfo.timestamp;
+    ts1 := SafeBox.GetBlockInfo(FromBlock-1).timestamp;
+    ts2 := SafeBox.GetBlockInfo(0).timestamp;
     BackBlocks := FromBlock-1;
   end else begin
     Result := 0;
@@ -1153,7 +1150,7 @@ begin
         Result := SafeBox.LoadSafeBoxFromStream(Stream,False,checkSafeboxHash,progressNotify,previousCheckedSafebox,LastReadBlock,errors);
       end;
       If Not Result then exit;
-      If SafeBox.BlocksCount>0 then FLastOperationBlock := SafeBox.Block(SafeBox.BlocksCount-1).blockchainInfo
+      If SafeBox.BlocksCount>0 then FLastOperationBlock := SafeBox.GetBlockInfo(SafeBox.BlocksCount-1)
       else begin
         FLastOperationBlock := TPCOperationsComp.GetFirstBlock;
         FLastOperationBlock.initial_safe_box_hash := TPCSafeBox.InitialSafeboxHash; // Genesis hash

+ 6 - 1
src/core/UCrypto.pas

@@ -332,6 +332,7 @@ begin
     ms.WriteBuffer(raw[Low(raw)],Length(raw));
     ms.Position := 0;
     if ms.Read(LNewPrivateKeyInfo.EC_OpenSSL_NID,sizeof(LNewPrivateKeyInfo.EC_OpenSSL_NID))<>sizeof(LNewPrivateKeyInfo.EC_OpenSSL_NID) then exit;
+    if Not TAccountComp.IsValidEC_OpenSSL_NID(LNewPrivateKeyInfo.EC_OpenSSL_NID) then Exit;
     If TStreamOp.ReadAnsiString(ms,aux)<0 then exit;
     {$IFDEF Use_OpenSSL}
     BNx := BN_bin2bn(PAnsiChar(aux),Length(aux),nil);
@@ -384,8 +385,12 @@ Var BNx,BNy : PBIGNUM;
   pub_key : PEC_POINT;
 {$ENDIF}
 begin
-{$IFDEF Use_OpenSSL}
   Result := False;
+  if Not TAccountComp.IsValidEC_OpenSSL_NID(PubKey.EC_OpenSSL_NID) then begin
+    errors := 'Invalid NID '+IntToStr(PubKey.EC_OpenSSL_NID);
+    Exit(False);
+  end;
+{$IFDEF Use_OpenSSL}
   BNx := BN_bin2bn(PAnsiChar(PubKey.x),length(PubKey.x),nil);
   if Not Assigned(BNx) then Exit;
   try

+ 9 - 13
src/core/UNetProtocol.pas

@@ -1574,7 +1574,7 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
 
           ant_nblock := auxBlock.block;
           //
-          sbBlock := TNode.Node.Bank.SafeBox.Block(auxBlock.block).blockchainInfo;
+          sbBlock := TNode.Node.Bank.SafeBox.GetBlockInfo(auxBlock.block);
           if TPCOperationsComp.EqualsOperationBlock(sbBlock,auxBlock) then begin
             distinctmin := auxBlock.block;
             OperationBlock := auxBlock;
@@ -1601,7 +1601,6 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
     OpComp,OpExecute : TPCOperationsComp;
     oldBlockchainOperations : TOperationsHashTree;
     opsResume : TOperationsResumeList;
-    newBlock : TBlockAccount;
     errors : String;
     start,start_c : Cardinal;
     finished : Boolean;
@@ -1663,7 +1662,7 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
                 break;
               end;
               TNode.Node.MarkVerifiedECDSASignaturesFromMemPool(OpExecute); // Improvement speed v4.0.2
-              if Bank.AddNewBlockChainBlock(OpExecute,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,newBlock,errors) then begin
+              if Bank.AddNewBlockChainBlock(OpExecute,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,errors) then begin
                 inc(i);
               end else begin
                 TLog.NewLog(lterror,CT_LogSender,'Error creating new bank with client Operations. Block:'+TPCOperationsComp.OperationBlockToText(OpExecute.OperationBlock)+' Error:'+errors);
@@ -1940,7 +1939,6 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
   var safeboxStream : TMemoryStream;
     newTmpBank : TPCBank;
     safebox_last_operation_block : TOperationBlock;
-    newBlock : TBlockAccount;
     opComp : TPCOperationsComp;
     errors : String;
     blocksList : TList<TPCOperationsComp>;
@@ -1982,7 +1980,7 @@ Const CT_LogSender = 'GetNewBlockChainFromClient';
                 end;
                 for i:=0 to blocksList.Count-1 do begin
                   opComp := TPCOperationsComp( blocksList[i] );
-                  if Not newTmpBank.AddNewBlockChainBlock(opComp,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,newBlock,errors) then begin
+                  if Not newTmpBank.AddNewBlockChainBlock(opComp,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,errors) then begin
                     TLog.NewLog(lterror,CT_LogSender,'Error adding new block with client Operations. Block:'+TPCOperationsComp.OperationBlockToText(opComp.OperationBlock)+' Error:'+errors);
                     // Add to blacklist !
                     Connection.DisconnectInvalidClient(false,'Invalid BlockChain on Block '+TPCOperationsComp.OperationBlockToText(opComp.OperationBlock)+' with errors:'+errors);
@@ -2907,7 +2905,6 @@ procedure TNetConnection.DoProcess_GetBlocks_Response(HeaderData: TNetHeaderData
     LOpCountCardinal,c : Cardinal;
     LOpCount : Integer;
     i : Integer;
-    newBlockAccount : TBlockAccount;
   errors : String;
   DoDisconnect : Boolean;
   LBlocks : TList<TPCOperationsComp>;
@@ -2964,13 +2961,13 @@ begin
 
       for i := 0 to LBlocks.Count-1 do begin
         if (LBlocks[i].OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
-          if (TNode.Node.Bank.AddNewBlockChainBlock(LBlocks[i],TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock, newBlockAccount,errors)) then begin
+          if (TNode.Node.Bank.AddNewBlockChainBlock(LBlocks[i],TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock, errors)) then begin
             // Ok, one more!
           end else begin
             // Is not a valid entry????
             // Perhaps an orphan blockchain: Me or Client!
             TLog.NewLog(ltinfo,Classname,'Distinct operation block found! My:'+
-                TPCOperationsComp.OperationBlockToText(TNode.Node.Bank.SafeBox.Block(TNode.Node.Bank.BlocksCount-1).blockchainInfo)+
+                TPCOperationsComp.OperationBlockToText(TNode.Node.Bank.SafeBox.GetBlockInfo(TNode.Node.Bank.BlocksCount-1))+
                 ' remote:'+TPCOperationsComp.OperationBlockToText(LBlocks[i].OperationBlock)+' Errors: '+errors);
           end;
         end else begin
@@ -3042,7 +3039,7 @@ begin
       b := b_start;
       total_b := 0;
       repeat
-        ob := TNode.Node.Bank.SafeBox.Block(b).blockchainInfo;
+        ob := TNode.Node.Bank.SafeBox.GetBlockInfo(b);
         If TPCOperationsComp.SaveOperationBlockToStream(ob,msops) then begin
           blocksstr := blocksstr + inttostr(b)+',';
           b := b + inc_b;
@@ -3266,7 +3263,7 @@ begin
       //
       opht := TOperationsHashTree.Create;
       try
-        If Not opht.LoadOperationsHashTreeFromStream(dataReceived,False,TNode.Node.Bank.SafeBox.CurrentProtocol,TNode.Node.Bank.SafeBox.CurrentProtocol,Nil,errors) then begin
+        If Not opht.LoadOperationsHashTreeFromStream(dataReceived,False,FRemoteOperationBlock.protocol_version,FRemoteOperationBlock.protocol_version,Nil,errors) then begin
           DisconnectInvalidClient(False,'Invalid operations hash tree stream: '+errors);
           Exit;
         end;
@@ -3815,8 +3812,7 @@ var operationsComp : TPCOperationsComp;
     DoDisconnect := False;
     Result := True;
   end;
-var bacc : TBlockAccount;
-  c : Cardinal;
+var c : Cardinal;
 begin
   errors := '';
   DoDisconnect := true;
@@ -3854,7 +3850,7 @@ begin
                 end;
               end;
             end;
-            If Not TNode.Node.AddNewBlockChain(Self,operationsComp,bacc,errors) then begin
+            If Not TNode.Node.AddNewBlockChain(Self,operationsComp,errors) then begin
               // Check valid header, if not, scammer... Disconnect
               if Not TPCSafeBox.IsValidOperationBlock(operationsComp.OperationBlock,errors) then begin
                 DoDisconnect := True;

+ 5 - 6
src/core/UNode.pas

@@ -93,7 +93,7 @@ Type
     function LockMempoolWrite : TPCOperationsComp;
     procedure UnlockMempoolWrite;
     //
-    Function AddNewBlockChain(SenderConnection : TNetConnection; NewBlockOperations: TPCOperationsComp; var newBlockAccount: TBlockAccount; var errors: String): Boolean;
+    Function AddNewBlockChain(SenderConnection : TNetConnection; NewBlockOperations: TPCOperationsComp; var errors: String): Boolean;
     Function AddOperations(SenderConnection : TNetConnection; AOperationsHashTreeToAdd : TOperationsHashTree; OperationsResult : TOperationsResumeList; var errors: String): Integer;
     Function AddOperation(SenderConnection : TNetConnection; Operation : TPCOperation; var errors: String): Boolean;
     Function SendNodeMessage(Target : TNetConnection; const TheMessage : String; var errors : String) : Boolean;
@@ -210,8 +210,7 @@ var _Node : TNode;
 
 { TNode }
 
-function TNode.AddNewBlockChain(SenderConnection: TNetConnection; NewBlockOperations: TPCOperationsComp;
-  var newBlockAccount: TBlockAccount; var errors: String): Boolean;
+function TNode.AddNewBlockChain(SenderConnection: TNetConnection; NewBlockOperations: TPCOperationsComp; var errors: String): Boolean;
 Var i,j,maxResend : Integer;
   nc : TNetConnection;
   s,sClientRemoteAddr : String;
@@ -255,7 +254,7 @@ begin
       MarkVerifiedECDSASignaturesFromMemPool(NewBlockOperations); // Improvement speed v4.0.2
       // Improvement TNode speed 2.1.6
       // Does not need to save a FOperations backup because is Sanitized by "TNode.OnBankNewBlock"
-      Result := Bank.AddNewBlockChainBlock(NewBlockOperations,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,newBlockAccount,errors);
+      Result := Bank.AddNewBlockChainBlock(NewBlockOperations,TNetData.NetData.NetworkAdjustedTime.GetMaxAllowedTimestampForNewBlock,errors);
       if Result then begin
         if Assigned(SenderConnection) then begin
           FNodeLog.NotifyNewLog(ltupdate,SenderConnection.ClassName,Format(';%d;%s;%s;;%d;%d;%d;%s',[OpBlock.block,sClientRemoteAddr,OpBlock.block_payload.ToPrintable,
@@ -877,7 +876,7 @@ end;
 
 class function TNode.NodeVersion: String;
 begin
-  Result := CT_ClientAppVersion{$IFDEF LINUX}+'L'{$ELSE}+'W'{$ENDIF}{$IFDEF FPC}{$IFDEF LCL}+'l'{$ELSE}+'f'{$ENDIF}{$ENDIF}{$IFDEF FPC}{$IFDEF CPU32}+'32b'{$ELSE}+'64b'{$ENDIF}{$ELSE}{$IFDEF CPU32BITS}+'32b'{$ELSE}+'64b'{$ENDIF}{$ENDIF};
+  Result := CT_ClientAppVersion{$IFDEF LINUX}+'L'{$ELSE}+'W'{$ENDIF}{$IFDEF FPC}{$IFDEF LCL}+'l'{$ELSE}+'f'{$ENDIF}{$ENDIF}{$IFDEF FPC}{$IFDEF CPU32}+'32b'{$ELSE}+'64b'{$ENDIF}{$ELSE}{$IFDEF CPU32BITS}+'32b'{$ELSE}+'64b'{$ENDIF}{$ENDIF}+'of';
 end;
 
 procedure TNode.Notification(AComponent: TComponent; Operation: TOperation);
@@ -1114,7 +1113,7 @@ begin
             Or
             (n_operation_high>n_operation_low) and (op.GetAccountN_Operation(account)<=n_operation) and (op.GetAccountN_Operation(account)>=n_operation_low) and (op.GetAccountN_Operation(account)<=n_operation_high) then begin
             TPCOperation.OperationToOperationResume(block,op,True,account,opr);
-            opr.time:=Bank.SafeBox.Block(block).blockchainInfo.timestamp;
+            opr.time:=Bank.SafeBox.GetBlockInfo(block).timestamp;
             opr.NOpInsideBlock:=i;
             opr.Balance:=-1;
             OpResumeList.Add(opr);

+ 28 - 9
src/core/UPCRPCFindAccounts.pas

@@ -27,7 +27,7 @@ interface
 Uses classes, SysUtils,
   UJSONFunctions, UAccounts, UBaseTypes, UOpTransaction, UConst,
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
-  URPC, UCrypto, UWallet, UBlockChain, ULog;
+  URPC, UCrypto, UWallet, UBlockChain, ULog, UPCOrderedLists;
 
 
 Type
@@ -149,7 +149,7 @@ var
   LErrors : String;
   LAccPubKey : TAccountKey;
   LOutput : TPCJSONArray;
-
+  LStartsWith : TOrderedRawList;
 begin
   // Get Parameters
   Result := False;
@@ -240,13 +240,32 @@ begin
     end;
   end else LSearchByPubkey := False;
   // Search by name
-  if ((Length(LAccountName)>0) AND (LSearchByNameType in [st_exact] )) then begin
-    LAccountNumber := ASender.Node.Bank.SafeBox.FindAccountByName(LAccountName);
-    if LAccountNumber >= 0 then begin
-      LAccount := ASender.Node.GetMempoolAccount(LAccountNumber);
-      if (_IsValidAccount(LAccount)) and
-        ((Not LSearchByPubkey) OR (TAccountComp.EqualAccountKeys(LAccPubKey,LAccount.accountInfo.accountKey))) then begin
-         TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
+  if ((Length(LAccountName)>0) AND (LSearchByNameType in [st_exact,st_startswith] )) then begin
+    if (LSearchByNameType in [st_exact]) then begin
+      LAccountNumber := ASender.Node.Bank.SafeBox.FindAccountByName(LAccountName);
+      if LAccountNumber >= 0 then begin
+        LAccount := ASender.Node.GetMempoolAccount(LAccountNumber);
+        if (_IsValidAccount(LAccount)) and
+          ((Not LSearchByPubkey) OR (TAccountComp.EqualAccountKeys(LAccPubKey,LAccount.accountInfo.accountKey))) then begin
+           TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
+        end;
+      end;
+    end else begin
+      // Starts-with indexed
+      LStartsWith := TOrderedRawList.Create;
+      try
+        LRaw.FromString(LAccountName);
+        ASender.Node.Bank.SafeBox.FindAccountsStartingByName(LRaw,LStartsWith,LMax);
+        for i := 0 to LStartsWith.Count-1 do begin
+          LAccountNumber := LStartsWith.GetTag(i);
+          LAccount := ASender.Node.GetMempoolAccount(LAccountNumber);
+          if (_IsValidAccount(LAccount)) and
+            ((Not LSearchByPubkey) OR (TAccountComp.EqualAccountKeys(LAccPubKey,LAccount.accountInfo.accountKey))) then begin
+             TPascalCoinJSONComp.FillAccountObject(LAccount,LOutput.GetAsObject(LOutput.Count));
+          end;
+        end;
+      finally
+        LStartsWith.Free;
       end;
     end;
   end else begin

+ 1 - 2
src/core/UPoolMining.pas

@@ -852,7 +852,6 @@ function TPoolMiningServer.MinerSubmit(Client: TJSONRPCTcpIpClient; params: TPCJ
 Var s : String;
   nbOperations : TPCOperationsComp;
   errors, sJobInfo : String;
-  nba : TBlockAccount;
   json : TPCJSONObject;
   p1,p2,p3 : TRawBytes;
   P : PPoolJob;
@@ -917,7 +916,7 @@ begin
       FPoolJobs.UnlockList;
     End;
     if Assigned(nbOperations) then begin
-      If FNodeNotifyEvents.Node.AddNewBlockChain(nil,nbOperations,nba,errors) then begin
+      If FNodeNotifyEvents.Node.AddNewBlockChain(nil,nbOperations,errors) then begin
         // CONGRATS !!!
         json := TPCJSONObject.Create;
         try

+ 1 - 1
src/core/URPC.pas

@@ -178,7 +178,7 @@ begin
     If ANode.Bank.BlocksCount<=nBlock then begin
       Exit;
     end;
-    ob := ANode.Bank.SafeBox.Block(nBlock).blockchainInfo;
+    ob := ANode.Bank.SafeBox.GetBlockInfo(nBlock);
 
     jsonObject.GetAsVariant('block').Value:=ob.block;
     jsonObject.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(ob.account_key));

+ 50 - 8
src/gui-classic/UFRMWalletKeys.pas

@@ -168,12 +168,24 @@ begin
   CheckIsWalletKeyValidPassword;
   if Not GetSelectedWalletKey(wk) then exit;
   if Assigned(wk.PrivateKey) then begin
-    if InputQueryPassword('Export private key','Insert a password to export',pwd1) then begin
-      if InputQueryPassword('Export private key','Repeat the password to export',pwd2) then begin
+    if InputQueryPassword('Export private key','Insert a password to export (empty for non encrypted)',pwd1) then begin
+      if InputQueryPassword('Export private key','Repeat the password to export (empty for non encrypted)',pwd2) then begin
         if pwd1<>pwd2 then raise Exception.Create('Passwords does not match!');
-        enc := TPCEncryption.DoPascalCoinAESEncrypt(wk.PrivateKey.ExportToRaw,TEncoding.ANSI.GetBytes(pwd1)).ToHexaString;
-        Clipboard.AsText := enc;
-        Application.MessageBox(PChar('The password has been encrypted with your password and copied to the clipboard.'+
+        if Length(pwd1)=0 then begin
+          enc := wk.PrivateKey.ExportToRaw.ToHexaString;
+          Clipboard.AsText := enc;
+          Application.MessageBox(PChar('Exported PRIVATE KEY without encryption'+
+          #10+#10+
+          'Key name: "'+wk.Name+'"'+#10+
+          #10+
+          'Exported value without encryption (Copied to the clipboard):'+#10+
+          enc+
+          #10+#10+'Length='+Inttostr(length(enc))+' bytes'),
+          PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
+        end else begin
+          enc := TPCEncryption.DoPascalCoinAESEncrypt(wk.PrivateKey.ExportToRaw,TEncoding.ANSI.GetBytes(pwd1)).ToHexaString;
+          Clipboard.AsText := enc;
+          Application.MessageBox(PChar('The PRIVATE KEY has been encrypted with your password and copied to the clipboard.'+
           #10+#10+
           'Password: "'+pwd1+'"'+#10+
           #10+
@@ -181,6 +193,7 @@ begin
           enc+
           #10+#10+'Length='+Inttostr(length(enc))+' bytes'),
           PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
+        end;
       end else raise Exception.Create('Cancelled operation');
     end;
   end;
@@ -283,6 +296,9 @@ var s : String;
   function ParseRawKey(EC_OpenSSL_NID : Word; const rawPrivateKey : TRawBytes) : boolean;
   begin
     FreeAndNil(EC); ParseRawKey := False;
+    // Check valid NID
+    if Not TAccountComp.IsValidEC_OpenSSL_NID(EC_OpenSSL_NID) then Exit(False);
+    //
     EC := TECPrivateKey.Create;
     Try
       EC.SetPrivateKeyFromHexa(EC_OpenSSL_NID, TCrypto.ToHexaString(rawPrivateKey));
@@ -295,6 +311,27 @@ var s : String;
     end;
   end;
 
+  function ParseUnencryptedKey(ARawUnencryptedPrivateKey : TRawBytes) : Boolean;
+  var LStream : TStream;
+    LNID : Word;
+    LRawPrivateKey : TRawBytes;
+  begin
+    Result := False;
+    LStream := TMemoryStream.Create;
+    try
+      LStream.WriteBuffer(ARawUnencryptedPrivateKey[Low(ARawUnencryptedPrivateKey)],Length(ARawUnencryptedPrivateKey));
+      LStream.Position := 0;
+      if LStream.Read(LNID,2)<>2 then Exit;
+      // Check valid NID
+      if Not TAccountComp.IsValidEC_OpenSSL_NID(LNID) then Exit;
+      // Try to parse
+      if TStreamOp.ReadAnsiString(LStream,LRawPrivateKey,LStream.Size - 4)<=0 then Exit;
+      Result := ParseRawKey(LNID,LRawPrivateKey);
+    finally
+      LStream.Free;
+    end;
+  end;
+
   function ParseEncryptedKey : boolean;
   var LRawPassword : TRawBytes;
   begin
@@ -328,6 +365,8 @@ var s : String;
       Until Length(desenc)>0;
   end;
 
+
+
 begin
   EC := Nil;
   CheckIsWalletKeyValidPassword;
@@ -337,16 +376,19 @@ begin
     if (s='') then raise Exception.Create('No valid key');
     enc := TCrypto.HexaToRaw(s);
     if Length(enc)=0 then raise Exception.Create('Invalid text... You must enter an hexadecimal value ("0".."9" or "A".."F")');
-    case Length(enc) of
+    // Allow unencrypted private keys
+    if Not ParseUnencryptedKey(enc) then begin
+      case Length(enc) of
          32: parseResult := ParseRawKey(CT_NID_secp256k1,enc);
          35,36: parseResult := ParseRawKey(CT_NID_sect283k1,enc);
          48: parseResult := ParseRawKey(CT_NID_secp384r1,enc);
          65,66: parseResult := ParseRawKey(CT_NID_secp521r1,enc);
          64, 80, 96: parseResult := ParseEncryptedKey;
          else Exception.Create('Invalidly formatted private key string. Ensure it is an encrypted private key export or raw private key hexstring.');
+      end;
+      if (parseResult = False) then
+        exit;
     end;
-    if (parseResult = False) then
-       exit;
     Try
       // EC is assigned by ParseRawKey/ImportEncryptedKey
       if Not Assigned(EC) then begin

+ 2 - 4
src/gui-classic/UGridUtils.pas

@@ -201,7 +201,6 @@ Type
     MinerPayload : TRawBytes;
     PoW : TRawBytes;
     SafeBoxHash : TRawBytes;
-    AccumulatedWork : UInt64;
     TimeAverage200 : Real;
     TimeAverage150 : Real;
     TimeAverage100 : Real;
@@ -275,7 +274,7 @@ Type
   End;
 
 Const
-  CT_TBlockChainData_NUL : TBlockChainData = (Block:0;Timestamp:0;BlockProtocolVersion:0;BlockProtocolAvailable:0;OperationsCount:-1;Volume:-1;Reward:0;Fee:0;Target:0;HashRateTargetHs:0;HashRateHs:0;HashRateTargetKhs:0;HashRateKhs:0;MinerPayload:Nil;PoW:Nil;SafeBoxHash:Nil;AccumulatedWork:0;TimeAverage200:0;TimeAverage150:0;TimeAverage100:0;TimeAverage75:0;TimeAverage50:0;TimeAverage25:0;TimeAverage10:0);
+  CT_TBlockChainData_NUL : TBlockChainData = (Block:0;Timestamp:0;BlockProtocolVersion:0;BlockProtocolAvailable:0;OperationsCount:-1;Volume:-1;Reward:0;Fee:0;Target:0;HashRateTargetHs:0;HashRateHs:0;HashRateTargetKhs:0;HashRateKhs:0;MinerPayload:Nil;PoW:Nil;SafeBoxHash:Nil;TimeAverage200:0;TimeAverage150:0;TimeAverage100:0;TimeAverage75:0;TimeAverage50:0;TimeAverage25:0;TimeAverage10:0);
   CT_TAccountsGridFilter_NUL : TAccountsGridFilter = (MinBalance:-1;MaxBalance:-1;OrderedAccountsKeyList:Nil;indexAccountsKeyList:-1);
 
 implementation
@@ -1407,7 +1406,7 @@ begin
     opc.bank := ANode.Bank;
     while (ABlockStart<=ABlockEnd) and (Not Terminated) do begin
       bcd := CT_TBlockChainData_NUL;
-      opb := ANode.Bank.SafeBox.Block(ABlockEnd).blockchainInfo;
+      opb := ANode.Bank.SafeBox.GetBlockInfo(ABlockEnd);
       bcd.Block:=opb.block;
       bcd.Timestamp := opb.timestamp;
       bcd.BlockProtocolVersion := opb.protocol_version;
@@ -1432,7 +1431,6 @@ begin
       bcd.MinerPayload := opb.block_payload;
       bcd.PoW := opb.proof_of_work;
       bcd.SafeBoxHash := opb.initial_safe_box_hash;
-      bcd.AccumulatedWork := ANode.Bank.SafeBox.Block(bcd.Block).AccumulatedWork;
       if (Not Terminated) then begin
         If (ANode.Bank.LoadOperations(opc,ABlockEnd)) then begin
           bcd.OperationsCount := opc.Count;