Browse Source

Merge pull request #46 from PascalCoinDev/master

Ready for 5.4
Albert Molina 4 years ago
parent
commit
805c282be6

+ 3 - 4
src/core/UAccounts.pas

@@ -501,7 +501,6 @@ uses
   // This issue is not detected on current Delphi memory manager (Tested on Delphi 10.3.2)
   // This issue is not detected on current Delphi memory manager (Tested on Delphi 10.3.2)
 {$ENDIF}
 {$ENDIF}
 
 
-
 { This function is for testing purpose only.
 { This function is for testing purpose only.
   Will check if Account Names are well assigned and stored }
   Will check if Account Names are well assigned and stored }
 function Check_Safebox_Names_Consistency(sb : TPCSafeBox; const title :String; var errors : String) : Boolean;
 function Check_Safebox_Names_Consistency(sb : TPCSafeBox; const title :String; var errors : String) : Boolean;
@@ -3590,9 +3589,9 @@ begin
             if ((iblock + (CT_BankToDiskEveryNBlocks * 10)) >= sbHeader.blockscount) then begin
             if ((iblock + (CT_BankToDiskEveryNBlocks * 10)) >= sbHeader.blockscount) then begin
             {$ENDIF}
             {$ENDIF}
               {$IFDEF ASSUME_VALID_POW_OLD_PROTOCOLS}
               {$IFDEF ASSUME_VALID_POW_OLD_PROTOCOLS}
-              LAddToMultiThreadOperationsBlockValidator := (LUseMultiThreadOperationsBlockValidator) and (LBlock.blockchainInfo.protocol_version>=CT_PROTOCOL_5) and (Assigned(LPCOperationsBlockValidator));
+              LAddToMultiThreadOperationsBlockValidator := False;
               {$ELSE}
               {$ELSE}
-              LAddToMultiThreadOperationsBlockValidator := (LUseMultiThreadOperationsBlockValidator) and (LBlock.blockchainInfo.protocol_version>=CT_PROTOCOL_4) and (Assigned(LPCOperationsBlockValidator));
+              LAddToMultiThreadOperationsBlockValidator := (LUseMultiThreadOperationsBlockValidator) and (LBlock.blockchainInfo.protocol_version=CT_PROTOCOL_4) and (Assigned(LPCOperationsBlockValidator));
               {$ENDIF}
               {$ENDIF}
               If not IsValidNewOperationsBlock(LBlock.blockchainInfo,False,Not LAddToMultiThreadOperationsBlockValidator,aux_errors) then begin
               If not IsValidNewOperationsBlock(LBlock.blockchainInfo,False,Not LAddToMultiThreadOperationsBlockValidator,aux_errors) then begin
                 errors := errors + ' > ' + aux_errors;
                 errors := errors + ' > ' + aux_errors;
@@ -3638,6 +3637,7 @@ begin
             Exit;
             Exit;
           end;
           end;
         end;
         end;
+
         // Add
         // Add
         {$IFDEF USE_ABSTRACTMEM}
         {$IFDEF USE_ABSTRACTMEM}
         FPCAbstractMem.SetBlockAccount(LBlock);
         FPCAbstractMem.SetBlockAccount(LBlock);
@@ -3682,7 +3682,6 @@ begin
         // Assign to previous
         // Assign to previous
         LPreviousProofOfWork := LBlock.blockchainInfo.proof_of_work;
         LPreviousProofOfWork := LBlock.blockchainInfo.proof_of_work;
       end; // For iBlock ...
       end; // For iBlock ...
-
         if Assigned(LPCOperationsBlockValidator) then begin
         if Assigned(LPCOperationsBlockValidator) then begin
           repeat
           repeat
             LPCOperationsBlockValidator.GetStatus(LValidatedOPOk, LValidatedOPError, LValidatedOPPending);
             LPCOperationsBlockValidator.GetStatus(LValidatedOPOk, LValidatedOPError, LValidatedOPPending);

+ 2 - 1
src/core/UBlockChain.pas

@@ -188,6 +188,7 @@ Type
     Balance : Int64;
     Balance : Int64;
     OriginalPayload : TOperationPayload;
     OriginalPayload : TOperationPayload;
     PrintablePayload : String;
     PrintablePayload : String;
+    DecodedEPasaPayload : String;
     OperationHash : TRawBytes;
     OperationHash : TRawBytes;
     OperationHash_OLD : TRawBytes; // Will include old oeration hash value
     OperationHash_OLD : TRawBytes; // Will include old oeration hash value
     errors : String;
     errors : String;
@@ -574,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:'';DecodedEPasaPayload:'';OperationHash:Nil;OperationHash_OLD:Nil;errors:'';isMultiOperation:False;Senders:Nil;Receivers:Nil;changers: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_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;

+ 2 - 2
src/core/UConst.pas

@@ -132,7 +132,7 @@ Const
 
 
   CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}$05000005{$ENDIF};
   CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}$05000005{$ENDIF};
 
 
-  CT_NetProtocol_Version: Word = 10;
+  CT_NetProtocol_Version: Word = 12;
   // IMPORTANT NOTE!!!
   // IMPORTANT NOTE!!!
   // NetProtocol_Available MUST BE always >= NetProtocol_version
   // NetProtocol_Available MUST BE always >= NetProtocol_version
   CT_NetProtocol_Available: Word = {$IFDEF PRODUCTION}12{$ELSE}12{$ENDIF};
   CT_NetProtocol_Available: Word = {$IFDEF PRODUCTION}12{$ELSE}12{$ENDIF};
@@ -198,7 +198,7 @@ Const
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Receiver              = 104;
   CT_OpSubtype_Data_Receiver              = 104;
 
 
-  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.4.Beta5'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.4.Beta5'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.4'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.4'{$ELSE}{$ENDIF}{$ENDIF};
 
 
   CT_Discover_IPs = {$IFDEF PRODUCTION}'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.dynamic-dns.net;pascalcoin2.dynamic-dns.net;pascalcoin1.dns1.us;pascalcoin2.dns1.us;pascalcoin1.dns2.us;pascalcoin2.dns2.us'
   CT_Discover_IPs = {$IFDEF PRODUCTION}'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.dynamic-dns.net;pascalcoin2.dynamic-dns.net;pascalcoin1.dns1.us;pascalcoin2.dns1.us;pascalcoin1.dns2.us;pascalcoin2.dns2.us'
                     {$ELSE}'pascaltestnet1.dynamic-dns.net;pascaltestnet2.dynamic-dns.net;pascaltestnet1.dns1.us;pascaltestnet2.dns1.us'{$ENDIF};
                     {$ELSE}'pascaltestnet1.dynamic-dns.net;pascaltestnet2.dynamic-dns.net;pascaltestnet1.dns1.us;pascaltestnet2.dns1.us'{$ENDIF};

+ 12 - 1
src/core/UEPasa.pas

@@ -29,7 +29,8 @@ uses
   uregexpr,
   uregexpr,
   UCommon,
   UCommon,
   UCrypto,
   UCrypto,
-  UEncoding;
+  UEncoding,
+  SyncObjs;
 
 
 type
 type
 
 
@@ -140,6 +141,7 @@ type
   TEPasaParser = class
   TEPasaParser = class
     strict private
     strict private
       class var FEPasaRegex: TCustomRegex;
       class var FEPasaRegex: TCustomRegex;
+      class var FEPasaLocker : TCriticalSection;
       class constructor CreateRegexEPasaParser();
       class constructor CreateRegexEPasaParser();
       class destructor DestroyRegexEPasaParser();
       class destructor DestroyRegexEPasaParser();
 
 
@@ -496,11 +498,13 @@ end;
 class constructor TEPasaParser.CreateRegexEPasaParser;
 class constructor TEPasaParser.CreateRegexEPasaParser;
 begin
 begin
   FEPasaRegex := TCustomRegex.Create(EPasaPattern);
   FEPasaRegex := TCustomRegex.Create(EPasaPattern);
+  FEPasaLocker := TCriticalSection.Create;
 end;
 end;
 
 
 class destructor TEPasaParser.DestroyRegexEPasaParser;
 class destructor TEPasaParser.DestroyRegexEPasaParser;
 begin
 begin
   FEPasaRegex.Free;
   FEPasaRegex.Free;
+  FEPasaLocker.Free;
 end;
 end;
 
 
 function TEPasaParser.Parse(const AEPasaText: String): TEPasa;
 function TEPasaParser.Parse(const AEPasaText: String): TEPasa;
@@ -535,6 +539,9 @@ begin
     Exit(False);
     Exit(False);
   end;
   end;
 
 
+  FEPasaLocker.Acquire; // Protect against multithread
+  Try
+
   FEPasaRegex.Match(AEPasaText);
   FEPasaRegex.Match(AEPasaText);
 
 
   LChecksumDelim := FEPasaRegex.GetMatchFromName('ChecksumDelim');
   LChecksumDelim := FEPasaRegex.GetMatchFromName('ChecksumDelim');
@@ -555,6 +562,10 @@ begin
     Exit(False);
     Exit(False);
   end;
   end;
 
 
+  Finally
+    FEPasaLocker.Release;
+  End;
+
   if (LAccountName <> #0) then begin
   if (LAccountName <> #0) then begin
     // Account Name
     // Account Name
     if (string.IsNullOrEmpty(LAccountName)) then begin
     if (string.IsNullOrEmpty(LAccountName)) then begin

+ 4 - 2
src/core/UEPasaDecoder.pas

@@ -28,7 +28,7 @@ uses
   SysUtils,
   SysUtils,
   TypInfo,
   TypInfo,
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
-  UBlockChain, UNode, UBaseTypes,
+  UBlockChain, UNode, UBaseTypes, UPCDataTypes,
   UAccounts,
   UAccounts,
   UEncoding,
   UEncoding,
   UEPasa,
   UEPasa,
@@ -64,6 +64,7 @@ var
   LUnencryptedPayloadBytes, LPwd : TBytes;
   LUnencryptedPayloadBytes, LPwd : TBytes;
   LDone : Boolean;
   LDone : Boolean;
   i : Integer;
   i : Integer;
+  LAccount : TAccount;
 begin
 begin
   LUnencryptedPayloadBytes := Nil;
   LUnencryptedPayloadBytes := Nil;
   AEPasa.Clear;
   AEPasa.Clear;
@@ -88,7 +89,8 @@ begin
       AEPasa.AccountName := '@';
       AEPasa.AccountName := '@';
     end else begin
     end else begin
       if Assigned(ANode) then begin
       if Assigned(ANode) then begin
-        AEPasa.AccountName := ANode.GetMempoolAccount(AAccount).name.ToPrintable;
+        LAccount := ANode.GetMempoolAccount(AAccount);
+        AEPasa.AccountName := LAccount.name.ToPrintable;
       end;
       end;
       if AEPasa.AccountName='' then begin
       if AEPasa.AccountName='' then begin
         ADecodeEPasaResult := der_AccountNameNotFound; // Will continue processing
         ADecodeEPasaResult := der_AccountNameNotFound; // Will continue processing

+ 44 - 22
src/core/UPCRPCSend.pas

@@ -122,6 +122,7 @@ var
  LPayload_method, LEncodePwd, LErrors : String;
  LPayload_method, LEncodePwd, LErrors : String;
  LOpt : TOpTransaction;
  LOpt : TOpTransaction;
  LOpr : TOperationResume;
  LOpr : TOperationResume;
+ LTmpTarget : Cardinal;
 begin
 begin
   // Get Parameters
   // Get Parameters
   Result := False;
   Result := False;
@@ -137,32 +138,53 @@ begin
     exit;
     exit;
   end;
   end;
 
 
-  if Not TPascalCoinJSONComp.CaptureAccountNumber(AInputParams,'sender',ASender.Node,LSender.account,AErrorDesc) then begin
-    AErrorNum := CT_RPC_ErrNum_InvalidAccount;
-    Exit;
-  end else LSender := ASender.Node.GetMempoolAccount(LSender.account);
+  // Do new operation
+  ASender.Node.OperationSequenceLock.Acquire;  // Use lock to prevent N_Operation race-condition on concurrent sends
+  try
 
 
-  LTarget := CT_Account_NUL;
-  if Not TPascalCoinJSONComp.CaptureEPASA(AInputParams,'target',ASender.Node, LTargetEPASA, LTarget.account, LTargetKey, LTargetRequiresPurchase, AErrorDesc) then begin
-    AErrorNum := CT_RPC_ErrNum_InvalidAccount;
-    Exit;
-  end else LTarget := ASender.Node.GetMempoolAccount(LTarget.account);
+    if Not TPascalCoinJSONComp.CaptureAccountNumber(AInputParams,'sender',ASender.Node,LSender.account,AErrorDesc) then begin
+      AErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      Exit;
+    end else LSender := ASender.Node.GetMempoolAccount(LSender.account);
+
+    LTarget := CT_Account_NUL;
+    if Not TPascalCoinJSONComp.CaptureEPASA(AInputParams,'target',ASender.Node, LTargetEPASA, LTarget.account, LTargetKey, LTargetRequiresPurchase, AErrorDesc) then begin
+      AErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      Exit;
+    end else LTarget := ASender.Node.GetMempoolAccount(LTarget.account);
+
+    if (LTargetEPASA.PayloadType.ToProtocolValue=0) and ((LTarget.account=0) or (LTarget.account=LSender.account)) then begin
+      // Try to decode from payload
+      // String payload:
+      if TPascalCoinJSONComp.CaptureEPASA(AInputParams,'payload',ASender.Node, LTargetEPASA, LTmpTarget, LTargetKey, LTargetRequiresPurchase, AErrorDesc) then begin
+        if LTargetRequiresPurchase then begin
+          AInputParams.GetAsVariant('payload').Value := LTargetEPASA.GetRawPayloadBytes.ToHexaString;
+          LTarget := ASender.Node.GetMempoolAccount(LTmpTarget);
+        end;
+      end;
+      if (Not LTargetRequiresPurchase) then begin
+        // HEXASTRING payload:
+        if (TPascalCoinJSONComp.CaptureEPASA(TCrypto.HexaToRaw(AInputParams.AsString('payload','')).ToPrintable, ASender.Node, LTargetEPASA, LTmpTarget, LTargetKey, LTargetRequiresPurchase, AErrorDesc)) then begin
+          if LTargetRequiresPurchase then begin
+            AInputParams.GetAsVariant('payload').Value := LTargetEPASA.GetRawPayloadBytes.ToHexaString;
+            LTarget := ASender.Node.GetMempoolAccount(LTmpTarget);
+          end;
+        end;
+      end;
+    end;
 
 
-  if Not TPascalCoinJSONComp.OverridePayloadParams(AInputParams, LTargetEPASA) then begin
-    AErrorNum := CT_RPC_ErrNum_AmbiguousPayload;
-    AErrorDesc := 'Target EPASA payload conflicts with argument payload.';
-    Exit;
-  end;
+    if Not TPascalCoinJSONComp.OverridePayloadParams(AInputParams, LTargetEPASA) then begin
+      AErrorNum := CT_RPC_ErrNum_AmbiguousPayload;
+      AErrorDesc := 'Target EPASA payload conflicts with argument payload.';
+      Exit;
+    end;
 
 
-  LAmount := TPascalCoinJSONComp.ToPascalCoins(AInputParams.AsDouble('amount',0));
-  LFee := TPascalCoinJSONComp.ToPascalCoins(AInputParams.AsDouble('fee',0));
-  LRawPayload := TCrypto.HexaToRaw(AInputParams.AsString('payload',''));
-  LPayload_method := AInputParams.AsString('payload_method','dest');
-  LEncodePwd := AInputParams.AsString('pwd','');
+    LAmount := TPascalCoinJSONComp.ToPascalCoins(AInputParams.AsDouble('amount',0));
+    LFee := TPascalCoinJSONComp.ToPascalCoins(AInputParams.AsDouble('fee',0));
+    LRawPayload := TCrypto.HexaToRaw(AInputParams.AsString('payload',''));
+    LPayload_method := AInputParams.AsString('payload_method','dest');
+    LEncodePwd := AInputParams.AsString('pwd','');
 
 
-  // Do new operation
-  ASender.Node.OperationSequenceLock.Acquire;  // Use lock to prevent N_Operation race-condition on concurrent sends
-  try
     // Create operation
     // Create operation
     if LTargetRequiresPurchase then begin
     if LTargetRequiresPurchase then begin
       // Buy Account
       // Buy Account

+ 42 - 6
src/core/URPC.pas

@@ -79,7 +79,8 @@ Type
     class function CheckAndGetEncodedRAWPayload(Const ARawPayload : TRawBytes; const APayloadType : TPayloadType; Const APayload_method, AEncodePwdForAES : String; const ASenderAccounKey, ATargetAccountKey : TAccountKey; out AOperationPayload : TOperationPayload; Var AErrorNum : Integer; Var AErrorDesc : String) : Boolean;
     class function CheckAndGetEncodedRAWPayload(Const ARawPayload : TRawBytes; const APayloadType : TPayloadType; Const APayload_method, AEncodePwdForAES : String; const ASenderAccounKey, ATargetAccountKey : TAccountKey; out AOperationPayload : TOperationPayload; Var AErrorNum : Integer; Var AErrorDesc : String) : Boolean;
     class Function CaptureNOperation(const AInputParams : TPCJSONObject; const AParamName : String; const ANode : TNode; out ALastNOp: Cardinal; var AErrorParam : String) : Boolean;
     class Function CaptureNOperation(const AInputParams : TPCJSONObject; const AParamName : String; const ANode : TNode; out ALastNOp: Cardinal; var AErrorParam : String) : Boolean;
     class Function CaptureAccountNumber(const AInputParams : TPCJSONObject; const AParamName : String; const ANode : TNode; out AResolvedAccount: Cardinal; var AErrorParam : String) : Boolean;
     class Function CaptureAccountNumber(const AInputParams : TPCJSONObject; const AParamName : String; const ANode : TNode; out AResolvedAccount: Cardinal; var AErrorParam : String) : Boolean;
-    class Function CaptureEPASA(const AInputParams : TPCJSONObject; const AParamName : String; const ANode : TNode; out AEPasa: TEPasa; out AResolvedAccount: Cardinal; out AResolvedKey : TAccountKey; out ARequiresPurchase : Boolean; var AErrorParam : String) : Boolean;
+    class Function CaptureEPASA(const AInputParams : TPCJSONObject; const AParamName : String; const ANode : TNode; out AEPasa: TEPasa; out AResolvedAccount: Cardinal; out AResolvedKey : TAccountKey; out ARequiresPurchase : Boolean; var AErrorParam : String) : Boolean; overload;
+    class Function CaptureEPASA(const AEPasaText : String; const ANode : TNode; out AEPasa: TEPasa; out AResolvedAccount: Cardinal; out AResolvedKey : TAccountKey; out ARequiresPurchase : Boolean; var AErrorParam : String) : Boolean; overload;
     class Function OverridePayloadParams(const AInputParams : TPCJSONObject; const AEPASA : TEPasa) : Boolean;
     class Function OverridePayloadParams(const AInputParams : TPCJSONObject; const AEPASA : TEPasa) : Boolean;
   end;
   end;
 
 
@@ -105,7 +106,7 @@ Type
     Function GetLogFileName : String;
     Function GetLogFileName : String;
     procedure SetValidIPs(const Value: String);  protected
     procedure SetValidIPs(const Value: String);  protected
     Function IsValidClientIP(Const clientIp : String; clientPort : Word) : Boolean;
     Function IsValidClientIP(Const clientIp : String; clientPort : Word) : Boolean;
-    Procedure AddRPCLog(Const Sender : String; Const Message : String);
+    Procedure AddRPCLog(Const Sender : String; ACallsCounter : Int64; Const Message : String);
     Function GetNewCallCounter : Int64;
     Function GetNewCallCounter : Int64;
   public
   public
     Constructor Create;
     Constructor Create;
@@ -470,6 +471,41 @@ Begin
   end;
   end;
 end;
 end;
 
 
+class function TPascalCoinJSONComp.CaptureEPASA(const AEPasaText: String;
+  const ANode: TNode; out AEPasa: TEPasa; out AResolvedAccount: Cardinal;
+  out AResolvedKey: TAccountKey; out ARequiresPurchase: Boolean;
+  var AErrorParam: String): Boolean;
+Begin
+  AEPasa.Clear;
+  AResolvedAccount := 0;
+  AResolvedKey.Clear;
+  ARequiresPurchase := False;
+  AErrorParam := '';
+  if Length(AEPasaText)>0 then begin
+    if Not TEPasa.TryParse(AEPasaText, AEPasa) then begin
+      AEPasa := TEPasa.Empty;
+      AResolvedAccount := CT_AccountNo_NUL;
+      AResolvedKey := CT_Account_NUL.accountInfo.accountKey;
+      AErrorParam := Format('"%s" is not valid Account EPASA',[AEPasaText]);
+      Exit(False);
+    end;
+    if Assigned(ANode) then begin
+      Result := ANode.TryResolveEPASA(AEPasa, AResolvedAccount, AResolvedKey, ARequiresPurchase, AErrorParam);
+    end else begin
+      // Offline EPASA
+      Result := TryResolveOfflineEPASA(AEPasa, AResolvedAccount, AErrorParam);
+      AResolvedKey := CT_Account_NUL.accountInfo.accountKey;
+      ARequiresPurchase := False;
+    end;
+  end else begin
+    AEPasa := TEPasa.Empty;
+    AResolvedAccount := CT_AccountNo_NUL;
+    AResolvedKey := CT_Account_NUL.accountInfo.accountKey;
+    AErrorParam := Format('EPasa not provided or null',[]);
+    Exit(False);
+  end;
+end;
+
 class function TPascalCoinJSONComp.OverridePayloadParams(const AInputParams : TPCJSONObject; const AEPASA : TEPasa) : Boolean;
 class function TPascalCoinJSONComp.OverridePayloadParams(const AInputParams : TPCJSONObject; const AEPASA : TEPasa) : Boolean;
 var LPayloadmethod_old,LPayloadmethod_new : String;
 var LPayloadmethod_old,LPayloadmethod_new : String;
     LPayload_old, LPayload_new : String;
     LPayload_old, LPayload_new : String;
@@ -813,10 +849,10 @@ end;
 
 
 { TRPCServer }
 { TRPCServer }
 
 
-Procedure TRPCServer.AddRPCLog(Const Sender : String; Const Message : String);
+Procedure TRPCServer.AddRPCLog(Const Sender : String; ACallsCounter : Int64; Const Message : String);
 Begin
 Begin
   If Not Assigned(FRPCLog) then exit;
   If Not Assigned(FRPCLog) then exit;
-  FRPCLog.NotifyNewLog(ltinfo,Sender+' '+Inttostr(FCallsCounter),Message);
+  FRPCLog.NotifyNewLog(ltinfo,Sender+' '+Inttostr(ACallsCounter),Message);
 end;
 end;
 
 
 Function TRPCServer.GetLogFileName : String;
 Function TRPCServer.GetLogFileName : String;
@@ -1014,7 +1050,7 @@ begin
   // IP Protection
   // IP Protection
   If (Not _RPCServer.IsValidClientIP(FSock.GetRemoteSinIP,FSock.GetRemoteSinPort)) then begin
   If (Not _RPCServer.IsValidClientIP(FSock.GetRemoteSinIP,FSock.GetRemoteSinPort)) then begin
     TLog.NewLog(lterror,Classname,FSock.GetRemoteSinIP+':'+inttostr(FSock.GetRemoteSinPort)+' INVALID IP');
     TLog.NewLog(lterror,Classname,FSock.GetRemoteSinIP+':'+inttostr(FSock.GetRemoteSinPort)+' INVALID IP');
-    _RPCServer.AddRPCLog(FSock.GetRemoteSinIP+':'+InttoStr(FSock.GetRemoteSinPort),' INVALID IP');
+    _RPCServer.AddRPCLog(FSock.GetRemoteSinIP+':'+InttoStr(FSock.GetRemoteSinPort),callcounter,' INVALID IP');
     exit;
     exit;
   end;
   end;
   errNum := CT_RPC_ErrNum_InternalError;
   errNum := CT_RPC_ErrNum_InternalError;
@@ -1138,7 +1174,7 @@ begin
           FSock.SendString(jsonresponsetxt);
           FSock.SendString(jsonresponsetxt);
         end;
         end;
       end;
       end;
-      _RPCServer.AddRPCLog(FSock.GetRemoteSinIP+':'+InttoStr(FSock.GetRemoteSinPort),'Method:'+methodName+' Params:'+paramsTxt+' '+Inttostr(errNum)+':'+errDesc+' Time:'+FormatFloat('0.000',(TPlatform.GetElapsedMilliseconds(tc)/1000)));
+      _RPCServer.AddRPCLog(FSock.GetRemoteSinIP+':'+InttoStr(FSock.GetRemoteSinPort),callcounter,'Method:'+methodName+' Params:'+paramsTxt+' '+Inttostr(errNum)+':'+errDesc+' Time:'+FormatFloat('0.000',(TPlatform.GetElapsedMilliseconds(tc)/1000)));
     finally
     finally
       jsonresponse.free;
       jsonresponse.free;
       Headers.Free;
       Headers.Free;

+ 2 - 2
src/gui-classic/UFRMWallet.pas

@@ -482,7 +482,7 @@ begin
     TSettings.FirstTime := false;
     TSettings.FirstTime := false;
     miAboutPascalCoinClick(Nil);
     miAboutPascalCoinClick(Nil);
   end;
   end;
-
+  PageControlChange(Nil);
 end;
 end;
 
 
 procedure TFRMWallet.bbAccountsRefreshClick(Sender: TObject);
 procedure TFRMWallet.bbAccountsRefreshClick(Sender: TObject);
@@ -1379,7 +1379,7 @@ begin
   UpdatePrivateKeys;
   UpdatePrivateKeys;
   UpdateBlockChainState;
   UpdateBlockChainState;
   UpdateConnectionStatus;
   UpdateConnectionStatus;
-  PageControl.ActivePage := tsMyAccounts;
+  PageControl.ActivePage := tsOperations;
   pcAccountsOptions.ActivePage := tsAccountOperations;
   pcAccountsOptions.ActivePage := tsAccountOperations;
   ebFilterOperationsStartBlock.Text := '';
   ebFilterOperationsStartBlock.Text := '';
   ebFilterOperationsEndBlock.Text := '';
   ebFilterOperationsEndBlock.Text := '';

+ 1 - 1
src/gui-classic/UFRMWalletKeys.pas

@@ -556,7 +556,7 @@ begin
     if wk.Name='' then lblKeyName.Caption := '(No name)'
     if wk.Name='' then lblKeyName.Caption := '(No name)'
     else lblKeyName.Caption := wk.Name;
     else lblKeyName.Caption := wk.Name;
     memoPrivateKey.Font.Color := clBlack;
     memoPrivateKey.Font.Color := clBlack;
-    s := TAccountComp.AccountPublicKeyExport(wk.AccountKey);
+    s := '@['+TAccountComp.AccountPublicKeyExport(wk.AccountKey)+']'; // PayToPubkey EPASA format
     memoPrivateKey.Lines.Text:=s;
     memoPrivateKey.Lines.Text:=s;
   finally
   finally
     lblEncryptionTypeCaption.Enabled := ok;
     lblEncryptionTypeCaption.Enabled := ok;

+ 8 - 6
src/gui-classic/UGridUtils.pas

@@ -1070,8 +1070,8 @@ begin
   Finally
   Finally
     for i := 0 to AList.Count-1 do begin
     for i := 0 to AList.Count-1 do begin
       OPR := AList[i];
       OPR := AList[i];
-      if TEPasaDecoder.TryDecodeEPASA(OPR.AffectedAccount,OPR.OriginalPayload,ANode,AWalleTKeys,APasswords,LEPasa) then begin
-        OPR.PrintablePayload := LEPasa.ToString(True);
+      if TEPasaDecoder.TryDecodeEPASA(OPR.DestAccount,OPR.OriginalPayload,ANode,AWalleTKeys,APasswords,LEPasa) then begin
+        OPR.DecodedEPasaPayload := LEPasa.ToString(True);
         AList[i] := OPR;
         AList[i] := OPR;
       end;
       end;
     end;
     end;
@@ -1236,12 +1236,14 @@ begin
           DrawGrid.Canvas.Font.Color := clBlue;
           DrawGrid.Canvas.Font.Color := clBlue;
           DrawGrid.Canvas.Font.Style := [fsBold];
           DrawGrid.Canvas.Font.Style := [fsBold];
           Canvas_TextRect(DrawGrid.Canvas,LRectLeft,saux,State,[tfLeft,tfVerticalCenter,tfSingleLine]);
           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
+          if opr.DecodedEPasaPayload<>'' then begin
+            DrawGrid.Canvas.Font.Style := [fsBold];
+            s := opr.DecodedEPasaPayload
+          end else DrawGrid.Canvas.Font.Style := [];
+        end else if opr.OriginalPayload.payload_raw.ToString=s then begin
           DrawGrid.Canvas.Font.Style := [fsBold];
           DrawGrid.Canvas.Font.Style := [fsBold];
         end;
         end;
+        DrawGrid.Canvas.Font.Color := clBlack;
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine])
         Canvas_TextRect(DrawGrid.Canvas,Rect,s,State,[tfLeft,tfVerticalCenter,tfSingleLine])
       end else begin
       end else begin
         s := '(???)';
         s := '(???)';