Bladeren bron

Merge upstream

Herman Schoenfeld 7 jaren geleden
bovenliggende
commit
c2cf8ad028
6 gewijzigde bestanden met toevoegingen van 299 en 222 verwijderingen
  1. 6 6
      src/core/UBlockChain.pas
  2. 2 1
      src/core/UConst.pas
  3. 8 8
      src/core/UNode.pas
  4. 235 201
      src/core/URPC.pas
  5. 45 3
      src/core/UTxMultiOperation.pas
  6. 3 3
      src/libraries/pascalcoin/UGridUtils.pas

+ 6 - 6
src/core/UBlockChain.pas

@@ -200,7 +200,7 @@ Type
     procedure InitializeData; virtual;
     function SaveOpToStream(Stream: TStream; SaveExtendedData : 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_Destination_updated_block : Cardinal read FPrevious_Destination_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;
     procedure AffectedAccounts(list : TList); 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 OperationAmountByAccount(account : Cardinal) : Int64; virtual;
     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_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_TOpChangeAccountInfoType_Txt : Array[Low(TOpChangeAccountInfoType)..High(TOpChangeAccountInfoType)] of AnsiString = ('public_key','account_name','account_type');
 
 implementation
 
@@ -2356,7 +2357,7 @@ begin
   FSignatureChecked := False;
 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
   // XXXXXXXXXXXXXXXX
   // TODO
@@ -2455,7 +2456,7 @@ begin
   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;
   s : AnsiString;
 begin
@@ -2593,7 +2594,6 @@ begin
     end;
     CT_Op_MultiOperation : Begin
       OperationResume.isMultiOperation:=True;
-      OperationResume.OpSubtype := CT_OpSubtype_MultiOperation;
       OperationResume.OperationTxt := Operation.ToString;
       OperationResume.Amount := Operation.OperationAmountByAccount(Affected_account_number);
       OperationResume.Fee := 0;
@@ -2609,7 +2609,7 @@ begin
     OperationResume.OperationHash_OLD:=TPCOperation.OperationHash_OLD(Operation,Block);
   end;
   OperationResume.valid := true;
-  Operation.FillOperationResume(Block,Affected_account_number,OperationResume);
+  Operation.FillOperationResume(Block,getInfoForAllAccounts,Affected_account_number,OperationResume);
 end;
 
 function TPCOperation.IsSignerAccount(account: Cardinal): Boolean;

+ 2 - 1
src/core/UConst.pas

@@ -147,7 +147,8 @@ Const
   CT_OpSubtype_BuyAccountSeller           = 63;
   CT_OpSubtype_ChangeKeySigned            = 71;
   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};
 

+ 8 - 8
src/core/UNode.pas

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

+ 235 - 201
src/core/URPC.pas

@@ -41,6 +41,20 @@ Type
 
   { TRPCServer }
 
+  { TPascalCoinJSONComp }
+
+  TPascalCoinJSONComp = Class
+  private
+    class function OperationsHashTreeToHexaString(Const OperationsHashTree : TOperationsHashTree) : AnsiString;
+  public
+    class function ToJSONCurrency(pascalCoins : Int64) : Real;
+    class procedure FillAccountObject(Const account : TAccount; jsonObj : TPCJSONObject);
+    class procedure FillBlockObject(nBlock : Cardinal; ANode : TNode; jsonObject: TPCJSONObject);
+    class procedure FillOperationObject(Const OPR : TOperationResume; currentNodeBlocksCount : Cardinal; jsonObject : TPCJSONObject);
+    class procedure FillOperationsHashTreeObject(Const OperationsHashTree : TOperationsHashTree; jsonObject : TPCJSONObject);
+    class procedure FillPublicKeyObject(const PubKey : TAccountKey; jsonObj : TPCJSONObject);
+  end;
+
   TRPCServerThread = Class;
   TRPCServer = Class
   private
@@ -108,6 +122,192 @@ Uses  {$IFNDEF FPC}windows,{$ENDIF}
 
 var _RPCServer : TRPCServer = Nil;
 
+{ TPascalCoinJSONComp }
+
+class function TPascalCoinJSONComp.ToJSONCurrency(pascalCoins: Int64): Real;
+Begin
+  Result := RoundTo( pascalCoins / 10000 , -4);
+end;
+
+class procedure TPascalCoinJSONComp.FillBlockObject(nBlock : Cardinal; ANode : TNode; jsonObject: TPCJSONObject);
+var pcops : TPCOperationsComp;
+  ob : TOperationBlock;
+begin
+  pcops := TPCOperationsComp.Create(Nil);
+  try
+    If ANode.Bank.BlocksCount<=nBlock then begin
+      Exit;
+    end;
+    ob := ANode.Bank.SafeBox.Block(nBlock).blockchainInfo;
+
+    jsonObject.GetAsVariant('block').Value:=ob.block;
+    jsonObject.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(ob.account_key));
+    jsonObject.GetAsVariant('reward').Value:=ToJSONCurrency(ob.reward);
+    jsonObject.GetAsVariant('fee').Value:=ToJSONCurrency(ob.fee);
+    jsonObject.GetAsVariant('ver').Value:=ob.protocol_version;
+    jsonObject.GetAsVariant('ver_a').Value:=ob.protocol_available;
+    jsonObject.GetAsVariant('timestamp').Value:=Int64(ob.timestamp);
+    jsonObject.GetAsVariant('target').Value:=Int64(ob.compact_target);
+    jsonObject.GetAsVariant('nonce').Value:=Int64(ob.nonce);
+    jsonObject.GetAsVariant('payload').Value:=ob.block_payload;
+    jsonObject.GetAsVariant('sbh').Value:=TCrypto.ToHexaString(ob.initial_safe_box_hash);
+    jsonObject.GetAsVariant('oph').Value:=TCrypto.ToHexaString(ob.operations_hash);
+    jsonObject.GetAsVariant('pow').Value:=TCrypto.ToHexaString(ob.proof_of_work);
+    jsonObject.GetAsVariant('hashratekhs').Value := ANode.Bank.SafeBox.CalcBlockHashRateInKhs(ob.Block,50);
+    jsonObject.GetAsVariant('maturation').Value := ANode.Bank.BlocksCount - ob.block - 1;
+    If ANode.Bank.LoadOperations(pcops,nBlock) then begin
+      jsonObject.GetAsVariant('operations').Value:=pcops.Count;
+    end;
+  finally
+    pcops.Free;
+  end;
+end;
+
+class procedure TPascalCoinJSONComp.FillOperationObject(const OPR: TOperationResume; currentNodeBlocksCount : Cardinal; jsonObject: TPCJSONObject);
+Var i : Integer;
+  jsonArr : TPCJSONArray;
+  auxObj : TPCJSONObject;
+Begin
+  if Not OPR.valid then begin
+    jsonObject.GetAsVariant('valid').Value := OPR.valid;
+  end;
+  if (OPR.errors<>'') And (Not OPR.valid) then begin
+    jsonObject.GetAsVariant('errors').Value := OPR.errors;
+  end;
+  if OPR.valid then begin
+    jsonObject.GetAsVariant('block').Value:=OPR.Block;
+    jsonObject.GetAsVariant('time').Value:=OPR.time;
+    jsonObject.GetAsVariant('opblock').Value:=OPR.NOpInsideBlock;
+    if (OPR.Block>0) And (OPR.Block<currentNodeBlocksCount) then
+      jsonObject.GetAsVariant('maturation').Value := currentNodeBlocksCount - OPR.Block - 1
+    else jsonObject.GetAsVariant('maturation').Value := null;
+  end;
+  jsonObject.GetAsVariant('optype').Value:=OPR.OpType;
+  jsonObject.GetAsVariant('subtype').Value:=OPR.OpSubtype;
+  If (Not OPR.isMultiOperation) then Begin
+    jsonObject.GetAsVariant('account').Value:=OPR.AffectedAccount;
+    jsonObject.GetAsVariant('signer_account').Value:=OPR.SignerAccount;
+    jsonObject.GetAsVariant('n_operation').Value:=OPR.n_operation;
+  end else begin
+    jsonArr := jsonObject.GetAsArray('senders');
+    for i:=Low(OPR.senders) to High(OPR.Senders) do begin
+      auxObj := jsonArr.GetAsObject(jsonArr.Count);
+      auxObj.GetAsVariant('account').Value := OPR.Senders[i].Account;
+      auxObj.GetAsVariant('n_operation').Value := OPR.Senders[i].N_Operation;
+      auxObj.GetAsVariant('amount').Value := ToJSONCurrency(OPR.Senders[i].Amount * (-1));
+      auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Senders[i].Payload);
+    end;
+    //
+    jsonArr := jsonObject.GetAsArray('receivers');
+    for i:=Low(OPR.Receivers) to High(OPR.Receivers) do begin
+      auxObj := jsonArr.GetAsObject(jsonArr.Count);
+      auxObj.GetAsVariant('account').Value := OPR.Receivers[i].Account;
+      auxObj.GetAsVariant('amount').Value := ToJSONCurrency(OPR.Receivers[i].Amount);
+      auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Receivers[i].Payload);
+    end;
+    jsonArr := jsonObject.GetAsArray('changers');
+    for i:=Low(OPR.Changers) to High(OPR.Changers) do begin
+      auxObj := jsonArr.GetAsObject(jsonArr.Count);
+      auxObj.GetAsVariant('account').Value := OPR.Changers[i].Account;
+      auxObj.GetAsVariant('n_operation').Value := OPR.Changers[i].N_Operation;
+      If public_key in OPR.Changers[i].Changes_type then begin
+        auxObj.GetAsVariant('new_enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(OPR.Changers[i].New_Accountkey));
+      end;
+      If account_name in OPR.Changers[i].Changes_type then begin
+        auxObj.GetAsVariant('new_name').Value := OPR.Changers[i].New_Name;
+      end;
+      If account_type in OPR.Changers[i].Changes_type then begin
+        auxObj.GetAsVariant('new_type').Value := OPR.Changers[i].New_Type;
+      end;
+    end;
+  end;
+  jsonObject.GetAsVariant('optxt').Value:=OPR.OperationTxt;
+  jsonObject.GetAsVariant('fee').Value:=ToJSONCurrency(OPR.Fee);
+  if (Not OPR.isMultiOperation) then begin
+    jsonObject.GetAsVariant('amount').Value:=ToJSONCurrency(OPR.Amount);
+    if (OPR.Balance>=0) And (OPR.valid) then jsonObject.GetAsVariant('balance').Value:=ToJSONCurrency(OPR.Balance);
+    jsonObject.GetAsVariant('payload').Value:=TCrypto.ToHexaString(OPR.OriginalPayload);
+  end else begin
+    jsonObject.GetAsVariant('totalamount').Value:=ToJSONCurrency(OPR.Amount);
+    if (OPR.Balance>=0) And (OPR.valid) then jsonObject.GetAsVariant('balance').Value:=ToJSONCurrency(OPR.Balance);
+  end;
+  If (OPR.OpType = CT_Op_Transaction) then begin
+    If OPR.SignerAccount>=0 then begin
+      jsonObject.GetAsVariant('sender_account').Value:=OPR.SignerAccount;
+    end;
+    If OPR.DestAccount>=0 then begin
+      jsonObject.GetAsVariant('dest_account').Value:=OPR.DestAccount;
+    end;
+  end;
+  If OPR.newKey.EC_OpenSSL_NID>0 then begin
+    jsonObject.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(OPR.newKey));
+  end;
+  if (OPR.valid) And (OPR.OperationHash<>'') then begin
+    jsonObject.GetAsVariant('ophash').Value := TCrypto.ToHexaString(OPR.OperationHash);
+    if (OPR.Block<CT_Protocol_Upgrade_v2_MinBlock) then begin
+      jsonObject.GetAsVariant('old_ophash').Value := TCrypto.ToHexaString(OPR.OperationHash_OLD);
+    end;
+  end;
+end;
+
+class procedure TPascalCoinJSONComp.FillAccountObject(const account: TAccount; jsonObj: TPCJSONObject);
+Begin
+  jsonObj.GetAsVariant('account').Value:=account.account;
+  jsonObj.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountInfo.accountKey));
+  jsonObj.GetAsVariant('balance').Value:=ToJSONCurrency(account.balance);
+  jsonObj.GetAsVariant('n_operation').Value:=account.n_operation;
+  jsonObj.GetAsVariant('updated_b').Value:=account.updated_block;
+  case account.accountInfo.state of
+    as_Normal : jsonObj.GetAsVariant('state').Value:='normal';
+    as_ForSale : begin
+      jsonObj.GetAsVariant('state').Value:='listed';
+      jsonObj.GetAsVariant('locked_until_block').Value:=account.accountInfo.locked_until_block;
+      jsonObj.GetAsVariant('price').Value:=account.accountInfo.price;
+      jsonObj.GetAsVariant('seller_account').Value:=account.accountInfo.account_to_pay;
+      jsonObj.GetAsVariant('private_sale').Value:= (account.accountInfo.new_publicKey.EC_OpenSSL_NID<>0);
+      if not (account.accountInfo.new_publicKey.EC_OpenSSL_NID<>0) then begin
+        jsonObj.GetAsVariant('new_enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountInfo.new_publicKey));
+      end;
+    end
+  else raise Exception.Create('ERROR DEV 20170425-1');
+  end;
+  jsonObj.GetAsVariant('name').Value := account.name;
+  jsonObj.GetAsVariant('type').Value := account.account_type;
+end;
+
+class procedure TPascalCoinJSONComp.FillOperationsHashTreeObject(const OperationsHashTree: TOperationsHashTree; jsonObject: TPCJSONObject);
+begin
+  jsonObject.GetAsVariant('operations').Value:=OperationsHashTree.OperationsCount;
+  jsonObject.GetAsVariant('amount').Value:=ToJSONCurrency(OperationsHashTree.TotalAmount);
+  jsonObject.GetAsVariant('fee').Value:=ToJSONCurrency(OperationsHashTree.TotalFee);
+  jsonObject.GetAsVariant('rawoperations').Value:=OperationsHashTreeToHexaString(OperationsHashTree);
+end;
+
+class procedure TPascalCoinJSONComp.FillPublicKeyObject(const PubKey: TAccountKey; jsonObj: TPCJSONObject);
+begin
+  jsonObj.GetAsVariant('ec_nid').Value := PubKey.EC_OpenSSL_NID;
+  jsonObj.GetAsVariant('x').Value := TCrypto.ToHexaString(PubKey.x);
+  jsonObj.GetAsVariant('y').Value := TCrypto.ToHexaString(PubKey.y);
+  jsonObj.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(PubKey));
+  jsonObj.GetAsVariant('b58_pubkey').Value := TAccountComp.AccountPublicKeyExport(PubKey);
+end;
+
+class function TPascalCoinJSONComp.OperationsHashTreeToHexaString(const OperationsHashTree: TOperationsHashTree): AnsiString;
+var ms : TMemoryStream;
+  raw : TRawBytes;
+Begin
+  ms := TMemoryStream.Create;
+  Try
+    OperationsHashTree.SaveOperationsHashTreeToStream(ms,false);
+    ms.Position := 0;
+    SetLength(raw,ms.Size);
+    ms.ReadBuffer(raw[1],ms.Size);
+    Result := TCrypto.ToHexaString(raw);
+  Finally
+    ms.Free;
+  End;
+end;
+
 { TRPCServer }
 
 Procedure TRPCServer.AddRPCLog(Const Sender : String; Const Message : String);
@@ -446,155 +646,23 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     End;
   End;
 
-  Function OperationsHashTreeToHexaString(Const OperationsHashTree : TOperationsHashTree) : AnsiString;
-  var ms : TMemoryStream;
-    raw : TRawBytes;
-  Begin
-    ms := TMemoryStream.Create;
-    Try
-      OperationsHashTree.SaveOperationsHashTreeToStream(ms,false);
-      ms.Position := 0;
-      SetLength(raw,ms.Size);
-      ms.ReadBuffer(raw[1],ms.Size);
-      Result := TCrypto.ToHexaString(raw);
-    Finally
-      ms.Free;
-    End;
-  End;
-
   Function GetBlock(nBlock : Cardinal; jsonObject : TPCJSONObject) : Boolean;
-  var pcops : TPCOperationsComp;
-    ob : TOperationBlock;
   begin
-    pcops := TPCOperationsComp.Create(Nil);
-    try
-      If FNode.Bank.BlocksCount<=nBlock then begin
-        ErrorNum := CT_RPC_ErrNum_InvalidBlock;
-        ErrorDesc := 'Cannot load Block: '+IntToStr(nBlock);
-        Result := False;
-        Exit;
-      end;
-      ob := FNode.Bank.SafeBox.Block(nBlock).blockchainInfo;
-
-      jsonObject.GetAsVariant('block').Value:=ob.block;
-      jsonObject.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(ob.account_key));
-      jsonObject.GetAsVariant('reward').Value:=ToJSONCurrency(ob.reward);
-      jsonObject.GetAsVariant('fee').Value:=ToJSONCurrency(ob.fee);
-      jsonObject.GetAsVariant('ver').Value:=ob.protocol_version;
-      jsonObject.GetAsVariant('ver_a').Value:=ob.protocol_available;
-      jsonObject.GetAsVariant('timestamp').Value:=Int64(ob.timestamp);
-      jsonObject.GetAsVariant('target').Value:=Int64(ob.compact_target);
-      jsonObject.GetAsVariant('nonce').Value:=Int64(ob.nonce);
-      jsonObject.GetAsVariant('payload').Value:=ob.block_payload;
-      jsonObject.GetAsVariant('sbh').Value:=TCrypto.ToHexaString(ob.initial_safe_box_hash);
-      jsonObject.GetAsVariant('oph').Value:=TCrypto.ToHexaString(ob.operations_hash);
-      jsonObject.GetAsVariant('pow').Value:=TCrypto.ToHexaString(ob.proof_of_work);
-      jsonObject.GetAsVariant('hashratekhs').Value := FNode.Bank.SafeBox.CalcBlockHashRateInKhs(ob.Block,50);
-      jsonObject.GetAsVariant('maturation').Value := FNode.Bank.BlocksCount - ob.block - 1;
-      If FNode.Bank.LoadOperations(pcops,nBlock) then begin
-        jsonObject.GetAsVariant('operations').Value:=pcops.Count;
-      end;
-      Result := True;
-    finally
-      pcops.Free;
+    If FNode.Bank.BlocksCount<=nBlock then begin
+      ErrorNum := CT_RPC_ErrNum_InvalidBlock;
+      ErrorDesc := 'Cannot load Block: '+IntToStr(nBlock);
+      Result := False;
+      Exit;
     end;
+    TPascalCoinJSONComp.FillBlockObject(nBlock,FNode,jsonObject);
+    Result := True;
   end;
 
   Procedure FillOperationResumeToJSONObject(Const OPR : TOperationResume; jsonObject : TPCJSONObject);
-  Var i : Integer;
-    jsonArr : TPCJSONArray;
-    auxObj : TPCJSONObject;
   Begin
-    if Not OPR.valid then begin
-      jsonObject.GetAsVariant('valid').Value := OPR.valid;
-    end;
-    if (OPR.errors<>'') And (Not OPR.valid) then begin
-      jsonObject.GetAsVariant('errors').Value := OPR.errors;
-    end;
-    if OPR.valid then begin
-      jsonObject.GetAsVariant('block').Value:=OPR.Block;
-      jsonObject.GetAsVariant('time').Value:=OPR.time;
-      jsonObject.GetAsVariant('opblock').Value:=OPR.NOpInsideBlock;
-      if (OPR.Block>0) And (OPR.Block<FNode.Bank.BlocksCount) then
-        jsonObject.GetAsVariant('maturation').Value := FNode.Bank.BlocksCount - OPR.Block - 1
-      else jsonObject.GetAsVariant('maturation').Value := null;
-    end;
-    jsonObject.GetAsVariant('optype').Value:=OPR.OpType;
-    jsonObject.GetAsVariant('subtype').Value:=OPR.OpSubtype;
-    If (Not OPR.isMultiOperation) then Begin
-      jsonObject.GetAsVariant('account').Value:=OPR.AffectedAccount;
-      jsonObject.GetAsVariant('signer_account').Value:=OPR.SignerAccount;
-      jsonObject.GetAsVariant('n_operation').Value:=OPR.n_operation;
-    end else begin
-      jsonArr := jsonObject.GetAsArray('senders');
-      for i:=Low(OPR.senders) to High(OPR.Senders) do begin
-        auxObj := jsonArr.GetAsObject(jsonArr.Count);
-        auxObj.GetAsVariant('account').Value := OPR.Senders[i].Account;
-        auxObj.GetAsVariant('n_operation').Value := OPR.Senders[i].N_Operation;
-        auxObj.GetAsVariant('amount').Value := ToJSONCurrency(OPR.Senders[i].Amount * (-1));
-        auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Senders[i].Payload);
-      end;
-      //
-      jsonArr := jsonObject.GetAsArray('receivers');
-      for i:=Low(OPR.Receivers) to High(OPR.Receivers) do begin
-        auxObj := jsonArr.GetAsObject(jsonArr.Count);
-        auxObj.GetAsVariant('account').Value := OPR.Receivers[i].Account;
-        auxObj.GetAsVariant('amount').Value := ToJSONCurrency(OPR.Receivers[i].Amount);
-        auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Receivers[i].Payload);
-      end;
-      jsonArr := jsonObject.GetAsArray('changers');
-      for i:=Low(OPR.Changers) to High(OPR.Changers) do begin
-        auxObj := jsonArr.GetAsObject(jsonArr.Count);
-        auxObj.GetAsVariant('account').Value := OPR.Changers[i].Account;
-        auxObj.GetAsVariant('n_operation').Value := OPR.Changers[i].N_Operation;
-        If public_key in OPR.Changers[i].Changes_type then begin
-          auxObj.GetAsVariant('new_enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(OPR.Changers[i].New_Accountkey));
-        end;
-        If account_name in OPR.Changers[i].Changes_type then begin
-          auxObj.GetAsVariant('new_name').Value := OPR.Changers[i].New_Name;
-        end;
-        If account_type in OPR.Changers[i].Changes_type then begin
-          auxObj.GetAsVariant('new_type').Value := OPR.Changers[i].New_Type;
-        end;
-      end;
-    end;
-    jsonObject.GetAsVariant('optxt').Value:=OPR.OperationTxt;
-    jsonObject.GetAsVariant('fee').Value:=ToJSONCurrency(OPR.Fee);
-    if (Not OPR.isMultiOperation) then begin
-      jsonObject.GetAsVariant('amount').Value:=ToJSONCurrency(OPR.Amount);
-      if (OPR.Balance>=0) And (OPR.valid) then jsonObject.GetAsVariant('balance').Value:=ToJSONCurrency(OPR.Balance);
-      jsonObject.GetAsVariant('payload').Value:=TCrypto.ToHexaString(OPR.OriginalPayload);
-    end else begin
-      jsonObject.GetAsVariant('totalamount').Value:=ToJSONCurrency(OPR.Amount);
-      if (OPR.Balance>=0) And (OPR.valid) then jsonObject.GetAsVariant('balance').Value:=ToJSONCurrency(OPR.Balance);
-    end;
-    If (OPR.OpType = CT_Op_Transaction) then begin
-      If OPR.SignerAccount>=0 then begin
-        jsonObject.GetAsVariant('sender_account').Value:=OPR.SignerAccount;
-      end;
-      If OPR.DestAccount>=0 then begin
-        jsonObject.GetAsVariant('dest_account').Value:=OPR.DestAccount;
-      end;
-    end;
-    If OPR.newKey.EC_OpenSSL_NID>0 then begin
-      jsonObject.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(OPR.newKey));
-    end;
-    if (OPR.valid) And (OPR.OperationHash<>'') then begin
-      jsonObject.GetAsVariant('ophash').Value := TCrypto.ToHexaString(OPR.OperationHash);
-      if (OPR.Block<CT_Protocol_Upgrade_v2_MinBlock) then begin
-        jsonObject.GetAsVariant('old_ophash').Value := TCrypto.ToHexaString(OPR.OperationHash_OLD);
-      end;
-    end;
+    TPascalCoinJSONComp.FillOperationObject(OPR,FNode.Bank.BlocksCount,jsonObject);
   end;
 
-  Procedure FillOperationsHashTreeToJSONObject(Const OperationsHashTree : TOperationsHashTree; jsonObject : TPCJSONObject);
-  Begin
-    jsonObject.GetAsVariant('operations').Value:=OperationsHashTree.OperationsCount;
-    jsonObject.GetAsVariant('amount').Value:=ToJSONCurrency(OperationsHashTree.TotalAmount);
-    jsonObject.GetAsVariant('fee').Value:=ToJSONCurrency(OperationsHashTree.TotalFee);
-    jsonObject.GetAsVariant('rawoperations').Value:=OperationsHashTreeToHexaString(OperationsHashTree);
-  End;
-
   Function GetAccountOperations(accountNumber : Cardinal; jsonArray : TPCJSONArray; maxBlocksDepth, startReg, maxReg: Integer; forceStartBlock : Cardinal) : Boolean;
   var list : TList;
     Op : TPCOperation;
@@ -620,7 +688,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           FNode.Operations.OperationsHashTree.GetOperationsAffectingAccount(accountNumber,list);
           for i := list.Count - 1 downto 0 do begin
             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.Block := FNode.Operations.OperationBlock.block;
               OPR.Balance := FNode.Operations.SafeBoxTransaction.Account(accountNumber).balance;
@@ -760,7 +828,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorNum := CT_RPC_ErrNum_InvalidOperation;
           Exit;
         end;
-        TPCOperation.OperationToOperationResume(0,opt,sender,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,sender,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         Result := true;
       finally
@@ -791,7 +859,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       if opt=nil then exit;
       try
         OperationsHashTree.AddOperationToHashTree(opt);
-        FillOperationsHashTreeToJSONObject(OperationsHashTree,GetResultObject);
+        TPascalCoinJSONComp.FillOperationsHashTreeObject(OperationsHashTree,GetResultObject);
         Result := true;
       finally
         opt.Free;
@@ -879,7 +947,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorNum := CT_RPC_ErrNum_InvalidOperation;
           Exit;
         end;
-        TPCOperation.OperationToOperationResume(0,opck,account_signer,opr);
+        TPCOperation.OperationToOperationResume(0,opck,False,account_signer,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
         Result := true;
       finally
@@ -1174,7 +1242,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       if opck=nil then exit;
       try
         OperationsHashTree.AddOperationToHashTree(opck);
-        FillOperationsHashTreeToJSONObject(OperationsHashTree,GetResultObject);
+        TPascalCoinJSONComp.FillOperationsHashTreeObject(OperationsHashTree,GetResultObject);
         Result := true;
       finally
         opck.Free;
@@ -1202,7 +1270,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       for i := 0 to OperationsHashTree.OperationsCount - 1 do begin
         Op := OperationsHashTree.GetOperation(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.Balance := -1;
         end else OPR := CT_TOperationResume_NUL;
@@ -1248,40 +1316,6 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     End;
   End;
 
-  Procedure FillAccountObject(Const account : TAccount; jsonObj : TPCJSONObject);
-  Begin
-    jsonObj.GetAsVariant('account').Value:=account.account;
-    jsonObj.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountInfo.accountKey));
-    jsonObj.GetAsVariant('balance').Value:=ToJSONCurrency(account.balance);
-    jsonObj.GetAsVariant('n_operation').Value:=account.n_operation;
-    jsonObj.GetAsVariant('updated_b').Value:=account.updated_block;
-    case account.accountInfo.state of
-      as_Normal : jsonObj.GetAsVariant('state').Value:='normal';
-      as_ForSale : begin
-        jsonObj.GetAsVariant('state').Value:='listed';
-        jsonObj.GetAsVariant('locked_until_block').Value:=account.accountInfo.locked_until_block;
-        jsonObj.GetAsVariant('price').Value:=account.accountInfo.price;
-        jsonObj.GetAsVariant('seller_account').Value:=account.accountInfo.account_to_pay;
-        jsonObj.GetAsVariant('private_sale').Value:= (account.accountInfo.new_publicKey.EC_OpenSSL_NID<>0);
-        if not (account.accountInfo.new_publicKey.EC_OpenSSL_NID<>0) then begin
-          jsonObj.GetAsVariant('new_enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountInfo.new_publicKey));
-        end;
-      end
-    else raise Exception.Create('ERROR DEV 20170425-1');
-    end;
-    jsonObj.GetAsVariant('name').Value := account.name;
-    jsonObj.GetAsVariant('type').Value := account.account_type;
-  end;
-
-  Procedure FillPublicKeyObject(const PubKey : TAccountKey; jsonObj : TPCJSONObject);
-  Begin
-    jsonObj.GetAsVariant('ec_nid').Value := PubKey.EC_OpenSSL_NID;
-    jsonObj.GetAsVariant('x').Value := TCrypto.ToHexaString(PubKey.x);
-    jsonObj.GetAsVariant('y').Value := TCrypto.ToHexaString(PubKey.y);
-    jsonObj.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(PubKey));
-    jsonObj.GetAsVariant('b58_pubkey').Value := TAccountComp.AccountPublicKeyExport(PubKey);
-  End;
-
   Function DoEncrypt(RawPayload : TRawBytes; pub_key : TAccountKey; Const Payload_method, EncodePwd : AnsiString) : Boolean;
   Var f_raw : TRawBytes;
   begin
@@ -1473,7 +1507,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       last_n_operation := params.AsCardinal('last_n_operation',0);
       If not SignListAccountForSaleEx(params,OperationsHashTree,accountpubkey,last_n_operation) then Exit
       else Result := True;
-      FillOperationsHashTreeToJSONObject(OperationsHashTree,GetResultObject);
+      TPascalCoinJSONComp.FillOperationsHashTreeObject(OperationsHashTree,GetResultObject);
     finally
       OperationsHashTree.Free;
     end;
@@ -1682,7 +1716,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       last_n_operation := params.AsCardinal('last_n_operation',0);
       If not SignChangeAccountInfoEx(params,OperationsHashTree,accountpubkey,last_n_operation) then Exit
       else Result := True;
-      FillOperationsHashTreeToJSONObject(OperationsHashTree,GetResultObject);
+      TPascalCoinJSONComp.FillOperationsHashTreeObject(OperationsHashTree,GetResultObject);
     finally
       OperationsHashTree.Free;
     end;
@@ -1709,7 +1743,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       last_n_operation := params.AsCardinal('last_n_operation',0);
       If not SignDelistAccountForSaleEx(params,OperationsHashTree,accountpubkey,last_n_operation) then Exit
       else Result := True;
-      FillOperationsHashTreeToJSONObject(OperationsHashTree,GetResultObject);
+      TPascalCoinJSONComp.FillOperationsHashTreeObject(OperationsHashTree,GetResultObject);
     finally
       OperationsHashTree.Free;
     end;
@@ -1805,7 +1839,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       last_n_operation := params.AsCardinal('last_n_operation',0);
       If not SignBuyAccountEx(params,OperationsHashTree,accountpubkey,last_n_operation) then Exit
       else Result := True;
-      FillOperationsHashTreeToJSONObject(OperationsHashTree,GetResultObject);
+      TPascalCoinJSONComp.FillOperationsHashTreeObject(OperationsHashTree,GetResultObject);
     finally
       OperationsHashTree.Free;
     end;
@@ -1860,7 +1894,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := errors;
           Exit;
         end else Result := True;
-        TPCOperation.OperationToOperationResume(0,opt,c_account,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,c_account,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
       finally
         OperationsHashTree.Free;
@@ -1919,7 +1953,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := errors;
           Exit;
         end else Result := True;
-        TPCOperation.OperationToOperationResume(0,opt,c_account,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,c_account,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
       finally
         OperationsHashTree.Free;
@@ -1961,7 +1995,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := errors;
           Exit;
         end else Result := True;
-        TPCOperation.OperationToOperationResume(0,opt,c_account,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,c_account,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
       finally
         OperationsHashTree.Free;
@@ -2020,7 +2054,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := errors;
           Exit;
         end else Result := True;
-        TPCOperation.OperationToOperationResume(0,opt,c_account,opr);
+        TPCOperation.OperationToOperationResume(0,opt,False,c_account,opr);
         FillOperationResumeToJSONObject(opr,GetResultObject);
       finally
         OperationsHashTree.Free;
@@ -2071,7 +2105,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
        if accountNumber >= 0 then begin
           account := FNode.Operations.SafeBoxTransaction.Account(accountNumber);
           if (accountType = -1) OR (Integer(account.account_type) = accountType) then
-             FillAccountObject(account,output.GetAsObject(output.Count));
+             TPascalCoinJSONComp.FillAccountObject(account,output.GetAsObject(output.Count));
        end;
     end else begin
       // Search by type
@@ -2079,7 +2113,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         account := FNode.Operations.SafeBoxTransaction.Account(i);
         if (accountType = -1) OR (Integer(account.account_type) = accountType) then begin
           // Found a match
-          FillAccountObject(account,output.GetAsObject(output.Count));
+          TPascalCoinJSONComp.FillAccountObject(account,output.GetAsObject(output.Count));
           if output.Count>=max then break;
         end;
       end;
@@ -2167,7 +2201,7 @@ begin
     c := params.GetAsVariant('account').AsCardinal(CT_MaxAccount);
     if (c>=0) And (c<FNode.Bank.AccountsCount) then begin
       account := FNode.Operations.SafeBoxTransaction.Account(c);
-      FillAccountObject(account,GetResultObject);
+      TPascalCoinJSONComp.FillAccountObject(account,GetResultObject);
       Result := True;
     end else begin
       ErrorNum := CT_RPC_ErrNum_InvalidAccount;
@@ -2196,7 +2230,7 @@ begin
       for j := 0 to ocl.Count - 1 do begin
         if (j>=l) then begin
           account := FNode.Operations.SafeBoxTransaction.Account(ocl.Get(j));
-          FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+          TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
         end;
         if (k>0) And ((j+1)>=(k+l)) then break;
       end;
@@ -2210,7 +2244,7 @@ begin
         for j := 0 to ocl.Count - 1 do begin
           if (c>=l) then begin
             account := FNode.Operations.SafeBoxTransaction.Account(ocl.Get(j));
-            FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+            TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
           end;
           inc(c);
           if (k>0) And (c>=(k+l)) then break;
@@ -2288,7 +2322,7 @@ begin
         jso := jsonarr.GetAsObject(jsonarr.count);
         jso.GetAsVariant('name').Value := _RPCServer.WalletKeys.Key[i].Name;
         jso.GetAsVariant('can_use').Value := (_RPCServer.WalletKeys.Key[i].CryptedKey<>'');
-        FillPublicKeyObject(_RPCServer.WalletKeys.Key[i].AccountKey,jso);
+        TPascalCoinJSONComp.FillPublicKeyObject(_RPCServer.WalletKeys.Key[i].AccountKey,jso);
       end;
       if (k>0) And ((i+1)>=(j+k)) then break;
     end;
@@ -2304,7 +2338,7 @@ begin
       ErrorDesc := 'Public key not found in wallet';
       exit;
     end;
-    FillPublicKeyObject(_RPCServer.WalletKeys.AccountsKeyList.AccountKey[i],GetResultObject);
+    TPascalCoinJSONComp.FillPublicKeyObject(_RPCServer.WalletKeys.AccountsKeyList.AccountKey[i],GetResultObject);
     Result := true;
   end else if (method='getblock') then begin
     // Param "block" contains block number (0..getblockcount-1)
@@ -2373,7 +2407,7 @@ begin
           ErrorDesc := 'Block/Operation not found: '+IntToStr(c)+'/'+IntToStr(i)+' BlockOperations:'+IntToStr(pcops.Count);
           Exit;
         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.time:=pcops.OperationBlock.timestamp;
           opr.Balance := -1;
@@ -2405,7 +2439,7 @@ begin
         j := params.AsInteger('start',0);
         for i := 0 to pcops.Count - 1 do 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.time:=pcops.OperationBlock.timestamp;
               opr.Balance := -1; // Don't include!
@@ -2445,7 +2479,7 @@ begin
     // Create result
     GetResultArray;
     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;
         ErrorDesc := 'Error converting data';
         exit;
@@ -2497,7 +2531,7 @@ begin
           end;
       else Raise Exception.Create('ERROR DEV 20171120-4');
       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;
         ErrorDesc := 'Error 20161026-1';
       end;
@@ -2775,7 +2809,7 @@ begin
       exit;
     end;
     if (TAccountComp.IsValidAccountKey(account.accountInfo.accountKey,ansistr)) then begin
-      FillPublicKeyObject(account.accountInfo.accountKey,GetResultObject);
+      TPascalCoinJSONComp.FillPublicKeyObject(account.accountInfo.accountKey,GetResultObject);
       Result := True;
     end else begin
       ErrorDesc:= ansistr;
@@ -2832,7 +2866,7 @@ begin
     try
       ecpkey.GenerateRandomPrivateKey(params.AsInteger('ec_nid',CT_Default_EC_OpenSSL_NID));
       _RPCServer.FWalletKeys.AddPrivateKey(params.AsString('name',DateTimeToStr(now)),ecpkey);
-      FillPublicKeyObject(ecpkey.PublicKey,GetResultObject);
+      TPascalCoinJSONComp.FillPublicKeyObject(ecpkey.PublicKey,GetResultObject);
       Result := true;
     finally
       ecpkey.Free;

+ 45 - 3
src/core/UTxMultiOperation.pas

@@ -105,7 +105,7 @@ Type
     procedure InitializeData; override;
     function SaveOpToStream(Stream: TStream; SaveExtendedData : 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
     function GetBufferForOpHash(UseProtocolV2 : Boolean): TRawBytes; override;
 
@@ -141,6 +141,7 @@ Type
     Function IndexOfAccountReceiver(nAccount : Cardinal; startPos : Integer) : Integer;
     Function IndexOfAccountChanger(nAccount : Cardinal) : 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;
     Property Data : TOpMultiOperationData read FData;
@@ -187,12 +188,53 @@ begin
   Result := -1;
 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
-  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.Receivers := FData.txReceivers;
   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;
 
 function TOpMultiOperation.IndexOfAccountChangeNameTo(const newName: AnsiString): Integer;

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

@@ -899,7 +899,7 @@ begin
     if FPendingOperations then begin
       for i := Node.Operations.Count - 1 downto 0 do begin
         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.Block := Node.Bank.BlocksCount;
           OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SignerAccount).balance;
@@ -937,7 +937,7 @@ begin
               FOperationsResume.Add(OPR);
               // Reverse operations inside a block
               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.Block := bend;
                   opr.time := opc.OperationBlock.timestamp;
@@ -957,7 +957,7 @@ begin
           Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
           for i := list.Count - 1 downto 0 do begin
             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.Block := Node.Operations.OperationBlock.block;
               OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;