Browse Source

Added compatibility for V4 third party clients implementations

PascalCoin 5 years ago
parent
commit
febca94a12

+ 81 - 47
src/core/UBlockChain.pas

@@ -353,8 +353,8 @@ Type
     Procedure CopyFromHashTree(Sender : TOperationsHashTree);
     Procedure CopyFromHashTree(Sender : TOperationsHashTree);
     Property TotalAmount : Int64 read FTotalAmount;
     Property TotalAmount : Int64 read FTotalAmount;
     Property TotalFee : Int64 read FTotalFee;
     Property TotalFee : Int64 read FTotalFee;
-    function SaveOperationsHashTreeToStream(Stream: TStream; SaveToStorage : Boolean): Boolean;
-    function LoadOperationsHashTreeFromStream(Stream: TStream; LoadingFromStorage : Boolean; ASetOperationsToProtocolVersion : Word; ALoadVersion : Word; PreviousUpdatedBlocks : TAccountPreviousBlockInfo; var errors : String): Boolean;
+    function SaveOperationsHashTreeToStream(AStream: TStream; ASaveToStorage : Boolean): Boolean;
+    function LoadOperationsHashTreeFromStream(AStream: TStream; ALoadingFromStorage : Boolean; ASetOperationsToProtocolVersion : Word; ALoadFromStorageVersion : Word; APreviousUpdatedBlocks : TAccountPreviousBlockInfo; var AErrors : String): Boolean;
     function IndexOfOperation(op : TPCOperation) : Integer;
     function IndexOfOperation(op : TPCOperation) : Integer;
     function CountOperationsBySameSignerWithoutFee(account_number : Cardinal) : Integer;
     function CountOperationsBySameSignerWithoutFee(account_number : Cardinal) : Integer;
     Procedure Delete(index : Integer);
     Procedure Delete(index : Integer);
@@ -1221,8 +1221,8 @@ Begin
         errors := 'Bank blockcount<>OperationBlock.Block';
         errors := 'Bank blockcount<>OperationBlock.Block';
         exit;
         exit;
       end;
       end;
-      if OperationBlock.protocol_version <> op.ProtocolVersion then begin
-        errors := Format('Operation protocol:%d <> current protocol:%d on %s',[op.ProtocolVersion,OperationBlock.protocol_version, op.ToString]);
+      if OperationBlock.protocol_version < op.ProtocolVersion then begin
+        errors := Format('Operation protocol:%d > current protocol:%d on %s',[op.ProtocolVersion,OperationBlock.protocol_version, op.ToString]);
         Tlog.NewLog(lterror,ClassName,errors);
         Tlog.NewLog(lterror,ClassName,errors);
         Exit;
         Exit;
       end;
       end;
@@ -2616,60 +2616,85 @@ begin
   Index := L;
   Index := L;
 end;
 end;
 
 
-function TOperationsHashTree.LoadOperationsHashTreeFromStream(Stream: TStream; LoadingFromStorage : Boolean; ASetOperationsToProtocolVersion : Word; ALoadVersion : Word; PreviousUpdatedBlocks : TAccountPreviousBlockInfo; var errors: String): Boolean;
+function TOperationsHashTree.LoadOperationsHashTreeFromStream(AStream: TStream; ALoadingFromStorage : Boolean; ASetOperationsToProtocolVersion : Word; ALoadFromStorageVersion : Word; APreviousUpdatedBlocks : TAccountPreviousBlockInfo; var AErrors : String): Boolean;
 Var c, i: Cardinal;
 Var c, i: Cardinal;
-  OpType: Cardinal;
-  bcop: TPCOperation;
+  LOpTypeWord : Word;
+  LOpProtocolVersion : Word;
+  LOperation: TPCOperation;
   j: Integer;
   j: Integer;
-  OpClass: TPCOperationClass;
-  lastNE : TNotifyEvent;
+  LOpClass: TPCOperationClass;
+  LLastNE : TNotifyEvent;
 begin
 begin
   Result := false;
   Result := false;
   //
   //
-  If Stream.Read(c, 4)<4 then begin
-    errors := 'Cannot read operations count';
-    exit;
+  If AStream.Read(c, 4)<4 then begin
+    AErrors := 'Cannot read operations count';
+    Exit;
   end;
   end;
-  lastNE := FOnChanged;
+  LLastNE := FOnChanged;
   FOnChanged:=Nil;
   FOnChanged:=Nil;
   try
   try
     // c = operations count
     // c = operations count
     for i := 1 to c do begin
     for i := 1 to c do begin
-      if Stream.Size - Stream.Position < 4 then begin
-        errors := 'Invalid operation structure ' + inttostr(i) + '/' + inttostr(c);
-        exit;
+      if AStream.Size - AStream.Position < 4 then begin
+        AErrors := 'Invalid operation structure ' + inttostr(i) + '/' + inttostr(c);
+        Exit;
+      end;
+      // New proposal for V5:
+      // Previously (V4 and below) didn't saved which protocol was used for an
+      // operation. That didn't allowed to save info based on protocol version
+      // On V4 the "OpType" was saved using a 4 bytes (uInt32) little endian
+      // but OpType is always a value <=255 so only 1 byte is needed.
+      // On V5 the first 2 bytes will be the "OpType" and the other 2 bytes
+      // will be used to store Protocol (5) or (0 = Protocol 4) that will
+      // allow fully compatiblity with third party clients that save operations
+      // On V4:
+      // AStream.Read(LOpTypeCardinal, 4);
+      // On V5:
+      AStream.Read(LOpTypeWord, 2);
+      AStream.Read(LOpProtocolVersion, 2);
+      if LOpProtocolVersion=0 then begin
+        // For backward compatibility (not saved protocol version)
+        // will assume that is a version from V1..V4
+        if (ASetOperationsToProtocolVersion <= CT_PROTOCOL_4) {$IFDEF TESTNET}or (ALoadingFromStorage){$ENDIF} then
+          LOpProtocolVersion := ASetOperationsToProtocolVersion
+        else LOpProtocolVersion := CT_PROTOCOL_4;
+      end;
+      if (LOpProtocolVersion<1) or (LOpProtocolVersion>ASetOperationsToProtocolVersion) then begin
+        AErrors := 'Invalid protocol version '+IntToStr(LOpProtocolVersion)+' ('+IntToStr(ASetOperationsToProtocolVersion)+') found at ' + inttostr(i) + '/' + inttostr(c) + ' with optype:' + InttoHex(LOpTypeWord, 2);
+        Exit;
       end;
       end;
-      Stream.Read(OpType, 4);
-      j := TPCOperationsComp.IndexOfOperationClassByOpType(OpType);
+
+      j := TPCOperationsComp.IndexOfOperationClassByOpType(LOpTypeWord);
       if j >= 0 then
       if j >= 0 then
-        OpClass := _OperationsClass[j]
+        LOpClass := _OperationsClass[j]
       else
       else
-        OpClass := Nil;
-      if Not Assigned(OpClass) then begin
-        errors := 'Invalid operation structure ' + inttostr(i) + '/' + inttostr(c) + ' optype not valid:' + InttoHex(OpType, 4);
-        exit;
+        LOpClass := Nil;
+      if Not Assigned(LOpClass) then begin
+        AErrors := 'Invalid operation structure ' + inttostr(i) + '/' + inttostr(c) + ' optype not valid:' + InttoHex(LOpTypeWord, 2);
+        Exit;
       end;
       end;
-      bcop := OpClass.Create(ASetOperationsToProtocolVersion);
+      LOperation := LOpClass.Create(LOpProtocolVersion);
       Try
       Try
-        if LoadingFromStorage then begin
-          If not bcop.LoadFromStorage(Stream,ALoadVersion,PreviousUpdatedBlocks) then begin
-            errors := 'Invalid operation load from storage ' + inttostr(i) + '/' + inttostr(c)+' Class:'+OpClass.ClassName;
-            exit;
+        if ALoadingFromStorage then begin
+          If not LOperation.LoadFromStorage(AStream,ALoadFromStorageVersion,APreviousUpdatedBlocks) then begin
+            AErrors := 'Invalid operation load from storage ' + inttostr(i) + '/' + inttostr(c)+' Class:'+LOpClass.ClassName;
+            Exit;
           end;
           end;
-        end else if not bcop.LoadFromNettransfer(Stream) then begin
-          errors := 'Invalid operation load from stream ' + inttostr(i) + '/' + inttostr(c)+' Class:'+OpClass.ClassName;
-          exit;
+        end else if not LOperation.LoadFromNettransfer(AStream) then begin
+          AErrors := 'Invalid operation load from stream ' + inttostr(i) + '/' + inttostr(c)+' Class:'+LOpClass.ClassName;
+          Exit;
         end;
         end;
-        AddOperationToHashTree(bcop);
+        AddOperationToHashTree(LOperation);
       Finally
       Finally
-        FreeAndNil(bcop);
+        FreeAndNil(LOperation);
       end;
       end;
     end;
     end;
   finally
   finally
-    FOnChanged := lastNE;
+    FOnChanged := LLastNE;
   end;
   end;
   If Assigned(FOnChanged) then FOnChanged(Self);
   If Assigned(FOnChanged) then FOnChanged(Self);
-  errors := '';
+  AErrors := '';
   Result := true;
   Result := true;
 end;
 end;
 
 
@@ -2744,22 +2769,31 @@ begin
   End;
   End;
 end;
 end;
 
 
-function TOperationsHashTree.SaveOperationsHashTreeToStream(Stream: TStream; SaveToStorage: Boolean): Boolean;
-Var c, i, OpType: Cardinal;
-  bcop: TPCOperation;
-  l : TList<Pointer>;
+function TOperationsHashTree.SaveOperationsHashTreeToStream(AStream: TStream; ASaveToStorage: Boolean): Boolean;
+Var c, i : Cardinal;
+  LOpTypeWord : Word;
+  LOpProtocol : Word;
+  LOperation: TPCOperation;
+  Llist : TList<Pointer>;
 begin
 begin
-  l := FHashTreeOperations.LockList;
+  LList := FHashTreeOperations.LockList;
   Try
   Try
-    c := l.Count;
-    Stream.Write(c, 4);
+    c := Llist.Count;
+    AStream.Write(c, 4);
     // c = operations count
     // c = operations count
     for i := 1 to c do begin
     for i := 1 to c do begin
-      bcop := GetOperation(i - 1);
-      OpType := bcop.OpType;
-      Stream.write(OpType, 4);
-      if SaveToStorage then bcop.SaveToStorage(Stream)
-      else bcop.SaveToNettransfer(Stream);
+      LOperation := GetOperation(i - 1);
+      LOpTypeWord := LOperation.OpType;
+      if LOperation.ProtocolVersion >= CT_PROTOCOL_5 then
+        LOpProtocol := LOperation.ProtocolVersion
+      else LOpProtocol := 0;
+      // On V5 will save LOpProtocol when LOperation.ProtocolVersion >= V5
+      // On V4 LOpProtocol was not saved (always 0): AStream.write(OpType, 4);
+      AStream.Write(LOpTypeWord,2);
+      AStream.Write(LOpProtocol,2);
+
+      if ASaveToStorage then LOperation.SaveToStorage(AStream)
+      else LOperation.SaveToNettransfer(AStream);
     end;
     end;
     Result := true;
     Result := true;
   Finally
   Finally

+ 1 - 1
src/core/UConst.pas

@@ -132,7 +132,7 @@ Const
   CT_NetProtocol_Version: Word = $0009; // Version 4.0.2 Will allow only net protocol 9
   CT_NetProtocol_Version: Word = $0009; // Version 4.0.2 Will allow only net protocol 9
   // IMPORTANT NOTE!!!
   // IMPORTANT NOTE!!!
   // NetProtocol_Available MUST BE always >= NetProtocol_version
   // NetProtocol_Available MUST BE always >= NetProtocol_version
-  CT_NetProtocol_Available: Word = {$IFDEF PRODUCTION}$0009{$ELSE}$0009{$ENDIF};  // Version 4.0.0 will start accepting protocol 8 but 4.0.1 will accept 9 due to 4.0.0 bug
+  CT_NetProtocol_Available: Word = {$IFDEF PRODUCTION}$0009{$ELSE}$000A{$ENDIF};  //
 
 
   CT_MaxAccountOperationsPerBlockWithoutFee = 1;
   CT_MaxAccountOperationsPerBlockWithoutFee = 1;
 
 

+ 43 - 35
src/core/UOpTransaction.pas

@@ -490,8 +490,10 @@ end;
 
 
 function TOpChangeAccountInfo.DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean;
 function TOpChangeAccountInfo.DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean;
 Var account_signer, account_target : TAccount;
 Var account_signer, account_target : TAccount;
+  LSafeboxCurrentProtocol : Integer;
 begin
 begin
   Result := false;
   Result := false;
+  LSafeboxCurrentProtocol := AccountTransaction.FreezedSafeBox.CurrentProtocol;
   if (FData.account_signer>=AccountTransaction.FreezedSafeBox.AccountsCount) then begin
   if (FData.account_signer>=AccountTransaction.FreezedSafeBox.AccountsCount) then begin
     errors := 'Invalid account number';
     errors := 'Invalid account number';
     Exit;
     Exit;
@@ -526,7 +528,7 @@ begin
   end;
   end;
   if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
   if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
     errors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
     errors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
-    If (ProtocolVersion>=CT_PROTOCOL_2) then begin
+    If (LSafeboxCurrentProtocol>=CT_PROTOCOL_2) then begin
       Exit; // BUG from protocol 1
       Exit; // BUG from protocol 1
     end;
     end;
   end;
   end;
@@ -535,12 +537,12 @@ begin
     errors := 'Account signer is currently locked';
     errors := 'Account signer is currently locked';
     exit;
     exit;
   end;
   end;
-  if (ProtocolVersion<CT_PROTOCOL_2) then begin
+  if (LSafeboxCurrentProtocol<CT_PROTOCOL_2) then begin
     errors := 'NOT ALLOWED ON PROTOCOL 1';
     errors := 'NOT ALLOWED ON PROTOCOL 1';
     exit;
     exit;
   end;
   end;
   If (public_key in FData.changes_type) then begin
   If (public_key in FData.changes_type) then begin
-    If Not TAccountComp.IsValidAccountKey( FData.new_accountkey, ProtocolVersion, errors) then begin
+    If Not TAccountComp.IsValidAccountKey( FData.new_accountkey, LSafeboxCurrentProtocol, errors) then begin
       exit;
       exit;
     end;
     end;
   end;
   end;
@@ -803,13 +805,13 @@ Var s_new, t_new : Int64;
   LTotalAmount : Cardinal;
   LTotalAmount : Cardinal;
   LSender,LTarget,LSeller : TAccount;
   LSender,LTarget,LSeller : TAccount;
   LRecipientSignable, LIsCoinSwap : Boolean;
   LRecipientSignable, LIsCoinSwap : Boolean;
-  LCurrentBlock, LCurrentProtocol : Integer;
+  LCurrentBlock, LSafeboxCurrentProtocol : Integer;
   LBuyAccountNewPubkey : TAccountKey;
   LBuyAccountNewPubkey : TAccountKey;
 begin
 begin
   Result := false;
   Result := false;
   AErrors := '';
   AErrors := '';
   LCurrentBlock := ASafeBoxTransaction.FreezedSafeBox.BlocksCount;
   LCurrentBlock := ASafeBoxTransaction.FreezedSafeBox.BlocksCount;
-  LCurrentProtocol := ProtocolVersion;
+  LSafeboxCurrentProtocol := ASafeboxTransaction.FreezedSafeBox.CurrentProtocol;
 
 
   {$region 'Common Validation'}
   {$region 'Common Validation'}
 
 
@@ -835,7 +837,7 @@ begin
   end;
   end;
   if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
   if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
     AErrors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
     AErrors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
-    If (LCurrentProtocol>=CT_PROTOCOL_2) then begin
+    If (LSafeboxCurrentProtocol>=CT_PROTOCOL_2) then begin
       Exit; // BUG from protocol 1
       Exit; // BUG from protocol 1
     end;
     end;
   end;
   end;
@@ -849,10 +851,10 @@ begin
   //  - TIME LOCK not expired
   //  - TIME LOCK not expired
   LRecipientSignable :=
   LRecipientSignable :=
     ( FData.opTransactionStyle = buy_Account )
     ( FData.opTransactionStyle = buy_Account )
-    And (TAccountComp.IsOperationRecipientSignable(LSender, LTarget, LCurrentBlock, LCurrentProtocol));
+    And (TAccountComp.IsOperationRecipientSignable(LSender, LTarget, LCurrentBlock, LSafeboxCurrentProtocol));
 
 
   LIsCoinSwap := TAccountComp.IsAccountForCoinSwap(LTarget.accountInfo)
   LIsCoinSwap := TAccountComp.IsAccountForCoinSwap(LTarget.accountInfo)
-    And (TAccountComp.IsAccountForSaleOrSwapAcceptingTransactions(LTarget, LCurrentBlock, LCurrentProtocol, FData.payload.payload_raw));
+    And (TAccountComp.IsAccountForSaleOrSwapAcceptingTransactions(LTarget, LCurrentBlock, LSafeboxCurrentProtocol, FData.payload.payload_raw));
 
 
   if (FData.sender=FData.target) AND (NOT LRecipientSignable) then begin
   if (FData.sender=FData.target) AND (NOT LRecipientSignable) then begin
     AErrors := Format('Sender=Target and Target is not recipient-signable. Account: %d',[FData.sender]);
     AErrors := Format('Sender=Target and Target is not recipient-signable. Account: %d',[FData.sender]);
@@ -908,7 +910,7 @@ begin
   // Is buy account ?
   // Is buy account ?
   if (FData.opTransactionStyle = buy_Account ) then begin
   if (FData.opTransactionStyle = buy_Account ) then begin
     {$region 'Buy Account Validation'}
     {$region 'Buy Account Validation'}
-    if (LCurrentProtocol<CT_PROTOCOL_2) then begin
+    if (LSafeboxCurrentProtocol<CT_PROTOCOL_2) then begin
       AErrors := 'Buy account is not allowed on Protocol 1';
       AErrors := 'Buy account is not allowed on Protocol 1';
       exit;
       exit;
     end;
     end;
@@ -918,7 +920,7 @@ begin
       Exit;
       Exit;
     end;
     end;
 
 
-    if (LCurrentProtocol < CT_PROTOCOL_5) then begin
+    if (LSafeboxCurrentProtocol < CT_PROTOCOL_5) then begin
       if (TAccountComp.IsAccountForSwap(LTarget.accountInfo)) then begin
       if (TAccountComp.IsAccountForSwap(LTarget.accountInfo)) then begin
         AErrors := 'Atomic swaps are not allowed until Protocol 5';
         AErrors := 'Atomic swaps are not allowed until Protocol 5';
         exit;
         exit;
@@ -964,7 +966,7 @@ begin
       AErrors := Format('Signed price (%d) is not the same of account price (%d)',[FData.AccountPrice,LTarget.accountInfo.price]);
       AErrors := Format('Signed price (%d) is not the same of account price (%d)',[FData.AccountPrice,LTarget.accountInfo.price]);
       exit;
       exit;
     end;
     end;
-    if NOT TAccountComp.IsValidNewAccountKey(LTarget.accountInfo, FData.new_accountkey, LCurrentProtocol) then begin
+    if NOT TAccountComp.IsValidNewAccountKey(LTarget.accountInfo, FData.new_accountkey, LSafeboxCurrentProtocol) then begin
       AErrors := Format('Specified new public key for %d does not equal (or is not valid) the new public key stored in account: %s <> %s',
       AErrors := Format('Specified new public key for %d does not equal (or is not valid) the new public key stored in account: %s <> %s',
       [LTarget.account,
       [LTarget.account,
        TAccountComp.AccountKey2RawString(LTarget.accountInfo.new_publicKey).ToHexaString,
        TAccountComp.AccountKey2RawString(LTarget.accountInfo.new_publicKey).ToHexaString,
@@ -972,23 +974,23 @@ begin
       exit;
       exit;
     end;
     end;
 
 
-    If Not (TAccountComp.IsValidAccountKey(FData.new_accountkey,ProtocolVersion,AErrors)) then exit;
+    If Not (TAccountComp.IsValidAccountKey(FData.new_accountkey,LSafeboxCurrentProtocol,AErrors)) then exit;
     LBuyAccountNewPubkey := FData.new_accountkey;
     LBuyAccountNewPubkey := FData.new_accountkey;
     {$endregion}
     {$endregion}
   end else if // (is auto buy) OR (is transaction that can buy)
   end else if // (is auto buy) OR (is transaction that can buy)
               (
               (
                 (FData.opTransactionStyle in [transaction,transaction_with_auto_buy_account,transaction_with_auto_atomic_swap]) AND
                 (FData.opTransactionStyle in [transaction,transaction_with_auto_buy_account,transaction_with_auto_atomic_swap]) AND
-                (LCurrentProtocol >= CT_PROTOCOL_2) AND
-                (TAccountComp.IsAccountForSaleOrSwapAcceptingTransactions(LTarget, LCurrentBlock, LCurrentProtocol, FData.payload.payload_raw)) AND
+                (LSafeboxCurrentProtocol >= CT_PROTOCOL_2) AND
+                (TAccountComp.IsAccountForSaleOrSwapAcceptingTransactions(LTarget, LCurrentBlock, LSafeboxCurrentProtocol, FData.payload.payload_raw)) AND
                 ((LTarget.balance + FData.amount >= LTarget.accountInfo.price))
                 ((LTarget.balance + FData.amount >= LTarget.accountInfo.price))
               )  then begin
               )  then begin
     {$region 'Transaction Auto Buy Validation'}
     {$region 'Transaction Auto Buy Validation'}
-    if (LCurrentProtocol<CT_PROTOCOL_2) then begin
+    if (LSafeboxCurrentProtocol<CT_PROTOCOL_2) then begin
       AErrors := 'Tx-Buy account is not allowed on Protocol 1';
       AErrors := 'Tx-Buy account is not allowed on Protocol 1';
       exit;
       exit;
     end;
     end;
 
 
-    If (LCurrentProtocol<CT_PROTOCOL_5) then begin
+    If (LSafeboxCurrentProtocol<CT_PROTOCOL_5) then begin
       if (TAccountComp.IsAccountForSwap( LTarget.accountInfo )) then begin
       if (TAccountComp.IsAccountForSwap( LTarget.accountInfo )) then begin
         AErrors := 'Tx-Buy atomic swaps are not allowed until Protocol 5';
         AErrors := 'Tx-Buy atomic swaps are not allowed until Protocol 5';
         exit;
         exit;
@@ -996,14 +998,14 @@ begin
         // the below line was a bug fix that introduced a new bug, and is retained here for
         // the below line was a bug fix that introduced a new bug, and is retained here for
         // V2-V4 consistency
         // V2-V4 consistency
         //------
         //------
-        if Not (TAccountComp.IsValidAccountKey(FData.new_accountkey,ProtocolVersion,AErrors)) then exit;
+        if Not (TAccountComp.IsValidAccountKey(FData.new_accountkey,LSafeboxCurrentProtocol,AErrors)) then exit;
         //------
         //------
       end;
       end;
     end;
     end;
 
 
     // Check that stored "new_publicKey" is valid (when not in coin swap)
     // Check that stored "new_publicKey" is valid (when not in coin swap)
     if (Not TAccountComp.IsAccountForCoinSwap(LTarget.accountInfo)) and
     if (Not TAccountComp.IsAccountForCoinSwap(LTarget.accountInfo)) and
-       (Not (TAccountComp.IsValidAccountKey(LTarget.accountInfo.new_publicKey,ProtocolVersion,AErrors))) then exit;
+       (Not (TAccountComp.IsValidAccountKey(LTarget.accountInfo.new_publicKey,LSafeboxCurrentProtocol,AErrors))) then exit;
 
 
     // NOTE: This is a Transaction opereation (not a buy account operation) that
     // NOTE: This is a Transaction opereation (not a buy account operation) that
     // has some "added" effects (private sale, swap...)
     // has some "added" effects (private sale, swap...)
@@ -1042,13 +1044,13 @@ begin
 
 
   if (FData.opTransactionStyle in [buy_account, transaction_with_auto_buy_account, transaction_with_auto_atomic_swap]) then begin
   if (FData.opTransactionStyle in [buy_account, transaction_with_auto_buy_account, transaction_with_auto_atomic_swap]) then begin
     // account purchase
     // account purchase
-    if (LCurrentProtocol<CT_PROTOCOL_2) then begin
+    if (LSafeboxCurrentProtocol<CT_PROTOCOL_2) then begin
       AErrors := 'NOT ALLOWED ON PROTOCOL 1';
       AErrors := 'NOT ALLOWED ON PROTOCOL 1';
       exit;
       exit;
     end;
     end;
 
 
     if (LTarget.accountInfo.state in [as_ForAtomicAccountSwap, as_ForAtomicCoinSwap]) AND
     if (LTarget.accountInfo.state in [as_ForAtomicAccountSwap, as_ForAtomicCoinSwap]) AND
-       (LCurrentProtocol<CT_PROTOCOL_5) then begin
+       (LSafeboxCurrentProtocol<CT_PROTOCOL_5) then begin
       AErrors := 'NOT ALLOWED UNTIL PROTOCOL 5';
       AErrors := 'NOT ALLOWED UNTIL PROTOCOL 5';
       exit;
       exit;
     end;
     end;
@@ -1417,8 +1419,10 @@ end;
 
 
 function TOpChangeKey.DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean;
 function TOpChangeKey.DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean;
 Var account_signer, account_target : TAccount;
 Var account_signer, account_target : TAccount;
+  LSafeboxCurrentProtocol : Integer;
 begin
 begin
   Result := false;
   Result := false;
+  LSafeboxCurrentProtocol := AccountTransaction.FreezedSafeBox.CurrentProtocol;
   if (FData.account_signer>=AccountTransaction.FreezedSafeBox.AccountsCount) then begin
   if (FData.account_signer>=AccountTransaction.FreezedSafeBox.AccountsCount) then begin
     errors := 'Invalid account number';
     errors := 'Invalid account number';
     Exit;
     Exit;
@@ -1453,7 +1457,7 @@ begin
   end;
   end;
   if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
   if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
     errors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
     errors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
-    If (ProtocolVersion>=CT_PROTOCOL_2) then begin
+    If (LSafeboxCurrentProtocol>=CT_PROTOCOL_2) then begin
       Exit; // BUG from protocol 1
       Exit; // BUG from protocol 1
     end;
     end;
   end;
   end;
@@ -1462,11 +1466,11 @@ begin
     errors := 'Account signer is currently locked';
     errors := 'Account signer is currently locked';
     exit;
     exit;
   end;
   end;
-  If Not TAccountComp.IsValidAccountKey( FData.new_accountkey,ProtocolVersion,errors) then begin
+  If Not TAccountComp.IsValidAccountKey( FData.new_accountkey,LSafeboxCurrentProtocol,errors) then begin
     exit;
     exit;
   end;
   end;
   // NEW v2 protocol protection: Does not allow to change key for same key
   // NEW v2 protocol protection: Does not allow to change key for same key
-  if (ProtocolVersion>=CT_PROTOCOL_2) then begin
+  if (LSafeboxCurrentProtocol>=CT_PROTOCOL_2) then begin
     if (TAccountComp.EqualAccountKeys(account_target.accountInfo.accountKey,FData.new_accountkey)) then begin
     if (TAccountComp.EqualAccountKeys(account_target.accountInfo.accountKey,FData.new_accountkey)) then begin
       errors := 'New public key is the same public key';
       errors := 'New public key is the same public key';
       exit;
       exit;
@@ -1490,7 +1494,7 @@ begin
       errors := 'Signer and target accounts have different public key';
       errors := 'Signer and target accounts have different public key';
       exit;
       exit;
     end;
     end;
-    if (ProtocolVersion<CT_PROTOCOL_2) then begin
+    if (LSafeboxCurrentProtocol<CT_PROTOCOL_2) then begin
       errors := 'NOT ALLOWED ON PROTOCOL 1';
       errors := 'NOT ALLOWED ON PROTOCOL 1';
       exit;
       exit;
     end;
     end;
@@ -1739,8 +1743,10 @@ end;
 
 
 function TOpRecoverFounds.DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean;
 function TOpRecoverFounds.DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean;
 Var acc : TAccount;
 Var acc : TAccount;
+  LSafeboxCurrentProtocol : Integer;
 begin
 begin
   Result := false;
   Result := false;
+  LSafeboxCurrentProtocol := AccountTransaction.FreezedSafeBox.CurrentProtocol;
   if TAccountComp.IsAccountBlockedByProtocol(FData.account,AccountTransaction.FreezedSafeBox.BlocksCount) then begin
   if TAccountComp.IsAccountBlockedByProtocol(FData.account,AccountTransaction.FreezedSafeBox.BlocksCount) then begin
     errors := 'account is blocked for protocol';
     errors := 'account is blocked for protocol';
     Exit;
     Exit;
@@ -1770,7 +1776,7 @@ begin
     errors := 'Insuficient funds';
     errors := 'Insuficient funds';
     exit;
     exit;
   end;
   end;
-  if Not TAccountComp.IsValidAccountKey(FData.new_accountkey,ProtocolVersion,errors) then begin
+  if Not TAccountComp.IsValidAccountKey(FData.new_accountkey,LSafeboxCurrentProtocol,errors) then begin
     Exit;
     Exit;
   end;
   end;
   Result := AccountTransaction.UpdateAccountInfo(AccountPreviousUpdatedBlock,
   Result := AccountTransaction.UpdateAccountInfo(AccountPreviousUpdatedBlock,
@@ -1911,7 +1917,7 @@ function TOpListAccount.DoOperation(AccountPreviousUpdatedBlock : TAccountPrevio
 Var
 Var
   account_signer, account_target : TAccount;
   account_signer, account_target : TAccount;
   LIsDelist, LIsSale, LIsPrivateSale, LIsPublicSale, LIsSwap, LIsAccountSwap, LIsCoinSwap : boolean;
   LIsDelist, LIsSale, LIsPrivateSale, LIsPublicSale, LIsSwap, LIsAccountSwap, LIsCoinSwap : boolean;
-  LCurrentProtocol : Integer;
+  LSafeboxCurrentProtocol : Integer;
 begin
 begin
   Result := false;
   Result := false;
   // Determine which flow this function will execute
   // Determine which flow this function will execute
@@ -1943,12 +1949,12 @@ begin
     LIsCoinSwap := false;
     LIsCoinSwap := false;
   end;
   end;
 
 
-  LCurrentProtocol := ProtocolVersion;
-  if (LCurrentProtocol<CT_PROTOCOL_2) then begin
+  LSafeboxCurrentProtocol := AccountTransaction.FreezedSafeBox.CurrentProtocol;
+  if (LSafeboxCurrentProtocol<CT_PROTOCOL_2) then begin
     errors := 'List/Delist Account is not allowed on Protocol 1';
     errors := 'List/Delist Account is not allowed on Protocol 1';
     exit;
     exit;
   end;
   end;
-  if LIsSwap AND (LCurrentProtocol<CT_PROTOCOL_5) then begin
+  if LIsSwap AND (LSafeboxCurrentProtocol<CT_PROTOCOL_5) then begin
     errors := 'Atomic Swaps are not allowed before Protocol 5';
     errors := 'Atomic Swaps are not allowed before Protocol 5';
     exit;
     exit;
   end;
   end;
@@ -2000,11 +2006,11 @@ begin
       exit;
       exit;
     end;
     end;
     if LIsPrivateSale OR LIsAccountSwap then begin
     if LIsPrivateSale OR LIsAccountSwap then begin
-      If Not TAccountComp.IsValidAccountKey( FData.new_public_key,ProtocolVersion,errors) then begin
+      If Not TAccountComp.IsValidAccountKey( FData.new_public_key,LSafeboxCurrentProtocol,errors) then begin
         errors := 'Invalid new public key: '+errors;
         errors := 'Invalid new public key: '+errors;
         exit;
         exit;
       end;
       end;
-    end else if (LCurrentProtocol>=CT_PROTOCOL_5) then begin
+    end else if (LSafeboxCurrentProtocol>=CT_PROTOCOL_5) then begin
       // COIN SWAP or PUBLIC SALE must set FData.new_public_key to NULL
       // COIN SWAP or PUBLIC SALE must set FData.new_public_key to NULL
       if Not TAccountComp.IsNullAccountKey(FData.new_public_key) then begin
       if Not TAccountComp.IsNullAccountKey(FData.new_public_key) then begin
         errors := 'Coin swap/Public sale needs a NULL new public key';
         errors := 'Coin swap/Public sale needs a NULL new public key';
@@ -2360,7 +2366,7 @@ begin
     ms.Write(FData.account_price,Sizeof(FData.account_price));
     ms.Write(FData.account_price,Sizeof(FData.account_price));
     ms.Write(FData.account_to_pay,Sizeof(FData.account_to_pay));
     ms.Write(FData.account_to_pay,Sizeof(FData.account_to_pay));
     ms.Write(FData.fee,Sizeof(FData.fee));
     ms.Write(FData.fee,Sizeof(FData.fee));
-    if ProtocolVersion>=CT_PROTOCOL_5 then begin
+    if FProtocolVersion>=CT_PROTOCOL_5 then begin
       ms.Write(FData.payload.payload_type,SizeOf(FData.payload.payload_type));
       ms.Write(FData.payload.payload_type,SizeOf(FData.payload.payload_type));
     end;
     end;
     if Length(FData.payload.payload_raw)>0 then
     if Length(FData.payload.payload_raw)>0 then
@@ -2375,12 +2381,12 @@ begin
       ms.WriteBuffer(s[Low(s)],Length(s));
       ms.WriteBuffer(s[Low(s)],Length(s));
     ms.Write(FData.locked_until_block,Sizeof(FData.locked_until_block));
     ms.Write(FData.locked_until_block,Sizeof(FData.locked_until_block));
     // VERSION 5: write the new account state and hash-lock
     // VERSION 5: write the new account state and hash-lock
-    if (ProtocolVersion >= CT_PROTOCOL_5) then begin
+    if (FProtocolVersion >= CT_PROTOCOL_5) then begin
       w := Word(FData.account_state);
       w := Word(FData.account_state);
       ms.Write(w, 2);
       ms.Write(w, 2);
       TStreamOp.WriteAnsiString(ms, FData.hash_lock); // the hash-lock if any
       TStreamOp.WriteAnsiString(ms, FData.hash_lock); // the hash-lock if any
     end;
     end;
-    if (ProtocolVersion<=CT_PROTOCOL_3) then begin
+    if (FProtocolVersion<=CT_PROTOCOL_3) then begin
       ms.Position := 0;
       ms.Position := 0;
       SetLength(Result,ms.Size);
       SetLength(Result,ms.Size);
       ms.ReadBuffer(Result[Low(Result)],ms.Size);
       ms.ReadBuffer(Result[Low(Result)],ms.Size);
@@ -2652,9 +2658,11 @@ function TOpData.DoOperation(
   AccountPreviousUpdatedBlock: TAccountPreviousBlockInfo;
   AccountPreviousUpdatedBlock: TAccountPreviousBlockInfo;
   AccountTransaction: TPCSafeBoxTransaction; var errors: String): Boolean;
   AccountTransaction: TPCSafeBoxTransaction; var errors: String): Boolean;
 Var account_signer, account_sender, account_target : TAccount;
 Var account_signer, account_sender, account_target : TAccount;
+  LSafeboxCurrentProtocol : Integer;
 begin
 begin
   Result := false;
   Result := false;
-  if (ProtocolVersion<CT_PROTOCOL_4) then begin
+  LSafeboxCurrentProtocol := AccountTransaction.FreezedSafeBox.CurrentProtocol;
+  if (LSafeboxCurrentProtocol<CT_PROTOCOL_4) then begin
     errors := 'OpData is not allowed on Protocol < 4';
     errors := 'OpData is not allowed on Protocol < 4';
     exit;
     exit;
   end;
   end;

+ 4 - 2
src/core/UTxMultiOperation.pas

@@ -557,11 +557,13 @@ var i,j : Integer;
   senders,senders_n_operation,receivers : Array of Cardinal;
   senders,senders_n_operation,receivers : Array of Cardinal;
   senders_amount : Array of UInt64;
   senders_amount : Array of UInt64;
   receivers_amount : Array of UInt64;
   receivers_amount : Array of UInt64;
+  LSafeboxCurrentProtocol : Integer;
 begin
 begin
   // Check valid info:
   // Check valid info:
   Result := False;
   Result := False;
   errors := '';
   errors := '';
-  if (AccountTransaction.FreezedSafeBox.CurrentProtocol<CT_PROTOCOL_3) then begin
+  LSafeboxCurrentProtocol := AccountTransaction.FreezedSafeBox.CurrentProtocol;
+  if (LSafeboxCurrentProtocol<CT_PROTOCOL_3) then begin
     errors := 'NEED PROTOCOL 3';
     errors := 'NEED PROTOCOL 3';
     exit;
     exit;
   end;
   end;
@@ -670,7 +672,7 @@ begin
       exit;
       exit;
     end;
     end;
     If (public_key in chi.Changes_type) then begin
     If (public_key in chi.Changes_type) then begin
-      If Not TAccountComp.IsValidAccountKey( chi.New_Accountkey, ProtocolVersion, errors) then begin
+      If Not TAccountComp.IsValidAccountKey( chi.New_Accountkey, LSafeboxCurrentProtocol, errors) then begin
         Exit;
         Exit;
       end;
       end;
     end;
     end;

+ 3 - 3
src/gui-classic/UFRMOperationsExplorer.pas

@@ -684,7 +684,7 @@ begin
   If Assigned(op) then begin
   If Assigned(op) then begin
     mOperationInfo.Lines.Add(Format('%s',[op.ToString]));
     mOperationInfo.Lines.Add(Format('%s',[op.ToString]));
     mOperationInfo.Lines.Add('');
     mOperationInfo.Lines.Add('');
-    mOperationInfo.Lines.Add(Format('OpType:%d ClassName:%s',[op.OpType,op.ClassName]));
+    mOperationInfo.Lines.Add(Format('OpType:%d ClassName:%s Protocol:%d',[op.OpType,op.ClassName,op.ProtocolVersion]));
     l := TList<Cardinal>.Create;
     l := TList<Cardinal>.Create;
     Try
     Try
       op.AffectedAccounts(l); aux := '';
       op.AffectedAccounts(l); aux := '';
@@ -707,7 +707,7 @@ begin
       mOperationInfo.Lines.Add(Format('Size: %.2f Kb (%d bytes)',[ms.Size/1024,ms.Size]));
       mOperationInfo.Lines.Add(Format('Size: %.2f Kb (%d bytes)',[ms.Size/1024,ms.Size]));
       ms.Position:=0;
       ms.Position:=0;
       SetLength(raw,ms.Size);
       SetLength(raw,ms.Size);
-      ms.ReadBuffer(raw[1],ms.Size);
+      ms.ReadBuffer(raw[0],ms.Size);
       mOperationExport.Lines.Text := TCrypto.ToHexaString(raw);
       mOperationExport.Lines.Text := TCrypto.ToHexaString(raw);
     finally
     finally
       ms.Free;
       ms.Free;
@@ -739,7 +739,7 @@ begin
       if (opht.OperationsCount>0) then begin
       if (opht.OperationsCount>0) then begin
         ms.Position:=0;
         ms.Position:=0;
         SetLength(raw,ms.Size);
         SetLength(raw,ms.Size);
-        ms.ReadBuffer(raw[1],ms.Size);
+        ms.ReadBuffer(raw[0],ms.Size);
         mOperationExport.Lines.Text := TCrypto.ToHexaString(raw);
         mOperationExport.Lines.Text := TCrypto.ToHexaString(raw);
         jsonObj := TPCJSONObject.Create;
         jsonObj := TPCJSONObject.Create;
         Try
         Try