Эх сурвалжийг харах

PIP-0033 implementation. Pending "finddataoperations" call

PascalCoin 6 жил өмнө
parent
commit
cb41ff41d8

+ 5 - 1
README.md

@@ -40,6 +40,7 @@ Also, consider a donation at PascalCoin development account: "0-10"
 - Implementation of PIP-0030 (Safebox root) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0030.md
 - Implementation of PIP-0029 (Account Seals) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0029.md
 - Implementation of PIP-0024 (Account Data) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0024.md
+- Implementation of PIP-0033 (OpData JOSN-RPC calls) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0033.md
 - Updated "OP_DATA" operation: (PIP-0016)
   - New digest hash value for OP_DATA ( PIP-0016 ) on Protocol 5
   - Added "id" field (GUID/UUID type as described on PIP-0016), was missing on V4, added on V5
@@ -48,7 +49,7 @@ Also, consider a donation at PascalCoin development account: "0-10"
   - Updated digest hash value adding "new_data" field  
 - Hardcoded RandomHash digest/hash values for quick speed safebox check on fresh installation
 - JSON-RPC changes:  
-  - Updated "listaccountforsale" call to allow ATOMIC SWAPS (PIP-0032)
+  - Updated "listaccountforsale" method to allow ATOMIC SWAPS (PIP-0032)
     - Added "type" to discrimine between kind of listing. Available values are:
       - "public_sale"
       - "private_sale": Need to provide a valid "new_enc_pubkey" or "new_b58_pubkey"
@@ -58,6 +59,8 @@ Also, consider a donation at PascalCoin development account: "0-10"
     - Added "enc_hash_lock" (HEXASTRING) that must be exactly a 32 bytes value (stored as 64 bytes because is HexaString)
   - Updated "changeaccountinfo" and "signchangeaccountinfo" calls to allow add "new_data" field for change Account.Data value (PIP-0024)
     - New param "new_data" (HEXASTRING) if provided will change Account Data info. Limited from 0 to 32 bytes.
+  - New method "senddata" as described on PIP-0033 returning an "Operation Object"
+  - New method "signdata" as described on PIP-0033 returning a "Raw Operations Object"
   - Updated "Account Object" return values:
     - "state": Can return "normal", "listed", "account_swap", "coin_swap"
     - "hashed_secret" : (HEXASTRING) will contain the SHA256( SECRET ) value that must match Payload received data for Atomic Swaps (only when "state" in "account_swap" or "coin_swap")
@@ -82,6 +85,7 @@ TODO
 - TODO: RPC calls for PIP-0029
 - TODO: RPC calls for PIP-0030
 - TODO: RPC calls for PIP-0016
+- TODO: RPC "finddataoperations" call for PIP-0033
 
 ### Build 4.0.3.1 - 2019-04-12
 - Fixed core bug #182 in RPC calls

+ 4 - 3
src/core/UOpTransaction.pas

@@ -350,7 +350,7 @@ Type
     function N_Operation : Cardinal; override;
     procedure AffectedAccounts(list : TList<Cardinal>); override;
     function OperationAmountByAccount(account : Cardinal) : Int64; override;
-    Constructor CreateOpData( ACurrentProtocol : word; account_signer, account_sender, account_target : Cardinal; signer_key:TECPrivateKey; n_operation : Cardinal; dataType, dataSequence : Word; amount, fee : UInt64; payload: TRawBytes);
+    Constructor CreateOpData( ACurrentProtocol : word; account_signer, account_sender, account_target : Cardinal; signer_key:TECPrivateKey; n_operation : Cardinal; dataType, dataSequence : Word; AGUID : TGUID; amount, fee : UInt64; payload: TRawBytes);
     Property Data : TOpDataData read FData;
     Function toString : String; Override;
     Function GetDigestToSign(current_protocol : Word) : TRawBytes; override;
@@ -2768,7 +2768,7 @@ end;
 
 constructor TOpData.CreateOpData(ACurrentProtocol : word; account_signer, account_sender,
   account_target: Cardinal; signer_key: TECPrivateKey; n_operation: Cardinal;
-  dataType, dataSequence: Word; amount, fee: UInt64; payload: TRawBytes);
+  dataType, dataSequence: Word; AGUID : TGUID; amount, fee: UInt64; payload: TRawBytes);
 begin
   Inherited Create(ACurrentProtocol);
   FData.account_sender:=account_sender;
@@ -2780,8 +2780,9 @@ begin
   FData.payload:=payload;
   FData.dataSequence:=dataSequence;
   FData.dataType:=dataType;
+  FData.guid := AGUID;
   if Assigned(signer_key) then begin
-    FData.sign := TCrypto.ECDSASign(signer_key.PrivateKey, GetDigestToSign(CT_PROTOCOL_4));
+    FData.sign := TCrypto.ECDSASign(signer_key.PrivateKey, GetDigestToSign(ACurrentProtocol));
     FHasValidSignature := true;
     FUsedPubkeyForSignature := signer_key.PublicKey;
   end else begin

+ 261 - 0
src/core/UPCRPCOpData.pas

@@ -0,0 +1,261 @@
+unit UPCRPCOpData;
+
+{ Copyright (c) 2019 by Albert Molina
+
+  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:
+  Web: https://www.pascalcoin.org
+  Source: https://github.com/PascalCoin/PascalCoin
+
+  If you like it, consider a donation using Bitcoin:
+  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
+
+  THIS LICENSE HEADER MUST NOT BE REMOVED.
+}
+
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
+interface
+
+{$I config.inc}
+
+Uses classes, SysUtils,
+  UJSONFunctions, UAccounts, UBaseTypes, UOpTransaction, UConst,
+  {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF},
+  URPC, UCrypto, UWallet, UBlockChain;
+
+
+Type
+  TRPCOpData = Class
+  private
+    class Function CreateOpData(ARPCProcess : TRPCProcess; ACurrent_protocol : Word;
+       AInputParams : TPCJSONObject;
+       const AAccountSignerPublicKey : TAccountKey;
+       AAccountSigner, AAccountSender, AAccountTarget, ASender_last_n_operation : Cardinal;
+       Const ARawPayload : TRawBytes;
+       var AErrorNum: Integer; var AErrorDesc: String; var AOpData : TOpData): Boolean;
+  public
+    class function OpData_SendOpData(const ASender : TRPCProcess; const AMethodName : String; AInputParams, AJSONResponse : TPCJSONObject; var AErrorNum : Integer; var AErrorDesc : String) : Boolean;
+    class function OpData_SignOpData(const ASender : TRPCProcess; const AMethodName : String; AInputParams, AJSONResponse : TPCJSONObject; var AErrorNum : Integer; var AErrorDesc : String) : Boolean;
+    class function OpData_FindOpDataOperations(const ASender : TRPCProcess; const AMethodName : String; AInputParams, AJSONResponse : TPCJSONObject; var AErrorNum : Integer; var AErrorDesc : String) : Boolean;
+  End;
+
+implementation
+
+{ TRPCOpData }
+
+class function TRPCOpData.CreateOpData(ARPCProcess: TRPCProcess;
+  ACurrent_protocol: Word;
+  AInputParams : TPCJSONObject;
+  const AAccountSignerPublicKey : TAccountKey;
+  AAccountSigner, AAccountSender, AAccountTarget, ASender_last_n_operation: Cardinal;
+  const ARawPayload: TRawBytes;
+  var AErrorNum: Integer; var AErrorDesc: String; var AOpData : TOpData): Boolean;
+var LSignerKey : TECPrivateKey;
+  LGUID : TGUID;
+  LStringGuid : String;
+begin
+  Result := False;
+  AOpData := Nil;
+  if (Not ARPCProcess.RPCServer.AllowUsePrivateKeys) then begin
+    // Protection when server is locked to avoid private keys call
+    AErrorNum := CT_RPC_ErrNum_NotAllowedCall;
+    Exit;
+  end;
+  If Not ARPCProcess.RPCServer.WalletKeys.IsValidPassword then begin
+    AErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+    AErrorDesc := 'Wallet is password protected. Unlock first';
+    Exit;
+  end;
+  if Not ARPCProcess.RPCServer.CheckAndGetPrivateKeyInWallet(AAccountSignerPublicKey,LSignerKey,AErrorNum,AErrorDesc) then Exit;
+
+  LStringGuid := AInputParams.AsString('guid','');
+  if LStringGuid<>'' then begin
+    try
+      LGUID := StringToGUID(LStringGuid);
+    except
+      On E:Exception do begin
+        AErrorNum := CT_RPC_ErrNum_InvalidData;
+        AErrordesc := 'Invalid "guid" value '+E.Message;
+        Exit;
+      end;
+    end;
+  end else LGUID := CT_TOpDataData_NUL.guid;
+
+  AOpData := TOpData.CreateOpData(ACurrent_protocol,
+    AAccountSigner,
+    AAccountSender,
+    AAccountTarget,
+    LSignerKey,
+    ASender_last_n_operation+1,
+    AInputParams.AsInteger('data_type',0),
+    AInputParams.AsInteger('data_sequence',0),
+    LGUID,
+    TPascalCoinJSONComp.ToPascalCoins(AInputParams.AsDouble('amount',0)),
+    TPascalCoinJSONComp.ToPascalCoins(AInputParams.AsDouble('fee',0)),
+    ARawPayload);
+  Result := True;
+end;
+
+class function TRPCOpData.OpData_FindOpDataOperations(
+  const ASender: TRPCProcess; const AMethodName: String; AInputParams,
+  AJSONResponse: TPCJSONObject; var AErrorNum: Integer;
+  var AErrorDesc: String): Boolean;
+begin
+  // TODO TODO TODO TODO
+  // TODO TODO TODO TODO
+  // TODO TODO TODO TODO
+  // TODO TODO TODO TODO
+  // TODO TODO TODO TODO
+  AErrorNum := CT_RPC_ErrNum_NotImplemented;
+  AErrorDesc := 'This method is not implemented. PENDING TODO';
+  Result := False;
+end;
+
+class function TRPCOpData.OpData_SendOpData(const ASender: TRPCProcess;
+  const AMethodName: String; AInputParams, AJSONResponse: TPCJSONObject;
+  var AErrorNum: Integer; var AErrorDesc: String): Boolean;
+var LOpData : TOpData;
+  LSigner, LSender, LTarget : TAccount;
+  LEncodedRawPayload : TRawBytes;
+  LErrors : String;
+  LOPR : TOperationResume;
+begin
+  Result := False;
+  if Not ASender.RPCServer.GetMempoolAccount(AInputParams.AsInteger('sender',CT_MaxAccount),LSender) then begin
+    AErrorNum := CT_RPC_ErrNum_InvalidAccount;
+    AErrorDesc := 'Invalid "sender"';
+    Exit;
+  end;
+  if (AInputParams.IndexOfName('signer')>=0) then begin
+    if Not ASender.RPCServer.GetMempoolAccount(AInputParams.AsInteger('signer',CT_MaxAccount),LSigner) then begin
+      AErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      AErrorDesc := 'Invalid "signer"';
+      Exit;
+    end;
+  end else LSigner := LSender; // If no "signer" param, then use "sender" as signer by default
+  if Not ASender.RPCServer.GetMempoolAccount(AInputParams.AsInteger('target',CT_MaxAccount),LTarget) then begin
+    AErrorNum := CT_RPC_ErrNum_InvalidAccount;
+    AErrorDesc := 'Invalid "target"';
+    Exit;
+  end;
+
+  if not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(
+    TCrypto.HexaToRaw(AInputParams.AsString('payload','')),
+    AInputParams.AsString('payload_method','none'),
+    AInputParams.AsString('pwd',''),
+    LSender.accountInfo.accountKey,
+    LTarget.accountInfo.accountKey,
+    LEncodedRawPayload,AErrorNum,AErrorDesc) Then Exit;
+
+
+  if Not CreateOpData(ASender,
+    ASender.Node.Bank.SafeBox.CurrentProtocol,
+    AInputParams,
+    LSigner.accountInfo.accountKey,
+    LSigner.account,
+    LSender.account,
+    LTarget.account,
+    LSigner.n_operation,
+    LEncodedRawPayload,
+    AErrorNum, AErrorDesc, LOpData) then Exit;
+
+  if LOpData=nil then Exit;
+  try
+    If not ASender.Node.AddOperation(Nil,LOpData,LErrors) then begin
+      AErrorDesc := 'Error adding operation: '+LErrors;
+      AErrorNum := CT_RPC_ErrNum_InvalidOperation;
+      Exit;
+    end;
+    TPCOperation.OperationToOperationResume(0,LOpData,False,LSender.account,LOPR);
+    TPascalCoinJSONComp.FillOperationObject(LOPR,ASender.Node.Bank.BlocksCount,AJSONResponse.GetAsObject('result'));
+    Result := True;
+  finally
+    LOpData.free;
+  end;
+end;
+
+class function TRPCOpData.OpData_SignOpData(const ASender: TRPCProcess;
+  const AMethodName: String; AInputParams, AJSONResponse: TPCJSONObject;
+  var AErrorNum: Integer; var AErrorDesc: String): Boolean;
+var LOpData : TOpData;
+  LEncodedRawPayload : TRawBytes;
+  LErrors : String;
+  LOPR : TOperationResume;
+  LEncodePayloadType : String;
+  LPayloadPubkey, LSignerPubkey : TAccountKey;
+  LOperationsHashTree : TOperationsHashTree;
+  LSigner : Cardinal;
+begin
+  Result := False;
+
+  if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(AInputParams.AsString('rawoperations',''),LOperationsHashTree,LErrors) then begin
+    AErrorNum:=CT_RPC_ErrNum_InvalidData;
+    AErrorDesc:= 'Error decoding param "rawoperations": '+LErrors;
+    Exit;
+  end;
+  try
+
+    LEncodePayloadType := AInputParams.AsString('payload_method','none');
+    if (LEncodePayloadType='sender') then begin
+      if Not TPascalCoinJSONComp.CapturePubKey(AInputParams,'sender_',LPayloadPubkey,AErrorDesc) then begin
+        AErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+        Exit;
+      end;
+    end else if (LEncodePayloadType='dest') then begin
+      if Not TPascalCoinJSONComp.CapturePubKey(AInputParams,'target_',LPayloadPubkey,AErrorDesc) then begin
+        AErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+        Exit;
+      end;
+    end;
+
+    if Not TPascalCoinJSONComp.CapturePubKey(AInputParams,'signer_',LSignerPubkey,AErrorDesc) then begin
+      AErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+      Exit;
+    end;
+
+    if not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(
+      TCrypto.HexaToRaw(AInputParams.AsString('payload','')),
+      AInputParams.AsString('payload_method','dest'),
+      AInputParams.AsString('pwd',''),
+      LPayloadPubkey,
+      LPayloadPubkey,
+      LEncodedRawPayload,AErrorNum,AErrorDesc) then Exit;
+
+    if Not CreateOpData(ASender,
+      AInputParams.AsInteger('protocol',CT_BUILD_PROTOCOL),
+      AInputParams,
+      LSignerPubkey,
+      AInputParams.AsCardinal('signer',CT_MaxAccount),
+      AInputParams.AsCardinal('sender',CT_MaxAccount),
+      AInputParams.AsCardinal('target',CT_MaxAccount),
+      AInputParams.AsCardinal('last_n_operation',0),
+      LEncodedRawPayload,
+      AErrorNum, AErrorDesc, LOpData) then Exit;
+    if LOpData=nil then Exit;
+    try
+      LOperationsHashTree.AddOperationToHashTree(LOpData);
+      TPascalCoinJSONComp.FillOperationsHashTreeObject(LOperationsHashTree,AJSONResponse.GetAsObject('result'));
+      Result := true;
+    finally
+      LOpData.Free;
+    end;
+  finally
+    LOperationsHashTree.Free;
+  end;
+end;
+
+initialization
+  TRPCProcess.RegisterProcessMethod('senddata',TRPCOpData.OpData_SendOpData);
+  TRPCProcess.RegisterProcessMethod('signdata',TRPCOpData.OpData_SignOpData);
+  TRPCProcess.RegisterProcessMethod('finddataoperations',TRPCOpData.OpData_FindOpDataOperations);
+finalization
+  TRPCProcess.UnregisterProcessMethod('senddata');
+  TRPCProcess.UnregisterProcessMethod('signdata');
+  TRPCProcess.UnregisterProcessMethod('finddataoperations');
+end.

+ 264 - 143
src/core/URPC.pas

@@ -67,6 +67,11 @@ Type
     class procedure FillOperationsHashTreeObject(Const OperationsHashTree : TOperationsHashTree; jsonObject : TPCJSONObject);
     class procedure FillMultiOperationObject(current_protocol : Word; Const multiOperation : TOpMultiOperation; jsonObject : TPCJSONObject);
     class procedure FillPublicKeyObject(const PubKey : TAccountKey; jsonObj : TPCJSONObject);
+    class function ToPascalCoins(jsonCurr : Real) : Int64;
+    //
+    class Function HexaStringToOperationsHashTree(Const AHexaStringOperationsHashTree : String; out AOperationsHashTree : TOperationsHashTree; var AErrors : String) : Boolean;
+    class Function CapturePubKey(const AInputParams : TPCJSONObject; const APrefix : String; var APubKey : TAccountKey; var AErrortxt : String) : Boolean;
+    class function CheckAndGetEncodedRAWPayload(Const ARawPayload : TRawBytes; Const APayload_method, AEncodePwdForAES : String; const ASenderAccounKey, ATargetAccountKey : TAccountKey; var AEncodedRAWPayload : TRawBytes; Var AErrorNum : Integer; Var AErrorDesc : String) : Boolean;
   end;
 
   TRPCServerThread = Class;
@@ -83,6 +88,7 @@ Type
     FCallsCounter : Int64;
     FValidIPs: String;
     FAllowUsePrivateKeys: Boolean;
+    FNode : TNode;
     procedure SetActive(AValue: Boolean);
     procedure SetIniFileName(const Value: String);
     procedure SetLogFileName(const Value: String);
@@ -103,41 +109,64 @@ Type
     Property LogFileName : String read GetLogFileName write SetLogFileName;
     Property ValidIPs : String read FValidIPs write SetValidIPs;
     Property AllowUsePrivateKeys : Boolean read FAllowUsePrivateKeys write FAllowUsePrivateKeys; // New v4 protection for free access server
+    Property Node : TNode read FNode;
+    //
+    Function CheckAndGetPrivateKeyInWallet(const APublicKey : TAccountKey; var APrivateKey : TECPrivateKey; Var AErrorNum : Integer; Var AErrorDesc : String) : Boolean;
+    Function GetMempoolAccount(AAccountNumber : Cardinal; var AAccount : TAccount) : Boolean;
   end;
 
   { TRPCServerThread }
 
   TRPCServerThread = Class(TPCThread)
+    FRPCServer : TRPCServer;
     FServerSocket:TTCPBlockSocket;
     FPort : Word;
   protected
     procedure BCExecute; override;
   public
-    Constructor Create(Port : Word);
+    Constructor Create(ARPCServer : TRPCServer; APort : Word);
     Destructor Destroy; Override;
   End;
 
   { TRPCProcess }
 
+  TRPCProcess = class;
+  TRPCProcessMethod = function(const ASender : TRPCProcess; const AMethodName : String; AInputParams, AJSONResponse : TPCJSONObject; var AErrorNum : Integer; var AErrorDesc : String) : Boolean of object;
+
   TRPCProcess = class(TPCThread)
   private
     FSock:TTCPBlockSocket;
     FNode : TNode;
+    FRPCServer : TRPCServer;
   public
-    Constructor Create (hsock:tSocket);
+    Constructor Create (ARPCServer : TRPCServer; AHSock:tSocket);
     Destructor Destroy; override;
     procedure BCExecute; override;
     function ProcessMethod(Const method : String; params : TPCJSONObject; jsonresponse : TPCJSONObject; Var ErrorNum : Integer; Var ErrorDesc : String) : Boolean;
+    property Node : TNode read FNode;
+    property RPCServer : TRPCServer read FRPCServer;
+    class procedure RegisterProcessMethod(Const AMethodName : String; ARPCProcessMethod : TRPCProcessMethod);
+    class procedure UnregisterProcessMethod(Const AMethodName : String);
+    class function FindRegisteredProcessMethod(Const AMethodName : String) : TRPCProcessMethod;
   end;
 
 
 implementation
 
 Uses  {$IFNDEF FPC}windows,{$ENDIF}
-  SysUtils, Synautil;
+  SysUtils, Synautil,
+  UPCRPCOpData;
+
+Type
+  TRegisteredRPCProcessMethod = Record
+    MethodName : String;
+    RPCProcessMethod : TRPCProcessMethod;
+  end;
 
 var _RPCServer : TRPCServer = Nil;
 
+  _RPCProcessMethods : TList<TRegisteredRPCProcessMethod> = Nil;
+
 { TPascalCoinJSONComp }
 
 class procedure TPascalCoinJSONComp.FillBlockObject(nBlock : Cardinal; ANode : TNode; jsonObject: TPCJSONObject);
@@ -313,6 +342,70 @@ Begin
   end;
 end;
 
+class function TPascalCoinJSONComp.CapturePubKey(
+  const AInputParams: TPCJSONObject; const APrefix: String;
+  var APubKey: TAccountKey; var AErrortxt: String): Boolean;
+var LErrors_aux : String;
+  LAuxpubkey : TAccountKey;
+begin
+  APubKey := CT_Account_NUL.accountInfo.accountKey;
+  AErrortxt := '';
+  Result := false;
+  //
+  if (AInputParams.IndexOfName(APrefix+'b58_pubkey')>=0) then begin
+    If Not TAccountComp.AccountPublicKeyImport(AInputParams.AsString(APrefix+'b58_pubkey',''),APubKey,Lerrors_aux) then begin
+      AErrortxt:= 'Invalid value of param "'+APrefix+'b58_pubkey": '+Lerrors_aux;
+      Exit;
+    end;
+    if (AInputParams.IndexOfName(APrefix+'enc_pubkey')>=0) then begin
+      LAuxpubkey := TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(AInputParams.AsString(APrefix+'enc_pubkey','')));
+      if (Not TAccountComp.EqualAccountKeys(LAuxpubkey,APubKey)) then begin
+        AErrortxt := 'Params "'+APrefix+'b58_pubkey" and "'+APrefix+'enc_pubkey" public keys are not the same public key';
+        exit;
+      end;
+    end;
+  end else begin
+    if (AInputParams.IndexOfName(APrefix+'enc_pubkey')<0) then begin
+      AErrortxt := 'Need param "'+APrefix+'enc_pubkey" or "'+APrefix+'b58_pubkey"';
+      exit;
+    end;
+    APubKey := TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(AInputParams.AsString(APrefix+'enc_pubkey','')));
+  end;
+  // Final confirmation
+  If Not TAccountComp.IsValidAccountKey(APubKey,LErrors_aux) then begin
+    AErrortxt := 'Invalid public key: '+LErrors_aux;
+  end else Result := True;
+end;
+
+class function TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(
+  const ARawPayload: TRawBytes; const APayload_method, AEncodePwdForAES: String;
+  const ASenderAccounKey, ATargetAccountKey: TAccountKey;
+  var AEncodedRAWPayload: TRawBytes; var AErrorNum: Integer;
+  var AErrorDesc: String): Boolean;
+begin
+  if (Length(ARawPayload)>0) then begin
+    if (APayload_method='none') then begin
+      AEncodedRAWPayload:=ARawPayload;
+      Result := True;
+    end else if (APayload_method='dest') then begin
+      Result := TPCEncryption.DoPascalCoinECIESEncrypt(ATargetAccountKey,ARawPayload,AEncodedRAWPayload);
+    end else if (APayload_method='sender') then begin
+      Result := TPCEncryption.DoPascalCoinECIESEncrypt(ASenderAccounKey,ARawPayload,AEncodedRAWPayload);
+    end else if (APayload_method='aes') then begin
+      AEncodedRAWPayload := TPCEncryption.DoPascalCoinAESEncrypt(ARawPayload,TEncoding.ANSI.GetBytes(AEncodePwdForAES));
+      Result := True;
+    end else begin
+      Result := False;
+      AErrorNum:=CT_RPC_ErrNum_InvalidOperation;
+      AErrorDesc:='Invalid encode payload method: '+APayload_method;
+      Exit;
+    end;
+  end else begin
+    AEncodedRAWPayload := Nil;
+    Result := True;
+  end;
+end;
+
 class procedure TPascalCoinJSONComp.FillAccountObject(const account: TAccount; jsonObj: TPCJSONObject);
 Begin
   jsonObj.GetAsVariant('account').Value:=account.account;
@@ -448,6 +541,35 @@ begin
   jsonObj.GetAsVariant('b58_pubkey').Value := TAccountComp.AccountPublicKeyExport(PubKey);
 end;
 
+class function TPascalCoinJSONComp.HexaStringToOperationsHashTree(
+  const AHexaStringOperationsHashTree: String;
+  out AOperationsHashTree: TOperationsHashTree; var AErrors: String): Boolean;
+var Lraw : TRawBytes;
+  ms : TMemoryStream;
+Begin
+  Result := False;
+  Lraw := TCrypto.HexaToRaw(AHexaStringOperationsHashTree);
+  if (AHexaStringOperationsHashTree<>'') And (Length(Lraw)=0) then begin
+    AErrors := 'Invalid HexaString as operations';
+    exit;
+  end;
+  ms := TMemoryStream.Create;
+  Try
+    ms.WriteBuffer(Lraw[Low(Lraw)],Length(Lraw));
+    ms.Position := 0;
+    AOperationsHashTree := TOperationsHashTree.Create;
+    if (Length(Lraw)>0) then begin
+      If not AOperationsHashTree.LoadOperationsHashTreeFromStream(ms,False,CT_PROTOCOL_1,Nil,AErrors) then begin
+        FreeAndNil(AOperationsHashTree);
+        Exit;
+      end;
+    end;
+    Result := true;
+  Finally
+    ms.Free;
+  End;
+end;
+
 class function TPascalCoinJSONComp.OperationsHashTreeToHexaString(const OperationsHashTree: TOperationsHashTree): String;
 var ms : TMemoryStream;
   raw : TRawBytes;
@@ -464,6 +586,11 @@ Begin
   End;
 end;
 
+class function TPascalCoinJSONComp.ToPascalCoins(jsonCurr: Real): Int64;
+begin
+  Result := Round(jsonCurr * 10000);
+end;
+
 { TRPCServer }
 
 Procedure TRPCServer.AddRPCLog(Const Sender : String; Const Message : String);
@@ -479,6 +606,17 @@ Begin
   else Result := '';
 end;
 
+function TRPCServer.GetMempoolAccount(AAccountNumber: Cardinal; var AAccount: TAccount): Boolean;
+begin
+  if (AAccountNumber<0) Or (AAccountNumber>=Node.Bank.AccountsCount) then begin
+    AAccount := CT_Account_NUL;
+    Result := False;
+  end else begin
+    AAccount := Node.GetMempoolAccount(AAccountNumber);
+    Result := True;
+  end;
+end;
+
 function TRPCServer.GetNewCallCounter: Int64;
 begin
   inc(FCallsCounter);
@@ -490,7 +628,7 @@ begin
   if FActive=AValue then Exit;
   FActive:=AValue;
   if (FActive) then begin
-    FRPCServerThread := TRPCServerThread.Create(FPort);
+    FRPCServerThread := TRPCServerThread.Create(Self,FPort);
   end else begin
     FRPCServerThread.Terminate;
     FRPCServerThread.WaitFor;
@@ -543,6 +681,30 @@ begin
   end;
 end;
 
+function TRPCServer.CheckAndGetPrivateKeyInWallet(const APublicKey : TAccountKey; var APrivateKey : TECPrivateKey; Var AErrorNum : Integer; Var AErrorDesc : String) : Boolean;
+var i : Integer;
+begin
+  Result := False;
+  APrivateKey := Nil;
+  i := FWalletKeys.IndexOfAccountKey(APublicKey);
+  if i<0 then begin
+    AErrorDesc := 'Sender Public Key not found in wallet: '+TAccountComp.AccountPublicKeyExport(APublicKey);
+    AErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+    Exit;
+  end;
+  APrivateKey := FWalletKeys.Key[i].PrivateKey;
+  if (Not assigned(APrivateKey)) then begin
+    if Length(FWalletKeys.Key[i].CryptedKey)>0 then begin
+      // Wallet is password protected
+      AErrorDesc := 'Wallet is password protected';
+      AErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+    end else begin
+      AErrorDesc := 'Wallet private key not found in Wallet';
+      AErrorNum := CT_RPC_ErrNum_InvalidPubKey;
+    end;
+  end else Result := True;
+end;
+
 constructor TRPCServer.Create;
 begin
   FActive := false;
@@ -556,6 +718,7 @@ begin
   FCallsCounter := 0;
   FValidIPs := '127.0.0.1;localhost'; // New Build 1.5 - By default, only localhost can access to RPC
   FAllowUsePrivateKeys := True;       // New Build 3.0.2 - By default RPC allows to use private keys functions
+  FNode := TNode.Node;
   If Not assigned(_RPCServer) then _RPCServer := Self;
 end;
 
@@ -569,15 +732,17 @@ end;
 
 { TRPCProcess }
 
-constructor TRPCProcess.Create(hsock: tSocket);
+constructor TRPCProcess.Create(ARPCServer : TRPCServer; AHSock:tSocket);
 begin
+  FRPCServer := ARPCServer;
   FSock:=TTCPBlockSocket.create;
-  FSock.socket:=HSock;
+  FSock.socket:=AHSock;
   FreeOnTerminate:=true;
   FNode := TNode.Node;
   //Priority:=tpNormal;
-  inherited create(false);
+  inherited create(True);
   FreeOnTerminate:=true;
+  Suspended := False;
 end;
 
 destructor TRPCProcess.Destroy;
@@ -586,6 +751,20 @@ begin
   inherited Destroy;
 end;
 
+class function TRPCProcess.FindRegisteredProcessMethod(const AMethodName: String): TRPCProcessMethod;
+var i : Integer;
+begin
+  Result := Nil;
+  if Not Assigned(_RPCProcessMethods) then Exit;
+  i := 0;
+  while (i<_RPCProcessMethods.Count) and (Not Assigned(Result)) do begin
+    if AnsiSameStr( _RPCProcessMethods.Items[i].MethodName , AMethodName) then begin
+      Result := _RPCProcessMethods.Items[i].RPCProcessMethod;
+    end;
+    inc(i);
+  end;
+end;
+
 procedure TRPCProcess.BCExecute;
 var
   timeout: integer;
@@ -774,34 +953,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
 
   Function ToPascalCoins(jsonCurr : Real) : Int64;
   Begin
-    Result := Round(jsonCurr * 10000);
-  End;
-
-  Function HexaStringToOperationsHashTree(Const HexaStringOperationsHashTree : String; out OperationsHashTree : TOperationsHashTree; var errors : String) : Boolean;
-  var raw : TRawBytes;
-    ms : TMemoryStream;
-  Begin
-    Result := False;
-    raw := TCrypto.HexaToRaw(HexaStringOperationsHashTree);
-    if (HexaStringOperationsHashTree<>'') And (Length(raw)=0) then begin
-      errors := 'Invalid HexaString as operations';
-      exit;
-    end;
-    ms := TMemoryStream.Create;
-    Try
-      ms.WriteBuffer(raw[Low(raw)],Length(raw));
-      ms.Position := 0;
-      OperationsHashTree := TOperationsHashTree.Create;
-      if (Length(raw)>0) then begin
-        If not OperationsHashTree.LoadOperationsHashTreeFromStream(ms,false,CT_PROTOCOL_1,Nil,errors) then begin
-          FreeAndNil(OperationsHashTree);
-          exit;
-        end;
-      end;
-      Result := true;
-    Finally
-      ms.Free;
-    End;
+    Result := TPascalCoinJSONComp.ToPascalCoins(jsonCurr);
   End;
 
   Function HexaStringToOperationsHashTreeAndGetMultioperation(AProtocolVersion : Word; Const HexaStringOperationsHashTree : String; canCreateNewOne : Boolean; out OperationsHashTree : TOperationsHashTree; out multiOperation : TOpMultiOperation; var errors : String) : Boolean;
@@ -811,7 +963,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
   var op : TPCOperation;
   Begin
     multiOperation := Nil;
-    Result := HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors);
+    Result := TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors);
     If (Result) then begin
       Try
         If (OperationsHashTree.OperationsCount=0) And (canCreateNewOne) then begin
@@ -976,51 +1128,6 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     end;
   end;
 
-  Function CheckAndGetPrivateKeyInWallet(const publicKey : TAccountKey; var privateKey : TECPrivateKey) : Boolean;
-  Var i : Integer;
-    f_raw : TRawBytes;
-  Begin
-    Result := False;
-    privateKey := Nil;
-    i := _RPCServer.FWalletKeys.IndexOfAccountKey(publicKey);
-    if i<0 then begin
-      ErrorDesc:='Sender Public Key not found in wallet: '+TAccountComp.AccountPublicKeyExport(publicKey);
-      ErrorNum:=CT_RPC_ErrNum_InvalidPubKey;
-      Exit;
-    end;
-    privateKey := _RPCServer.FWalletKeys.Key[i].PrivateKey;
-    if (Not assigned(privateKey)) then begin
-      if Length(_RPCServer.FWalletKeys.Key[i].CryptedKey)>0 then begin
-        // Wallet is password protected
-        ErrorDesc := 'Wallet is password protected';
-        ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
-      end else begin
-        ErrorDesc := 'Wallet private key not found in Wallet';
-        ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
-      end;
-    end else Result := True;
-  End;
-
-  Function CheckAndGetEncodedRAWPayload(Const RawPayload : TRawBytes; Const Payload_method, EncodePwdForAES : String; const senderAccounKey, targetAccountKey : TAccountKey; var EncodedRAWPayload : TRawBytes) : Boolean;
-  begin
-    Result := False;
-    if (length(RawPayload)>0) then begin
-      if (Payload_method='none') then EncodedRAWPayload:=RawPayload
-      else if (Payload_method='dest') then begin
-        TPCEncryption.DoPascalCoinECIESEncrypt(targetAccountKey,RawPayload,EncodedRAWPayload);
-      end else if (Payload_method='sender') then begin
-        TPCEncryption.DoPascalCoinECIESEncrypt(senderAccounKey,RawPayload,EncodedRAWPayload);
-      end else if (Payload_method='aes') then begin
-        EncodedRAWPayload := TPCEncryption.DoPascalCoinAESEncrypt(RawPayload,TEncoding.ANSI.GetBytes(EncodePwdForAES));
-      end else begin
-        ErrorNum:=CT_RPC_ErrNum_InvalidOperation;
-        ErrorDesc:='Invalid encode payload method: '+Payload_method;
-        exit;
-      end;
-    end else EncodedRAWPayload := Nil;
-    Result := True;
-  end;
-
   // This function creates a TOpTransaction without looking for balance/private key of sender account
   // It assumes that sender,target,sender_last_n_operation,senderAccountKey and targetAccountKey are correct
   Function CreateOperationTransaction(current_protocol : Word; sender, target, sender_last_n_operation : Cardinal; amount, fee : UInt64;
@@ -1031,8 +1138,8 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     privateKey : TECPrivateKey;
   Begin
     Result := Nil;
-    if Not CheckAndGetPrivateKeyInWallet(senderAccounKey,privateKey) then Exit(Nil);
-    if Not CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,senderAccounKey,targetAccountKey,f_raw) then Exit(Nil);
+    if Not RPCServer.CheckAndGetPrivateKeyInWallet(senderAccounKey,privateKey,ErrorNum,ErrorDesc) then Exit(Nil);
+    if Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,senderAccounKey,targetAccountKey,f_raw,ErrorNum,ErrorDesc) then Exit(Nil);
     Result := TOpTransaction.CreateTransaction(current_protocol, sender,sender_last_n_operation+1,target,privateKey,amount,fee,f_raw);
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
@@ -1097,7 +1204,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     opt : TOpTransaction;
   begin
     Result := false;
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param "rawoperations": '+errors;
       Exit;
@@ -1127,8 +1234,8 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     privateKey : TECPrivateKey;
   Begin
     Result := Nil;
-    if Not CheckAndGetPrivateKeyInWallet(account_pubkey,privateKey) then Exit(Nil);
-    if Not CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_pubkey,new_pubkey,f_raw) then Exit(Nil);
+    if Not RPCServer.CheckAndGetPrivateKeyInWallet(account_pubkey,privateKey,ErrorNum,ErrorDesc) then Exit(Nil);
+    if Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_pubkey,new_pubkey,f_raw,ErrorNum,ErrorDesc) then Exit(Nil);
     If account_signer=account_target then begin
       Result := TOpChangeKey.Create(current_protocol,account_signer,account_last_n_operation+1,account_target,privateKey,new_pubkey,fee,f_raw);
     end else begin
@@ -1190,12 +1297,12 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     aux_target_pubkey : TAccountKey;
   Begin
     Result := Nil;
-    if Not CheckAndGetPrivateKeyInWallet(account_signer_pubkey,privateKey) then Exit(Nil);
+    if Not RPCServer.CheckAndGetPrivateKeyInWallet(account_signer_pubkey,privateKey,ErrorNum,ErrorDesc) then Exit(Nil);
     if (Payload_method='dest') And (new_account_pubkey.EC_OpenSSL_NID<>CT_TECDSA_Public_Nul.EC_OpenSSL_NID) then begin
         // If using 'dest', only will apply if there is a fixed new public key, otherwise will use current public key of account
        aux_target_pubkey := new_account_pubkey;
     end else aux_target_pubkey := account_signer_pubkey;
-    if Not CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,aux_target_pubkey,f_raw) then Exit(Nil);
+    if Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,aux_target_pubkey,f_raw,ErrorNum,ErrorDesc) then Exit(Nil);
     Result := TOpListAccountForSaleOrSwap.CreateListAccountForSaleOrSwap(
       current_protocol,
       ANewAccountState,
@@ -1228,8 +1335,8 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     f_raw : TRawBytes;
   Begin
     Result := Nil;
-    if Not CheckAndGetPrivateKeyInWallet(account_signer_pubkey,privateKey) then Exit(Nil);
-    if Not CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,account_signer_pubkey,f_raw) then Exit(Nil);
+    if Not RPCServer.CheckAndGetPrivateKeyInWallet(account_signer_pubkey,privateKey,ErrorNum,ErrorDesc) then Exit(Nil);
+    if Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,account_signer_pubkey,f_raw,ErrorNum,ErrorDesc) then Exit(Nil);
     Result := TOpDelistAccountForSale.CreateDelistAccountForSale(current_protocol,account_signer,account_last_n_operation+1,account_delisted,fee,privateKey,f_raw);
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
@@ -1251,8 +1358,8 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     f_raw : TRawBytes;
   Begin
     Result := Nil;
-    if Not CheckAndGetPrivateKeyInWallet(account_pubkey,privateKey) then Exit(Nil);
-    if Not CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_pubkey,new_account_pubkey,f_raw) then Exit(Nil);
+    if Not RPCServer.CheckAndGetPrivateKeyInWallet(account_pubkey,privateKey,ErrorNum,ErrorDesc) then Exit(Nil);
+    if Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_pubkey,new_account_pubkey,f_raw,ErrorNum,ErrorDesc) then Exit(Nil);
     Result := TOpBuyAccount.CreateBuy(current_protocol,account_number,account_last_n_operation+1,account_to_buy,account_to_pay,account_price,amount,fee,new_account_pubkey,privateKey,f_raw);
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
@@ -1384,7 +1491,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     opck : TOpChangeKey;
   begin
     Result := false;
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param "rawoperations": '+errors;
       Exit;
@@ -1412,7 +1519,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     Op : TPCOperation;
     i : Integer;
   Begin
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param "rawoperations": '+errors;
       Exit;
@@ -1440,7 +1547,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     i : Integer;
     OperationsResumeList : TOperationsResumeList;
   Begin
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param "rawoperations": '+errors;
       Exit;
@@ -1533,40 +1640,9 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     Result := true;
   End;
 
-  Function CapturePubKeyExt(const jsonObjParams : TPCJSONObject; const prefix : String; var pubkey : TAccountKey; var errortxt : String) : Boolean;
-  var errors_aux : String;
-    auxpubkey : TAccountKey;
-  begin
-    pubkey := CT_Account_NUL.accountInfo.accountKey;
-    errortxt := '';
-    Result := false;
-    if (jsonObjparams.IndexOfName(prefix+'b58_pubkey')>=0) then begin
-      If Not TAccountComp.AccountPublicKeyImport(jsonObjparams.AsString(prefix+'b58_pubkey',''),pubkey,errors_aux) then begin
-        errortxt:= 'Invalid value of param "'+prefix+'b58_pubkey": '+errors_aux;
-        exit;
-      end;
-      if (jsonObjparams.IndexOfName(prefix+'enc_pubkey')>=0) then begin
-        auxpubkey := TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(jsonObjparams.AsString(prefix+'enc_pubkey','')));
-        if (Not TAccountComp.EqualAccountKeys(auxpubkey,pubkey)) then begin
-          errortxt := 'Params "'+prefix+'b58_pubkey" and "'+prefix+'enc_pubkey" public keys are not the same public key';
-          exit;
-        end;
-      end;
-    end else begin
-      if (jsonObjparams.IndexOfName(prefix+'enc_pubkey')<0) then begin
-        errortxt := 'Need param "'+prefix+'enc_pubkey" or "'+prefix+'b58_pubkey"';
-        exit;
-      end;
-      pubkey := TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(jsonObjparams.AsString(prefix+'enc_pubkey','')));
-    end;
-    If Not TAccountComp.IsValidAccountKey(pubkey,errors_aux) then begin
-      errortxt := 'Invalid public key: '+errors_aux;
-    end else Result := true;
-  end;
-
   Function CapturePubKey(const prefix : String; var pubkey : TAccountKey; var errortxt : String) : Boolean;
   begin
-    Result := CapturePubKeyExt(params,prefix,pubkey,errortxt);
+    Result := TPascalCoinJSONComp.CapturePubKey(params,prefix,pubkey,errortxt);
   end;
 
   function SignListAccountForSaleEx(params : TPCJSONObject; OperationsHashTree : TOperationsHashTree; current_protocol : Word; const actualAccounKey : TAccountKey; last_n_operation : Cardinal) : boolean;
@@ -1712,7 +1788,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     current_protocol : Word;
   begin
     Result := false;
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param previous operations hash tree raw value: '+errors;
       Exit;
@@ -1791,12 +1867,12 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     aux_target_pubkey : TAccountKey;
   Begin
     Result := Nil;
-    if Not CheckAndGetPrivateKeyInWallet(account_signer_pubkey,privateKey) then Exit(Nil);
+    if Not RPCServer.CheckAndGetPrivateKeyInWallet(account_signer_pubkey,privateKey,ErrorNum,ErrorDesc) then Exit(Nil);
     if (Payload_method='dest') And (new_account_pubkey.EC_OpenSSL_NID<>CT_TECDSA_Public_Nul.EC_OpenSSL_NID) then begin
         // If using 'dest', only will apply if there is a fixed new public key, otherwise will use current public key of account
        aux_target_pubkey := new_account_pubkey;
     end else aux_target_pubkey := account_signer_pubkey;
-    if Not CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,aux_target_pubkey,f_raw) then Exit(Nil);
+    if Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,aux_target_pubkey,f_raw,ErrorNum,ErrorDesc) then Exit(Nil);
     Result := TOpChangeAccountInfo.CreateChangeAccountInfo(current_protocol,
       account_signer,account_last_n_operation+1,account_target,
       privateKey,
@@ -1920,7 +1996,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     current_protocol : Word;
   begin
     Result := false;
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param previous operations hash tree raw value: '+errors;
       Exit;
@@ -1949,7 +2025,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     current_protocol : Word;
   begin
     Result := false;
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param previous operations hash tree raw value: '+errors;
       Exit;
@@ -2047,7 +2123,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     current_protocol : Word;
   begin
     Result := false;
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,OperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param previous operations hash tree raw value: '+errors;
       Exit;
@@ -2573,7 +2649,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
 
         if (jsonArr.GetAsObject(i).IndexOfName('new_b58_pubkey')>=0) or (jsonArr.GetAsObject(i).IndexOfName('new_enc_pubkey')>=0) then begin
           changeinfo.Changes_type:=changeinfo.Changes_type + [public_key];
-          If Not CapturePubKeyExt(jsonArr.GetAsObject(i),'new_',changeinfo.New_Accountkey,ErrorDesc) then begin
+          If Not TPascalCoinJSONComp.CapturePubKey(jsonArr.GetAsObject(i),'new_',changeinfo.New_Accountkey,ErrorDesc) then begin
             ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
             Exit;
           end;
@@ -2635,7 +2711,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       ErrorDesc:= 'Param digest with invalid hexadecimal data';
       Exit;
     end;
-    If Not CapturePubKeyExt(params,'',pubKey,ErrorDesc) then begin
+    If Not TPascalCoinJSONComp.CapturePubKey(params,'',pubKey,ErrorDesc) then begin
       ErrorNum := CT_RPC_ErrNum_InvalidPubKey;
       Exit;
     end;
@@ -2702,7 +2778,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     if (Not (_RPCServer.FWalletKeys.IsValidPassword)) then Exit;
     for i := 0 to accounts_and_keys.Count-1 do begin
       nAccount := accounts_and_keys.GetAsObject(i).AsCardinal('account',CT_MaxAccount);
-      If CapturePubKeyExt(accounts_and_keys.GetAsObject(i),'',pubKey,_error_desc) then begin
+      If TPascalCoinJSONComp.CapturePubKey(accounts_and_keys.GetAsObject(i),'',pubKey,_error_desc) then begin
         iKey := _RPCServer.FWalletKeys.IndexOfAccountKey(pubKey);
         if (iKey>=0) then begin
           if (Assigned(_RPCServer.FWalletKeys.Key[iKey].PrivateKey)) then begin
@@ -2807,7 +2883,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     errors : String;
   begin
     Result := False;
-    if Not HexaStringToOperationsHashTree(HexaStringOperationsHashTree,senderOperationsHashTree,errors) then begin
+    if Not TPascalCoinJSONComp.HexaStringToOperationsHashTree(HexaStringOperationsHashTree,senderOperationsHashTree,errors) then begin
       ErrorNum:=CT_RPC_ErrNum_InvalidData;
       ErrorDesc:= 'Error decoding param previous operations hash tree raw value: '+errors;
       Exit;
@@ -2842,6 +2918,7 @@ Var c,c2,c3 : Cardinal;
   ocl : TOrderedCardinalList;
   jsonarr : TPCJSONArray;
   jso : TPCJSONObject;
+  LRPCProcessMethod : TRPCProcessMethod;
 begin
   _ro := Nil;
   _ra := Nil;
@@ -3808,8 +3885,36 @@ begin
     Get_node_ip_stats;
     Result := True;
   end else begin
-    ErrorNum := CT_RPC_ErrNum_MethodNotFound;
-    ErrorDesc := 'Method not found: "'+method+'"';
+    LRPCProcessMethod := FindRegisteredProcessMethod(method);
+    if Assigned(LRPCProcessMethod) then begin
+      Result := LRPCProcessMethod(Self,method,params,jsonresponse,ErrorNum,ErrorDesc);
+    end else begin
+      ErrorNum := CT_RPC_ErrNum_MethodNotFound;
+      ErrorDesc := 'Method not found: "'+method+'"';
+    end;
+  end;
+end;
+
+class procedure TRPCProcess.RegisterProcessMethod(const AMethodName: String; ARPCProcessMethod: TRPCProcessMethod);
+var LRegistered : TRegisteredRPCProcessMethod;
+begin
+  if Not Assigned(_RPCProcessMethods) then begin
+    _RPCProcessMethods := TList<TRegisteredRPCProcessMethod>.Create;
+  end;
+  if Assigned(FindRegisteredProcessMethod(AMethodName)) then Exit; // Duplicated!
+  LRegistered.MethodName := AMethodName;
+  LRegistered.RPCProcessMethod := ARPCProcessMethod;
+  _RPCProcessMethods.Add(LRegistered);
+end;
+
+class procedure TRPCProcess.UnregisterProcessMethod(const AMethodName: String);
+var i : Integer;
+begin
+  if Not Assigned(_RPCProcessMethods) then Exit;
+  for i := _RPCProcessMethods.Count-1 downto 0 do begin
+    if AnsiSameStr(_RPCProcessMethods.Items[i].MethodName , AMethodName) then begin
+      _RPCProcessMethods.Delete(i);
+    end;
   end;
 end;
 
@@ -3830,7 +3935,7 @@ begin
         if canread(1000) then begin
           ClientSock:=accept;
           if lastError=0 then begin
-            TRPCProcess.create(ClientSock);
+            TRPCProcess.create(FRPCServer,ClientSock);
           end;
         end;
       Except
@@ -3843,11 +3948,12 @@ begin
   end;
 end;
 
-constructor TRPCServerThread.Create(Port: Word);
+constructor TRPCServerThread.Create(ARPCServer : TRPCServer; APort : Word);
 begin
-  TLog.NewLog(ltInfo,ClassName,'Activating RPC-JSON Server on port '+inttostr(Port));
+  TLog.NewLog(ltInfo,ClassName,'Activating RPC-JSON Server on port '+inttostr(APort));
+  FRPCServer := ARPCServer;
   FServerSocket:=TTCPBlockSocket.create;
-  FPort := Port;
+  FPort := APort;
   inherited create(false);
 end;
 
@@ -3858,4 +3964,19 @@ begin
   inherited Destroy;
 end;
 
+procedure DoFinalize;
+var i : Integer;
+begin
+  if Assigned(_RPCProcessMethods) then begin
+    for i := _RPCProcessMethods.Count-1 downto 0 do begin
+      _RPCProcessMethods.Delete(i);
+    end;
+  end;
+  FreeAndNil(_RPCProcessMethods);
+  FreeAndNil(_RPCServer);
+end;
+
+initialization
+finalization
+  DoFinalize;
 end.