Browse Source

PIP-0015 CT_NetOp_GetBlockchainOperations

Implemented second step described at PIP-0015 and updated testnet version to 3.0.5
PascalCoin 6 years ago
parent
commit
02f57e044d

+ 53 - 2
src/core/UBlockChain.pas

@@ -23,7 +23,7 @@ unit UBlockChain;
 interface
 interface
 
 
 uses
 uses
-  Classes, UCrypto, UAccounts, ULog, UThread, SyncObjs, UBaseTypes;
+  Classes, UCrypto, UAccounts, ULog, UThread, SyncObjs, UBaseTypes, SysUtils;
 {$I config.inc}
 {$I config.inc}
 
 
 {
 {
@@ -251,6 +251,9 @@ Type
     class function GetOpReferenceN_Operation(const opReference : TOpReference) : Cardinal;
     class function GetOpReferenceN_Operation(const opReference : TOpReference) : Cardinal;
     function Sha256 : TRawBytes;
     function Sha256 : TRawBytes;
     function GetOpReference : TOpReference;
     function GetOpReference : TOpReference;
+    //
+    function GetOperationStreamData : TBytes;
+    class function GetOperationFromStreamData(StreamData : TBytes) : TPCOperation;
   End;
   End;
 
 
   { TOperationsHashTree }
   { TOperationsHashTree }
@@ -496,7 +499,7 @@ Const
 implementation
 implementation
 
 
 uses
 uses
-  SysUtils, Variants,
+  Variants,
   UTime, UConst, UOpTransaction;
   UTime, UConst, UOpTransaction;
 
 
 { TPCBank }
 { TPCBank }
@@ -2419,6 +2422,54 @@ 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(StreamData : TBytes): TPCOperation;
+  // Loads an TPCOperation saved using "GetOperationStreamData"
+  // 1 byte for OpType
+  // N bytes for Operation specific data (saved at SaveOpToStream)
+Var stream : TStream;
+  b : Byte;
+  j: Integer;
+  OpClass: TPCOperationClass;
+  auxOp: TPCOperation;
+begin
+  Result := Nil;
+  stream := TMemoryStream.Create;
+  Try
+    stream.WriteBuffer(StreamData,Length(StreamData));
+    stream.Position := 0;
+    stream.Read(b,1);
+    j := TPCOperationsComp.IndexOfOperationClassByOpType(b);
+    if j >= 0 then
+      OpClass := _OperationsClass[j]
+    else Exit;
+    auxOp := OpClass.Create;
+    if auxOp.LoadOpFromStream(stream,False) then Result := auxOp
+    else auxOp.Free;
+  Finally
+    stream.Free;
+  End;
+end;
+
+function TPCOperation.GetOperationStreamData: TBytes;
+  // OperationStreamData fills an array of bytes with info needed to store an operation
+  // 1 byte for OpType
+  // N bytes for Operation specific data (saved at SaveOpToStream)
+var stream : TStream;
+  b : Byte;
+begin
+  stream := TMemoryStream.Create;
+  Try
+    b := OpType;
+    stream.Write(b,1);
+    SaveOpToStream(stream,False);
+    SetLength(Result,stream.Size);
+    stream.Position := 0;
+    stream.ReadBuffer(Result,stream.Size);
+  Finally
+    stream.Free;
+  End;
+end;
+
 function TPCOperation.GetOpReference: TOpReference;
 function TPCOperation.GetOpReference: TOpReference;
   // Described on PIP-0015 by Herman Schoenfeld
   // Described on PIP-0015 by Herman Schoenfeld
   // Will return a 64 bit value composed by SignerAccount (first 4 bytes) and n_Operation (last 4 bytes)
   // Will return a 64 bit value composed by SignerAccount (first 4 bytes) and n_Operation (last 4 bytes)

+ 1 - 1
src/core/UConst.pas

@@ -167,7 +167,7 @@ Const
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Receiver              = 104;
   CT_OpSubtype_Data_Receiver              = 104;
 
 
-  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'3.0.2'{$ELSE}{$IFDEF TESTNET}'TESTNET 3.0.4'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'3.0.2'{$ELSE}{$IFDEF TESTNET}'TESTNET 3.0.5'{$ELSE}{$ENDIF}{$ENDIF};
 
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.dynamic-dns.net;pascalcoin2.dynamic-dns.net;pascalcoin1.dns1.us;pascalcoin2.dns1.us;pascalcoin1.dns2.us;pascalcoin2.dns2.us'{$IFDEF TESTNET}+';99.254.181.147;159.89.12.242;18.236.158.185'{$ENDIF};
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.dynamic-dns.net;pascalcoin2.dynamic-dns.net;pascalcoin1.dns1.us;pascalcoin2.dns1.us;pascalcoin1.dns2.us;pascalcoin2.dns2.us'{$IFDEF TESTNET}+';99.254.181.147;159.89.12.242;18.236.158.185'{$ENDIF};
 
 

+ 235 - 59
src/core/UNetProtocol.pas

@@ -45,6 +45,7 @@ Const
   CT_NetOp_GetBlocks            = $0010;
   CT_NetOp_GetBlocks            = $0010;
   CT_NetOp_NewBlock             = $0011;
   CT_NetOp_NewBlock             = $0011;
   CT_NetOp_NewBlock_Fast_Propagation = $0012; // New V4 protocol: Allows PIP-0015 Fast block propagation
   CT_NetOp_NewBlock_Fast_Propagation = $0012; // New V4 protocol: Allows PIP-0015 Fast block propagation
+  CT_NetOp_GetBlockchainOperations   = $0013; // New V4 protocol: Allows PIP-0015 Fast block propagation
   CT_NetOp_AddOperations        = $0020;
   CT_NetOp_AddOperations        = $0020;
   CT_NetOp_GetSafeBox           = $0021; // V2 Protocol: Allows to send/receive Safebox in chunk parts
   CT_NetOp_GetSafeBox           = $0021; // V2 Protocol: Allows to send/receive Safebox in chunk parts
 
 
@@ -71,6 +72,8 @@ Const
   CT_MIN_NODESERVERS_BUFFER = 50;
   CT_MIN_NODESERVERS_BUFFER = 50;
   CT_MAX_NODESERVERS_BUFFER = 300;
   CT_MAX_NODESERVERS_BUFFER = 300;
 
 
+  CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS = 10000;
+
 Type
 Type
   {
   {
   Net Protocol:
   Net Protocol:
@@ -381,6 +384,7 @@ 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_GetOperationsBlock_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_GetOperationsBlock_Request(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_NewBlock(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_NewBlock(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_AddOperations(HeaderData : TNetHeaderData; DataBuffer: TStream);
     Procedure DoProcess_AddOperations(HeaderData : TNetHeaderData; DataBuffer: TStream);
@@ -688,6 +692,7 @@ begin
             end;
             end;
           end;
           end;
         end;
         end;
+        SetLength(nsa,0);
       end else begin
       end else begin
         SetLength(nsa,0);
         SetLength(nsa,0);
         if FListByIp.Count>0 then begin
         if FListByIp.Count>0 then begin
@@ -2120,6 +2125,7 @@ begin
     CT_NetOp_GetBlockHeaders : Result := 'GET BLOCK HEADERS';
     CT_NetOp_GetBlockHeaders : Result := 'GET BLOCK HEADERS';
     CT_NetOp_NewBlock : Result := 'NEW BLOCK';
     CT_NetOp_NewBlock : Result := 'NEW BLOCK';
     CT_NetOp_NewBlock_Fast_Propagation : Result := 'NEW BLOCK FAST PROPAGATION';
     CT_NetOp_NewBlock_Fast_Propagation : Result := 'NEW BLOCK FAST PROPAGATION';
+    CT_NetOp_GetBlockchainOperations : Result := 'GET BLOCKCHAIN OPERATIONS';
     CT_NetOp_AddOperations : Result := 'ADD OPERATIONS';
     CT_NetOp_AddOperations : Result := 'ADD OPERATIONS';
     CT_NetOp_GetSafeBox : Result := 'GET SAFEBOX';
     CT_NetOp_GetSafeBox : Result := 'GET SAFEBOX';
     CT_NetOp_GetPendingOperations : Result := 'GET PENDING OPERATIONS';
     CT_NetOp_GetPendingOperations : Result := 'GET PENDING OPERATIONS';
@@ -2555,6 +2561,99 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TNetConnection.DoProcess_GetBlockchainOperations_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
+  {
+  As described on PIP-0015 this will return Operations stored in a specified Block of the Blockchain
+  Input:
+    operations_count : 4 bytes
+    foreach operations_count
+      BLOCK_OP_REF : 8 bytes -> BLOCK_OP_REF = (QWord(BlockNumber) SHL 32) BIT-OR QWord(OperationIndex)
+  Output:
+    operations_count : 4 bytes -> Must match input.operations_count
+    foreach operations_count
+      op_size : 4 bytes
+      op_data : (op_size) bytes
+  }
+  function GetBlock(bufferOperationsBlock : TList; nBlock : Integer) : TPCOperationsComp;
+  var i : Integer;
+  begin
+    // Search at buffer:
+    i := 0; Result := Nil;
+    while (i<bufferOperationsBlock.Count) And (TPCOperationsComp( bufferOperationsBlock[i] ).OperationBlock.block <> nBlock) do inc(i);
+    if (i>=bufferOperationsBlock.Count) then begin
+      // Not found !
+      Result := TPCOperationsComp.Create(Nil);
+      if Not TNode.Node.Bank.LoadOperations(Result,nBlock) then FreeAndNil(Result);
+    end else Result := TPCOperationsComp( bufferOperationsBlock[i] );
+  end;
+Var input_operations_count, cBlock, cBlockOpIndex, c : Cardinal;
+  block_op_ref : UInt64;
+  i : Integer;
+  bufferOperationsBlock : TList;
+  opc : TPCOperationsComp;
+  outputBuffer : TStream;
+  opindexdata : TStream;
+  opsdata : TBytes;
+  errors : AnsiString;
+  DoDisconnect : Boolean;
+
+begin
+  errors := 'Invalid structure';
+  DoDisconnect := true;
+  outputBuffer := TMemoryStream.Create;
+  try
+    if HeaderData.header_type<>ntp_request then begin
+      errors := 'Not request';
+      Exit;
+    end;
+    DataBuffer.Read(input_operations_count,SizeOf(input_operations_count));
+    if (input_operations_count>CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS) then Exit;
+    outputBuffer.Write(input_operations_count,SizeOf(input_operations_count));
+    bufferOperationsBlock := TList.Create;
+    opindexdata := TStream.Create;
+    Try
+      for i := 1 to input_operations_count do begin
+        if DataBuffer.Read(block_op_ref,SizeOf(block_op_ref))<>SizeOf(block_op_ref) then Exit; // read 8 bytes
+        cBlock := block_op_ref SHR 32;
+        cBlockOpIndex := Cardinal(block_op_ref AND ($00000000FFFFFFFF));
+        opc := GetBlock(bufferOperationsBlock, cBlock);
+        if Assigned(opc) then begin
+          if (cBlockOpIndex<opc.Count) then begin
+            opsdata := opc.Operation[cBlockOpIndex].GetOperationStreamData;
+            c := Length(opsdata);
+            outputBuffer.Write(c,SizeOf(c));
+            outputBuffer.WriteBuffer(opsdata,Length(opsdata));
+            SetLength(opsdata,0);
+          end else begin
+            // OpIndex not found on block -> Add NIL reference: data 0 size = No operation
+            c := 0;
+            outputBuffer.Write(c,SizeOf(c));
+          end;
+        end else begin
+          // Block not found -> Add NIL reference: data 0 size = No operation
+          c := 0;
+          outputBuffer.Write(c,SizeOf(c));
+        end;
+      end;
+      DoDisconnect := False;
+      // Send back
+      outputBuffer.Position := 0;
+      Send(ntp_response,HeaderData.operation,0,HeaderData.request_id,outputBuffer);
+    Finally
+      opindexdata.Free;
+      for i := 0 to bufferOperationsBlock.Count-1 do begin
+        TPCOperationsComp(bufferOperationsBlock[i]).Free;
+      end;
+      bufferOperationsBlock.Free;
+    End;
+  finally
+    outputBuffer.Free;
+    if DoDisconnect then begin
+      DisconnectInvalidClient(false,errors+' > '+TNetData.HeaderDataToText(HeaderData)+' BuffSize: '+inttostr(DataBuffer.Size));
+    end;
+  end;
+end;
+
 procedure TNetConnection.DoProcess_GetBlocks_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
 procedure TNetConnection.DoProcess_GetBlocks_Request(HeaderData: TNetHeaderData; DataBuffer: TStream);
 Var b,b_start,b_end:Cardinal;
 Var b,b_start,b_end:Cardinal;
     op : TPCOperationsComp;
     op : TPCOperationsComp;
@@ -3352,14 +3451,120 @@ begin
 end;
 end;
 
 
 procedure TNetConnection.DoProcess_NewBlock(HeaderData: TNetHeaderData; DataBuffer: TStream);
 procedure TNetConnection.DoProcess_NewBlock(HeaderData: TNetHeaderData; DataBuffer: TStream);
-var op : TPCOperationsComp;
-var bacc : TBlockAccount;
-  errors : AnsiString;
+Type
+  TNewFastPropagationBlockOperation = Record
+    opReference : TOpReference;
+    opStreamData : TBytes;
+  end;
+  TNewFastPropagationBlockOperationsArray = Array of TNewFastPropagationBlockOperation;
+
+var operationsComp : TPCOperationsComp;
   DoDisconnect : Boolean;
   DoDisconnect : Boolean;
-  oprefcount : Cardinal;
-  i, iNodeOpReference : Integer;
-  opReference : TOpReference;
-  opReferencesArr : TOpReferenceArray;
+  errors : AnsiString;
+
+  function ProcessNewFastBlockPropagation : Boolean;
+  var nfpboarr : TNewFastPropagationBlockOperationsArray;
+    oprefcount, notFoundOpReferencesCount, c : Cardinal;
+    i,iNodeOpReference : Integer;
+    sendStream, receiveStream : TStream;
+    block_op_ref : UInt64;
+    headerData : TNetHeaderData;
+    auxOp : TPCOperation;
+    tc : TTickCount;
+  begin
+    Result := False;
+    DoDisconnect := True;
+    tc := TPlatform.GetTickCount;
+    SetLength(nfpboarr,0);
+    if DataBuffer.Read(oprefcount,SizeOf(oprefcount))<>SizeOf(oprefcount) then Exit;
+    if DataBuffer.Size - DataBuffer.Position < (oprefcount * SizeOf(TOpReference)) then Exit;
+    SetLength(nfpboarr,oprefcount);
+    if (oprefcount>0) then begin
+      for i := 0 to Integer(Integer(oprefcount)-1) do begin
+        if DataBuffer.Read(nfpboarr[i].opReference,SizeOf(TOpReference))<>SizeOf(TOpReference) then Exit;
+        SetLength(nfpboarr[i].opStreamData,0);
+      end;
+    end;
+    DoDisconnect := False;
+    notFoundOpReferencesCount := 0;
+    // Try TNode locking process
+    If Not TNode.Node.TryLockNode(3000) then Exit; // Cannot lock...
+    Try
+      if (operationsComp.OperationBlock.block<>TNode.Node.Bank.BlocksCount) then Exit; // Meanwhile other threads have added it
+      // Fill not included operations:
+      for i:=0 to High(nfpboarr) do begin
+        iNodeOpReference := TNode.Node.Operations.OperationsHashTree.IndexOfOpReference(nfpboarr[i].opReference);
+        if iNodeOpReference>=0 then begin
+          nfpboarr[i].opStreamData := TNode.Node.Operations.OperationsHashTree.GetOperation(iNodeOpReference).GetOperationStreamData;
+        end else begin
+          inc(notFoundOpReferencesCount);
+        end;
+      end;
+    Finally
+      TNode.Node.UnlockNode;
+    End;
+    if (notFoundOpReferencesCount>CT_MAX_OPS_PER_BLOCKCHAINOPERATIONS) then begin
+      // A lot of operations pending! Calling GetBlocks
+      TLog.NewLog(ltdebug,ClassName,Format('Too many pending operations (%d of %d) in Fast propagation block %d',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block]));
+      Exit;
+    end else if (notFoundOpReferencesCount>0) then begin
+      // Must obtain not found calling CT_NetOp_GetBlockchainOperations
+      TLog.NewLog(ltdebug,ClassName,Format('Pending operations (%d of %d) in Fast propagation block %d',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block]));
+      sendStream := TMemoryStream.Create;
+      receiveStream := TMemoryStream.Create;
+      Try
+        sendStream.Write(notFoundOpReferencesCount,SizeOf(notFoundOpReferencesCount)); // 4 bytes for count
+        for i:=0 to High(nfpboarr) do begin
+          if Length(nfpboarr[i].opStreamData)=0 then begin
+            // Need this!
+            block_op_ref := UInt64(UInt64(operationsComp.OperationBlock.block) SHL 32) + i;
+            sendStream.Write(block_op_ref,SizeOf(block_op_ref)); // 8 bytes for Block_op_ref
+          end;
+        end;
+        // Send & wait
+        if Not DoSendAndWaitForResponse(CT_NetOp_GetBlockchainOperations,TNetData.NetData.NewRequestId,sendStream,receiveStream,30000,headerData) then begin
+          TLog.NewLog(ltdebug,ClassName,Format('Not received Pending operations (%d of %d) in Fast propagation block %d',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block]));
+          Exit;
+        end;
+        DoDisconnect := True; // If bad received data... then DoDisconnect
+        if (headerData.is_error) then Exit;
+        receiveStream.Position := 0;
+        receiveStream.Read(c,SizeOf(c));
+        if (c<>notFoundOpReferencesCount) then Exit; // Error!
+        // Process Response
+        for i:=0 to High(nfpboarr) do begin
+          if Length(nfpboarr[i].opStreamData)=0 then begin
+            // Read it from response:
+            if receiveStream.Read(c,SizeOf(c)) <> SizeOf(c) then Exit;
+            if receiveStream.Size - receiveStream.Position < c then Exit; // Not enough received data
+            SetLength(nfpboarr[i].opStreamData,c);
+            receiveStream.ReadBuffer(nfpboarr[i].opStreamData,c);
+          end;
+        end;
+        DoDisconnect := False;
+      finally
+        sendStream.Free;
+        receiveStream.Free;
+      end;
+    end;
+    // Now we have nfpboarr with full data
+    for i := 0 to High(nfpboarr) do begin
+      auxOp := TPCOperation.GetOperationFromStreamData( nfpboarr[i].opStreamData );
+      if not Assigned(auxOp) then begin
+      end else begin
+        if Not operationsComp.AddOperation(False,auxOp,errors) then Exit;
+        auxOp.Free;
+      end;
+    end;
+    // Finished
+    if (notFoundOpReferencesCount > 0) then begin
+      TLog.NewLog(ltdebug,ClassName,Format('Processed NewFastBlockPropagation with Pending operations (%d of %d) in Fast propagation block %d for %d miliseconds',[notFoundOpReferencesCount,oprefcount,operationsComp.OperationBlock.block,TPlatform.GetElapsedMilliseconds(tc)]));
+    end;
+    DoDisconnect := False;
+    Result := True;
+  end;
+var bacc : TBlockAccount;
+  c : Cardinal;
 begin
 begin
   errors := '';
   errors := '';
   DoDisconnect := true;
   DoDisconnect := true;
@@ -3368,84 +3573,50 @@ begin
       errors := 'Not autosend';
       errors := 'Not autosend';
       exit;
       exit;
     end;
     end;
-    op := TPCOperationsComp.Create(nil);
+    operationsComp := TPCOperationsComp.Create(nil);
     try
     try
-      op.bank := TNode.Node.Bank;
-      if Not op.LoadBlockFromStream(DataBuffer,errors) then begin
+      operationsComp.bank := TNode.Node.Bank;
+      if Not operationsComp.LoadBlockFromStream(DataBuffer,errors) then begin
         errors := 'Error decoding new account: '+errors;
         errors := 'Error decoding new account: '+errors;
         exit;
         exit;
       end else begin
       end else begin
         DoDisconnect := false;
         DoDisconnect := false;
         DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
         DataBuffer.Read(FRemoteAccumulatedWork,SizeOf(FRemoteAccumulatedWork));
-        if op.IsOnlyOperationBlock then begin
-          TLog.NewLog(ltdebug,ClassName,'Received NEW FAST PROPAGATION BLOCK with height: '+inttostr(op.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork));
+        if operationsComp.IsOnlyOperationBlock then begin
+          TLog.NewLog(ltdebug,ClassName,'Received NEW FAST PROPAGATION BLOCK with height: '+inttostr(operationsComp.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork)+' from '+ClientRemoteAddr);
         end else begin
         end else begin
-          TLog.NewLog(ltdebug,ClassName,'Received NEW BLOCK with height: '+inttostr(op.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork));
+          TLog.NewLog(ltdebug,ClassName,'Received NEW BLOCK with height: '+inttostr(operationsComp.OperationBlock.block)+' Accumulated work '+IntToStr(FRemoteAccumulatedWork)+' from '+ClientRemoteAddr);
         end;
         end;
-        FRemoteOperationBlock := op.OperationBlock;
+        FRemoteOperationBlock := operationsComp.OperationBlock;
         if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
         if (FRemoteAccumulatedWork>TNode.Node.Bank.SafeBox.WorkSum) then begin
-          if (op.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
+          if (operationsComp.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
             // New block candidate:
             // New block candidate:
-            if (op.IsOnlyOperationBlock) then begin
+            if (operationsComp.IsOnlyOperationBlock) then begin
               // Received a FAST PROPAGATION BLOCK as described at PIP-0015
               // Received a FAST PROPAGATION BLOCK as described at PIP-0015
               // Fill operations reference:
               // Fill operations reference:
-              DoDisconnect := True;
-              if DataBuffer.Read(oprefcount,SizeOf(oprefcount))<>SizeOf(oprefcount) then Exit;
-              if DataBuffer.Size - DataBuffer.Position < (oprefcount * SizeOf(TOpReference)) then Exit;
-              SetLength(opReferencesArr,oprefcount);
-              if (oprefcount>0) then begin
-                for i := 0 to Integer(Integer(oprefcount)-1) do begin
-                  if DataBuffer.Read(opReference,SizeOf(opReference))<>SizeOf(opReference) then Exit;
-                  opReferencesArr[i] := opReference;
+              If Not ProcessNewFastBlockPropagation then begin
+                if DoDisconnect then Exit
+                else begin
+                  Send_GetBlocks(operationsComp.OperationBlock.block,1,c);
+                  Exit;
                 end;
                 end;
               end;
               end;
-              DoDisconnect := False;
-              // Try TNode locking process
-              If TNode.Node.TryLockNode(3000) then begin
-                Try
-                  if (op.OperationBlock.block<>TNode.Node.Bank.BlocksCount) then Exit; // Meanwhile other threads have added it
-                  // Fill not included operations:
-                  for i:=0 to High(opReferencesArr) do begin
-                    iNodeOpReference := TNode.Node.Operations.OperationsHashTree.IndexOfOpReference(opReferencesArr[i]);
-                    if iNodeOpReference<0 then begin
-                      // Warning: Operation not found on mempool... cannot continue, must call block
-                      TLog.NewLog(ltError,ClassName,Format('OpReference %d:%d not found on MemPool for new block %d at OpReference %d/%d',
-                        [TPCOperation.GetOpReferenceAccount(opReferencesArr[i]),TPCOperation.GetOpReferenceN_Operation(opReferencesArr[i]),
-                        op.OperationBlock.block,i+1,Length(opReferencesArr)]));
-                      Send_GetBlocks(op.OperationBlock.block,1,oprefcount);
-                      Exit;
-                    end else begin
-                      // Add it!
-                      if Not (op.AddOperation(True,TNode.Node.Operations.Operation[iNodeOpReference],errors)) then begin
-                        TLog.NewLog(ltError,ClassName,Format('OpReference %d:%d (%d/%d) from MemPool invalid to be added at block %d - Error:%s',
-                          [TPCOperation.GetOpReferenceAccount(opReferencesArr[i]),TPCOperation.GetOpReferenceN_Operation(opReferencesArr[i]),
-                          i+1,Length(opReferencesArr),op.OperationBlock.block,errors]));
-                        Send_GetBlocks(op.OperationBlock.block,1,oprefcount);
-                        Exit;
-                      end;
-                    end;
-                  end;
-                Finally
-                  TNode.Node.UnlockNode;
-                End;
-              end;
             end;
             end;
-            //
-            If Not TNode.Node.AddNewBlockChain(Self,op,bacc,errors) then begin
+            If Not TNode.Node.AddNewBlockChain(Self,operationsComp,bacc,errors) then begin
               // Really is a new block? (Check it)
               // Really is a new block? (Check it)
-              if (op.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
+              if (operationsComp.OperationBlock.block=TNode.Node.Bank.BlocksCount) then begin
                 // Received a new invalid block... perhaps I'm an orphan blockchain
                 // Received a new invalid block... perhaps I'm an orphan blockchain
                 TNetData.NetData.GetNewBlockChainFromClient(Self,'Higher Work with same block height. I''m a orphan blockchain candidate');
                 TNetData.NetData.GetNewBlockChainFromClient(Self,'Higher Work with same block height. I''m a orphan blockchain candidate');
               end;
               end;
             end;
             end;
           end else begin
           end else begin
             // Received a new higher work
             // Received a new higher work
-            TNetData.NetData.GetNewBlockChainFromClient(Self,Format('Higher Work and distinct blocks count. Need to download BlocksCount:%d  my BlocksCount:%d',[op.OperationBlock.block+1,TNode.Node.Bank.BlocksCount]));
+            TNetData.NetData.GetNewBlockChainFromClient(Self,Format('Higher Work and distinct blocks count. Need to download BlocksCount:%d  my BlocksCount:%d',[operationsComp.OperationBlock.block+1,TNode.Node.Bank.BlocksCount]));
           end;
           end;
         end;
         end;
       end;
       end;
     finally
     finally
-      op.Free;
+      operationsComp.Free;
     end;
     end;
   finally
   finally
     if DoDisconnect then begin
     if DoDisconnect then begin
@@ -3524,6 +3695,11 @@ begin
                   CT_NetOp_NewBlock, CT_NetOp_NewBlock_Fast_Propagation : Begin
                   CT_NetOp_NewBlock, CT_NetOp_NewBlock_Fast_Propagation : Begin
                     DoProcess_NewBlock(HeaderData,ReceiveDataBuffer);
                     DoProcess_NewBlock(HeaderData,ReceiveDataBuffer);
                   End;
                   End;
+                  CT_NetOp_GetBlockchainOperations : Begin
+                    if HeaderData.header_type=ntp_request then
+                      DoProcess_GetBlockchainOperations_Request(HeaderData,ReceiveDataBuffer)
+                    else TLog.NewLog(ltdebug,Classname,'Received old response of: '+TNetData.HeaderDataToText(HeaderData));
+                  End;
                   CT_NetOp_AddOperations : Begin
                   CT_NetOp_AddOperations : Begin
                     DoProcess_AddOperations(HeaderData,ReceiveDataBuffer);
                     DoProcess_AddOperations(HeaderData,ReceiveDataBuffer);
                   End;
                   End;

+ 2 - 1
src/gui-classic/UFRMOperationsExplorer.pas

@@ -29,7 +29,8 @@ uses
   {$ENDIF}
   {$ENDIF}
   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
   Menus, ActnList, UAccounts, UBlockChain, UNode, UCrypto, UBaseTypes,
   Menus, ActnList, UAccounts, UBlockChain, UNode, UCrypto, UBaseTypes,
-  UFileStorage, UWallet, UConst, UTxMultiOperation, UOpTransaction, URPC, UJSONFunctions;
+  UFileStorage, UWallet, UConst, UTxMultiOperation, UOpTransaction, URPC, UJSONFunctions,
+  System.Actions;
 
 
 
 
 type
 type