Browse Source

Merge pull request #44 from PascalCoinDev/master

Finalize E-PASA implementation on JSON-RPC calls and document it
Albert Molina 4 years ago
parent
commit
d90c188e67

+ 10 - 0
CHANGELOG.md

@@ -13,6 +13,16 @@
   - Added "ABSTRACTMEM_USE_CACHE_ON_LISTS","ABSTRACTMEM_CACHE_MAX_ACCOUNTS","ABSTRACTMEM_CACHE_MAX_PUBKEYS" in order to customize cache values
   - Added "ABSTRACTMEM_USE_CACHE_ON_LISTS","ABSTRACTMEM_CACHE_MAX_ACCOUNTS","ABSTRACTMEM_CACHE_MAX_PUBKEYS" in order to customize cache values
 - Improved performance when downloading Safebox (Fresh installation)
 - Improved performance when downloading Safebox (Fresh installation)
 - JSON-RPC changes:  
 - JSON-RPC changes:  
+  - Updated "Operation Object" and "Multi Operation Object" return values:
+    **(IF THE WALLET IS UNLOCKED Will automatically try to decrypt encoded payloads and also return E-PASA used)**
+    - "senders" or "receivers" : ARRAY
+      - "account_epasa" : (String) If operation was using valid E-PASA format and can be decoded, will return E-PASA format used
+      - "unenc_payload" : (String) If payload can be decoded returns unencoded value in readable format (no HEXASTRING)
+      - "unenc_hexpayload" : (HEXASTRING) Unencoded value in hexastring
+      - "payload_method" : (String) Can be "key" or "pwd"
+      - "enc_pubkey" : HexaString with public key (if "payload_method"="key")
+      - "pwd" : String with password used (if "payload_method"="pwd")
+  - Payload encoding will automatically set "payload_type" value based on encoding params in order to store E-PASA standard
   - Updated "findaccounts": 
   - Updated "findaccounts": 
     -New param "end" (integer, -1 for default): Will search from "start" to "end" (if "end"=-1 will search to the end)
     -New param "end" (integer, -1 for default): Will search from "start" to "end" (if "end"=-1 will search to the end)
   - New method "findblocks": Will search and return an array of "Block objects"
   - New method "findblocks": Will search and return an array of "Block objects"

+ 1 - 102
src/core/UAccounts.pas

@@ -26,7 +26,7 @@ interface
 
 
 uses
 uses
   Classes, SysUtils, UConst, UCrypto, SyncObjs, UThread, UBaseTypes,
   Classes, SysUtils, UConst, UCrypto, SyncObjs, UThread, UBaseTypes,
-  UPCOrderedLists, UPCDataTypes, UPCSafeBoxRootHash, UEPasa,
+  UPCOrderedLists, UPCDataTypes, UPCSafeBoxRootHash,
   UPCHardcodedRandomHashTable, UJSONFunctions,
   UPCHardcodedRandomHashTable, UJSONFunctions,
   {$IFDEF USE_ABSTRACTMEM}
   {$IFDEF USE_ABSTRACTMEM}
   UPCAbstractMem, UPCAbstractMemAccountKeys,
   UPCAbstractMem, UPCAbstractMemAccountKeys,
@@ -118,8 +118,6 @@ Type
     Class procedure SaveTOperationBlockToStream(const stream : TStream; const operationBlock:TOperationBlock);
     Class procedure SaveTOperationBlockToStream(const stream : TStream; const operationBlock:TOperationBlock);
     Class Function LoadTOperationBlockFromStream(const stream : TStream; var operationBlock:TOperationBlock) : Boolean;
     Class Function LoadTOperationBlockFromStream(const stream : TStream; var operationBlock:TOperationBlock) : Boolean;
     Class Function AccountToTxt(const Account : TAccount) : String;
     Class Function AccountToTxt(const Account : TAccount) : String;
-    Class Function DecodeEPASAPartial(AAccount : Cardinal; const APayload : TBytes; APayloadType : Byte; ADefault : TEPasa) : TEPasa;
-    Class Function TryDecodeEPASAPartial(AAccount : Cardinal; const APayload : TBytes; APayloadType : Byte; out AEPasa : TEPasa) : Boolean;
   End;
   End;
 
 
   TPCSafeBox = Class;
   TPCSafeBox = Class;
@@ -1900,105 +1898,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-class Function TAccountComp.DecodeEPASAPartial(AAccount : Cardinal; const APayload : TBytes; APayloadType : Byte; ADefault : TEPasa) : TEPasa;
-begin
-  if NOT TryDecodeEPASAPartial(AAccount, APayload, APayloadType, Result) then
-    Result := ADefault;
-end;
-
-class Function TAccountComp.TryDecodeEPASAPartial(AAccount : Cardinal; const APayload : TBytes; APayloadType : Byte; out AEPasa : TEPasa) : Boolean;
-var
-  LPayloadType : TPayloadType;
-  LUnencryptedPayloadBytes : TBytes;
-  LEPasaStr : String;
-  LPublic, LRecipientKeyEncrypted, LSenderKeyEncrypted,
-  LPasswordEncrypted, LAsciiFormatted, LHexFormatted, LBase58Formatted, LAddressedByName : Boolean;
-begin
-  LPayloadType := TEPasaComp.FromProtocolValue(APayloadType);
-  LPublic := LPayloadType.HasTrait(ptPublic);
-  LRecipientKeyEncrypted := LPayloadType.HasTrait(ptRecipientKeyEncrypted);
-  LSenderKeyEncrypted := LPayloadType.HasTrait(ptSenderKeyEncrypted);
-  LPasswordEncrypted := LPayloadType.HasTrait(ptPasswordEncrypted);
-  LAsciiFormatted := LPayloadType.HasTrait(ptAsciiFormatted);
-  LHexFormatted := LPayloadType.HasTrait(ptHexFormatted);
-  LBase58Formatted := LPayloadType.HasTrait(ptBase58Formatted);
-  LAddressedByName := LPayloadType.HasTrait(ptAddressedByName);
-
-  if LPayloadType.HasTrait(ptAddressedByName) then begin
-     (*LEPasaStr := Self.GetMempoolAccount(AAccount).name.ToPrintable;
-     if LEPasaStr.IsEmpty then
-       Exit(False); *)
-     // Note: since doing a name resolution for every encountered addressed-by-name EPASA,
-     // would overwhelm the SafeBox with lookups, names are not resolved.
-     // So in V5 addressed-by-name EPASA's auto-resolved as addressed-by-number
-     LEPasaStr := TAccountComp.AccountNumberToAccountTxtNumber(AAccount);
-  end else LEPasaStr := TAccountComp.AccountNumberToAccountTxtNumber(AAccount);
-
-
-  // payload opening char
-  if LPublic then begin
-     LEPasaStr := LEPasaStr + '[';
-  end;
-
-  if LSenderKeyEncrypted then begin
-     LEPasaStr := LEPasaStr + '<';
-  end;
-
-  if LRecipientKeyEncrypted then begin
-     LEPasaStr := LEPasaStr + '(';
-  end;
-
-  if LPasswordEncrypted then begin
-     LEPasaStr := LEPasaStr + '{';
-  end;
-
-  // payload data
-  if LPublic OR LSenderKeyEncrypted OR LRecipientKeyEncrypted OR LPasswordEncrypted then begin
-
-    if LPublic then
-      LUnencryptedPayloadBytes := APayload
-    else if LSenderKeyEncrypted then
-      Exit(False) // Todo: Partial decoding does not decrypt due to performance penalty if always decrypting. This needs to be implemented as a IFuture<TBytes> value with lazy evaluation.
-    else if LRecipientKeyEncrypted then
-      Exit(False) // Todo: Partial decoding does not decrypt due to performance penalty if always decrypting. This needs to be implemented as a IFuture<TBytes> value with lazy evaluation.
-    else if LPasswordEncrypted then
-      Exit(False) // Todo: Partial decoding does not decrypt due to performance penalty if always decrypting. This needs to be implemented as a IFuture<TBytes> value with lazy evaluation..
-    else raise Exception.Create('Internal Error a0805389-df1a-4b40-b12e-d22327a3d049');
-
-    // decrypt data
-     if LAsciiFormatted then
-       LEPasaStr := LEPasaStr + '"' + TEncoding.ASCII.GetString(LUnencryptedPayloadBytes) + '"'
-     else if LHexFormatted then
-       LEPasaStr := LEPasaStr + '0x' + THexEncoding.Encode(LUnencryptedPayloadBytes)
-     else if LBase58Formatted then
-       LEPasaStr := LEPasaStr + TPascalBase58Encoding.Encode(LUnencryptedPayloadBytes)
-     else raise Exception.Create('Internal Error 67a61d3e-eef2-40a9-8d92-45570f400c1e');
-  end;
-
-  // payload closing char
-  if LPublic then begin
-     LEPasaStr := LEPasaStr + ']';
-  end;
-
-  if LSenderKeyEncrypted then begin
-     LEPasaStr := LEPasaStr + '>';
-  end;
-
-  if LRecipientKeyEncrypted then begin
-     LEPasaStr := LEPasaStr + ')';
-  end;
-
-  if LPasswordEncrypted then begin
-     LEPasaStr := LEPasaStr + '}';
-  end;
-
-  // Parse as EPASA
-  if NOT TEPasa.TryParse(LEPasaStr, AEPasa) then
-    Exit(False);
-
-  Result := true;
-end;
-
 {$IFNDEF VER210}
 {$IFNDEF VER210}
 {$DEFINE DELPHIXE}
 {$DEFINE DELPHIXE}
 {$ENDIF}
 {$ENDIF}

+ 5 - 5
src/core/UBlockChain.pas

@@ -28,7 +28,7 @@ uses
   Classes, UCrypto, UAccounts, ULog, UThread, SyncObjs, UBaseTypes, SysUtils,
   Classes, UCrypto, UAccounts, ULog, UThread, SyncObjs, UBaseTypes, SysUtils,
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
   {$IFDEF USE_ABSTRACTMEM}UPCAbstractMem,{$ENDIF}
   {$IFDEF USE_ABSTRACTMEM}UPCAbstractMem,{$ENDIF}
-  UPCDataTypes, UChunk, UEPasa;
+  UPCDataTypes, UChunk;
 
 
 {
 {
 
 
@@ -139,7 +139,6 @@ Type
 
 
   TMultiOpSender = Record
   TMultiOpSender = Record
     Account : Cardinal;
     Account : Cardinal;
-    AccountEPASA : TEPasa;
     Amount : Int64;
     Amount : Int64;
     N_Operation : Cardinal;
     N_Operation : Cardinal;
     OpData : TMultiOpData; // Filled only when Operation is TOpData type
     OpData : TMultiOpData; // Filled only when Operation is TOpData type
@@ -149,7 +148,6 @@ Type
   TMultiOpSenders = Array of TMultiOpSender;
   TMultiOpSenders = Array of TMultiOpSender;
   TMultiOpReceiver = Record
   TMultiOpReceiver = Record
     Account : Cardinal;
     Account : Cardinal;
-    AccountEPASA : TEPasa;
     Amount : Int64;
     Amount : Int64;
     Payload : TOperationPayload;
     Payload : TOperationPayload;
   end;
   end;
@@ -577,7 +575,7 @@ Type
 Const
 Const
   CT_TOperationPayload_NUL : TOperationPayload = (payload_type:0;payload_raw:Nil);
   CT_TOperationPayload_NUL : TOperationPayload = (payload_type:0;payload_raw:Nil);
   CT_TOperationResume_NUL : TOperationResume = (valid:false;Block:0;NOpInsideBlock:-1;OpType:0;OpSubtype:0;time:0;AffectedAccount:0;SignerAccount:-1;n_operation:0;DestAccount:-1;SellerAccount:-1;newKey:(EC_OpenSSL_NID:0;x:Nil;y:Nil);OperationTxt:'';Amount:0;Fee:0;Balance:0;OriginalPayload:(payload_type:0;payload_raw:nil);PrintablePayload:'';OperationHash:Nil;OperationHash_OLD:Nil;errors:'';isMultiOperation:False;Senders:Nil;Receivers:Nil;changers:Nil);
   CT_TOperationResume_NUL : TOperationResume = (valid:false;Block:0;NOpInsideBlock:-1;OpType:0;OpSubtype:0;time:0;AffectedAccount:0;SignerAccount:-1;n_operation:0;DestAccount:-1;SellerAccount:-1;newKey:(EC_OpenSSL_NID:0;x:Nil;y:Nil);OperationTxt:'';Amount:0;Fee:0;Balance:0;OriginalPayload:(payload_type:0;payload_raw:nil);PrintablePayload:'';OperationHash:Nil;OperationHash_OLD:Nil;errors:'';isMultiOperation:False;Senders:Nil;Receivers:Nil;changers:Nil);
-  CT_TMultiOpSender_NUL : TMultiOpSender =  (Account:0;(*AccountEPASA:TEPasa.Empty;*)Amount:0;N_Operation:0;Payload:(payload_type:0;payload_raw:Nil);Signature:(r:Nil;s:Nil));
+  CT_TMultiOpSender_NUL : TMultiOpSender =  (Account:0;Amount:0;N_Operation:0;Payload:(payload_type:0;payload_raw:Nil);Signature:(r:Nil;s:Nil));
   CT_TMultiOpReceiver_NUL : TMultiOpReceiver = (Account:0;Amount:0;Payload:(payload_type:0;payload_raw:Nil));
   CT_TMultiOpReceiver_NUL : TMultiOpReceiver = (Account:0;Amount:0;Payload:(payload_type:0;payload_raw:Nil));
   CT_TMultiOpChangeInfo_NUL : TMultiOpChangeInfo = (Account:0;N_Operation:0;Changes_type:[];New_Accountkey:(EC_OpenSSL_NID:0;x:Nil;y:Nil);New_Name:Nil;New_Type:0;New_Data:Nil;Seller_Account:-1;Account_Price:-1;Locked_Until_Block:0;
   CT_TMultiOpChangeInfo_NUL : TMultiOpChangeInfo = (Account:0;N_Operation:0;Changes_type:[];New_Accountkey:(EC_OpenSSL_NID:0;x:Nil;y:Nil);New_Name:Nil;New_Type:0;New_Data:Nil;Seller_Account:-1;Account_Price:-1;Locked_Until_Block:0;
     Hashed_secret:Nil;
     Hashed_secret:Nil;
@@ -3818,7 +3816,9 @@ begin
   l := FList.LockList;
   l := FList.LockList;
   try
   try
     if index<l.Count then Result := POperationResume(l[index])^
     if index<l.Count then Result := POperationResume(l[index])^
-    else Result := CT_TOperationResume_NUL;
+    else begin
+      Result := CT_TOperationResume_NUL;
+    end;
   finally
   finally
     FList.UnlockList;
     FList.UnlockList;
   end;
   end;

+ 36 - 1
src/core/UEPasa.pas

@@ -73,6 +73,7 @@ type
   public
   public
     function HasTrait(APayloadTrait: TPayloadTrait): Boolean; inline;
     function HasTrait(APayloadTrait: TPayloadTrait): Boolean; inline;
     function ToProtocolValue : byte;
     function ToProtocolValue : byte;
+    function IsValid : Boolean;
   end;
   end;
 
 
   { TEPasa }
   { TEPasa }
@@ -244,6 +245,33 @@ begin
   Result := APayloadTrait in Self;
   Result := APayloadTrait in Self;
 end;
 end;
 
 
+function TPayloadTypeHelper.IsValid: Boolean;
+var LValue, LEncryptedBits, LFormattedBits : Byte;
+begin
+  { As described on PIP-0027 E-PASA:
+    Bits 0..3 describe how payload is encrypted. 1 option (and only 1) must be selected
+    Bits 4..6 describe how is data encoded: String, Hexa or Base58. 1 option (and 1 only 1) must be selected
+
+    IsValid = 1 bit from 0..3 and 1 bit from 4..6 must be selected
+  }
+  LValue := Self.ToProtocolValue;
+  LEncryptedBits := (LValue and $0F); // 0000 1111
+  LFormattedBits := (LValue and $70); // 0111 0000
+  Result :=
+      (
+         ((LEncryptedBits and BYTE_BIT_0)=BYTE_BIT_0)
+      or ((LEncryptedBits and BYTE_BIT_1)=BYTE_BIT_1)
+      or ((LEncryptedBits and BYTE_BIT_2)=BYTE_BIT_2)
+      or ((LEncryptedBits and BYTE_BIT_3)=BYTE_BIT_3)
+      )
+      and
+      (
+         ((LFormattedBits and BYTE_BIT_4)=BYTE_BIT_4)
+      or ((LFormattedBits and BYTE_BIT_5)=BYTE_BIT_5)
+      or ((LFormattedBits and BYTE_BIT_6)=BYTE_BIT_6)
+      );
+end;
+
 function TPayloadTypeHelper.ToProtocolValue : Byte;
 function TPayloadTypeHelper.ToProtocolValue : Byte;
 begin
 begin
   Result := TEPasaComp.GetPayloadTypeProtocolByte(Self);
   Result := TEPasaComp.GetPayloadTypeProtocolByte(Self);
@@ -390,9 +418,12 @@ var
   LPayloadContent: String;
   LPayloadContent: String;
 begin
 begin
   Result := string.Empty;
   Result := string.Empty;
+  if PayloadType.HasTrait(ptNonDeterministic) then Exit;
+
   if (PayloadType.HasTrait(ptAddressedByName)) then begin
   if (PayloadType.HasTrait(ptAddressedByName)) then begin
     Result := Result + TPascal64Encoding.Escape(AccountName);
     Result := Result + TPascal64Encoding.Escape(AccountName);
   end else begin
   end else begin
+    if (Not Account.HasValue) then Exit;
     Result := Result + Account.Value.ToString();
     Result := Result + Account.Value.ToString();
     if (AccountChecksum.HasValue) then begin
     if (AccountChecksum.HasValue) then begin
       Result := Result + String.Format('-%u', [AccountChecksum.Value]);
       Result := Result + String.Format('-%u', [AccountChecksum.Value]);
@@ -423,6 +454,10 @@ begin
   end;
   end;
 
 
   if (not AOmitExtendedChecksum) then begin
   if (not AOmitExtendedChecksum) then begin
+    if (ExtendedChecksum='') then begin
+      // Need to compute:
+      ExtendedChecksum := TEPasaComp.ComputeExtendedChecksum(Result);
+    end;
     Result := Result + string.Format(':%s', [ExtendedChecksum]);
     Result := Result + string.Format(':%s', [ExtendedChecksum]);
   end;
   end;
 end;
 end;
@@ -494,7 +529,7 @@ var
   LActualAccountChecksum: Byte;
   LActualAccountChecksum: Byte;
 begin
 begin
   AErrorCode := EPasaErrorCode.Success;
   AErrorCode := EPasaErrorCode.Success;
-  AEPasa := TEPasa.Empty;
+  AEPasa.Clear;
   if (string.IsNullOrEmpty(AEPasaText)) then begin
   if (string.IsNullOrEmpty(AEPasaText)) then begin
     AErrorCode := EPasaErrorCode.BadFormat;
     AErrorCode := EPasaErrorCode.BadFormat;
     Exit(False);
     Exit(False);

+ 179 - 0
src/core/UEPasaDecoder.pas

@@ -0,0 +1,179 @@
+unit UEPasaDecoder;
+
+{ Copyright (c) PascalCoin Developers - Herman Schoenfeld - Albert Molina
+
+  PIP-0027: E-PASA Reference Implementation
+  See: https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0027.md
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  This unit is a part of the PascalCoin Project, an infinitely scalable
+  cryptocurrency. Find us here:
+  Source: https://github.com/PascalCoin/PascalCoin
+
+  THIS LICENSE HEADER MUST NOT BE REMOVED.
+}
+
+{$IFDEF FPC}
+  {$MODE DELPHI}
+  {$ZEROBASEDSTRINGS OFF}
+{$ENDIF FPC}
+
+interface
+
+{$I ./../config.inc}
+
+uses
+  SysUtils,
+  TypInfo,
+  {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
+  UBlockChain, UNode, UBaseTypes,
+  UAccounts,
+  UEncoding,
+  UEPasa,
+  UWallet;
+
+type
+  TDecodeEPasaResult = (der_Decoded, der_Undefined, der_NonDeterministic, der_InvalidPayloadType, der_AccountNameNotFound, der_NotEnoughData, der_PrivateKeyNotFound, der_PasswordNotFound);
+
+  TEPasaDecoder = Class
+  public
+    class Function TryDecodeEPASA(AAccount : Cardinal; const APayload : TOperationPayload; const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>;
+      out ADecodeEPasaResult : TDecodeEPasaResult; out AEPasa : TEPasa) : Boolean; overload;
+    class Function TryDecodeEPASA(AAccount : Cardinal; const APayload : TOperationPayload; const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>;
+      out AEPasa : TEPasa) : Boolean; overload;
+    class Function DecodeEPASA(AAccount : Cardinal; const APayload : TOperationPayload; const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>) : String; overload;
+  End;
+
+implementation
+
+uses UPCEncryption, UCommon;
+
+{ TEPasaDecoder }
+
+class function TEPasaDecoder.TryDecodeEPASA(AAccount: Cardinal;
+  const APayload: TOperationPayload; const ANode : TNode; const AWalletKeys: TWalletKeys;
+  const APasswords: TList<String>; out ADecodeEPasaResult: TDecodeEPasaResult;
+  out AEPasa: TEPasa): Boolean;
+var
+  LUnencryptedPayloadBytes, LPwd : TBytes;
+  LDone : Boolean;
+  i : Integer;
+begin
+  LUnencryptedPayloadBytes := Nil;
+  AEPasa.Clear;
+  Result := False;
+  ADecodeEPasaResult := der_Decoded;
+  AEPasa.Account := AAccount;
+  AEPasa.AccountChecksum := TEPasa.CalculateAccountChecksum(AAccount);
+  AEPasa.PayloadType := TEPasaComp.FromProtocolValue(APayload.payload_type);
+  if AEPasa.PayloadType.HasTrait(ptNonDeterministic) then begin
+    ADecodeEPasaResult := der_NonDeterministic;
+    Exit(False);
+  end;
+  if Not AEPasa.PayloadType.IsValid then begin
+    ADecodeEPasaResult := der_InvalidPayloadType;
+    Exit(False);
+  end;
+
+  if AEPasa.PayloadType.HasTrait(ptAddressedByName) then begin
+    if (AEPasa.PayloadType.HasTrait(ptPublic) and
+       AEPasa.PayloadType.HasTrait(ptBase58Formatted)) then begin
+      // PayToKey candidate...
+      AEPasa.AccountName := '@';
+    end else begin
+      if Assigned(ANode) then begin
+        AEPasa.AccountName := ANode.GetMempoolAccount(AAccount).name.ToPrintable;
+      end;
+      if AEPasa.AccountName='' then begin
+        ADecodeEPasaResult := der_AccountNameNotFound; // Will continue processing
+      end;
+    end;
+  end;
+
+  // payload data
+  if (Length(APayload.payload_raw)=0) then begin
+    // Nothing to decode...
+  end else if (AEPasa.PayloadType.HasTrait(ptSenderKeyEncrypted)) or (AEPasa.PayloadType.HasTrait(ptRecipientKeyEncrypted)) then begin
+    if Assigned(AWalletKeys) then begin
+      LDone := False;
+      i := 0;
+      while (Not LDone) and (i < AWalletKeys.Count) do begin
+        if Assigned(AWalletKeys.Key[i].PrivateKey) then begin
+          if TPCEncryption.DoPascalCoinECIESDecrypt(AWalletKeys.Key[i].PrivateKey.PrivateKey,APayload.payload_raw,LUnencryptedPayloadBytes) then begin
+            LDone := True;
+          end;
+        end;
+        inc(i);
+      end;
+      if Not LDone then begin
+        ADecodeEPasaResult := der_PrivateKeyNotFound;
+        Exit(False);
+      end;
+    end else begin
+      ADecodeEPasaResult := der_NotEnoughData;
+      Exit(False);
+    end;
+  end else if (AEPasa.PayloadType.HasTrait(ptPasswordEncrypted)) then begin
+    if Assigned(APasswords) then begin
+      LDone := False;
+      i := 0;
+      while (Not LDone) and (i < APasswords.Count) do begin
+        LPwd.FromString(APasswords[i]);
+        if TPCEncryption.DoPascalCoinAESDecrypt(APayload.payload_raw,LPwd,LUnencryptedPayloadBytes) then begin
+          AEPasa.Password := APasswords[i];
+          LDone := True;
+        end;
+        inc(i);
+      end;
+      if Not LDone then begin
+        ADecodeEPasaResult := der_PasswordNotFound;
+        Exit(False);
+      end;
+    end else begin
+      ADecodeEPasaResult := der_NotEnoughData;
+      Exit(False);
+    end;
+  end else begin
+    if (Not AEPasa.PayloadType.HasTrait(ptPublic)) then begin
+      // Internal Error
+      ADecodeEPasaResult := der_Undefined;
+      Exit(False);
+    end;
+    LUnencryptedPayloadBytes := APayload.payload_raw;
+  end;
+  // LUnencryptedPayloadBytes Has Value in RAW
+  if (AEPasa.PayloadType.HasTrait(ptAsciiFormatted)) then begin
+    AEPasa.Payload := LUnencryptedPayloadBytes.ToString;
+  end else if (AEPasa.PayloadType.HasTrait(ptHexFormatted)) then begin
+    AEPasa.Payload := THexEncoding.Encode(LUnencryptedPayloadBytes,True);
+  end else if (AEPasa.PayloadType.HasTrait(ptBase58Formatted)) then begin
+    AEPasa.Payload := TPascalBase58Encoding.Encode(LUnencryptedPayloadBytes);
+  end else begin
+    // Internal error
+    ADecodeEPasaResult := der_Undefined;
+    Exit(False);
+  end;
+  Result := true;
+end;
+
+class function TEPasaDecoder.DecodeEPASA(AAccount: Cardinal;
+  const APayload: TOperationPayload; const ANode: TNode;
+  const AWalletKeys: TWalletKeys; const APasswords: TList<String>): String;
+var LEPasa : TEPasa;
+begin
+  if TryDecodeEPASA(AAccount,APayload,ANode,AWalletKeys,APasswords,LEPasa) then begin
+    Result := LEPasa.ToClassicPASAString;
+  end else Result := '';
+end;
+
+class function TEPasaDecoder.TryDecodeEPASA(AAccount: Cardinal;
+  const APayload: TOperationPayload; const ANode : TNode; const AWalletKeys: TWalletKeys;
+  const APasswords: TList<String>; out AEPasa: TEPasa): Boolean;
+var LDecodeEPasaResult: TDecodeEPasaResult;
+begin
+  Result := TryDecodeEPASA(AAccount,APayload,ANode,AWalletKeys,APasswords,LDecodeEPasaResult,AEPasa);
+end;
+
+end.

+ 0 - 2
src/core/UOpTransaction.pas

@@ -1189,7 +1189,6 @@ begin
   SetLength(OperationResume.Senders,1);
   SetLength(OperationResume.Senders,1);
   OperationResume.Senders[0] := CT_TMultiOpSender_NUL;
   OperationResume.Senders[0] := CT_TMultiOpSender_NUL;
   OperationResume.Senders[0].Account:=FData.sender;
   OperationResume.Senders[0].Account:=FData.sender;
-  OperationResume.Senders[0].AccountEPASA := TAccountComp.DecodeEPASAPartial(FData.sender, FData.payload.payload_raw, FData.payload.payload_type, TEPasa.Empty);
   OperationResume.Senders[0].Amount:=Int64(FData.amount + FData.fee);
   OperationResume.Senders[0].Amount:=Int64(FData.amount + FData.fee);
   OperationResume.Senders[0].N_Operation:=FData.n_operation;
   OperationResume.Senders[0].N_Operation:=FData.n_operation;
   OperationResume.Senders[0].Payload:=FData.payload;
   OperationResume.Senders[0].Payload:=FData.payload;
@@ -1199,7 +1198,6 @@ begin
       SetLength(OperationResume.Receivers,1);
       SetLength(OperationResume.Receivers,1);
       OperationResume.Receivers[0] := CT_TMultiOpReceiver_NUL;
       OperationResume.Receivers[0] := CT_TMultiOpReceiver_NUL;
       OperationResume.Receivers[0].Account:=FData.target;
       OperationResume.Receivers[0].Account:=FData.target;
-      OperationResume.Receivers[0].AccountEPASA:=TAccountComp.DecodeEPASAPartial(FData.target, FData.payload.payload_raw, FData.payload.payload_type, TEPasa.Empty);
       OperationResume.Receivers[0].Amount:=FData.amount;
       OperationResume.Receivers[0].Amount:=FData.amount;
       OperationResume.Receivers[0].Payload:=FData.payload;
       OperationResume.Receivers[0].Payload:=FData.payload;
     end;
     end;

+ 6 - 2
src/core/UPCRPCOpData.pas

@@ -297,7 +297,9 @@ begin
     LResultArray := AJSONResponse.GetAsArray('result');
     LResultArray := AJSONResponse.GetAsArray('result');
 
 
     for i := 0 to LOperationsResumeList.Count-1 do begin
     for i := 0 to LOperationsResumeList.Count-1 do begin
-      TPascalCoinJSONComp.FillOperationObject(LOperationsResumeList.OperationResume[i],ASender.Node.Bank.BlocksCount,LResultArray.GetAsObject( LResultArray.Count ));
+      TPascalCoinJSONComp.FillOperationObject(LOperationsResumeList.OperationResume[i],ASender.Node.Bank.BlocksCount,
+        ASender.Node,ASender.RPCServer.WalletKeys,ASender.RPCServer.PayloadPasswords,
+        LResultArray.GetAsObject( LResultArray.Count ));
     end;
     end;
     Result := True;
     Result := True;
   finally
   finally
@@ -362,7 +364,9 @@ begin
       Exit;
       Exit;
     end;
     end;
     TPCOperation.OperationToOperationResume(0,LOpData,False,LSender.account,LOPR);
     TPCOperation.OperationToOperationResume(0,LOpData,False,LSender.account,LOPR);
-    TPascalCoinJSONComp.FillOperationObject(LOPR,ASender.Node.Bank.BlocksCount,AJSONResponse.GetAsObject('result'));
+    TPascalCoinJSONComp.FillOperationObject(LOPR,ASender.Node.Bank.BlocksCount,
+      ASender.Node,ASender.RPCServer.WalletKeys,ASender.RPCServer.PayloadPasswords,
+      AJSONResponse.GetAsObject('result'));
     Result := True;
     Result := True;
   finally
   finally
     LOpData.free;
     LOpData.free;

+ 3 - 1
src/core/UPCRPCSend.pas

@@ -188,7 +188,9 @@ begin
         Exit;
         Exit;
       end;
       end;
       TPCOperation.OperationToOperationResume(0,LOpt,False,LSender.account,LOpr);
       TPCOperation.OperationToOperationResume(0,LOpt,False,LSender.account,LOpr);
-      TPascalCoinJSONComp.FillOperationObject(LOpr,ASender.Node.Bank.BlocksCount,AJSONResponse.GetAsObject('result'));
+      TPascalCoinJSONComp.FillOperationObject(LOpr,ASender.Node.Bank.BlocksCount,
+        ASender.Node,ASender.RPCServer.WalletKeys,ASender.RPCServer.PayloadPasswords,
+        AJSONResponse.GetAsObject('result'));
       Result := true;
       Result := true;
     finally
     finally
       LOpt.free;
       LOpt.free;

+ 132 - 64
src/core/URPC.pas

@@ -67,10 +67,11 @@ Type
   public
   public
     class procedure FillAccountObject(Const account : TAccount; jsonObj : TPCJSONObject);
     class procedure FillAccountObject(Const account : TAccount; jsonObj : TPCJSONObject);
     class procedure FillBlockObject(nBlock : Cardinal; ANode : TNode; jsonObject: TPCJSONObject);
     class procedure FillBlockObject(nBlock : Cardinal; ANode : TNode; jsonObject: TPCJSONObject);
-    class procedure FillOperationObject(Const OPR : TOperationResume; currentNodeBlocksCount : Cardinal; jsonObject : TPCJSONObject);
+    class procedure FillOperationObject(Const OPR : TOperationResume; currentNodeBlocksCount : Cardinal; const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>; jsonObject : TPCJSONObject); overload;
     class procedure FillOperationsHashTreeObject(Const OperationsHashTree : TOperationsHashTree; jsonObject : TPCJSONObject);
     class procedure FillOperationsHashTreeObject(Const OperationsHashTree : TOperationsHashTree; jsonObject : TPCJSONObject);
-    class procedure FillMultiOperationObject(current_protocol : Word; Const multiOperation : TOpMultiOperation; jsonObject : TPCJSONObject);
+    class procedure FillMultiOperationObject(current_protocol : Word; Const multiOperation : TOpMultiOperation; const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>; jsonObject : TPCJSONObject);
     class procedure FillPublicKeyObject(const PubKey : TAccountKey; jsonObj : TPCJSONObject);
     class procedure FillPublicKeyObject(const PubKey : TAccountKey; jsonObj : TPCJSONObject);
+    class function FillEPasaOrDecrypt(const AAccount : Int64; Const APayload : TOperationPayload; const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>; jsonObject : TPCJSONObject) : Boolean;
     class function ToPascalCoins(jsonCurr : Real) : Int64;
     class function ToPascalCoins(jsonCurr : Real) : Int64;
     //
     //
     class Function HexaStringToOperationsHashTree(Const AHexaStringOperationsHashTree : String; ACurrentProtocol : Word; out AOperationsHashTree : TOperationsHashTree; var AErrors : String) : Boolean;
     class Function HexaStringToOperationsHashTree(Const AHexaStringOperationsHashTree : String; ACurrentProtocol : Word; out AOperationsHashTree : TOperationsHashTree; var AErrors : String) : Boolean;
@@ -97,6 +98,7 @@ Type
     FValidIPs: String;
     FValidIPs: String;
     FAllowUsePrivateKeys: Boolean;
     FAllowUsePrivateKeys: Boolean;
     FNode : TNode;
     FNode : TNode;
+    FPayloadPasswords: TList<String>;
     procedure SetActive(AValue: Boolean);
     procedure SetActive(AValue: Boolean);
     procedure SetIniFileName(const Value: String);
     procedure SetIniFileName(const Value: String);
     procedure SetLogFileName(const Value: String);
     procedure SetLogFileName(const Value: String);
@@ -111,6 +113,7 @@ Type
     Property Port : Word read FPort Write FPort;
     Property Port : Word read FPort Write FPort;
     Property Active : Boolean read FActive write SetActive;
     Property Active : Boolean read FActive write SetActive;
     Property WalletKeys : TWalletKeysExt read FWalletKeys write FWalletKeys;
     Property WalletKeys : TWalletKeysExt read FWalletKeys write FWalletKeys;
+    Property PayloadPasswords: TList<String> read FPayloadPasswords;
     //
     //
     Property JSON20Strict : Boolean read FJSON20Strict write FJSON20Strict;
     Property JSON20Strict : Boolean read FJSON20Strict write FJSON20Strict;
     Property IniFileName : String read FIniFileName write SetIniFileName;
     Property IniFileName : String read FIniFileName write SetIniFileName;
@@ -163,6 +166,7 @@ implementation
 Uses
 Uses
   {$IFNDEF FPC}windows,{$ENDIF}
   {$IFNDEF FPC}windows,{$ENDIF}
   SysUtils, Synautil,
   SysUtils, Synautil,
+  UEPasaDecoder,
   UPCRPCSend,
   UPCRPCSend,
   UPCRPCOpData, UPCRPCFindAccounts, UPCRPCFindBlocks, UPCRPCFileUtils;
   UPCRPCOpData, UPCRPCFindAccounts, UPCRPCFindBlocks, UPCRPCFileUtils;
 
 
@@ -214,12 +218,60 @@ begin
   end;
   end;
 end;
 end;
 
 
-class procedure TPascalCoinJSONComp.FillOperationObject(const OPR: TOperationResume; currentNodeBlocksCount : Cardinal; jsonObject: TPCJSONObject);
+class function TPascalCoinJSONComp.FillEPasaOrDecrypt(const AAccount: Int64;
+  const APayload: TOperationPayload; const ANode: TNode;
+  const AWalletKeys: TWalletKeys; const APasswords: TList<String>;
+  jsonObject: TPCJSONObject) : Boolean;
+var LEPasa : TEPasa;
+  i : Integer;
+  pkey : TECPrivateKey;
+  decrypted_payload : TRawBytes;
+  LDecodeEPasaResult : TDecodeEPasaResult;
+begin
+  Result := False;
+  if AAccount>=0 then begin
+    if TEPasaDecoder.TryDecodeEPASA(AAccount,APayload,ANode,AWalletKeys,APasswords,LDecodeEPasaResult,LEPasa) then begin
+      jsonObject.GetAsVariant('account_epasa').Value := LEPasa.ToClassicPASAString;
+      jsonObject.GetAsVariant('unenc_payload').Value := LEPasa.Payload;
+      jsonObject.GetAsVariant('unenc_hexpayload').Value := LEPasa.GetRawPayloadBytes.ToHexaString;
+      Result := True;
+    end;
+  end;
+  if (Not Result) and (Assigned(AWalletKeys)) and (LDecodeEPasaResult<>der_PrivateKeyNotFound) then begin
+    for i := 0 to AWalletKeys.Count - 1 do begin
+      pkey := AWalletKeys.Key[i].PrivateKey;
+      if (assigned(pkey)) then begin
+        if TPCEncryption.DoPascalCoinECIESDecrypt(pkey.PrivateKey,APayload.payload_raw,decrypted_payload) then begin
+          jsonObject.GetAsVariant('unenc_payload').Value:= decrypted_payload.ToPrintable;
+          jsonObject.GetAsVariant('unenc_hexpayload').Value:= TCrypto.ToHexaString(decrypted_payload);
+          jsonObject.GetAsVariant('payload_method').Value:= 'key';
+          jsonObject.GetAsVariant('enc_pubkey').Value:= TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(pkey.PublicKey));
+          Result := true;
+        end;
+      end;
+    end;
+  end;
+  if (Not Result) And Assigned(APasswords) and (LDecodeEPasaResult<>der_PasswordNotFound) then begin
+    for i := 0 to APasswords.Count - 1 do begin
+      if TPCEncryption.DoPascalCoinAESDecrypt(APayload.payload_raw,TEncoding.ANSI.GetBytes(APasswords[i]),decrypted_payload) then begin
+        jsonObject.GetAsVariant('unenc_payload').Value:= decrypted_payload.ToPrintable;
+        jsonObject.GetAsVariant('unenc_hexpayload').Value:= TCrypto.ToHexaString(decrypted_payload);
+        jsonObject.GetAsVariant('payload_method').Value:= 'pwd';
+        jsonObject.GetAsVariant('pwd').Value:=APasswords[i];
+        Result := true;
+      end;
+    end;
+  end;
+end;
+
+class procedure TPascalCoinJSONComp.FillOperationObject(const OPR: TOperationResume; currentNodeBlocksCount : Cardinal;
+  const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>; jsonObject: TPCJSONObject);
 Var i : Integer;
 Var i : Integer;
   LOpChangeAccountInfoType : TOpChangeAccountInfoType;
   LOpChangeAccountInfoType : TOpChangeAccountInfoType;
   LString : String;
   LString : String;
   jsonArr : TPCJSONArray;
   jsonArr : TPCJSONArray;
   auxObj : TPCJSONObject;
   auxObj : TPCJSONObject;
+  LEPasa : TEPasa;
 
 
   procedure FillOpDataObject(AParentObj : TPCJSONObject; const AOpData : TMultiOpData);
   procedure FillOpDataObject(AParentObj : TPCJSONObject; const AOpData : TMultiOpData);
   var LDataObj : TPCJSONObject;
   var LDataObj : TPCJSONObject;
@@ -258,7 +310,7 @@ Begin
       LString := TCrypto.ToHexaString(OPR.Senders[i].Payload.payload_raw);
       LString := TCrypto.ToHexaString(OPR.Senders[i].Payload.payload_raw);
       auxObj := jsonArr.GetAsObject(jsonArr.Count);
       auxObj := jsonArr.GetAsObject(jsonArr.Count);
       auxObj.GetAsVariant('account').Value := OPR.Senders[i].Account;
       auxObj.GetAsVariant('account').Value := OPR.Senders[i].Account;
-      auxObj.GetAsVariant('account_epasa').Value := OPR.Senders[i].AccountEPASA.ToString();
+      FillEPasaOrDecrypt(OPR.Senders[i].Account,OPR.Senders[i].Payload,ANode,AWalletKeys,APasswords,auxObj);
       if (OPR.Senders[i].N_Operation>0) then auxObj.GetAsVariant('n_operation').Value := OPR.Senders[i].N_Operation;
       if (OPR.Senders[i].N_Operation>0) then auxObj.GetAsVariant('n_operation').Value := OPR.Senders[i].N_Operation;
       auxObj.GetAsVariant('amount').Value := TAccountComp.FormatMoneyDecimal(OPR.Senders[i].Amount * (-1));
       auxObj.GetAsVariant('amount').Value := TAccountComp.FormatMoneyDecimal(OPR.Senders[i].Amount * (-1));
       auxObj.GetAsVariant('amount_s').Value := TAccountComp.FormatMoney (OPR.Senders[i].Amount * (-1));
       auxObj.GetAsVariant('amount_s').Value := TAccountComp.FormatMoney (OPR.Senders[i].Amount * (-1));
@@ -273,6 +325,7 @@ Begin
     for i:=Low(OPR.Receivers) to High(OPR.Receivers) do begin
     for i:=Low(OPR.Receivers) to High(OPR.Receivers) do begin
       auxObj := jsonArr.GetAsObject(jsonArr.Count);
       auxObj := jsonArr.GetAsObject(jsonArr.Count);
       auxObj.GetAsVariant('account').Value := OPR.Receivers[i].Account;
       auxObj.GetAsVariant('account').Value := OPR.Receivers[i].Account;
+      FillEPasaOrDecrypt(OPR.Receivers[i].Account,OPR.Receivers[i].Payload,ANode,AWalletKeys,APasswords,auxObj);
       auxObj.GetAsVariant('amount').Value :=  TAccountComp.FormatMoneyDecimal(OPR.Receivers[i].Amount);
       auxObj.GetAsVariant('amount').Value :=  TAccountComp.FormatMoneyDecimal(OPR.Receivers[i].Amount);
       auxObj.GetAsVariant('amount_s').Value :=  TAccountComp.FormatMoney(OPR.Receivers[i].Amount);
       auxObj.GetAsVariant('amount_s').Value :=  TAccountComp.FormatMoney(OPR.Receivers[i].Amount);
       auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Receivers[i].Payload.payload_raw);
       auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Receivers[i].Payload.payload_raw);
@@ -424,18 +477,18 @@ begin
      Exit(False);
      Exit(False);
 
 
    if AEPASA.PayloadType.HasTrait(ptPublic) then begin
    if AEPASA.PayloadType.HasTrait(ptPublic) then begin
-     AInputParams.SetAs('payload_method', TPCJSONVariantValue.CreateFromVariant('none'));
-     AInputParams.SetAs('payload', TPCJSONVariantValue.CreateFromVariant(AEPASA.GetRawPayloadBytes.ToHexaString));
+     AInputParams.GetAsVariant('payload_method').Value := 'none';
+     AInputParams.GetAsVariant('payload').Value := AEPASA.GetRawPayloadBytes.ToHexaString;
    end else if AEPASA.PayloadType.HasTrait(ptSenderKeyEncrypted) then begin
    end else if AEPASA.PayloadType.HasTrait(ptSenderKeyEncrypted) then begin
-     AInputParams.SetAs('payload_method', TPCJSONVariantValue.CreateFromVariant('sender'));
-     AInputParams.SetAs('payload', TPCJSONVariantValue.CreateFromVariant(AEPASA.GetRawPayloadBytes().ToHexaString()));
+     AInputParams.GetAsVariant('payload_method').Value := 'sender';
+     AInputParams.GetAsVariant('payload').Value := AEPASA.GetRawPayloadBytes.ToHexaString;
    end else if AEPASA.PayloadType.HasTrait(ptRecipientKeyEncrypted) then begin
    end else if AEPASA.PayloadType.HasTrait(ptRecipientKeyEncrypted) then begin
-     AInputParams.SetAs('payload_method', TPCJSONVariantValue.CreateFromVariant('dest'));
-     AInputParams.SetAs('payload', TPCJSONVariantValue.CreateFromVariant(AEPASA.GetRawPayloadBytes().ToHexaString()));
+     AInputParams.GetAsVariant('payload_method').Value := 'dest';
+     AInputParams.GetAsVariant('payload').Value := AEPASA.GetRawPayloadBytes.ToHexaString;
    end else if AEPASA.PayloadType.HasTrait(ptPasswordEncrypted) then begin
    end else if AEPASA.PayloadType.HasTrait(ptPasswordEncrypted) then begin
-     AInputParams.SetAs('payload_method', TPCJSONVariantValue.CreateFromVariant('aes'));
-     AInputParams.SetAs('payload', TPCJSONVariantValue.CreateFromVariant(AEPASA.GetRawPayloadBytes().ToHexaString()));
-     AInputParams.SetAs('pwd', TPCJSONVariantValue.CreateFromVariant(AEPASA.Password));
+     AInputParams.GetAsVariant('payload_method').Value := 'aes';
+     AInputParams.GetAsVariant('payload').Value := AEPASA.GetRawPayloadBytes.ToHexaString;
+     AInputParams.GetAsVariant('pwd').Value := AEPASA.Password;
      Result := True;
      Result := True;
    end;
    end;
    Result := True;
    Result := True;
@@ -484,20 +537,39 @@ class function TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(
   out AOperationPayload : TOperationPayload;
   out AOperationPayload : TOperationPayload;
   var AErrorNum: Integer;
   var AErrorNum: Integer;
   var AErrorDesc: String): Boolean;
   var AErrorDesc: String): Boolean;
+var LNewPayloadType : TPayloadType;
 begin
 begin
   AOperationPayload := CT_TOperationPayload_NUL;
   AOperationPayload := CT_TOperationPayload_NUL;
   AOperationPayload.payload_type := APayloadType.ToProtocolValue;
   AOperationPayload.payload_type := APayloadType.ToProtocolValue;
   if (Length(ARawPayload)>0) then begin
   if (Length(ARawPayload)>0) then begin
+    if ARawPayload.ToPrintable.CompareTo(ARawPayload.ToString)=0 then LNewPayloadType := [ptAsciiFormatted]
+    else LNewPayloadType := [];
     if (APayload_method='none') then begin
     if (APayload_method='none') then begin
       AOperationPayload.payload_raw:=ARawPayload;
       AOperationPayload.payload_raw:=ARawPayload;
+      if (AOperationPayload.payload_type=0) then begin
+        LNewPayloadType := LNewPayloadType + [ptPublic];
+        AOperationPayload.payload_type := LNewPayloadType.ToProtocolValue;
+      end;
       Result := True;
       Result := True;
     end else if (APayload_method='dest') then begin
     end else if (APayload_method='dest') then begin
       Result := TPCEncryption.DoPascalCoinECIESEncrypt(ATargetAccountKey,ARawPayload,AOperationPayload.payload_raw);
       Result := TPCEncryption.DoPascalCoinECIESEncrypt(ATargetAccountKey,ARawPayload,AOperationPayload.payload_raw);
+      if (AOperationPayload.payload_type=0) then begin
+        LNewPayloadType := LNewPayloadType + [ptRecipientKeyEncrypted];
+        AOperationPayload.payload_type := LNewPayloadType.ToProtocolValue;
+      end;
     end else if (APayload_method='sender') then begin
     end else if (APayload_method='sender') then begin
       Result := TPCEncryption.DoPascalCoinECIESEncrypt(ASenderAccounKey,ARawPayload,AOperationPayload.payload_raw);
       Result := TPCEncryption.DoPascalCoinECIESEncrypt(ASenderAccounKey,ARawPayload,AOperationPayload.payload_raw);
+      if (AOperationPayload.payload_type=0) then begin
+        LNewPayloadType := LNewPayloadType + [ptSenderKeyEncrypted];
+        AOperationPayload.payload_type := LNewPayloadType.ToProtocolValue;
+      end;
     end else if (APayload_method='aes') then begin
     end else if (APayload_method='aes') then begin
       AOperationPayload.payload_raw := TPCEncryption.DoPascalCoinAESEncrypt(ARawPayload,TEncoding.ANSI.GetBytes(AEncodePwdForAES));
       AOperationPayload.payload_raw := TPCEncryption.DoPascalCoinAESEncrypt(ARawPayload,TEncoding.ANSI.GetBytes(AEncodePwdForAES));
       Result := True;
       Result := True;
+      if (AOperationPayload.payload_type=0) then begin
+        LNewPayloadType := LNewPayloadType + [ptPasswordEncrypted];
+        AOperationPayload.payload_type := LNewPayloadType.ToProtocolValue;
+      end;
     end else begin
     end else begin
       Result := False;
       Result := False;
       AErrorNum:=CT_RPC_ErrNum_InvalidOperation;
       AErrorNum:=CT_RPC_ErrNum_InvalidOperation;
@@ -564,7 +636,8 @@ begin
   jsonObject.GetAsVariant('rawoperations').Value:=OperationsHashTreeToHexaString(OperationsHashTree);
   jsonObject.GetAsVariant('rawoperations').Value:=OperationsHashTreeToHexaString(OperationsHashTree);
 end;
 end;
 
 
-class procedure TPascalCoinJSONComp.FillMultiOperationObject(current_protocol : Word; const multiOperation: TOpMultiOperation; jsonObject: TPCJSONObject);
+class procedure TPascalCoinJSONComp.FillMultiOperationObject(current_protocol : Word; const multiOperation: TOpMultiOperation;
+  const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>; jsonObject: TPCJSONObject);
 Var i, nSigned, nNotSigned : Integer;
 Var i, nSigned, nNotSigned : Integer;
   opht : TOperationsHashTree;
   opht : TOperationsHashTree;
   jsonArr : TPCJSONArray;
   jsonArr : TPCJSONArray;
@@ -593,7 +666,7 @@ begin
     LStr := TCrypto.ToHexaString(multiOperation.Data.txSenders[i].Payload.payload_raw);
     LStr := TCrypto.ToHexaString(multiOperation.Data.txSenders[i].Payload.payload_raw);
     auxObj := jsonArr.GetAsObject(jsonArr.Count);
     auxObj := jsonArr.GetAsObject(jsonArr.Count);
     auxObj.GetAsVariant('account').Value := multiOperation.Data.txSenders[i].Account;
     auxObj.GetAsVariant('account').Value := multiOperation.Data.txSenders[i].Account;
-    auxObj.GetAsVariant('account_epasa').Value := multiOperation.Data.txSenders[i].AccountEPASA.ToString();
+    FillEPasaOrDecrypt(multiOperation.Data.txSenders[i].Account,multiOperation.Data.txSenders[i].Payload,ANode,AWalletKeys,APasswords,auxObj);
     auxObj.GetAsVariant('n_operation').Value := multiOperation.Data.txSenders[i].N_Operation;
     auxObj.GetAsVariant('n_operation').Value := multiOperation.Data.txSenders[i].N_Operation;
     auxObj.GetAsVariant('amount').Value := TAccountComp.FormatMoneyDecimal(multiOperation.Data.txSenders[i].Amount * (-1));
     auxObj.GetAsVariant('amount').Value := TAccountComp.FormatMoneyDecimal(multiOperation.Data.txSenders[i].Amount * (-1));
     auxObj.GetAsVariant('payload').Value := LStr;
     auxObj.GetAsVariant('payload').Value := LStr;
@@ -605,7 +678,7 @@ begin
     LStr := TCrypto.ToHexaString(multiOperation.Data.txSenders[i].Payload.payload_raw);
     LStr := TCrypto.ToHexaString(multiOperation.Data.txSenders[i].Payload.payload_raw);
     auxObj := jsonArr.GetAsObject(jsonArr.Count);
     auxObj := jsonArr.GetAsObject(jsonArr.Count);
     auxObj.GetAsVariant('account').Value := multiOperation.Data.txReceivers[i].Account;
     auxObj.GetAsVariant('account').Value := multiOperation.Data.txReceivers[i].Account;
-    auxObj.GetAsVariant('account_epasa').Value := multiOperation.Data.txReceivers[i].AccountEPASA.ToString();
+    FillEPasaOrDecrypt(multiOperation.Data.txReceivers[i].Account,multiOperation.Data.txReceivers[i].Payload,ANode,AWalletKeys,APasswords,auxObj);
     auxObj.GetAsVariant('amount').Value := TAccountComp.FormatMoneyDecimal(multiOperation.Data.txReceivers[i].Amount);
     auxObj.GetAsVariant('amount').Value := TAccountComp.FormatMoneyDecimal(multiOperation.Data.txReceivers[i].Amount);
     auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(multiOperation.Data.txReceivers[i].Payload.payload_raw);
     auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(multiOperation.Data.txReceivers[i].Payload.payload_raw);
     auxObj.GetAsVariant('payload_type').Value := multiOperation.Data.txReceivers[i].Payload.payload_type;
     auxObj.GetAsVariant('payload_type').Value := multiOperation.Data.txReceivers[i].Payload.payload_type;
@@ -840,6 +913,7 @@ end;
 
 
 constructor TRPCServer.Create;
 constructor TRPCServer.Create;
 begin
 begin
+  FPayloadPasswords := TList<String>.Create;
   FActive := false;
   FActive := false;
   FRPCLog := Nil;
   FRPCLog := Nil;
   FIniFile := Nil;
   FIniFile := Nil;
@@ -858,6 +932,7 @@ end;
 destructor TRPCServer.Destroy;
 destructor TRPCServer.Destroy;
 begin
 begin
   FreeAndNil(FRPCLog);
   FreeAndNil(FRPCLog);
+  FreeAndNil(FPayloadPasswords);
   active := false;
   active := false;
   if _RPCServer=Self then _RPCServer:=Nil;
   if _RPCServer=Self then _RPCServer:=Nil;
   inherited Destroy;
   inherited Destroy;
@@ -1132,7 +1207,9 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
 
 
   Procedure FillOperationResumeToJSONObject(Const OPR : TOperationResume; jsonObject : TPCJSONObject);
   Procedure FillOperationResumeToJSONObject(Const OPR : TOperationResume; jsonObject : TPCJSONObject);
   Begin
   Begin
-    TPascalCoinJSONComp.FillOperationObject(OPR,FNode.Bank.BlocksCount,jsonObject);
+    TPascalCoinJSONComp.FillOperationObject(OPR,FNode.Bank.BlocksCount,
+      Node,RPCServer.WalletKeys,RPCServer.PayloadPasswords,
+      jsonObject);
   end;
   end;
 
 
   Function GetAccountOperations(accountNumber : Cardinal; jsonArray : TPCJSONArray; maxBlocksDepth, startReg, maxReg: Integer; forceStartBlock : Cardinal) : Boolean;
   Function GetAccountOperations(accountNumber : Cardinal; jsonArray : TPCJSONArray; maxBlocksDepth, startReg, maxReg: Integer; forceStartBlock : Cardinal) : Boolean;
@@ -1611,7 +1688,9 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         If TPCOperation.OperationToOperationResume(0,Op,True,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 begin
+          OPR := CT_TOperationResume_NUL;
+        end;
         FillOperationResumeToJSONObject(OPR,Obj);
         FillOperationResumeToJSONObject(OPR,Obj);
       end;
       end;
       Result := true;
       Result := true;
@@ -1675,48 +1754,44 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     Result := true;
     Result := true;
   end;
   end;
 
 
-  Function DoDecrypt(RawEncryptedPayload : TRawBytes; jsonArrayPwds : TPCJSONArray) : Boolean;
+  Function DoDecrypt(jsonArrayPwds : TPCJSONArray) : Boolean;
   var i : Integer;
   var i : Integer;
     pkey : TECPrivateKey;
     pkey : TECPrivateKey;
     decrypted_payload : TRawBytes;
     decrypted_payload : TRawBytes;
+    LPayload : TOperationPayload;
+    s : String;
+    Lpasswords : TList<String>;
   Begin
   Begin
-    Result := false;
-    if Length(RawEncryptedPayload)=0 then begin
-      GetResultObject.GetAsVariant('result').Value:= False;
-      GetResultObject.GetAsVariant('enc_payload').Value:= '';
-      Result := true;
-      exit;
+    if Length(params.AsString('payload',''))=0 then begin
+      ErrorNum:= CT_RPC_ErrNum_InvalidData;
+      ErrorDesc := 'Need param "payload"';
+      Exit(False);
     end;
     end;
-    for i := 0 to _RPCServer.WalletKeys.Count - 1 do begin
-      pkey := _RPCServer.WalletKeys.Key[i].PrivateKey;
-      if (assigned(pkey)) then begin
-        if TPCEncryption.DoPascalCoinECIESDecrypt(pkey.PrivateKey,RawEncryptedPayload,decrypted_payload) then begin
-          GetResultObject.GetAsVariant('result').Value:= true;
-          GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
-          GetResultObject.GetAsVariant('unenc_payload').Value:= decrypted_payload.ToPrintable;
-          GetResultObject.GetAsVariant('unenc_hexpayload').Value:= TCrypto.ToHexaString(decrypted_payload);
-          GetResultObject.GetAsVariant('payload_method').Value:= 'key';
-          GetResultObject.GetAsVariant('enc_pubkey').Value:= TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(pkey.PublicKey));
-          Result := true;
-          Exit;
-        end;
-      end;
+    LPayload.payload_raw := TCrypto.HexaToRaw(params.AsString('payload',''));
+    LPayload.payload_type := params.AsInteger('payload_type',0);
+    if Length(LPayload.payload_raw)=0 then begin
+      ErrorNum:= CT_RPC_ErrNum_InvalidData;
+      ErrorDesc := '"payload" param is not an HEXASTRING';
+      Exit(False);
     end;
     end;
-    for i := 0 to jsonArrayPwds.Count - 1 do begin
-      if TPCEncryption.DoPascalCoinAESDecrypt(RawEncryptedPayload,TEncoding.ANSI.GetBytes(jsonArrayPwds.GetAsVariant(i).AsString('')),decrypted_payload) then begin
-        GetResultObject.GetAsVariant('result').Value:= true;
-        GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
-        GetResultObject.GetAsVariant('unenc_payload').Value:= decrypted_payload.ToPrintable;
-        GetResultObject.GetAsVariant('unenc_hexpayload').Value:= TCrypto.ToHexaString(decrypted_payload);
-        GetResultObject.GetAsVariant('payload_method').Value:= 'pwd';
-        GetResultObject.GetAsVariant('pwd').Value:= jsonArrayPwds.GetAsVariant(i).AsString('');
-        Result := true;
-        exit;
+    Lpasswords := TList<String>.Create;
+    Try
+      for i := 0 to jsonArrayPwds.Count-1 do begin
+        s := jsonArrayPwds.GetAsVariant(i).AsString('');
+        if Lpasswords.IndexOf(s)<0 then Lpasswords.Add(s);
       end;
       end;
-    end;
-    // Not found
-    GetResultObject.GetAsVariant('result').Value:= False;
-    GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
+
+      if TPascalCoinJSONComp.FillEPasaOrDecrypt(-1,LPayload,FNode,FRPCServer.WalletKeys,Lpasswords,GetResultObject) then begin
+        GetResultObject.GetAsVariant('result').Value:= True;
+      end else begin
+        GetResultObject.GetAsVariant('result').Value:= False;
+      end;
+      GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(LPayload.payload_raw);
+
+    Finally
+      Lpasswords.Free;
+    End;
+
     Result := true;
     Result := true;
   End;
   End;
 
 
@@ -2610,7 +2685,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         end;
         end;
       end;
       end;
       // Return multioperation object:
       // Return multioperation object:
-      TPascalCoinJSONComp.FillMultiOperationObject(FNode.Bank.SafeBox.CurrentProtocol,mop,GetResultObject);
+      TPascalCoinJSONComp.FillMultiOperationObject(FNode.Bank.SafeBox.CurrentProtocol,mop,FNode,FRPCServer.WalletKeys,FRPCServer.PayloadPasswords, GetResultObject);
     finally
     finally
       OperationsHashTree.Free;
       OperationsHashTree.Free;
     end;
     end;
@@ -2747,7 +2822,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     Try
     Try
       InternalMultiOperationSignCold(mop,protocol,params.GetAsArray('accounts_and_keys'),j);
       InternalMultiOperationSignCold(mop,protocol,params.GetAsArray('accounts_and_keys'),j);
       // Return multioperation object:
       // Return multioperation object:
-      TPascalCoinJSONComp.FillMultiOperationObject(protocol,mop,GetResultObject);
+      TPascalCoinJSONComp.FillMultiOperationObject(protocol,mop,FNode,FRPCServer.WalletKeys,FRPCServer.PayloadPasswords,GetResultObject);
       Result := True;
       Result := True;
     finally
     finally
       senderOperationsHashTree.Free;
       senderOperationsHashTree.Free;
@@ -2798,7 +2873,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         lSigners.Free;
         lSigners.Free;
       end;
       end;
       // Return multioperation object:
       // Return multioperation object:
-      TPascalCoinJSONComp.FillMultiOperationObject(FNode.Bank.SafeBox.CurrentProtocol,mop,GetResultObject);
+      TPascalCoinJSONComp.FillMultiOperationObject(FNode.Bank.SafeBox.CurrentProtocol,mop,FNode,FRPCServer.WalletKeys,FRPCServer.PayloadPasswords,GetResultObject);
       Result := True;
       Result := True;
     finally
     finally
       senderOperationsHashTree.Free;
       senderOperationsHashTree.Free;
@@ -3641,19 +3716,12 @@ begin
       ErrorNum := CT_RPC_ErrNum_NotAllowedCall;
       ErrorNum := CT_RPC_ErrNum_NotAllowedCall;
       Exit;
       Exit;
     end;
     end;
-    // Decrypts a "payload" searching for wallet private keys and for array of strings in "pwds" param
-    // Returns an JSON Object with "result" (Boolean) and
-    if (params.AsString('payload','')='') then begin
-      ErrorNum:= CT_RPC_ErrNum_InvalidData;
-      ErrorDesc := 'Need param "payload"';
-      exit;
-    end;
     If Not _RPCServer.WalletKeys.IsValidPassword then begin
     If Not _RPCServer.WalletKeys.IsValidPassword then begin
       ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
       ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
       ErrorDesc := 'Wallet is password protected. Unlock first';
       ErrorDesc := 'Wallet is password protected. Unlock first';
       exit;
       exit;
     end;
     end;
-    Result := DoDecrypt(TCrypto.HexaToRaw(params.AsString('payload','')),params.GetAsArray('pwds'));
+    Result := DoDecrypt(params.GetAsArray('pwds'));
   end else if (method='getconnections') then begin
   end else if (method='getconnections') then begin
     if (Not _RPCServer.AllowUsePrivateKeys) then begin
     if (Not _RPCServer.AllowUsePrivateKeys) then begin
       // Protection when server is locked to avoid private keys call
       // Protection when server is locked to avoid private keys call

+ 1 - 1
src/core/UTxMultiOperation.pas

@@ -23,7 +23,7 @@ unit UTxMultiOperation;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, UCrypto, UBlockChain, UAccounts, UBaseTypes,
+  Classes, SysUtils, UCrypto, UBlockChain, UAccounts, UBaseTypes, UEPasa,
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
   UPCDataTypes;
   UPCDataTypes;
 
 

+ 32 - 15
src/gui-classic/UFRMOperation.dfm

@@ -90,7 +90,7 @@ object FRMOperation: TFRMOperation
   object bbCancel: TBitBtn
   object bbCancel: TBitBtn
     Left = 461
     Left = 461
     Top = 476
     Top = 476
-    Width = 116
+    Width = 120
     Height = 31
     Height = 31
     Kind = bkCancel
     Kind = bkCancel
     NumGlyphs = 2
     NumGlyphs = 2
@@ -185,7 +185,7 @@ object FRMOperation: TFRMOperation
         object lblEncryptionErrors: TLabel
         object lblEncryptionErrors: TLabel
           Left = 255
           Left = 255
           Top = 96
           Top = 96
-          Width = 187
+          Width = 152
           Height = 33
           Height = 33
           AutoSize = False
           AutoSize = False
           Caption = 'Errors detected'
           Caption = 'Errors detected'
@@ -211,7 +211,7 @@ object FRMOperation: TFRMOperation
         object rbEncryptedWithEC: TRadioButton
         object rbEncryptedWithEC: TRadioButton
           Left = 15
           Left = 15
           Top = 35
           Top = 35
-          Width = 207
+          Width = 234
           Height = 19
           Height = 19
           Caption = 'Encrypted with dest account public key'
           Caption = 'Encrypted with dest account public key'
           Checked = True
           Checked = True
@@ -222,7 +222,7 @@ object FRMOperation: TFRMOperation
         object rbEncrptedWithPassword: TRadioButton
         object rbEncrptedWithPassword: TRadioButton
           Left = 15
           Left = 15
           Top = 53
           Top = 53
-          Width = 141
+          Width = 234
           Height = 19
           Height = 19
           Caption = 'Encrypted with password'
           Caption = 'Encrypted with password'
           TabOrder = 2
           TabOrder = 2
@@ -232,7 +232,7 @@ object FRMOperation: TFRMOperation
         object rbNotEncrypted: TRadioButton
         object rbNotEncrypted: TRadioButton
           Left = 15
           Left = 15
           Top = 93
           Top = 93
-          Width = 162
+          Width = 234
           Height = 19
           Height = 19
           Caption = 'Dont encrypt (Public payload)'
           Caption = 'Dont encrypt (Public payload)'
           TabOrder = 4
           TabOrder = 4
@@ -266,21 +266,25 @@ object FRMOperation: TFRMOperation
         end
         end
         object rbEncryptedWithOldEC: TRadioButton
         object rbEncryptedWithOldEC: TRadioButton
           Left = 15
           Left = 15
-          Top = 16
-          Width = 159
+          Top = 12
+          Width = 234
           Height = 19
           Height = 19
           Caption = 'Encrypted with old public key'
           Caption = 'Encrypted with old public key'
           TabOrder = 0
           TabOrder = 0
           TabStop = True
           TabStop = True
           OnClick = memoPayloadClick
           OnClick = memoPayloadClick
         end
         end
-        object cbPayloadAsHex: TCheckBox
-          Left = 448
+        object cbPayloadDataInputType: TComboBox
+          Left = 413
           Top = 96
           Top = 96
-          Width = 97
-          Height = 17
-          Caption = 'As Hex'
+          Width = 89
+          Height = 21
+          Style = csDropDownList
           TabOrder = 6
           TabOrder = 6
+          Items.Strings = (
+            'As String'#11
+            'As Hexadecimal'#11
+            'As Base58')
         end
         end
       end
       end
       object ebFee: TEdit
       object ebFee: TEdit
@@ -373,20 +377,33 @@ object FRMOperation: TFRMOperation
             OnClick = sbSearchDestinationAccountClick
             OnClick = sbSearchDestinationAccountClick
           end
           end
           object ebDestAccount: TEdit
           object ebDestAccount: TEdit
-            Left = 114
+            Left = 115
             Top = 29
             Top = 29
-            Width = 370
+            Width = 369
             Height = 21
             Height = 21
             Anchors = [akLeft, akTop, akRight]
             Anchors = [akLeft, akTop, akRight]
             TabOrder = 0
             TabOrder = 0
           end
           end
           object ebAmount: TEdit
           object ebAmount: TEdit
             Left = 115
             Left = 115
-            Top = 58
+            Top = 56
             Width = 87
             Width = 87
             Height = 21
             Height = 21
             TabOrder = 1
             TabOrder = 1
           end
           end
+          object memoEPASA: TMemo
+            Left = 13
+            Top = 96
+            Width = 492
+            Height = 65
+            TabStop = False
+            BorderStyle = bsNone
+            ReadOnly = True
+            TabOrder = 2
+            WantReturns = False
+            OnChange = memoPayloadClick
+            OnClick = memoPayloadClick
+          end
         end
         end
         object tsChangePrivateKey: TTabSheet
         object tsChangePrivateKey: TTabSheet
           Caption = 'Change Key'
           Caption = 'Change Key'

+ 39 - 16
src/gui-classic/UFRMOperation.lfm

@@ -15,7 +15,7 @@ object FRMOperation: TFRMOperation
   OnCreate = FormCreate
   OnCreate = FormCreate
   OnDestroy = FormDestroy
   OnDestroy = FormDestroy
   Position = poOwnerFormCenter
   Position = poOwnerFormCenter
-  LCLVersion = '2.0.2.0'
+  LCLVersion = '2.0.10.0'
   object lblAccountCaption: TLabel
   object lblAccountCaption: TLabel
     Left = 25
     Left = 25
     Height = 13
     Height = 13
@@ -142,7 +142,7 @@ object FRMOperation: TFRMOperation
           Left = 255
           Left = 255
           Height = 33
           Height = 33
           Top = 87
           Top = 87
-          Width = 182
+          Width = 153
           AutoSize = False
           AutoSize = False
           Caption = 'Errors detected'
           Caption = 'Errors detected'
           Font.Color = clRed
           Font.Color = clRed
@@ -223,12 +223,18 @@ object FRMOperation: TFRMOperation
           OnClick = memoPayloadClick
           OnClick = memoPayloadClick
           TabOrder = 0
           TabOrder = 0
         end
         end
-        object cbPayloadAsHex: TCheckBox
-          Left = 444
-          Height = 19
-          Top = 92
-          Width = 54
-          Caption = 'As Hex'
+        object cbPayloadDataInputType: TComboBox
+          Left = 412
+          Height = 21
+          Top = 88
+          Width = 89
+          ItemHeight = 13
+          Items.Strings = (
+            'As String'#11
+            'As Hexadecimal'#11
+            'As Base58'
+          )
+          Style = csDropDownList
           TabOrder = 6
           TabOrder = 6
         end
         end
       end
       end
@@ -244,8 +250,8 @@ object FRMOperation: TFRMOperation
         Height = 167
         Height = 167
         Top = 11
         Top = 11
         Width = 521
         Width = 521
-        ActivePage = tsListAccount
-        TabIndex = 2
+        ActivePage = tsTransaction
+        TabIndex = 0
         TabOrder = 0
         TabOrder = 0
         OnChange = PageControlOpTypeChange
         OnChange = PageControlOpTypeChange
         object tsTransaction: TTabSheet
         object tsTransaction: TTabSheet
@@ -285,7 +291,7 @@ object FRMOperation: TFRMOperation
             Left = 115
             Left = 115
             Height = 21
             Height = 21
             Top = 29
             Top = 29
-            Width = 85
+            Width = 357
             TabOrder = 0
             TabOrder = 0
           end
           end
           object ebAmount: TEdit
           object ebAmount: TEdit
@@ -296,9 +302,9 @@ object FRMOperation: TFRMOperation
             TabOrder = 1
             TabOrder = 1
           end
           end
           object sbSearchDestinationAccount: TSpeedButton
           object sbSearchDestinationAccount: TSpeedButton
-            Left = 208
+            Left = 480
             Height = 22
             Height = 22
-            Top = 29
+            Top = 28
             Width = 23
             Width = 23
             Glyph.Data = {
             Glyph.Data = {
               36030000424D3803000000000000360000002800000010000000100000000100
               36030000424D3803000000000000360000002800000010000000100000000100
@@ -330,6 +336,23 @@ object FRMOperation: TFRMOperation
             }
             }
             OnClick = sbSearchDestinationAccountClick
             OnClick = sbSearchDestinationAccountClick
           end
           end
+          object memoEPASA: TMemo
+            Left = 13
+            Height = 48
+            Top = 88
+            Width = 492
+            BorderStyle = bsNone
+            Font.Color = clBlack
+            Font.Height = -16
+            Font.Name = 'Tahoma'
+            OnChange = memoPayloadClick
+            OnClick = memoPayloadClick
+            ParentFont = False
+            ReadOnly = True
+            TabOrder = 2
+            TabStop = False
+            WantReturns = False
+          end
         end
         end
         object tsChangePrivateKey: TTabSheet
         object tsChangePrivateKey: TTabSheet
           Caption = 'Change key'
           Caption = 'Change key'
@@ -1024,7 +1047,7 @@ object FRMOperation: TFRMOperation
     end
     end
     object tsGlobalError: TTabSheet
     object tsGlobalError: TTabSheet
       Caption = 'Notification'
       Caption = 'Notification'
-      ClientHeight = 325
+      ClientHeight = 357
       ClientWidth = 548
       ClientWidth = 548
       ImageIndex = 1
       ImageIndex = 1
       TabVisible = False
       TabVisible = False
@@ -1148,8 +1171,8 @@ object FRMOperation: TFRMOperation
     Text = 'ebSenderAccount'
     Text = 'ebSenderAccount'
   end
   end
   object ActionList: TActionList
   object ActionList: TActionList
-    left = 140
-    top = 350
+    Left = 140
+    Top = 350
     object actExecute: TAction
     object actExecute: TAction
       Caption = 'Execute (F12)'
       Caption = 'Execute (F12)'
       OnExecute = actExecuteExecute
       OnExecute = actExecuteExecute

+ 151 - 75
src/gui-classic/UFRMOperation.pas

@@ -32,7 +32,7 @@ uses
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls, UNode, UWallet, UCrypto, Buttons, UBlockChain,
   Dialogs, StdCtrls, UNode, UWallet, UCrypto, Buttons, UBlockChain,
   UAccounts, UFRMAccountSelect, ActnList, ComCtrls, Types, UFRMMemoText,
   UAccounts, UFRMAccountSelect, ActnList, ComCtrls, Types, UFRMMemoText,
-  UPCEncryption, UBaseTypes, UPCDataTypes, UPCOrderedLists, UEPasa;
+  UPCEncryption, UBaseTypes, UPCDataTypes, UPCOrderedLists, UEPasa, UEncoding;
 
 
 Const
 Const
   CM_PC_WalletKeysChanged = WM_USER + 1;
   CM_PC_WalletKeysChanged = WM_USER + 1;
@@ -129,9 +129,10 @@ type
     ebHashLock: TEdit;
     ebHashLock: TEdit;
     btnHashLock: TSpeedButton;
     btnHashLock: TSpeedButton;
     sbTimeLock: TSpeedButton;
     sbTimeLock: TSpeedButton;
-    cbPayloadAsHex: TCheckBox;
     lblChangeAccountData: TLabel;
     lblChangeAccountData: TLabel;
     ebChangeAccountData: TEdit;
     ebChangeAccountData: TEdit;
+    cbPayloadDataInputType: TComboBox;
+    memoEPASA: TMemo;
     procedure ebNewPublicKeyExit(Sender: TObject);
     procedure ebNewPublicKeyExit(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
@@ -159,6 +160,7 @@ type
     FDefaultFee: Int64;
     FDefaultFee: Int64;
     FEncodedPayload : TOperationPayload;
     FEncodedPayload : TOperationPayload;
     FDisabled : Boolean;
     FDisabled : Boolean;
+    FUpdating : Boolean;
     FSenderAccounts: TOrderedCardinalList; // TODO: TOrderedCardinalList should be replaced with a "TCardinalList" since signer account should be processed last
     FSenderAccounts: TOrderedCardinalList; // TODO: TOrderedCardinalList should be replaced with a "TCardinalList" since signer account should be processed last
     procedure SetWalletKeys(const Value: TWalletKeys);
     procedure SetWalletKeys(const Value: TWalletKeys);
     Procedure UpdateWalletKeys;
     Procedure UpdateWalletKeys;
@@ -167,7 +169,7 @@ type
     Function UpdateFee(var Fee : Int64; errors : String) : Boolean;
     Function UpdateFee(var Fee : Int64; errors : String) : Boolean;
     Function UpdateOperationOptions(var errors : String) : Boolean;
     Function UpdateOperationOptions(var errors : String) : Boolean;
     Function UpdatePayload(Const ASenderAccount : TAccount; var AErrors : String) : Boolean;
     Function UpdatePayload(Const ASenderAccount : TAccount; var AErrors : String) : Boolean;
-    Function UpdateOpTransaction(const ASenderAccount: TAccount; out LTargetEPASA : TEPasa;  out ATargetAccount : TAccount; out AResolvedTargetKey : TAccountKey; out ATargetRequiresPurchase : Boolean; out AAmount: Int64; out AErrors: String) : Boolean;
+    Function UpdateOpTransaction(const ASenderAccount: TAccount; out ATargetEPASA : TEPasa;  out ATargetAccount : TAccount; out AResolvedTargetKey : TAccountKey; out ATargetRequiresPurchase : Boolean; out AAmount: Int64; out AErrors: String) : Boolean;
     Function UpdateOpChangeKey(Const TargetAccount : TAccount; var SignerAccount : TAccount; var NewPublicKey : TAccountKey; var errors : String) : Boolean;
     Function UpdateOpChangeKey(Const TargetAccount : TAccount; var SignerAccount : TAccount; var NewPublicKey : TAccountKey; var errors : String) : Boolean;
     Function UpdateOpListAccount(Const TargetAccount : TAccount; var SalePrice : Int64; var SellerAccount,SignerAccount : TAccount; var NewOwnerPublicKey : TAccountKey; var LockedUntilBlock : Cardinal; var HashLock : T32Bytes; var errors : String) : Boolean;
     Function UpdateOpListAccount(Const TargetAccount : TAccount; var SalePrice : Int64; var SellerAccount,SignerAccount : TAccount; var NewOwnerPublicKey : TAccountKey; var LockedUntilBlock : Cardinal; var HashLock : T32Bytes; var errors : String) : Boolean;
     Function UpdateOpDelist(Const TargetAccount : TAccount; var SignerAccount : TAccount; var errors : String) : Boolean;
     Function UpdateOpDelist(Const TargetAccount : TAccount; var SignerAccount : TAccount; var errors : String) : Boolean;
@@ -179,6 +181,7 @@ type
     procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
     procedure CM_WalletChanged(var Msg: TMessage); message CM_PC_WalletKeysChanged;
     Function GetDefaultSenderAccount : TAccount;
     Function GetDefaultSenderAccount : TAccount;
     procedure ebAccountKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
     procedure ebAccountKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+    function CaptureEPasa(const AEPasaTxt : String; out AEPasa : TEPasa) : Boolean;
   protected
   protected
     procedure searchAccount(editBox : TCustomEdit);
     procedure searchAccount(editBox : TCustomEdit);
   public
   public
@@ -470,6 +473,41 @@ begin
 end;
 end;
 
 
 
 
+function TFRMOperation.CaptureEPasa(const AEPasaTxt: String; out AEPasa: TEPasa): Boolean;
+begin
+  Result := TEPasa.TryParse(AEPasaTxt,AEPasa);
+  //
+  if ((FUpdating) or (Not Result)) then Exit;
+  FUpdating := True;
+  try
+    if AEPasa.PayloadType.HasTrait(ptPublic) then rbNotEncrypted.Checked := True
+    else if AEPasa.PayloadType.HasTrait(ptSenderKeyEncrypted) then rbEncryptedWithOldEC.Checked := True
+    else if AEPasa.PayloadType.HasTrait(ptRecipientKeyEncrypted) then rbEncryptedWithEC.Checked := True
+    else if AEPasa.PayloadType.HasTrait(ptPasswordEncrypted) then begin
+      rbEncrptedWithPassword.Checked := True;
+      ebEncryptPassword.Text := AEPasa.Password;
+    end;
+    if AEPasa.PayloadType.HasTrait(ptAsciiFormatted) then cbPayloadDataInputType.ItemIndex := 0
+    else if AEPasa.PayloadType.HasTrait(ptHexFormatted) then cbPayloadDataInputType.ItemIndex := 1
+    else if AEPasa.PayloadType.HasTrait(ptBase58Formatted) then cbPayloadDataInputType.ItemIndex := 2;
+    if (AEPasa.PayloadType.HasTrait(ptAsciiFormatted) or AEPasa.PayloadType.HasTrait(ptHexFormatted) or AEPasa.PayloadType.HasTrait(ptBase58Formatted)) then begin
+      memoPayload.Lines.Text := AEPasa.Payload;
+    end;
+
+    memoEPASA.Lines.Clear;
+    if AEPasa.IsPayToKey then memoEPASA.Lines.Add('PayToKey EPASA');
+    if AEPasa.IsAddressedByName then memoEPASA.Lines.Add('Addressed by name: '+AEPasa.AccountName);
+    memoEPASA.Lines.Add( AEPasa.ToString );
+    if AEPasa.PayloadType.HasTrait(ptAsciiFormatted) or AEPasa.PayloadType.HasTrait(ptBase58Formatted) or AEPasa.PayloadType.HasTrait(ptHexFormatted) then begin
+      memoEPasa.Lines.Add( 'AS BYTES: 0x'+AEPasa.GetRawPayloadBytes.ToHexaString);
+      memoEPasa.Lines.Add( 'AS PRINTABLE: '+AEPasa.GetRawPayloadBytes.ToPrintable);
+    end;
+
+  finally
+    FUpdating := False;
+  end;
+end;
+
 procedure TFRMOperation.CM_WalletChanged(var Msg: TMessage);
 procedure TFRMOperation.CM_WalletChanged(var Msg: TMessage);
 begin
 begin
    UpdateWalletKeys;
    UpdateWalletKeys;
@@ -479,14 +517,14 @@ procedure TFRMOperation.ebAccountNumberExit(Sender: TObject);
 Var LEPasa : TEPASA;
 Var LEPasa : TEPASA;
   eb : TEdit;
   eb : TEdit;
 begin
 begin
-  if (Not assigned(Sender)) then exit;
+  if (Not assigned(Sender)) or (FUpdating) then exit;
   if (Not (Sender is TEdit)) then exit;
   if (Not (Sender is TEdit)) then exit;
   eb := TEdit(Sender);
   eb := TEdit(Sender);
-  If TEPasa.TryParse(eb.Text,LEPasa) then begin
+  if CaptureEPasa(eb.Text,LEPasa) then begin
     if LEPasa.IsClassicPASA then
     if LEPasa.IsClassicPASA then
       eb.Text := LEPasa.ToClassicPASAString()
       eb.Text := LEPasa.ToClassicPASAString()
     else
     else
-      eb.Text := LEPasa.ToString();
+      eb.Text := LEPasa.ToString(True);
   end else begin
   end else begin
     eb.Text := '';
     eb.Text := '';
   end;
   end;
@@ -497,7 +535,7 @@ procedure TFRMOperation.ebCurrencyExit(Sender: TObject);
 Var m : Int64;
 Var m : Int64;
   eb : TEdit;
   eb : TEdit;
 begin
 begin
-  if (Not assigned(Sender)) then exit;
+  if (Not assigned(Sender)) or (FUpdating) then exit;
   if (Not (Sender is TEdit)) then exit;
   if (Not (Sender is TEdit)) then exit;
   eb := TEdit(Sender);
   eb := TEdit(Sender);
   If Not (eb.ReadOnly) then begin
   If Not (eb.ReadOnly) then begin
@@ -544,10 +582,10 @@ procedure TFRMOperation.FormCreate(Sender: TObject);
 begin
 begin
   {$IFDEF USE_GNUGETTEXT}TranslateComponent(self);{$ENDIF}
   {$IFDEF USE_GNUGETTEXT}TranslateComponent(self);{$ENDIF}
   FDisabled := false;
   FDisabled := false;
+  FUpdating := False;
   FWalletKeys := Nil;
   FWalletKeys := Nil;
   FSenderAccounts := TOrderedCardinalList.Create;
   FSenderAccounts := TOrderedCardinalList.Create;
   FSenderAccounts.OnListChanged := OnSenderAccountsChanged;
   FSenderAccounts.OnListChanged := OnSenderAccountsChanged;
-  FDisabled := true;
   FNode := TNode.Node;
   FNode := TNode.Node;
   ebSenderAccount.OnKeyDown:=ebAccountKeyDown;
   ebSenderAccount.OnKeyDown:=ebAccountKeyDown;
   ebSenderAccount.Tag:=CT_AS_MyAccounts;
   ebSenderAccount.Tag:=CT_AS_MyAccounts;
@@ -620,6 +658,24 @@ begin
   ebFee.OnExit:= ebCurrencyExit;
   ebFee.OnExit:= ebCurrencyExit;
   memoAccounts.Lines.Clear;
   memoAccounts.Lines.Clear;
   PageControlOpType.ActivePage := tsTransaction;
   PageControlOpType.ActivePage := tsTransaction;
+  cbPayloadDataInputType.Items.Clear;
+  cbPayloadDataInputType.Items.Add('As String');
+  cbPayloadDataInputType.Items.Add('As Hexadecimal');
+  cbPayloadDataInputType.Items.Add('As Base58');
+  cbPayloadDataInputType.ItemIndex := 0;
+  cbPayloadDataInputType.OnChange := memoPayloadClick;
+  memoPayload.OnChange := memoPayloadClick;
+  memoPayload.OnClick := memoPayloadClick;
+  memoEPASA.ScrollBars := ssBoth;
+  memoEPASA.ReadOnly := False;
+  memoEPASA.TabStop := False;
+  memoEPASA.ParentFont := True;
+  {$IFDEF TESTNET}
+  memoEPASA.Visible := True;
+  {$ELSE}
+  memoEPASA.Visible := False;
+  {$ENDIF}
+  memoEPASA.Enabled := memoEPASA.Visible;
 end;
 end;
 
 
 procedure TFRMOperation.ebNewPublicKeyExit(Sender: TObject);
 procedure TFRMOperation.ebNewPublicKeyExit(Sender: TObject);
@@ -852,17 +908,15 @@ begin
   end;
   end;
 end;
 end;
 
 
-var GInUpdateInfoClick : boolean;
 procedure TFRMOperation.updateInfoClick(Sender: TObject);
 procedure TFRMOperation.updateInfoClick(Sender: TObject);
 Var errors : String;
 Var errors : String;
 begin
 begin
-  if NOT GInUpdateInfoClick then begin
-    GInUpdateInfoClick := true;
-    try
-      UpdateOperationOptions(errors);
-    finally
-    GInUpdateInfoClick := false;
-    end;
+  if FDisabled or FUpdating then Exit;
+  FDisabled := True;
+  try
+    UpdateOperationOptions(errors);
+  finally
+    FDisabled := False;
   end;
   end;
 end;
 end;
 
 
@@ -1261,8 +1315,6 @@ begin
   lblSignerAccount.Enabled := ebSignerAccount.Enabled;
   lblSignerAccount.Enabled := ebSignerAccount.Enabled;
   lblChangeName.Enabled:= (PageControlOpType.ActivePage=tsChangeInfo) And (SenderAccounts.Count=1);
   lblChangeName.Enabled:= (PageControlOpType.ActivePage=tsChangeInfo) And (SenderAccounts.Count=1);
   ebChangeName.Enabled:= lblChangeName.Enabled;
   ebChangeName.Enabled:= lblChangeName.Enabled;
-  //
-  UpdatePayload(sender_account, e);
 end;
 end;
 
 
 function TFRMOperation.UpdateOpListAccount(const TargetAccount: TAccount;
 function TFRMOperation.UpdateOpListAccount(const TargetAccount: TAccount;
@@ -1522,25 +1574,44 @@ begin
   End;
   End;
 end;
 end;
 
 
-function TFRMOperation.UpdateOpTransaction(const ASenderAccount: TAccount; out LTargetEPASA : TEPasa; out ATargetAccount : TAccount; out AResolvedTargetKey : TECDSA_Public; out ATargetRequiresPurchase : Boolean; out AAmount: Int64; out AErrors: String): Boolean;
+function TFRMOperation.UpdateOpTransaction(const ASenderAccount: TAccount; out ATargetEPASA : TEPasa; out ATargetAccount : TAccount; out AResolvedTargetKey : TECDSA_Public; out ATargetRequiresPurchase : Boolean; out AAmount: Int64; out AErrors: String): Boolean;
 Var
 Var
   LResolvedAccountNo : Cardinal;
   LResolvedAccountNo : Cardinal;
+  LPublicKey : TAccountKey;
 begin
 begin
   AErrors := '';
   AErrors := '';
   lblTransactionErrors.Caption := '';
   lblTransactionErrors.Caption := '';
   if PageControlOpType.ActivePage<>tsTransaction then exit;
   if PageControlOpType.ActivePage<>tsTransaction then exit;
-  if not TEPasa.TryParse(ebDestAccount.Text, LTargetEPASA) then begin
-    AErrors := 'Invalid dest. EPASA ('+ebDestAccount.Text+')';
+
+  if (Trim(ebDestAccount.Text)='') then begin
+    AErrors := 'Need a destintation or EPASA';
+    lblTransactionErrors.Caption := AErrors;
+    Exit(False);
+  end;
+
+
+  if Not CaptureEPasa(ebDestAccount.Text,ATargetEPasa) then begin
+    AErrors := 'Invalid EPASA value: '+ebDestAccount.Text;
     lblTransactionErrors.Caption := AErrors;
     lblTransactionErrors.Caption := AErrors;
     Exit(False);
     Exit(False);
   end;
   end;
 
 
-  Result := TNode.Node.TryResolveEPASA(LTargetEPASA, LResolvedAccountNo, AResolvedTargetKey, ATargetRequiresPurchase, AErrors);
+  Result := TNode.Node.TryResolveEPASA(ATargetEPASA, LResolvedAccountNo, AResolvedTargetKey, ATargetRequiresPurchase, AErrors);
   if NOT Result then begin
   if NOT Result then begin
     lblTransactionErrors.Caption := AErrors;
     lblTransactionErrors.Caption := AErrors;
     Exit(False);
     Exit(False);
   end;
   end;
 
 
+  // GUI Base58 protection: In order to prevent manual mistake, Base58 is only allowed when introducing
+  // a Public key, otherwise will need to use String ("") or Hexadecimal (0x..) input
+  if (ATargetEPASA.PayloadType.HasTrait(ptBase58Formatted)) then begin
+     if Not TAccountComp.AccountPublicKeyImport(ATargetEPASA.Payload,LPublicKey,AErrors) then begin
+       AErrors := 'Not a Base58 Public key: '+AErrors;
+       lblTransactionErrors.Caption := AErrors;
+       Exit(False);
+     end;
+  end;
+
   if LResolvedAccountNo <> CT_AccountNo_NUL then begin
   if LResolvedAccountNo <> CT_AccountNo_NUL then begin
     ATargetAccount := TNode.Node.GetMempoolAccount(LResolvedAccountNo);
     ATargetAccount := TNode.Node.GetMempoolAccount(LResolvedAccountNo);
     if ATargetAccount.account=ASenderAccount.account then begin
     if ATargetAccount.account=ASenderAccount.account then begin
@@ -1583,6 +1654,7 @@ Var
   LPayloadBytes : TRawBytes;
   LPayloadBytes : TRawBytes;
 begin
 begin
   LValid := false;
   LValid := false;
+  LPayloadBytes := Nil;
   LEncryptedPayloadBytes := Nil;
   LEncryptedPayloadBytes := Nil;
   FEncodedPayload := CT_TOperationPayload_NUL;
   FEncodedPayload := CT_TOperationPayload_NUL;
   LUserPayloadString := memoPayload.Lines.Text;
   LUserPayloadString := memoPayload.Lines.Text;
@@ -1590,55 +1662,60 @@ begin
   AErrors := 'Unknown error';
   AErrors := 'Unknown error';
   try
   try
     LTargetEPASA := TEPasa.Empty;
     LTargetEPASA := TEPasa.Empty;
-    If (PageControlOpType.ActivePage=tsTransaction) then begin
-      if NOT TEPasa.TryParse(ebDestAccount.Text, LTargetEPASA) then begin
-        AErrors := 'Indeterminable target';
-        Exit(False);
-      end;
 
 
-      if LTargetEPASA.IsPayToKey then begin
-        LValid := true;
-        Exit;
-      end;
-
-      if LTargetEPASA.HasPayload then begin
-        if LUserPayloadString <> '' then begin
-          AErrors := 'Ambiguous payload. Payload already specified by target EPASA.';
-          LValid := False;
-          Exit;
-        end;
-
-        if ebEncryptPassword.Text <> '' then begin
-          AErrors := 'Ambiguous payload. Password cannot be specified.';
-          LValid := False;
-          Exit;
-        end;
-      end;
-      FEncodedPayload.payload_type := LTargetEPASA.PayloadType.ToProtocolValue;
+    if NOT TEPasa.TryParse(ebDestAccount.Text, LTargetEPASA) then begin
+      AErrors := 'Indeterminable target';
+      Exit(False);
     end;
     end;
 
 
-    if (LUserPayloadString='') AND (LTargetEPASA.Payload.IsEmpty) then begin
-      LValid := true;
-      exit;
+    if (LUserPayloadString='') then begin
+      LValid := True;
+      Exit(True);
     end;
     end;
-    if LTargetEPASA.HasPayload then begin
-      LPayloadBytes := LTargetEPASA.GetRawPayloadBytes;
-    end else if cbPayloadAsHex.Checked then begin
-      if NOT TCrypto.HexaToRaw(LUserPayloadString, LPayloadBytes) then begin
-        LValid := false;
-        AErrors := 'Payload not hex-formatted';
-        exit;
+
+    LTargetEPASA.PayloadType := LTargetEPASA.PayloadType - [ptPublic] - [ptRecipientKeyEncrypted] - [ptSenderKeyEncrypted]
+      - [ptPasswordEncrypted] - [ptAsciiFormatted] - [ptHexFormatted] - [ptBase58Formatted];
+
+    case cbPayloadDataInputType.ItemIndex of
+      0 : begin
+           LTargetEPASA.PayloadType := LTargetEPASA.PayloadType + [ptAsciiFormatted];
+           LPayloadBytes := TEncoding.ASCII.GetBytes(LUserPayloadString);
+      end;
+      1 : begin
+         LTargetEPASA.PayloadType := LTargetEPASA.PayloadType + [ptHexFormatted];
+         if Not THexEncoding.TryDecode(LUserPayloadString,LPayloadBytes) then begin
+           AErrors := 'Payload is not an Hexadecimal string';
+           Exit(False);
+         end;
       end;
       end;
-    end else LPayloadBytes := TEncoding.ANSI.GetBytes(LUserPayloadString);
+      2 : begin
+         LTargetEPASA.PayloadType := LTargetEPASA.PayloadType + [ptBase58Formatted];
+         if Not TPascalBase58Encoding.TryDecode(LUserPayloadString,LPayloadBytes) then begin
+           AErrors := 'Payload is not a Base 58 string';
+           Exit(False);
+         end;
+
+         // GUI Base58 protection: In order to prevent manual mistake, Base58 is only allowed when introducing
+         // a Public key, otherwise will need to use String ("") or Hexadecimal (0x..) input
+         if Not TAccountComp.AccountPublicKeyImport(LUserPayloadString,LPublicKey,AErrors) then begin
+           AErrors := 'Not a Public key: '+AErrors;
+           Exit(False);
+         end;
+      end
+    else
+    end;
+    LTargetEPASA.Payload := LUserPayloadString;
 
 
-    if (NOT LTargetEPasa.HasPayload AND rbEncryptedWithOldEC.Checked) OR LTargetEPASA.PayloadType.HasTrait(ptSenderKeyEncrypted) then begin
+    if (Length(LPayloadBytes)>0) and (rbEncryptedWithOldEC.Checked) then begin
       // Use sender
       // Use sender
-      AErrors := 'Error encrypting';
+      LTargetEPASA.PayloadType := LTargetEPASA.PayloadType + [ptSenderKeyEncrypted];
+      AErrors := 'Error encrypting by sender';
       LAccount := FNode.GetMempoolAccount(ASenderAccount.account);
       LAccount := FNode.GetMempoolAccount(ASenderAccount.account);
       TPCEncryption.DoPascalCoinECIESEncrypt(LAccount.accountInfo.accountKey,LPayloadBytes,LEncryptedPayloadBytes);
       TPCEncryption.DoPascalCoinECIESEncrypt(LAccount.accountInfo.accountKey,LPayloadBytes,LEncryptedPayloadBytes);
       LValid := Length(LEncryptedPayloadBytes)>0;
       LValid := Length(LEncryptedPayloadBytes)>0;
-    end else if (NOT LTargetEPasa.HasPayload AND rbEncryptedWithEC.Checked) or LTargetEPASA.PayloadType.HasTrait(ptRecipientKeyEncrypted) then begin
-      AErrors := 'Error encrypting';
+    end else if (Length(LPayloadBytes)>0) and (rbEncryptedWithEC.Checked) then begin
+      AErrors := 'Error encrypting by recipient';
+      LTargetEPASA.PayloadType := LTargetEPASA.PayloadType + [ptRecipientKeyEncrypted];
       if (PageControlOpType.ActivePage=tsTransaction) or (PageControlOpType.ActivePage=tsListAccount) or (PageControlOpType.ActivePage=tsDelistAccount)
       if (PageControlOpType.ActivePage=tsTransaction) or (PageControlOpType.ActivePage=tsListAccount) or (PageControlOpType.ActivePage=tsDelistAccount)
         or (PageControlOpType.ActivePage=tsBuyAccount) then begin
         or (PageControlOpType.ActivePage=tsBuyAccount) then begin
 
 
@@ -1704,14 +1781,14 @@ begin
       end else begin
       end else begin
         AErrors := 'This operation does not allow this kind of payload';
         AErrors := 'This operation does not allow this kind of payload';
       end;
       end;
-    end else if (NOT LTargetEPasa.HasPayload AND rbEncrptedWithPassword.Checked) OR LTargetEPASA.PayloadType.HasTrait(ptPasswordEncrypted) then begin
-      if LTargetEPASA.PayloadType.HasTrait(ptPasswordEncrypted) then
-        LPassword := LTargetEPASA.Password
-      else
-        LPassword := ebEncryptPassword.Text;
+    end else if (Length(LPayloadBytes)>0) AND (rbEncrptedWithPassword.Checked) then begin
+      LTargetEPASA.PayloadType := LTargetEPASA.PayloadType + [ptPasswordEncrypted];
+      LPassword := ebEncryptPassword.Text;
       LEncryptedPayloadBytes := TPCEncryption.DoPascalCoinAESEncrypt(LPayloadBytes,TEncoding.ANSI.GetBytes(LPassword));
       LEncryptedPayloadBytes := TPCEncryption.DoPascalCoinAESEncrypt(LPayloadBytes,TEncoding.ANSI.GetBytes(LPassword));
+      LTargetEPASA.Password := LPassword;
       LValid := Length(LEncryptedPayloadBytes)>0;
       LValid := Length(LEncryptedPayloadBytes)>0;
-    end else if (NOT LTargetEPasa.HasPayload AND rbNotEncrypted.Checked) or LTargetEPASA.PayloadType.HasTrait(ptPublic) then begin
+    end else if (Length(LPayloadBytes)>0) AND (rbNotEncrypted.Checked) then begin
+      LTargetEPASA.PayloadType := LTargetEPASA.PayloadType + [ptPublic];
       LEncryptedPayloadBytes := LPayloadBytes;
       LEncryptedPayloadBytes := LPayloadBytes;
       LValid := true;
       LValid := true;
     end else begin
     end else begin
@@ -1726,19 +1803,18 @@ begin
     end;
     end;
     if LValid then begin
     if LValid then begin
       lblEncryptionErrors.Caption := '';
       lblEncryptionErrors.Caption := '';
-      if LTargetEPASA.HasPayload then
-        lblPayloadLength.Caption := Format('(%db -> %db)',[length(LTargetEPASA.Payload),length(LEncryptedPayloadBytes)])
-      else
-        lblPayloadLength.Caption := Format('(%db -> %db)',[length(LUserPayloadString),length(LEncryptedPayloadBytes)]);
+      lblPayloadLength.Caption := Format('(%db -> %db)',[length(LTargetEPASA.Payload),length(LEncryptedPayloadBytes)])
     end else begin
     end else begin
+      if Trim(AErrors)='' then AErrors := 'Undefined';
       lblEncryptionErrors.Caption := AErrors;
       lblEncryptionErrors.Caption := AErrors;
-      if LTargetEPASA.HasPayload then
-        lblPayloadLength.Caption := Format('(%db -> ?)',[length(LTargetEPASA.Payload)])
-      else
-        lblPayloadLength.Caption := Format('(%db -> ?)',[length(LUserPayloadString)]);
+      lblPayloadLength.Caption := Format('(%db -> ?)',[length(LTargetEPASA.Payload)])
     end;
     end;
+    FEncodedPayload.payload_type := LTargetEPASA.PayloadType.ToProtocolValue;
     FEncodedPayload.payload_raw := LEncryptedPayloadBytes;
     FEncodedPayload.payload_raw := LEncryptedPayloadBytes;
     Result := LValid;
     Result := LValid;
+    if (LValid) And (Not FUpdating) then begin
+      ebDestAccount.Text := LTargetEPASA.ToClassicPASAString;
+    end;
   end;
   end;
 end;
 end;
 
 

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

@@ -715,7 +715,9 @@ begin
     If op.OperationToOperationResume(FSourceNode.Bank.BlocksCount,op,True,op.SignerAccount,opr) then begin
     If op.OperationToOperationResume(FSourceNode.Bank.BlocksCount,op,True,op.SignerAccount,opr) then begin
       jsonObj := TPCJSONObject.Create;
       jsonObj := TPCJSONObject.Create;
       Try
       Try
-        TPascalCoinJSONComp.FillOperationObject(opr,FSourceNode.Bank.BlocksCount,jsonObj);
+        TPascalCoinJSONComp.FillOperationObject(opr,FSourceNode.Bank.BlocksCount,
+          SourceNode,SourceWalletKeys,Nil,
+          jsonObj);
         mOperationInfo.Lines.Add('JSON:');
         mOperationInfo.Lines.Add('JSON:');
         mOperationInfo.Lines.Add(jsonObj.ToJSON(False));
         mOperationInfo.Lines.Add(jsonObj.ToJSON(False));
       Finally
       Finally

+ 20 - 19
src/gui-classic/UFRMWallet.lfm

@@ -4,7 +4,7 @@ object FRMWallet: TFRMWallet
   Top = 201
   Top = 201
   Width = 865
   Width = 865
   Caption = 'Pascal full node Wallet (Classic GUI)'
   Caption = 'Pascal full node Wallet (Classic GUI)'
-  ClientHeight = 600
+  ClientHeight = 580
   ClientWidth = 865
   ClientWidth = 865
   Color = clBtnFace
   Color = clBtnFace
   Constraints.MinHeight = 600
   Constraints.MinHeight = 600
@@ -16,6 +16,7 @@ object FRMWallet: TFRMWallet
   OnCreate = FormCreate
   OnCreate = FormCreate
   OnDestroy = FormDestroy
   OnDestroy = FormDestroy
   Position = poScreenCenter
   Position = poScreenCenter
+  LCLVersion = '2.0.10.0'
   object pnlTop: TPanel
   object pnlTop: TPanel
     Left = 0
     Left = 0
     Height = 91
     Height = 91
@@ -311,7 +312,7 @@ object FRMWallet: TFRMWallet
   object StatusBar: TStatusBar
   object StatusBar: TStatusBar
     Left = 0
     Left = 0
     Height = 23
     Height = 23
-    Top = 577
+    Top = 557
     Width = 865
     Width = 865
     Panels = <    
     Panels = <    
       item
       item
@@ -331,7 +332,7 @@ object FRMWallet: TFRMWallet
   end
   end
   object PageControl: TPageControl
   object PageControl: TPageControl
     Left = 0
     Left = 0
-    Height = 486
+    Height = 466
     Top = 91
     Top = 91
     Width = 865
     Width = 865
     ActivePage = tsMyAccounts
     ActivePage = tsMyAccounts
@@ -341,11 +342,11 @@ object FRMWallet: TFRMWallet
     OnChange = PageControlChange
     OnChange = PageControlChange
     object tsMyAccounts: TTabSheet
     object tsMyAccounts: TTabSheet
       Caption = 'Account Explorer'
       Caption = 'Account Explorer'
-      ClientHeight = 460
+      ClientHeight = 440
       ClientWidth = 857
       ClientWidth = 857
       object Splitter1: TSplitter
       object Splitter1: TSplitter
         Left = 400
         Left = 400
-        Height = 394
+        Height = 374
         Top = 66
         Top = 66
         Width = 5
         Width = 5
       end
       end
@@ -471,17 +472,17 @@ object FRMWallet: TFRMWallet
       end
       end
       object pnlAccounts: TPanel
       object pnlAccounts: TPanel
         Left = 0
         Left = 0
-        Height = 394
+        Height = 374
         Top = 66
         Top = 66
         Width = 400
         Width = 400
         Align = alLeft
         Align = alLeft
         BevelOuter = bvNone
         BevelOuter = bvNone
-        ClientHeight = 394
+        ClientHeight = 374
         ClientWidth = 400
         ClientWidth = 400
         TabOrder = 1
         TabOrder = 1
         object dgAccounts: TDrawGrid
         object dgAccounts: TDrawGrid
           Left = 0
           Left = 0
-          Height = 360
+          Height = 340
           Top = 0
           Top = 0
           Width = 400
           Width = 400
           Align = alClient
           Align = alClient
@@ -495,7 +496,7 @@ object FRMWallet: TFRMWallet
         object pnlAccountsInfo: TPanel
         object pnlAccountsInfo: TPanel
           Left = 0
           Left = 0
           Height = 34
           Height = 34
-          Top = 360
+          Top = 340
           Width = 400
           Width = 400
           Align = alBottom
           Align = alBottom
           BevelOuter = bvNone
           BevelOuter = bvNone
@@ -576,7 +577,7 @@ object FRMWallet: TFRMWallet
       end
       end
       object pcAccountsOptions: TPageControl
       object pcAccountsOptions: TPageControl
         Left = 405
         Left = 405
-        Height = 394
+        Height = 374
         Top = 66
         Top = 66
         Width = 452
         Width = 452
         ActivePage = tsMultiSelectAccounts
         ActivePage = tsMultiSelectAccounts
@@ -603,12 +604,12 @@ object FRMWallet: TFRMWallet
         end
         end
         object tsMultiSelectAccounts: TTabSheet
         object tsMultiSelectAccounts: TTabSheet
           Caption = 'Selected Accounts For Batch Operation'
           Caption = 'Selected Accounts For Batch Operation'
-          ClientHeight = 368
+          ClientHeight = 348
           ClientWidth = 444
           ClientWidth = 444
           ImageIndex = 1
           ImageIndex = 1
           object dgSelectedAccounts: TDrawGrid
           object dgSelectedAccounts: TDrawGrid
             Left = 41
             Left = 41
-            Height = 311
+            Height = 291
             Top = 31
             Top = 31
             Width = 320
             Width = 320
             Align = alLeft
             Align = alLeft
@@ -645,7 +646,7 @@ object FRMWallet: TFRMWallet
           object pnlSelectedAccountsBottom: TPanel
           object pnlSelectedAccountsBottom: TPanel
             Left = 0
             Left = 0
             Height = 26
             Height = 26
-            Top = 342
+            Top = 322
             Width = 444
             Width = 444
             Align = alBottom
             Align = alBottom
             BevelOuter = bvNone
             BevelOuter = bvNone
@@ -687,12 +688,12 @@ object FRMWallet: TFRMWallet
           end
           end
           object pnlSelectedAccountsLeft: TPanel
           object pnlSelectedAccountsLeft: TPanel
             Left = 0
             Left = 0
-            Height = 311
+            Height = 291
             Top = 31
             Top = 31
             Width = 41
             Width = 41
             Align = alLeft
             Align = alLeft
             BevelOuter = bvNone
             BevelOuter = bvNone
-            ClientHeight = 311
+            ClientHeight = 291
             ClientWidth = 41
             ClientWidth = 41
             TabOrder = 3
             TabOrder = 3
             object sbSelectedAccountsAdd: TSpeedButton
             object sbSelectedAccountsAdd: TSpeedButton
@@ -1191,12 +1192,12 @@ object FRMWallet: TFRMWallet
   end
   end
   object TimerUpdateStatus: TTimer
   object TimerUpdateStatus: TTimer
     OnTimer = TimerUpdateStatusTimer
     OnTimer = TimerUpdateStatusTimer
-    left = 32
-    top = 56
+    Left = 32
+    Top = 56
   end
   end
   object MainMenu: TMainMenu
   object MainMenu: TMainMenu
-    left = 165
-    top = 160
+    Left = 165
+    Top = 160
     object miProject: TMenuItem
     object miProject: TMenuItem
       Caption = 'Project'
       Caption = 'Project'
       object miPrivatekeys: TMenuItem
       object miPrivatekeys: TMenuItem

+ 13 - 4
src/gui-classic/UFRMWallet.pas

@@ -35,7 +35,7 @@ uses
   UNode, UGridUtils, UJSONFunctions, UAccounts, Menus, ImgList, UNetProtocol,
   UNode, UGridUtils, UJSONFunctions, UAccounts, Menus, ImgList, UNetProtocol,
   UCrypto, Buttons, UPoolMining, URPC, UFRMAccountSelect, UConst,
   UCrypto, Buttons, UPoolMining, URPC, UFRMAccountSelect, UConst,
   UAccountKeyStorage, UBaseTypes, UPCDataTypes, UOrderedList,
   UAccountKeyStorage, UBaseTypes, UPCDataTypes, UOrderedList,
-  UFRMRPCCalls, UTxMultiOperation, USettings,
+  UFRMRPCCalls, UTxMultiOperation, USettings, UEPasa,
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
 
 
 Const
 Const
@@ -333,7 +333,7 @@ Uses UFolderHelper,{$IFDEF USE_GNUGETTEXT}gnugettext,{$ENDIF}
   {$ENDIF}
   {$ENDIF}
   UPCTNetDataExtraMessages,
   UPCTNetDataExtraMessages,
   UFRMAskForAccount,
   UFRMAskForAccount,
-  UAbstractBTree,
+  UAbstractBTree, UEPasaDecoder,
   UFRMAbout, UFRMOperation, UFRMWalletKeys, UFRMPayloadDecoder, UFRMNodesIp, UFRMMemoText,
   UFRMAbout, UFRMOperation, UFRMWalletKeys, UFRMPayloadDecoder, UFRMNodesIp, UFRMMemoText,
   UCommon, UPCOrderedLists;
   UCommon, UPCOrderedLists;
 
 
@@ -981,6 +981,7 @@ procedure TFRMWallet.FillOperationInformation(const Strings: TStrings;
   const OperationResume: TOperationResume);
   const OperationResume: TOperationResume);
 var i : Integer;
 var i : Integer;
   jsonObj : TPCJSONObject;
   jsonObj : TPCJSONObject;
+  LEPASA : TEPasa;
 begin
 begin
   If (not OperationResume.valid) then exit;
   If (not OperationResume.valid) then exit;
   If OperationResume.Block<FNode.Bank.BlocksCount then
   If OperationResume.Block<FNode.Bank.BlocksCount then
@@ -1009,7 +1010,10 @@ begin
   If (Length(OperationResume.OperationHash_OLD)>0) then begin
   If (Length(OperationResume.OperationHash_OLD)>0) then begin
     Strings.Add(Format('Old Operation Hash (old_ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash_OLD)]));
     Strings.Add(Format('Old Operation Hash (old_ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash_OLD)]));
   end;
   end;
-  Strings.Add(Format('Payload type:%d length:%d',[OperationResume.OriginalPayload.payload_type, length(OperationResume.OriginalPayload.payload_raw)]));
+  if TEPasaDecoder.TryDecodeEPASA(OperationResume.DestAccount,OperationResume.OriginalPayload,FNode,FWalletKeys,Nil,LEPASA) then begin
+    Strings.Add('EPASA: '+LEPASA.ToString);
+  end else Strings.Add('No EPASA format');
+  Strings.Add(Format('Payload type:%s length:%d',['0x'+IntToHex(OperationResume.OriginalPayload.payload_type,2), length(OperationResume.OriginalPayload.payload_raw)]));
   if (Length(OperationResume.OriginalPayload.payload_raw)>0) then begin
   if (Length(OperationResume.OriginalPayload.payload_raw)>0) then begin
     If OperationResume.PrintablePayload<>'' then begin
     If OperationResume.PrintablePayload<>'' then begin
       Strings.Add(Format('Payload (human): %s',[OperationResume.PrintablePayload]));
       Strings.Add(Format('Payload (human): %s',[OperationResume.PrintablePayload]));
@@ -1021,7 +1025,9 @@ begin
   end;
   end;
   jsonObj := TPCJSONObject.Create;
   jsonObj := TPCJSONObject.Create;
   Try
   Try
-    TPascalCoinJSONComp.FillOperationObject(OperationResume,FNode.Bank.BlocksCount,jsonObj);
+    TPascalCoinJSONComp.FillOperationObject(OperationResume,FNode.Bank.BlocksCount,
+      FNode,FWalletKeys,Nil,
+      jsonObj);
     Strings.Add('OPERATION JSON:');
     Strings.Add('OPERATION JSON:');
     Strings.Add(jsonObj.ToJSON(False));
     Strings.Add(jsonObj.ToJSON(False));
   Finally
   Finally
@@ -1348,14 +1354,17 @@ begin
   FOperationsAccountGrid := TOperationsGrid.Create(Self);
   FOperationsAccountGrid := TOperationsGrid.Create(Self);
   FOperationsAccountGrid.DrawGrid := dgAccountOperations;
   FOperationsAccountGrid.DrawGrid := dgAccountOperations;
   FOperationsAccountGrid.MustShowAlwaysAnAccount := true;
   FOperationsAccountGrid.MustShowAlwaysAnAccount := true;
+  FOperationsAccountGrid.WalletKeys := FWalletKeys;
   FPendingOperationsGrid := TOperationsGrid.Create(Self);
   FPendingOperationsGrid := TOperationsGrid.Create(Self);
   FPendingOperationsGrid.DrawGrid := dgPendingOperations;
   FPendingOperationsGrid.DrawGrid := dgPendingOperations;
   FPendingOperationsGrid.AccountNumber := -1; // all
   FPendingOperationsGrid.AccountNumber := -1; // all
   FPendingOperationsGrid.PendingOperations := true;
   FPendingOperationsGrid.PendingOperations := true;
+  FPendingOperationsGrid.WalletKeys := FWalletKeys;
   FOperationsExplorerGrid := TOperationsGrid.Create(Self);
   FOperationsExplorerGrid := TOperationsGrid.Create(Self);
   FOperationsExplorerGrid.DrawGrid := dgOperationsExplorer;
   FOperationsExplorerGrid.DrawGrid := dgOperationsExplorer;
   FOperationsExplorerGrid.AccountNumber := -1;
   FOperationsExplorerGrid.AccountNumber := -1;
   FOperationsExplorerGrid.PendingOperations := False;
   FOperationsExplorerGrid.PendingOperations := False;
+  FOperationsExplorerGrid.WalletKeys := FWalletKeys;
   FBlockChainGrid := TBlockChainGrid.Create(Self);
   FBlockChainGrid := TBlockChainGrid.Create(Self);
   FBlockChainGrid.DrawGrid := dgBlockChainExplorer;
   FBlockChainGrid.DrawGrid := dgBlockChainExplorer;
   FBlockChainGrid.ShowTimeAverageColumns:={$IFDEF SHOW_AVERAGE_TIME_STATS}True;{$ELSE}False;{$ENDIF}
   FBlockChainGrid.ShowTimeAverageColumns:={$IFDEF SHOW_AVERAGE_TIME_STATS}True;{$ELSE}False;{$ENDIF}

+ 38 - 5
src/gui-classic/UGridUtils.pas

@@ -134,7 +134,7 @@ Type
 
 
   TOperationsGridUpdateThread = Class(TPCThread)
   TOperationsGridUpdateThread = Class(TPCThread)
     FOperationsGrid : TOperationsGrid;
     FOperationsGrid : TOperationsGrid;
-    procedure DoUpdateOperationsGrid(ANode : TNode; var AList : TList<TOperationResume>);
+    procedure DoUpdateOperationsGrid(const ANode : TNode; const AWalleTKeys : TWalletKeys; const APasswords : TList<String>; var AList : TList<TOperationResume>);
   protected
   protected
     procedure BCExecute; override;
     procedure BCExecute; override;
   public
   public
@@ -152,6 +152,8 @@ Type
     FBlockEnd: Int64;
     FBlockEnd: Int64;
     FMustShowAlwaysAnAccount: Boolean;
     FMustShowAlwaysAnAccount: Boolean;
     FOperationsGridUpdateThread : TOperationsGridUpdateThread;
     FOperationsGridUpdateThread : TOperationsGridUpdateThread;
+    FWalletKeys: TWalletKeys;
+    FPasswords: TList<String>;
     Procedure OnNodeNewOperation(Sender : TObject);
     Procedure OnNodeNewOperation(Sender : TObject);
     Procedure OnNodeNewAccount(Sender : TObject);
     Procedure OnNodeNewAccount(Sender : TObject);
     Procedure InitGrid;
     Procedure InitGrid;
@@ -177,6 +179,8 @@ Type
     Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
     Property AccountNumber : Int64 read FAccountNumber write SetAccountNumber;
     Property MustShowAlwaysAnAccount : Boolean read FMustShowAlwaysAnAccount write SetMustShowAlwaysAnAccount;
     Property MustShowAlwaysAnAccount : Boolean read FMustShowAlwaysAnAccount write SetMustShowAlwaysAnAccount;
     Property Node : TNode read GetNode write SetNode;
     Property Node : TNode read GetNode write SetNode;
+    property WalletKeys : TWalletKeys read FWalletKeys write FWalletKeys;
+    property Passwords : TList<String> read FPasswords;
     Procedure UpdateAccountOperations; virtual;
     Procedure UpdateAccountOperations; virtual;
     Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
     Procedure ShowModalDecoder(WalletKeys: TWalletKeys; AppParams : TAppParams);
     Property BlockStart : Int64 read FBlockStart write SetBlockStart;
     Property BlockStart : Int64 read FBlockStart write SetBlockStart;
@@ -281,6 +285,7 @@ implementation
 
 
 uses
 uses
   Graphics, SysUtils, UTime, UOpTransaction, UConst,
   Graphics, SysUtils, UTime, UOpTransaction, UConst,
+  UEPasa, UEPasaDecoder,
   UFRMPayloadDecoder, ULog;
   UFRMPayloadDecoder, ULog;
 
 
 { TAccountsGridUpdateThread }
 { TAccountsGridUpdateThread }
@@ -940,7 +945,7 @@ var list : TList<TOperationResume>;
 begin
 begin
   list := TList<TOperationResume>.Create;
   list := TList<TOperationResume>.Create;
   try
   try
-    DoUpdateOperationsGrid(FOperationsGrid.Node,list);
+    DoUpdateOperationsGrid(FOperationsGrid.Node,FOperationsGrid.WalletKeys,FOperationsGrid.Passwords,list);
     if (Not Terminated) then begin
     if (Not Terminated) then begin
       FOperationsGrid.FOperationsResume.Clear;
       FOperationsGrid.FOperationsResume.Clear;
       for i := 0 to list.Count-1 do begin
       for i := 0 to list.Count-1 do begin
@@ -961,7 +966,8 @@ begin
   Suspended := False;
   Suspended := False;
 end;
 end;
 
 
-procedure TOperationsGridUpdateThread.DoUpdateOperationsGrid(ANode: TNode; var AList: TList<TOperationResume>);
+procedure TOperationsGridUpdateThread.DoUpdateOperationsGrid(const ANode : TNode; const AWalleTKeys : TWalletKeys;
+  const APasswords : TList<String>; var AList: TList<TOperationResume>);
 Var list : TList<Cardinal>;
 Var list : TList<Cardinal>;
   i,j : Integer;
   i,j : Integer;
   OPR : TOperationResume;
   OPR : TOperationResume;
@@ -970,6 +976,7 @@ Var list : TList<Cardinal>;
   bstart,bend : int64;
   bstart,bend : int64;
   LOperationsResume : TOperationsResumeList;
   LOperationsResume : TOperationsResumeList;
   LLockedMempool : TPCOperationsComp;
   LLockedMempool : TPCOperationsComp;
+  LEPasa : TEPasa;
 begin
 begin
   if Not Assigned(ANode) then exit;
   if Not Assigned(ANode) then exit;
   AList.Clear;
   AList.Clear;
@@ -1061,6 +1068,13 @@ begin
       end;
       end;
     end;
     end;
   Finally
   Finally
+    for i := 0 to AList.Count-1 do begin
+      OPR := AList[i];
+      if TEPasaDecoder.TryDecodeEPASA(OPR.AffectedAccount,OPR.OriginalPayload,ANode,AWalleTKeys,APasswords,LEPasa) then begin
+        OPR.PrintablePayload := LEPasa.ToString(True);
+        AList[i] := OPR;
+      end;
+    end;
   End;
   End;
 end;
 end;
 
 
@@ -1068,6 +1082,8 @@ end;
 
 
 constructor TOperationsGrid.Create(AOwner: TComponent);
 constructor TOperationsGrid.Create(AOwner: TComponent);
 begin
 begin
+  FPasswords := TList<String>.Create;
+  FWalletKeys := Nil;
   FAccountNumber := 0;
   FAccountNumber := 0;
   FDrawGrid := Nil;
   FDrawGrid := Nil;
   MustShowAlwaysAnAccount := false;
   MustShowAlwaysAnAccount := false;
@@ -1091,6 +1107,7 @@ begin
   end;
   end;
   FOperationsResume.Free;
   FOperationsResume.Free;
   FNodeNotifyEvents.Free;
   FNodeNotifyEvents.Free;
+  FPasswords.Free;
   inherited;
   inherited;
 end;
 end;
 
 
@@ -1135,8 +1152,9 @@ begin
 end;
 end;
 
 
 procedure TOperationsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
 procedure TOperationsGrid.OnGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
-Var s : String;
+Var s, saux : String;
   opr : TOperationResume;
   opr : TOperationResume;
+  LRectLeft, LRectRight : TRect;
 begin
 begin
   DrawGrid.Canvas.Font.Color:=clWindowText;
   DrawGrid.Canvas.Font.Color:=clWindowText;
   opr := CT_TOperationResume_NUL;
   opr := CT_TOperationResume_NUL;
@@ -1209,7 +1227,22 @@ begin
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfRight,tfVerticalCenter,tfSingleLine]);
       end else if ACol=7 then begin
       end else if ACol=7 then begin
         s := opr.PrintablePayload;
         s := opr.PrintablePayload;
-        Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
+        LRectRight := Rect;
+        if opr.OriginalPayload.payload_type>0 then begin
+          saux := '0x'+IntToHex(opr.OriginalPayload.payload_type,2);
+          LRectLeft := Rect;
+          LRectLeft.Width := 30;
+          Rect.Inflate(-32,0,0,0);
+          DrawGrid.Canvas.Font.Color := clBlue;
+          DrawGrid.Canvas.Font.Style := [fsBold];
+          Canvas_TextRect(DrawGrid.Canvas,LRectLeft,saux,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
+          DrawGrid.Canvas.Font.Style := [];
+        end;
+        DrawGrid.Canvas.Font.Color := clBlack;
+        if opr.OriginalPayload.payload_raw.ToString=s then begin
+          DrawGrid.Canvas.Font.Style := [fsBold];
+        end;
+        Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine])
       end else begin
       end else begin
         s := '(???)';
         s := '(???)';
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfCenter,tfVerticalCenter,tfSingleLine]);