Browse Source

Fixed FastPropagation bug caused by V4 to V5 upgrade

PascalCoin 5 years ago
parent
commit
d7ef72f71e
2 changed files with 79 additions and 21 deletions
  1. 57 7
      src/core/UBlockChain.pas
  2. 22 14
      src/core/UNetProtocol.pas

+ 57 - 7
src/core/UBlockChain.pas

@@ -278,7 +278,8 @@ Type
     function GetOpID : TRawBytes; // OPID is RipeMD160 hash of the operation
     function GetOpID : TRawBytes; // OPID is RipeMD160 hash of the operation
     //
     //
     function GetOperationStreamData : TBytes;
     function GetOperationStreamData : TBytes;
-    class function GetOperationFromStreamData(ACurrentProtocol: word; StreamData : TBytes) : TPCOperation;
+    function GetOperationStreamData_OLD_V4_Version : TBytes; // deprecated
+    class function GetOperationFromStreamData(AUseV5EncodeStyle : Boolean; ACurrentProtocol: word; StreamData : TBytes) : TPCOperation;
     //
     //
     function IsValidSignatureBasedOnCurrentSafeboxState(ASafeBoxTransaction : TPCSafeBoxTransaction) : Boolean; virtual; abstract;
     function IsValidSignatureBasedOnCurrentSafeboxState(ASafeBoxTransaction : TPCSafeBoxTransaction) : Boolean; virtual; abstract;
   End;
   End;
@@ -2972,27 +2973,47 @@ begin
   end else Raise Exception.Create('ERROR DEV 20170426-1'); // This should never happen, if good coded
   end else Raise Exception.Create('ERROR DEV 20170426-1'); // This should never happen, if good coded
 end;
 end;
 
 
-class function TPCOperation.GetOperationFromStreamData(ACurrentProtocol: word; StreamData : TBytes): TPCOperation;
+class function TPCOperation.GetOperationFromStreamData(AUseV5EncodeStyle : Boolean; ACurrentProtocol: word; StreamData : TBytes): TPCOperation;
   // Loads an TPCOperation saved using "GetOperationStreamData"
   // Loads an TPCOperation saved using "GetOperationStreamData"
-  // 1 byte for OpType
+  // For compatiblity will allow V4..V5 encode stype
+  // Old V4: 1 byte for OpType
+  // New V5: 2 bytes for OpType and 2 bytes for ProtocolVersion
   // N bytes for Operation specific data (saved at SaveOpToStream)
   // N bytes for Operation specific data (saved at SaveOpToStream)
+  //
+  // NOTE:
+  // AFTER V5 activation, all nodes must use new AUseV5EcnodeStyle = TRUE
 Var stream : TStream;
 Var stream : TStream;
   b : Byte;
   b : Byte;
   j: Integer;
   j: Integer;
   OpClass: TPCOperationClass;
   OpClass: TPCOperationClass;
   auxOp: TPCOperation;
   auxOp: TPCOperation;
+  LOpType, LOperationProtocolVersion : Word;
 begin
 begin
   Result := Nil;
   Result := Nil;
   stream := TMemoryStream.Create;
   stream := TMemoryStream.Create;
   Try
   Try
     stream.WriteBuffer(StreamData[0],Length(StreamData)); // Fixed bug 4.0.0
     stream.WriteBuffer(StreamData[0],Length(StreamData)); // Fixed bug 4.0.0
     stream.Position := 0;
     stream.Position := 0;
-    stream.Read(b,1);
-    j := TPCOperationsComp.IndexOfOperationClassByOpType(b);
+
+    if (AUseV5EncodeStyle) then begin
+      // 2 bytes (UInt16) for OpType
+      // 2 bytes (UInt16) for ProtocolVersion
+      Stream.Read(LOpType,2);
+      Stream.Read(LOperationProtocolVersion,2);
+      if (LOperationProtocolVersion<=0) or (LOperationProtocolVersion>CT_BUILD_PROTOCOL) then Exit;
+    end else begin
+      // 1 bytes (UInt8) for OpType
+      // Fixed ProtocolVersion = 4
+      stream.Read(b,1);
+      LOpType := b;
+      LOperationProtocolVersion:=ACurrentProtocol;
+    end;
+
+    j := TPCOperationsComp.IndexOfOperationClassByOpType(LOpType);
     if j >= 0 then
     if j >= 0 then
       OpClass := _OperationsClass[j]
       OpClass := _OperationsClass[j]
     else Exit;
     else Exit;
-    auxOp := OpClass.Create(ACurrentProtocol);
+    auxOp := OpClass.Create(LOperationProtocolVersion);
     if auxOp.LoadOpFromStream(stream,False) then Result := auxOp
     if auxOp.LoadOpFromStream(stream,False) then Result := auxOp
     else auxOp.Free;
     else auxOp.Free;
   Finally
   Finally
@@ -3000,10 +3021,14 @@ begin
   End;
   End;
 end;
 end;
 
 
-function TPCOperation.GetOperationStreamData: TBytes;
+function TPCOperation.GetOperationStreamData_OLD_V4_Version: TBytes;
   // OperationStreamData fills an array of bytes with info needed to store an operation
   // OperationStreamData fills an array of bytes with info needed to store an operation
   // 1 byte for OpType
   // 1 byte for OpType
   // N bytes for Operation specific data (saved at SaveOpToStream)
   // N bytes for Operation specific data (saved at SaveOpToStream)
+
+  //
+  // THIS FUNCTION IS DEPRECATED, Usable only for V4 to V5 upgrade process
+  //
 var stream : TStream;
 var stream : TStream;
   b : Byte;
   b : Byte;
 begin
 begin
@@ -3020,6 +3045,31 @@ begin
   End;
   End;
 end;
 end;
 
 
+function TPCOperation.GetOperationStreamData: TBytes;
+  // OperationStreamData fills an array of bytes with info needed to store an operation
+  // 2 bytes for OpType
+  // 2 bytes for ProtocolVersion
+  // N bytes for Operation specific data (saved at SaveOpToStream)
+var stream : TStream;
+  LOpType, LOperationProtocolVersion : Word;
+begin
+  stream := TMemoryStream.Create;
+  Try
+    LOpType := Self.OpType;
+    LOperationProtocolVersion := Self.ProtocolVersion;
+
+    Stream.Write(LOpType,2);
+    Stream.Write(LOperationProtocolVersion,2);
+
+    SaveOpToStream(stream,False);
+    SetLength(Result,stream.Size);
+    stream.Position := 0;
+    stream.ReadBuffer(Result[0],stream.Size); // Fixed bug 4.0.0
+  Finally
+    stream.Free;
+  End;
+end;
+
 function TPCOperation.GetOpID: TRawBytes;
 function TPCOperation.GetOpID: TRawBytes;
 begin
 begin
   Result := RipeMD160;
   Result := RipeMD160;

+ 22 - 14
src/core/UNetProtocol.pas

@@ -399,9 +399,9 @@ Type
     Procedure DoProcess_Message(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_Message(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetBlocks_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetBlocks_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetBlocks_Response(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetBlocks_Response(HeaderData : TNetHeaderData; DataBuffer: TStream);
-    Procedure DoProcess_GetBlockchainOperations_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
+    Procedure DoProcess_GetBlockchainOperations_Request(AHeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetOperationsBlock_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetOperationsBlock_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
-    Procedure DoProcess_NewBlock(HeaderData : TNetHeaderData; DataBuffer: TStream);
+    Procedure DoProcess_NewBlock(AHeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_AddOperations(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_AddOperations(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetSafeBox_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetSafeBox_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetPendingOperations_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetPendingOperations_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
@@ -2719,7 +2719,7 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TNetConnection.DoProcess_GetBlockchainOperations_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
+procedure TNetConnection.DoProcess_GetBlockchainOperations_Request(AHeaderData: TNetHeaderData; DataBuffer: TStream);
   {
   {
   As described on PIP-0015 this will return Operations stored in a specified Block of the Blockchain
   As described on PIP-0015 this will return Operations stored in a specified Block of the Blockchain
   Input:
   Input:
@@ -2761,7 +2761,7 @@ begin
   DoDisconnect := true;
   DoDisconnect := true;
   outputBuffer := TMemoryStream.Create;
   outputBuffer := TMemoryStream.Create;
   try
   try
-    if HeaderData.header_type<>ntp_request then begin
+    if AHeaderData.header_type<>ntp_request then begin
       errors := 'Not request';
       errors := 'Not request';
       Exit;
       Exit;
     end;
     end;
@@ -2784,7 +2784,11 @@ begin
         opc := GetBlock(bufferOperationsBlock, cBlock);
         opc := GetBlock(bufferOperationsBlock, cBlock);
         if Assigned(opc) then begin
         if Assigned(opc) then begin
           if (cBlockOpIndex<opc.Count) then begin
           if (cBlockOpIndex<opc.Count) then begin
-            opsdata := opc.Operation[cBlockOpIndex].GetOperationStreamData;
+            if AHeaderData.protocol.protocol_available >= 11 then begin
+              opsdata := opc.Operation[cBlockOpIndex].GetOperationStreamData;
+            end else begin
+              opsdata := opc.Operation[cBlockOpIndex].GetOperationStreamData_OLD_V4_Version;
+            end;
             c := Length(opsdata);
             c := Length(opsdata);
             outputBuffer.Write(c,SizeOf(c));
             outputBuffer.Write(c,SizeOf(c));
             outputBuffer.WriteBuffer(opsdata[0],Length(opsdata)); // Fixed bug 4.0.0
             outputBuffer.WriteBuffer(opsdata[0],Length(opsdata)); // Fixed bug 4.0.0
@@ -2803,7 +2807,7 @@ begin
       DoDisconnect := False;
       DoDisconnect := False;
       // Send back
       // Send back
       outputBuffer.Position := 0;
       outputBuffer.Position := 0;
-      Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,outputBuffer);
+      Send(ntp_response,AHeaderData.operation,0,AHeaderData.request_id,outputBuffer);
     Finally
     Finally
       opindexdata.Free;
       opindexdata.Free;
       for i := 0 to bufferOperationsBlock.Count-1 do begin
       for i := 0 to bufferOperationsBlock.Count-1 do begin
@@ -2814,7 +2818,7 @@ begin
   finally
   finally
     outputBuffer.Free;
     outputBuffer.Free;
     if DoDisconnect then begin
     if DoDisconnect then begin
-      DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
+      DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(AHeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
     end;
     end;
   end;
   end;
 end;
 end;
@@ -3672,11 +3676,12 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TNetConnection.DoProcess_NewBlock(HeaderData: TNetHeaderData; DataBuffer: TStream);
+procedure TNetConnection.DoProcess_NewBlock(AHeaderData: TNetHeaderData; DataBuffer: TStream);
 Type
 Type
   TNewFastPropagationBlockOperation = Record
   TNewFastPropagationBlockOperation = Record
     opReference : TOpReference;
     opReference : TOpReference;
     opStreamData : TBytes;
     opStreamData : TBytes;
+    opStreamDataUsingV5EncodeStyle : Boolean;
   end;
   end;
   TNewFastPropagationBlockOperationsArray = Array of TNewFastPropagationBlockOperation;
   TNewFastPropagationBlockOperationsArray = Array of TNewFastPropagationBlockOperation;
 
 
@@ -3690,7 +3695,7 @@ var operationsComp : TPCOperationsComp;
     i,iNodeOpReference : Integer;
     i,iNodeOpReference : Integer;
     sendStream, receiveStream : TStream;
     sendStream, receiveStream : TStream;
     block_op_ref : UInt64;
     block_op_ref : UInt64;
-    headerData : TNetHeaderData;
+    LHeaderData : TNetHeaderData;
     auxOp : TPCOperation;
     auxOp : TPCOperation;
     tc : TTickCount;
     tc : TTickCount;
     original_OperationBlock : TOperationBlock;
     original_OperationBlock : TOperationBlock;
@@ -3710,6 +3715,7 @@ var operationsComp : TPCOperationsComp;
       for i := 0 to Integer(Integer(oprefcount)-1) do begin
       for i := 0 to Integer(Integer(oprefcount)-1) do begin
         if DataBuffer.Read(nfpboarr[i].opReference,SizeOf(TOpReference))<>SizeOf(TOpReference) then Exit;
         if DataBuffer.Read(nfpboarr[i].opReference,SizeOf(TOpReference))<>SizeOf(TOpReference) then Exit;
         SetLength(nfpboarr[i].opStreamData,0);
         SetLength(nfpboarr[i].opStreamData,0);
+        nfpboarr[i].opStreamDataUsingV5EncodeStyle:=False;
       end;
       end;
     end;
     end;
     DoDisconnect := False;
     DoDisconnect := False;
@@ -3726,6 +3732,7 @@ var operationsComp : TPCOperationsComp;
             iNodeOpReference := LLockedMempool.OperationsHashTree.IndexOfOpReference(nfpboarr[i].opReference);
             iNodeOpReference := LLockedMempool.OperationsHashTree.IndexOfOpReference(nfpboarr[i].opReference);
             if iNodeOpReference>=0 then begin
             if iNodeOpReference>=0 then begin
               nfpboarr[i].opStreamData := LLockedMempool.OperationsHashTree.GetOperation(iNodeOpReference).GetOperationStreamData;
               nfpboarr[i].opStreamData := LLockedMempool.OperationsHashTree.GetOperation(iNodeOpReference).GetOperationStreamData;
+              nfpboarr[i].opStreamDataUsingV5EncodeStyle:=True; // Flag to indicate that opStreamData is saved in V5 format
             end else begin
             end else begin
               inc(notFoundOpReferencesCount);
               inc(notFoundOpReferencesCount);
             end;
             end;
@@ -3756,12 +3763,12 @@ var operationsComp : TPCOperationsComp;
           end;
           end;
         end;
         end;
         // Send & wait
         // Send & wait
-        if Not DoSendAndWaitForResponse(CT_NetOp_GetBlockchainOperations,TNetData.NetData.NewRequestId,sendStream,receiveStream,5000,headerData) then begin
+        if Not DoSendAndWaitForResponse(CT_NetOp_GetBlockchainOperations,TNetData.NetData.NewRequestId,sendStream,receiveStream,5000,LHeaderData) then begin
           TLog.NewLog(ltdebug,ClassName,Format('Not received Pending operations (%d of %d) in Fast propagation block %d',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block]));
           TLog.NewLog(ltdebug,ClassName,Format('Not received Pending operations (%d of %d) in Fast propagation block %d',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block]));
           Exit;
           Exit;
         end;
         end;
         DoDisconnect := True; // If bad received data... then DoDisconnect
         DoDisconnect := True; // If bad received data... then DoDisconnect
-        if (headerData.is_error) then Exit;
+        if (LHeaderData.is_error) then Exit;
         receiveStream.Position := 0;
         receiveStream.Position := 0;
         receiveStream.Read(c,SizeOf(c));
         receiveStream.Read(c,SizeOf(c));
         if (c<>notFoundOpReferencesCount) then Exit; // Error!
         if (c<>notFoundOpReferencesCount) then Exit; // Error!
@@ -3773,6 +3780,7 @@ var operationsComp : TPCOperationsComp;
             if receiveStream.Size - receiveStream.Position < c then Exit; // Not enough received data
             if receiveStream.Size - receiveStream.Position < c then Exit; // Not enough received data
             SetLength(nfpboarr[i].opStreamData,c);
             SetLength(nfpboarr[i].opStreamData,c);
             receiveStream.ReadBuffer(nfpboarr[i].opStreamData[0],c); // Fixed bug 4.0.0
             receiveStream.ReadBuffer(nfpboarr[i].opStreamData[0],c); // Fixed bug 4.0.0
+            nfpboarr[i].opStreamDataUsingV5EncodeStyle := (LHeaderData.protocol.protocol_available>=11)
           end;
           end;
         end;
         end;
         DoDisconnect := False;
         DoDisconnect := False;
@@ -3783,7 +3791,7 @@ var operationsComp : TPCOperationsComp;
     end;
     end;
     // Now we have nfpboarr with full data
     // Now we have nfpboarr with full data
     for i := 0 to High(nfpboarr) do begin
     for i := 0 to High(nfpboarr) do begin
-      auxOp := TPCOperation.GetOperationFromStreamData(original_OperationBlock.protocol_version,  nfpboarr[i].opStreamData );
+      auxOp := TPCOperation.GetOperationFromStreamData( (nfpboarr[i].opStreamDataUsingV5EncodeStyle), original_OperationBlock.protocol_version , nfpboarr[i].opStreamData );
       if not Assigned(auxOp) then begin
       if not Assigned(auxOp) then begin
         errors := Format('Op index not available (%d/%d) OpReference:%d size:%d',[i,High(nfpboarr),nfpboarr[i].opReference,Length(nfpboarr[i].opStreamData)]);
         errors := Format('Op index not available (%d/%d) OpReference:%d size:%d',[i,High(nfpboarr),nfpboarr[i].opReference,Length(nfpboarr[i].opStreamData)]);
         Exit;
         Exit;
@@ -3823,7 +3831,7 @@ begin
   errors := '';
   errors := '';
   DoDisconnect := true;
   DoDisconnect := true;
   try
   try
-    if HeaderData.header_type<>ntp_autosend then begin
+    if AHeaderData.header_type<>ntp_autosend then begin
       errors := 'Not autosend';
       errors := 'Not autosend';
       exit;
       exit;
     end;
     end;
@@ -3879,7 +3887,7 @@ begin
     end;
     end;
   finally
   finally
     if DoDisconnect then begin
     if DoDisconnect then begin
-      DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
+      DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(AHeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
     end;
     end;
   end;
   end;
 end;
 end;