Browse Source

Changes on OperationResume

Multioperation can affect multiple accounts at same time,
OperationResume needs to know if we're searching for "all" accounts info
or only for a single account
PascalCoin 7 years ago
parent
commit
732321e13e

+ 6 - 6
src/core/UBlockChain.pas

@@ -200,7 +200,7 @@ Type
     procedure InitializeData; virtual;
     procedure InitializeData; virtual;
     function SaveOpToStream(Stream: TStream; SaveExtendedData : Boolean): Boolean; virtual; abstract;
     function SaveOpToStream(Stream: TStream; SaveExtendedData : Boolean): Boolean; virtual; abstract;
     function LoadOpFromStream(Stream: TStream; LoadExtendedData : Boolean): Boolean; virtual; abstract;
     function LoadOpFromStream(Stream: TStream; LoadExtendedData : Boolean): Boolean; virtual; abstract;
-    procedure FillOperationResume(Block : Cardinal; Affected_account_number : Cardinal; var OperationResume : TOperationResume); virtual;
+    procedure FillOperationResume(Block : Cardinal; getInfoForAllAccounts : Boolean; Affected_account_number : Cardinal; var OperationResume : TOperationResume); virtual;
     Property Previous_Signer_updated_block : Cardinal read FPrevious_Signer_updated_block; // deprecated
     Property Previous_Signer_updated_block : Cardinal read FPrevious_Signer_updated_block; // deprecated
     Property Previous_Destination_updated_block : Cardinal read FPrevious_Destination_updated_block; // deprecated
     Property Previous_Destination_updated_block : Cardinal read FPrevious_Destination_updated_block; // deprecated
     Property Previous_Seller_updated_block : Cardinal read FPrevious_Seller_updated_block; // deprecated
     Property Previous_Seller_updated_block : Cardinal read FPrevious_Seller_updated_block; // deprecated
@@ -211,7 +211,7 @@ Type
     function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors: AnsiString): Boolean; virtual; abstract;
     function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors: AnsiString): Boolean; virtual; abstract;
     procedure AffectedAccounts(list : TList); virtual; abstract;
     procedure AffectedAccounts(list : TList); virtual; abstract;
     class function OpType: Byte; virtual; abstract;
     class function OpType: Byte; virtual; abstract;
-    Class Function OperationToOperationResume(Block : Cardinal; Operation : TPCOperation; Affected_account_number : Cardinal; var OperationResume : TOperationResume) : Boolean; virtual;
+    Class Function OperationToOperationResume(Block : Cardinal; Operation : TPCOperation; getInfoForAllAccounts : Boolean; Affected_account_number : Cardinal; var OperationResume : TOperationResume) : Boolean; virtual;
     function OperationAmount : Int64; virtual; abstract;
     function OperationAmount : Int64; virtual; abstract;
     function OperationAmountByAccount(account : Cardinal) : Int64; virtual;
     function OperationAmountByAccount(account : Cardinal) : Int64; virtual;
     function OperationFee: UInt64; virtual; abstract;
     function OperationFee: UInt64; virtual; abstract;
@@ -473,6 +473,7 @@ Const
   CT_TMultiOpSender_NUL : TMultiOpSender =  (Account:0;Amount:0;N_Operation:0;Payload:'';Signature:(r:'';s:''));
   CT_TMultiOpSender_NUL : TMultiOpSender =  (Account:0;Amount:0;N_Operation:0;Payload:'';Signature:(r:'';s:''));
   CT_TMultiOpReceiver_NUL : TMultiOpReceiver = (Account:0;Amount:0;Payload:'');
   CT_TMultiOpReceiver_NUL : TMultiOpReceiver = (Account:0;Amount:0;Payload:'');
   CT_TMultiOpChangeInfo_NUL : TMultiOpChangeInfo = (Account:0;N_Operation:0;Changes_type:[];New_Accountkey:(EC_OpenSSL_NID:0;x:'';y:'');New_Name:'';New_Type:0;Signature:(r:'';s:''));
   CT_TMultiOpChangeInfo_NUL : TMultiOpChangeInfo = (Account:0;N_Operation:0;Changes_type:[];New_Accountkey:(EC_OpenSSL_NID:0;x:'';y:'');New_Name:'';New_Type:0;Signature:(r:'';s:''));
+  CT_TOpChangeAccountInfoType_Txt : Array[Low(TOpChangeAccountInfoType)..High(TOpChangeAccountInfoType)] of AnsiString = ('public_key','account_name','account_type');
 
 
 implementation
 implementation
 
 
@@ -2356,7 +2357,7 @@ begin
   FSignatureChecked := False;
   FSignatureChecked := False;
 end;
 end;
 
 
-procedure TPCOperation.FillOperationResume(Block: Cardinal; Affected_account_number: Cardinal; var OperationResume: TOperationResume);
+procedure TPCOperation.FillOperationResume(Block: Cardinal; getInfoForAllAccounts : Boolean; Affected_account_number: Cardinal; var OperationResume: TOperationResume);
 begin
 begin
   // XXXXXXXXXXXXXXXX
   // XXXXXXXXXXXXXXXX
   // TODO
   // TODO
@@ -2455,7 +2456,7 @@ begin
   end;
   end;
 end;
 end;
 
 
-class function TPCOperation.OperationToOperationResume(Block : Cardinal; Operation: TPCOperation; Affected_account_number: Cardinal; var OperationResume: TOperationResume): Boolean;
+class function TPCOperation.OperationToOperationResume(Block : Cardinal; Operation: TPCOperation; getInfoForAllAccounts : Boolean; Affected_account_number: Cardinal; var OperationResume: TOperationResume): Boolean;
 Var spayload : AnsiString;
 Var spayload : AnsiString;
   s : AnsiString;
   s : AnsiString;
 begin
 begin
@@ -2593,7 +2594,6 @@ begin
     end;
     end;
     CT_Op_MultiOperation : Begin
     CT_Op_MultiOperation : Begin
       OperationResume.isMultiOperation:=True;
       OperationResume.isMultiOperation:=True;
-      OperationResume.OpSubtype := CT_OpSubtype_MultiOperation;
       OperationResume.OperationTxt := Operation.ToString;
       OperationResume.OperationTxt := Operation.ToString;
       OperationResume.Amount := Operation.OperationAmountByAccount(Affected_account_number);
       OperationResume.Amount := Operation.OperationAmountByAccount(Affected_account_number);
       OperationResume.Fee := 0;
       OperationResume.Fee := 0;
@@ -2609,7 +2609,7 @@ begin
     OperationResume.OperationHash_OLD:=TPCOperation.OperationHash_OLD(Operation,Block);
     OperationResume.OperationHash_OLD:=TPCOperation.OperationHash_OLD(Operation,Block);
   end;
   end;
   OperationResume.valid := true;
   OperationResume.valid := true;
-  Operation.FillOperationResume(Block,Affected_account_number,OperationResume);
+  Operation.FillOperationResume(Block,getInfoForAllAccounts,Affected_account_number,OperationResume);
 end;
 end;
 
 
 function TPCOperation.IsSignerAccount(account: Cardinal): Boolean;
 function TPCOperation.IsSignerAccount(account: Cardinal): Boolean;

+ 2 - 1
src/core/UConst.pas

@@ -147,7 +147,8 @@ Const
   CT_OpSubtype_BuyAccountSeller           = 63;
   CT_OpSubtype_BuyAccountSeller           = 63;
   CT_OpSubtype_ChangeKeySigned            = 71;
   CT_OpSubtype_ChangeKeySigned            = 71;
   CT_OpSubtype_ChangeAccountInfo          = 81;
   CT_OpSubtype_ChangeAccountInfo          = 81;
-  CT_OpSubtype_MultiOperation             = 91;
+  CT_OpSubtype_MultiOperation_Global      = 91;
+  CT_OpSubtype_MultiOperation_AccountInfo = 92;
 
 
   CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'2.1.6'{$ELSE}{$IFDEF TESTNET}'TESTNET 3.0 BETA'{$ELSE}{$ENDIF}{$ENDIF};
   CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'2.1.6'{$ELSE}{$IFDEF TESTNET}'TESTNET 3.0 BETA'{$ELSE}{$ENDIF}{$ENDIF};
 
 

+ 8 - 8
src/core/UNode.pas

@@ -387,7 +387,7 @@ begin
             TLog.NewLog(ltdebug,Classname,Format('AddOperation invalid/duplicated %d/%d: %s  - Error:%s',
             TLog.NewLog(ltdebug,Classname,Format('AddOperation invalid/duplicated %d/%d: %s  - Error:%s',
               [(j+1),OperationsHashTree.OperationsCount,ActOp.ToString,e]));
               [(j+1),OperationsHashTree.OperationsCount,ActOp.ToString,e]));
             if Assigned(OperationsResult) then begin
             if Assigned(OperationsResult) then begin
-              TPCOperation.OperationToOperationResume(0,ActOp,ActOp.SignerAccount,OPR);
+              TPCOperation.OperationToOperationResume(0,ActOp,True,ActOp.SignerAccount,OPR);
               OPR.valid := false;
               OPR.valid := false;
               OPR.NOpInsideBlock:=-1;
               OPR.NOpInsideBlock:=-1;
               OPR.OperationHash := '';
               OPR.OperationHash := '';
@@ -401,7 +401,7 @@ begin
               valids_operations.AddOperationToHashTree(ActOp);
               valids_operations.AddOperationToHashTree(ActOp);
               TLog.NewLog(ltdebug,Classname,Format('AddOperation %d/%d: %s',[(j+1),OperationsHashTree.OperationsCount,ActOp.ToString]));
               TLog.NewLog(ltdebug,Classname,Format('AddOperation %d/%d: %s',[(j+1),OperationsHashTree.OperationsCount,ActOp.ToString]));
               if Assigned(OperationsResult) then begin
               if Assigned(OperationsResult) then begin
-                TPCOperation.OperationToOperationResume(0,ActOp,ActOp.SignerAccount,OPR);
+                TPCOperation.OperationToOperationResume(0,ActOp,True,ActOp.SignerAccount,OPR);
                 OPR.NOpInsideBlock:=FOperations.Count-1;
                 OPR.NOpInsideBlock:=FOperations.Count-1;
                 OPR.Balance := FOperations.SafeBoxTransaction.Account(ActOp.SignerAccount).balance;
                 OPR.Balance := FOperations.SafeBoxTransaction.Account(ActOp.SignerAccount).balance;
                 OperationsResult.Add(OPR);
                 OperationsResult.Add(OPR);
@@ -412,7 +412,7 @@ begin
               TLog.NewLog(ltdebug,Classname,Format('AddOperation invalid/duplicated %d/%d: %s  - Error:%s',
               TLog.NewLog(ltdebug,Classname,Format('AddOperation invalid/duplicated %d/%d: %s  - Error:%s',
                 [(j+1),OperationsHashTree.OperationsCount,ActOp.ToString,e]));
                 [(j+1),OperationsHashTree.OperationsCount,ActOp.ToString,e]));
               if Assigned(OperationsResult) then begin
               if Assigned(OperationsResult) then begin
-                TPCOperation.OperationToOperationResume(0,ActOp,ActOp.SignerAccount,OPR);
+                TPCOperation.OperationToOperationResume(0,ActOp,True,ActOp.SignerAccount,OPR);
                 OPR.valid := false;
                 OPR.valid := false;
                 OPR.NOpInsideBlock:=-1;
                 OPR.NOpInsideBlock:=-1;
                 OPR.OperationHash := '';
                 OPR.OperationHash := '';
@@ -439,7 +439,7 @@ begin
           if (errors<>'') then errors := errors+' ';
           if (errors<>'') then errors := errors+' ';
           errors := errors + e;
           errors := errors + e;
           if Assigned(OperationsResult) then begin
           if Assigned(OperationsResult) then begin
-            TPCOperation.OperationToOperationResume(0,ActOp,ActOp.SignerAccount,OPR);
+            TPCOperation.OperationToOperationResume(0,ActOp,True,ActOp.SignerAccount,OPR);
             OPR.valid := false;
             OPR.valid := false;
             OPR.NOpInsideBlock:=-1;
             OPR.NOpInsideBlock:=-1;
             OPR.OperationHash := '';
             OPR.OperationHash := '';
@@ -744,7 +744,7 @@ procedure TNode.GetStoredOperationsFromAccount(const OperationsResume: TOperatio
           opc.OperationsHashTree.GetOperationsAffectingAccount(account_number,l);
           opc.OperationsHashTree.GetOperationsAffectingAccount(account_number,l);
           for i := l.Count - 1 downto 0 do begin
           for i := l.Count - 1 downto 0 do begin
             op := opc.Operation[PtrInt(l.Items[i])];
             op := opc.Operation[PtrInt(l.Items[i])];
-            If TPCOperation.OperationToOperationResume(block_number,Op,account_number,OPR) then begin
+            If TPCOperation.OperationToOperationResume(block_number,Op,False,account_number,OPR) then begin
               OPR.NOpInsideBlock := Op.tag; // Note: Used Op.tag to include operation index inside a list
               OPR.NOpInsideBlock := Op.tag; // Note: Used Op.tag to include operation index inside a list
               OPR.time := opc.OperationBlock.timestamp;
               OPR.time := opc.OperationBlock.timestamp;
               OPR.Block := block_number;
               OPR.Block := block_number;
@@ -867,7 +867,7 @@ begin
         op := Operations.Operation[i];
         op := Operations.Operation[i];
         If (op.IsSignerAccount(account)) then begin
         If (op.IsSignerAccount(account)) then begin
           If (op.GetAccountN_Operation(account)<=n_operation) then begin
           If (op.GetAccountN_Operation(account)<=n_operation) then begin
-            TPCOperation.OperationToOperationResume(0,op,account,opr);
+            TPCOperation.OperationToOperationResume(0,op,False,account,opr);
             opr.Balance:=-1;
             opr.Balance:=-1;
             OpResumeList.Add(opr);
             OpResumeList.Add(opr);
             dec(n_operation);
             dec(n_operation);
@@ -895,7 +895,7 @@ begin
           If (n_operation_high=n_operation_low) and (op.GetAccountN_Operation(account)=n_operation) // If searching only 1 n_operation, n_operation must match
           If (n_operation_high=n_operation_low) and (op.GetAccountN_Operation(account)=n_operation) // If searching only 1 n_operation, n_operation must match
             Or
             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
             (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,account,opr);
+            TPCOperation.OperationToOperationResume(block,op,True,account,opr);
             opr.time:=Bank.SafeBox.Block(block).blockchainInfo.timestamp;
             opr.time:=Bank.SafeBox.Block(block).blockchainInfo.timestamp;
             opr.NOpInsideBlock:=i;
             opr.NOpInsideBlock:=i;
             opr.Balance:=-1;
             opr.Balance:=-1;
@@ -912,8 +912,8 @@ begin
             end;
             end;
           end;
           end;
         end;
         end;
-        block := OperationComp.PreviousUpdatedBlocks.GetPreviousUpdatedBlock(account,block);
       end;
       end;
+      block := OperationComp.PreviousUpdatedBlocks.GetPreviousUpdatedBlock(account,block);
       if (block>aux_block) then exit // Error... not found a valid block positioning
       if (block>aux_block) then exit // Error... not found a valid block positioning
       else if (block=aux_block) then begin
       else if (block=aux_block) then begin
         if ((start_block=0) Or (allow_search_previous)) then dec(block) // downgrade until found a block with operations
         if ((start_block=0) Or (allow_search_previous)) then dec(block) // downgrade until found a block with operations

+ 12 - 12
src/core/URPC.pas

@@ -620,7 +620,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           FNode.Operations.OperationsHashTree.GetOperationsAffectingAccount(accountNumber,list);
           FNode.Operations.OperationsHashTree.GetOperationsAffectingAccount(accountNumber,list);
           for i := list.Count - 1 downto 0 do begin
           for i := list.Count - 1 downto 0 do begin
             Op := FNode.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
             Op := FNode.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
-            If TPCOperation.OperationToOperationResume(0,Op,accountNumber,OPR) then begin
+            If TPCOperation.OperationToOperationResume(0,Op,False,accountNumber,OPR) then begin
               OPR.NOpInsideBlock := i;
               OPR.NOpInsideBlock := i;
               OPR.Block := FNode.Operations.OperationBlock.block;
               OPR.Block := FNode.Operations.OperationBlock.block;
               OPR.Balance := FNode.Operations.SafeBoxTransaction.Account(accountNumber).balance;
               OPR.Balance := FNode.Operations.SafeBoxTransaction.Account(accountNumber).balance;
@@ -760,7 +760,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorNum := CT_RPC_ErrNum_InvalidOperation;
           ErrorNum := CT_RPC_ErrNum_InvalidOperation;
           Exit;
           Exit;
         end;
         end;
-        TPCOperation.OperationToOperationResume(0,opt,sender,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,sender,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         Result := true;
         Result := true;
       finally
       finally
@@ -879,7 +879,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorNum := CT_RPC_ErrNum_InvalidOperation;
           ErrorNum := CT_RPC_ErrNum_InvalidOperation;
           Exit;
           Exit;
         end;
         end;
-        TPCOperation.OperationToOperationResume(0,opck,account_signer,opr);
+        TPCOperation.OperationToOperationResume(0,opck,False,account_signer,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         Result := true;
         Result := true;
       finally
       finally
@@ -1202,7 +1202,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       for i := 0 to OperationsHashTree.OperationsCount - 1 do begin
       for i := 0 to OperationsHashTree.OperationsCount - 1 do begin
         Op := OperationsHashTree.GetOperation(i);
         Op := OperationsHashTree.GetOperation(i);
         Obj := jsonArray.GetAsObject(i);
         Obj := jsonArray.GetAsObject(i);
-        If TPCOperation.OperationToOperationResume(0,Op,Op.SignerAccount,OPR) then begin
+        If TPCOperation.OperationToOperationResume(0,Op,True,Op.SignerAccount,OPR) then begin
           OPR.NOpInsideBlock := i;
           OPR.NOpInsideBlock := i;
           OPR.Balance := -1;
           OPR.Balance := -1;
         end else OPR := CT_TOperationResume_NUL;
         end else OPR := CT_TOperationResume_NUL;
@@ -1860,7 +1860,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := errors;
           ErrorDesc := errors;
           Exit;
           Exit;
         end else Result := True;
         end else Result := True;
-        TPCOperation.OperationToOperationResume(0,opt,c_account,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,c_account,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         FillOperationResumeToJSONObject(opr,GetResultObject);
       finally
       finally
         OperationsHashTree.Free;
         OperationsHashTree.Free;
@@ -1919,7 +1919,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := errors;
           ErrorDesc := errors;
           Exit;
           Exit;
         end else Result := True;
         end else Result := True;
-        TPCOperation.OperationToOperationResume(0,opt,c_account,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,c_account,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         FillOperationResumeToJSONObject(opr,GetResultObject);
       finally
       finally
         OperationsHashTree.Free;
         OperationsHashTree.Free;
@@ -1961,7 +1961,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := errors;
           ErrorDesc := errors;
           Exit;
           Exit;
         end else Result := True;
         end else Result := True;
-        TPCOperation.OperationToOperationResume(0,opt,c_account,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,c_account,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         FillOperationResumeToJSONObject(opr,GetResultObject);
       finally
       finally
         OperationsHashTree.Free;
         OperationsHashTree.Free;
@@ -2020,7 +2020,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := errors;
           ErrorDesc := errors;
           Exit;
           Exit;
         end else Result := True;
         end else Result := True;
-        TPCOperation.OperationToOperationResume(0,opt,c_account,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,c_account,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         FillOperationResumeToJSONObject(opr,GetResultObject);
       finally
       finally
         OperationsHashTree.Free;
         OperationsHashTree.Free;
@@ -2373,7 +2373,7 @@ begin
           ErrorDesc := 'Block/Operation not found: '+IntToStr(c)+'/'+IntToStr(i)+' BlockOperations:'+IntToStr(pcops.Count);
           ErrorDesc := 'Block/Operation not found: '+IntToStr(c)+'/'+IntToStr(i)+' BlockOperations:'+IntToStr(pcops.Count);
           Exit;
           Exit;
         end;
         end;
-        If TPCOperation.OperationToOperationResume(c,pcops.Operation[i],pcops.Operation[i].SignerAccount,opr) then begin
+        If TPCOperation.OperationToOperationResume(c,pcops.Operation[i],True,pcops.Operation[i].SignerAccount,opr) then begin
           opr.NOpInsideBlock:=i;
           opr.NOpInsideBlock:=i;
           opr.time:=pcops.OperationBlock.timestamp;
           opr.time:=pcops.OperationBlock.timestamp;
           opr.Balance := -1;
           opr.Balance := -1;
@@ -2405,7 +2405,7 @@ begin
         j := params.AsInteger('start',0);
         j := params.AsInteger('start',0);
         for i := 0 to pcops.Count - 1 do begin
         for i := 0 to pcops.Count - 1 do begin
           if (i>=j) then begin
           if (i>=j) then begin
-            If TPCOperation.OperationToOperationResume(c,pcops.Operation[i],pcops.Operation[i].SignerAccount,opr) then begin
+            If TPCOperation.OperationToOperationResume(c,pcops.Operation[i],True,pcops.Operation[i].SignerAccount,opr) then begin
               opr.NOpInsideBlock:=i;
               opr.NOpInsideBlock:=i;
               opr.time:=pcops.OperationBlock.timestamp;
               opr.time:=pcops.OperationBlock.timestamp;
               opr.Balance := -1; // Don't include!
               opr.Balance := -1; // Don't include!
@@ -2445,7 +2445,7 @@ begin
     // Create result
     // Create result
     GetResultArray;
     GetResultArray;
     for i:=FNode.Operations.Count-1 downto 0 do begin
     for i:=FNode.Operations.Count-1 downto 0 do begin
-      if not TPCOperation.OperationToOperationResume(0,FNode.Operations.Operation[i],FNode.Operations.Operation[i].SignerAccount,opr) then begin
+      if not TPCOperation.OperationToOperationResume(0,FNode.Operations.Operation[i],True,FNode.Operations.Operation[i].SignerAccount,opr) then begin
         ErrorNum := CT_RPC_ErrNum_InternalError;
         ErrorNum := CT_RPC_ErrNum_InternalError;
         ErrorDesc := 'Error converting data';
         ErrorDesc := 'Error converting data';
         exit;
         exit;
@@ -2497,7 +2497,7 @@ begin
           end;
           end;
       else Raise Exception.Create('ERROR DEV 20171120-4');
       else Raise Exception.Create('ERROR DEV 20171120-4');
       end;
       end;
-      If not TPCOperation.OperationToOperationResume(c,pcops.Operation[i],pcops.Operation[i].SignerAccount,opr) then begin
+      If not TPCOperation.OperationToOperationResume(c,pcops.Operation[i],True,pcops.Operation[i].SignerAccount,opr) then begin
         ErrorNum := CT_RPC_ErrNum_InternalError;
         ErrorNum := CT_RPC_ErrNum_InternalError;
         ErrorDesc := 'Error 20161026-1';
         ErrorDesc := 'Error 20161026-1';
       end;
       end;

+ 45 - 3
src/core/UTxMultiOperation.pas

@@ -105,7 +105,7 @@ Type
     procedure InitializeData; override;
     procedure InitializeData; override;
     function SaveOpToStream(Stream: TStream; SaveExtendedData : Boolean): Boolean; override;
     function SaveOpToStream(Stream: TStream; SaveExtendedData : Boolean): Boolean; override;
     function LoadOpFromStream(Stream: TStream; LoadExtendedData : Boolean): Boolean; override;
     function LoadOpFromStream(Stream: TStream; LoadExtendedData : Boolean): Boolean; override;
-    procedure FillOperationResume(Block : Cardinal; Affected_account_number : Cardinal; var OperationResume : TOperationResume); override;
+    procedure FillOperationResume(Block : Cardinal; getInfoForAllAccounts : Boolean; Affected_account_number : Cardinal; var OperationResume : TOperationResume); override;
   public
   public
     function GetBufferForOpHash(UseProtocolV2 : Boolean): TRawBytes; override;
     function GetBufferForOpHash(UseProtocolV2 : Boolean): TRawBytes; override;
 
 
@@ -141,6 +141,7 @@ Type
     Function IndexOfAccountReceiver(nAccount : Cardinal; startPos : Integer) : Integer;
     Function IndexOfAccountReceiver(nAccount : Cardinal; startPos : Integer) : Integer;
     Function IndexOfAccountChanger(nAccount : Cardinal) : Integer; overload;
     Function IndexOfAccountChanger(nAccount : Cardinal) : Integer; overload;
     class Function IndexOfAccountChanger(nAccount : Cardinal; startPos : Integer; const changesInfo : TMultiOpChangesInfo) : Integer; overload;
     class Function IndexOfAccountChanger(nAccount : Cardinal; startPos : Integer; const changesInfo : TMultiOpChangesInfo) : Integer; overload;
+    class Function OpChangeAccountInfoTypesToText(const OpChangeAccountInfoTypes : TOpChangeAccountInfoTypes) : AnsiString;
     //
     //
     Function toString : String; Override;
     Function toString : String; Override;
     Property Data : TOpMultiOperationData read FData;
     Property Data : TOpMultiOperationData read FData;
@@ -187,12 +188,53 @@ begin
   Result := -1;
   Result := -1;
 end;
 end;
 
 
-procedure TOpMultiOperation.FillOperationResume(Block : Cardinal; Affected_account_number : Cardinal; var OperationResume : TOperationResume);
+class function TOpMultiOperation.OpChangeAccountInfoTypesToText(const OpChangeAccountInfoTypes: TOpChangeAccountInfoTypes): AnsiString;
+Var opcit : TOpChangeAccountInfoType;
 begin
 begin
-  inherited FillOperationResume(Block, Affected_account_number, OperationResume);
+  Result := '';
+  for opcit:=Low(opcit) to High(opcit) do begin
+    if opcit in OpChangeAccountInfoTypes then begin
+      If Result<>'' then Result := Result +',';
+      Result := Result + CT_TOpChangeAccountInfoType_Txt[opcit];
+    end;
+  end;
+end;
+
+procedure TOpMultiOperation.FillOperationResume(Block : Cardinal; getInfoForAllAccounts : Boolean; Affected_account_number : Cardinal; var OperationResume : TOperationResume);
+Var iSender,iReceiver,iChanger : Integer;
+  changerTxt : AnsiString;
+begin
+  inherited FillOperationResume(Block, getInfoForAllAccounts, Affected_account_number, OperationResume);
+  OperationResume.isMultiOperation:=True;
+
   OperationResume.Senders := FData.txSenders;
   OperationResume.Senders := FData.txSenders;
   OperationResume.Receivers := FData.txReceivers;
   OperationResume.Receivers := FData.txReceivers;
   OperationResume.Changers := FData.changesInfo;
   OperationResume.Changers := FData.changesInfo;
+  if (getInfoForAllAccounts) then begin
+    OperationResume.OperationTxt := ToString;
+    OperationResume.Amount := OperationAmount;
+    OperationResume.Fee := OperationFee * (-1);
+    OperationResume.OpSubtype := CT_OpSubtype_MultiOperation_Global;
+  end else begin
+    OperationResume.OpSubtype := CT_OpSubtype_MultiOperation_AccountInfo;
+    OperationResume.Fee := 0;
+    OperationResume.Amount := OperationAmountByAccount(Affected_account_number);
+    // Set Text and OpSubtype based on Affected_account_number
+    iSender := (IndexOfAccountSender(Affected_account_number));
+    iReceiver := (IndexOfAccountReceiver(Affected_account_number,0));
+    iChanger := (IndexOfAccountChanger(Affected_account_number));
+    if (iChanger>=0) then begin
+      changerTxt:='Changes ['+OpChangeAccountInfoTypesToText(FData.changesInfo[iChanger].Changes_type)+']';
+    end else changerTxt:='';
+    if (iSender>=0) then begin
+      // Is a Sender account
+      OperationResume.OperationTxt:='Multi Tx-Out '+TAccountComp.FormatMoney(OperationResume.Amount * (-1))+' PASC from '+TAccountComp.AccountNumberToAccountTxtNumber(Affected_account_number)+' '+changerTxt;
+    end else if (iReceiver>=0) then begin
+      OperationResume.OperationTxt:='Multi Tx-In '+TAccountComp.FormatMoney(OperationResume.Amount)+' PASC to '+TAccountComp.AccountNumberToAccountTxtNumber(Affected_account_number)+' '+changerTxt;
+    end else begin
+      OperationResume.OperationTxt:='Multi '+changerTxt+' to '+TAccountComp.AccountNumberToAccountTxtNumber(Affected_account_number);
+    end;
+  end;
 end;
 end;
 
 
 function TOpMultiOperation.IndexOfAccountChangeNameTo(const newName: AnsiString): Integer;
 function TOpMultiOperation.IndexOfAccountChangeNameTo(const newName: AnsiString): Integer;

+ 3 - 3
src/libraries/pascalcoin/UGridUtils.pas

@@ -899,7 +899,7 @@ begin
     if FPendingOperations then begin
     if FPendingOperations then begin
       for i := Node.Operations.Count - 1 downto 0 do begin
       for i := Node.Operations.Count - 1 downto 0 do begin
         Op := Node.Operations.OperationsHashTree.GetOperation(i);
         Op := Node.Operations.OperationsHashTree.GetOperation(i);
-        If TPCOperation.OperationToOperationResume(0,Op,Op.SignerAccount,OPR) then begin
+        If TPCOperation.OperationToOperationResume(0,Op,True,Op.SignerAccount,OPR) then begin
           OPR.NOpInsideBlock := i;
           OPR.NOpInsideBlock := i;
           OPR.Block := Node.Bank.BlocksCount;
           OPR.Block := Node.Bank.BlocksCount;
           OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SignerAccount).balance;
           OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SignerAccount).balance;
@@ -937,7 +937,7 @@ begin
               FOperationsResume.Add(OPR);
               FOperationsResume.Add(OPR);
               // Reverse operations inside a block
               // Reverse operations inside a block
               for i := opc.Count - 1 downto 0 do begin
               for i := opc.Count - 1 downto 0 do begin
-                if TPCOperation.OperationToOperationResume(bend,opc.Operation[i],opc.Operation[i].SignerAccount,opr) then begin
+                if TPCOperation.OperationToOperationResume(bend,opc.Operation[i],True,opc.Operation[i].SignerAccount,opr) then begin
                   opr.NOpInsideBlock := i;
                   opr.NOpInsideBlock := i;
                   opr.Block := bend;
                   opr.Block := bend;
                   opr.time := opc.OperationBlock.timestamp;
                   opr.time := opc.OperationBlock.timestamp;
@@ -957,7 +957,7 @@ begin
           Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
           Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
           for i := list.Count - 1 downto 0 do begin
           for i := list.Count - 1 downto 0 do begin
             Op := Node.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
             Op := Node.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
-            If TPCOperation.OperationToOperationResume(0,Op,AccountNumber,OPR) then begin
+            If TPCOperation.OperationToOperationResume(0,Op,False,AccountNumber,OPR) then begin
               OPR.NOpInsideBlock := i;
               OPR.NOpInsideBlock := i;
               OPR.Block := Node.Operations.OperationBlock.block;
               OPR.Block := Node.Operations.OperationBlock.block;
               OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
               OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;