Browse Source

TESTNET 5 Beta 2

Implemented PIP-0027 and PIP-0012 to 10 years
PascalCoin 6 years ago
parent
commit
b547629b13

+ 13 - 2
README.md

@@ -36,12 +36,17 @@ Also, consider a donation at PascalCoin development account: "0-10"
 
 ### Current Build (Pending release date)
 - Upgrade to Protocol 5 (Hard fork)
+- Implementation of PIP-0036 (RandomHash2 mining algo) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0036.md
+  - New PoW miner algo improving previous RandomHash (PIP-0009) added on Protocol 4
 - Implementation of PIP-0032 (Atomic Swaps) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0032.md
 - 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
-- Partial implementation of PIP-0012 (Recover Accounts option after 4 years) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0012.md
+- Implementation of PIP-0027 (E-PASA Inifine Address-Space) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0027.md
+  - Third party apps/implementations of hard coded operations need to pay attention of an extra byte added on each operation using Payload
+  - TODO: Explain "in core" changes
+- Implementation of PIP-0012 (Recover Accounts option after 10 years) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0012.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
@@ -60,6 +65,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.
+  - Updated "multioperationaddoperation call to allow add "payload_type" value as described on PIP-0027
+    - New param "payload_type" on "senders" and "receivers" array as optional value (default 0)
   - 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"
   - New method "finddataoperations" as described on PIP-0033 returning an ARRAY of "Raw Operations Object"
@@ -75,11 +82,14 @@ Also, consider a donation at PascalCoin development account: "0-10"
     - "seal" : (HEXASTRING) will return the Account Seal stored with PIP-0029
   - Updated "Operation Object" return values:
     - "senders" : ARRAY
+      - "payload_type" : (Byte) as described on PIP-0027
       - "data" : OBJECT will store OP_DATA information when operation is OP_DATA type as described on PIP-0016
         - "id" : (String) String representation of GUID/UUID as "00000000-0000-0000-0000-000000000000" that stores 16 bytes
         - "sequence" : (Integer)
         - "type" : (Integer)
-    - "changers" : ARRAY
+    - "receivers" : ARRAY
+      - "payload_type" : (Byte) as described on PIP-0027	
+    - "changers" : ARRAY	
       - "new_data" : (HEXASTRING) : If "data" is changed on "account"
       - "changes" : (String) Description of changes type made
   - Updated "Multi Operation Object" values:
@@ -90,6 +100,7 @@ TODO
 - TODO: RPC calls for PIP-0029
 - TODO: RPC calls for PIP-0030
 - TODO: RPC calls for PIP-0016
+- TODO: Store payload_type according to PIP-0027 when using standard RPC calls
 
 ### Build 4.1.0.0 - 2019-07-24
 - Hardcoded RandomHash digest/hash values for quick speed safebox check on fresh installation

+ 46 - 9
src/core/UBlockChain.pas

@@ -115,6 +115,19 @@ Type
   TOpChangeAccountInfoType = (public_key, account_name, account_type, list_for_public_sale, list_for_private_sale, delist, account_data, list_for_account_swap, list_for_coin_swap );
   TOpChangeAccountInfoTypes = Set of TOpChangeAccountInfoType;
 
+  TOperationPayload = record
+    { As described on PIP-0027 (introduced on Protocol V5)
+      the payload of an operation will contain an initial byte that will
+      provide information about the payload content.
+      The "payload_type" byte value will help in payload decoding if good used
+      but there is no core checking that payload_type has been used properly.
+      It's job of any third party app (Layer 2) working with payloads to
+      check/ensure they can read/decode properly Payload value if the
+      content is not saved using E-PASA standard (PIP-0027) }
+    payload_type : Byte;
+    payload_raw : TRawBytes;
+  end;
+
   // MultiOp... will allow a MultiOperation
   TMultiOpData = record
     ID : TGUID;
@@ -127,14 +140,14 @@ Type
     Amount : Int64;
     N_Operation : Cardinal;
     OpData : TMultiOpData; // Filled only when Operation is TOpData type
-    Payload : TRawBytes;
+    Payload : TOperationPayload;
     Signature : TECDSA_SIG;
   end;
   TMultiOpSenders = Array of TMultiOpSender;
   TMultiOpReceiver = Record
     Account : Cardinal;
     Amount : Int64;
-    Payload : TRawBytes;
+    Payload : TOperationPayload;
   end;
   TMultiOpReceivers = Array of TMultiOpReceiver;
   TMultiOpChangeInfo = Record
@@ -171,7 +184,7 @@ Type
     Amount : Int64;
     Fee : Int64;
     Balance : Int64;
-    OriginalPayload : TRawBytes;
+    OriginalPayload : TOperationPayload;
     PrintablePayload : String;
     OperationHash : TRawBytes;
     OperationHash_OLD : TRawBytes; // Will include old oeration hash value
@@ -226,6 +239,8 @@ Type
     Property Previous_Seller_updated_block : Cardinal read FPrevious_Seller_updated_block; // deprecated
     function IsValidECDSASignature(const PubKey: TECDSA_Public; current_protocol : Word; const Signature: TECDSA_SIG): Boolean;
     procedure CopyUsedPubkeySignatureFrom(SourceOperation : TPCOperation); virtual;
+    function SaveOperationPayloadToStream(const AStream : TStream; const APayload : TOperationPayload) : Boolean;
+    function LoadOperationPayloadFromStream(const AStream : TStream; out APayload : TOperationPayload) : Boolean;
   public
     constructor Create(AProtocolVersion : Word); virtual;
     destructor Destroy; override;
@@ -239,7 +254,7 @@ Type
     function OperationAmount : Int64; virtual; abstract;
     function OperationAmountByAccount(account : Cardinal) : Int64; virtual;
     function OperationFee: Int64; virtual; abstract;
-    function OperationPayload : TRawBytes; virtual; abstract;
+    function OperationPayload : TOperationPayload; virtual; abstract;
     function SignerAccount : Cardinal; virtual; abstract;
     procedure SignerAccounts(list : TList<Cardinal>); virtual;
     function IsSignerAccount(account : Cardinal) : Boolean; virtual;
@@ -556,9 +571,10 @@ Type
   End;
 
 Const
-  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:Nil;PrintablePayload:'';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:Nil;Signature:(r:Nil;s:Nil));
-  CT_TMultiOpReceiver_NUL : TMultiOpReceiver = (Account:0;Amount:0;Payload: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_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_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;
     Fee:0;Signature:(r:Nil;s:Nil));
@@ -3132,6 +3148,27 @@ begin
   end;
 end;
 
+function TPCOperation.LoadOperationPayloadFromStream(const AStream: TStream; out APayload: TOperationPayload): Boolean;
+begin
+  APayload := CT_TOperationPayload_NUL;
+  if FProtocolVersion>=CT_PROTOCOL_5 then begin
+    // payload_type will only be available on protocol 5
+    if AStream.Read(APayload.payload_type,SizeOf(APayload.payload_type))<>SizeOf(APayload.payload_type) then Exit(False);
+  end;
+  if TStreamOp.ReadAnsiString(AStream,APayload.payload_raw)<0 then Exit(False);
+  Result := True;
+end;
+
+function TPCOperation.SaveOperationPayloadToStream(const AStream: TStream; const APayload: TOperationPayload): Boolean;
+begin
+  if FProtocolVersion>=CT_PROTOCOL_5 then begin
+    // payload_type will only be available on protocol 5
+    AStream.Write(APayload.payload_type,SizeOf(APayload.payload_type));
+  end;
+  TStreamOp.WriteAnsiString(AStream,APayload.payload_raw);
+  Result := True;
+end;
+
 class function TPCOperation.OperationHash_OLD(op: TPCOperation; Block : Cardinal): TRawBytes;
   { OperationHash is a 32 bytes value.
     First 4 bytes (0..3) are Block in little endian
@@ -3412,8 +3449,8 @@ begin
   else Exit;
   end;
   OperationResume.OriginalPayload := Operation.OperationPayload;
-  If TCrypto.IsHumanReadable(OperationResume.OriginalPayload) then OperationResume.PrintablePayload := OperationResume.OriginalPayload.ToPrintable
-  else OperationResume.PrintablePayload := TCrypto.ToHexaString(OperationResume.OriginalPayload);
+  If TCrypto.IsHumanReadable(OperationResume.OriginalPayload.payload_raw) then OperationResume.PrintablePayload := OperationResume.OriginalPayload.payload_raw.ToPrintable
+  else OperationResume.PrintablePayload := TCrypto.ToHexaString(OperationResume.OriginalPayload.payload_raw);
   OperationResume.OperationHash:=TPCOperation.OperationHashValid(Operation,Block);
   if (Block>0) And (Block<CT_Protocol_Upgrade_v2_MinBlock) then begin
     OperationResume.OperationHash_OLD:=TPCOperation.OperationHash_OLD(Operation,Block);

+ 4 - 4
src/core/UConst.pas

@@ -58,7 +58,7 @@ Const
 
   CT_WaitNewBlocksBeforeTransaction = 100;
 
-  CT_RecoverFoundsWaitInactiveCount = 420480;  // After 4 years... if an account has no operations, money will be a reward for a miner!
+  CT_RecoverFoundsWaitInactiveCount = 1051200;  // After 10 years... if an account has no operations, money will be a reward for a miner!
   CT_MaxFutureBlocksLockedAccount = 105120; // Maximum future blocks an account can be locked
 
   CT_MaxTransactionAmount = 1000000000000; // ... can be deleted
@@ -127,7 +127,7 @@ Const
   CT_Protocol_Upgrade_v5_MinBlock = {$IFDEF PRODUCTION}999999999{$ELSE}500{$ENDIF}; // TODO Need define v5 for production!
 
 
-  CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}$05000001{$ENDIF}; // Unix timestamp 168048000 ... It's Albert birthdate!
+  CT_MagicNetIdentification = {$IFDEF PRODUCTION}$0A043580{$ELSE}$05000002{$ENDIF}; // Unix timestamp 168048000 ... It's Albert birthdate!
 
   CT_NetProtocol_Version: Word = $0009; // Version 4.0.2 Will allow only net protocol 9
   // IMPORTANT NOTE!!!
@@ -138,7 +138,7 @@ Const
 
   CT_SafeBoxBankVersion : Word = 3; // Protocol 2 upgraded safebox version from 2 to 3
 
-  CT_MagicIdentificator: String = {$IFDEF PRODUCTION}'PascalCoin'{$ELSE}'PascalCoinTESTNET_5.Beta.1'{$ENDIF}; //
+  CT_MagicIdentificator: String = {$IFDEF PRODUCTION}'PascalCoin'{$ELSE}'PascalCoinTESTNET_5.Beta.2'{$ENDIF}; //
 
   CT_PseudoOp_Reward = $0;
   // Value of Operations type in Protocol 1
@@ -193,7 +193,7 @@ Const
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Receiver              = 104;
 
-  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'4.1'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.Beta.1'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'4.1'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.Beta.2'{$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'
                     {$ELSE}'pascaltestnet1.dynamic-dns.net;pascaltestnet2.dynamic-dns.net;pascaltestnet1.dns1.us;pascaltestnet2.dns1.us'{$ENDIF};

+ 93 - 84
src/core/UOpTransaction.pas

@@ -43,7 +43,7 @@ Type
     target: Cardinal;
     amount: UInt64;
     fee: UInt64;
-    payload: TRawBytes;
+    payload: TOperationPayload;
     public_key: TECDSA_Public;
     sign: TECDSA_SIG;
     // Protocol 2
@@ -59,7 +59,7 @@ Type
     account_target: Cardinal;
     n_operation : Cardinal;
     fee: UInt64;
-    payload: TRawBytes;
+    payload: TOperationPayload;
     public_key: TECDSA_Public;
     new_accountkey: TAccountKey;
     sign: TECDSA_SIG;
@@ -73,8 +73,8 @@ Type
   End;
 
 Const
-  CT_TOpTransactionData_NUL : TOpTransactionData = (sender:0;n_operation:0;target:0;amount:0;fee:0;payload:Nil;public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);sign:(r:Nil;s:Nil);opTransactionStyle:transaction;AccountPrice:0;SellerAccount:0;new_accountkey:(EC_OpenSSL_NID:0;x:Nil;y:Nil));
-  CT_TOpChangeKeyData_NUL : TOpChangeKeyData = (account_signer:0;account_target:0;n_operation:0;fee:0;payload:Nil;public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);new_accountkey:(EC_OpenSSL_NID:0;x:Nil;y:Nil);sign:(r:Nil;s:Nil));
+  CT_TOpTransactionData_NUL : TOpTransactionData = (sender:0;n_operation:0;target:0;amount:0;fee:0;payload:(payload_type:0;payload_raw:Nil);public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);sign:(r:Nil;s:Nil);opTransactionStyle:transaction;AccountPrice:0;SellerAccount:0;new_accountkey:(EC_OpenSSL_NID:0;x:Nil;y:Nil));
+  CT_TOpChangeKeyData_NUL : TOpChangeKeyData = (account_signer:0;account_target:0;n_operation:0;fee:0;payload:(payload_type:0;payload_raw:Nil);public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);new_accountkey:(EC_OpenSSL_NID:0;x:Nil;y:Nil);sign:(r:Nil;s:Nil));
   CT_TOpRecoverFoundsData_NUL : TOpRecoverFoundsData = (account:0;n_operation:0;fee:0;new_accountkey:(EC_OpenSSL_NID:0;x:Nil;y:Nil));
 
 Type
@@ -96,7 +96,7 @@ Type
     class function OpType : Byte; override;
     function OperationAmount : Int64; override;
     function OperationFee : Int64; override;
-    function OperationPayload : TRawBytes; override;
+    function OperationPayload : TOperationPayload; override;
     function SignerAccount : Cardinal; override;
     function DestinationAccount : Int64; override;
     function SellerAccount : Int64; override;
@@ -104,7 +104,7 @@ Type
     function OperationAmountByAccount(account : Cardinal) : Int64; override;
     Property Data : TOpTransactionData read FData;
 
-    Constructor CreateTransaction(ACurrentProtocol : Word; sender, n_operation, target: Cardinal; key: TECPrivateKey; amount, fee: UInt64; payload: TRawBytes);
+    Constructor CreateTransaction(ACurrentProtocol : Word; sender, n_operation, target: Cardinal; key: TECPrivateKey; amount, fee: UInt64; const payload: TOperationPayload);
     Function toString : String; Override;
     Function GetDigestToSign(current_protocol : Word) : TRawBytes; override;
 
@@ -128,13 +128,13 @@ Type
     function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean; override;
     function OperationAmount : Int64; override;
     function OperationFee : Int64; override;
-    function OperationPayload : TRawBytes; override;
+    function OperationPayload : TOperationPayload; override;
     function SignerAccount : Cardinal; override;
     function DestinationAccount : Int64; override;
     function N_Operation : Cardinal; override;
     procedure AffectedAccounts(list : TList<Cardinal>); override;
     function OperationAmountByAccount(account : Cardinal) : Int64; override;
-    Constructor Create(ACurrentProtocol : Word; account_signer, n_operation, account_target: Cardinal; key:TECPrivateKey; new_account_key : TAccountKey; fee: UInt64; payload: TRawBytes);
+    Constructor Create(ACurrentProtocol : Word; account_signer, n_operation, account_target: Cardinal; key:TECPrivateKey; new_account_key : TAccountKey; fee: UInt64; const payload: TOperationPayload);
     Property Data : TOpChangeKeyData read FData;
     Function toString : String; Override;
     Function GetDigestToSign(current_protocol : Word) : TRawBytes; override;
@@ -167,7 +167,7 @@ Type
     function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean; override;
     function OperationAmount : Int64; override;
     function OperationFee : Int64; override;
-    function OperationPayload : TRawBytes; override;
+    function OperationPayload : TOperationPayload; override;
     function SignerAccount : Cardinal; override;
     function N_Operation : Cardinal; override;
     function OperationAmountByAccount(account : Cardinal) : Int64; override;
@@ -192,7 +192,7 @@ Type
     account_to_pay : Cardinal;
     fee: UInt64;
     hash_lock : T32Bytes;
-    payload: TRawBytes;
+    payload: TOperationPayload;
     public_key: TAccountKey;
     new_public_key: TAccountKey;   // If EC_OpenSSL_NID=0 then is OPEN, otherwise is for only 1 public key
     locked_until_block : Cardinal; //
@@ -204,7 +204,7 @@ Type
     account_target: Cardinal;
     n_operation : Cardinal;
     fee: UInt64;
-    payload: TRawBytes;
+    payload: TOperationPayload;
     public_key: TECDSA_Public;
     changes_type : TOpChangeAccountInfoTypes; // bits mask. $0001 = New account key , $0002 = New name , $0004 = New type , $0008 = New Data
     new_accountkey: TAccountKey;  // If (changes_mask and $0001)=$0001 then change account key
@@ -217,8 +217,8 @@ Type
 
 Const
   CT_TOpListAccountData_NUL : TOpListAccountData = (account_signer:0;account_target:0;operation_type:lat_Unknown;n_operation:0;account_state:as_Unknown;account_price:0;account_to_pay:0;fee:0;
-    hash_lock:(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);payload:Nil;public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);new_public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);locked_until_block:0;sign:(r:Nil;s:Nil));
-  CT_TOpChangeAccountInfoData_NUL : TOpChangeAccountInfoData = (account_signer:0;account_target:0;n_operation:0;fee:0;payload:Nil;public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);changes_type:[];
+    hash_lock:(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);payload:(payload_type:0;payload_raw:Nil);public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);new_public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);locked_until_block:0;sign:(r:Nil;s:Nil));
+  CT_TOpChangeAccountInfoData_NUL : TOpChangeAccountInfoData = (account_signer:0;account_target:0;n_operation:0;fee:0;payload:(payload_type:0;payload_raw:Nil);public_key:(EC_OpenSSL_NID:0;x:Nil;y:Nil);changes_type:[];
     new_accountkey:(EC_OpenSSL_NID:0;x:Nil;y:Nil);new_name:Nil;new_type:0;new_data:Nil;sign:(r:Nil;s:Nil));
 
 Type
@@ -238,7 +238,7 @@ Type
     function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean; override;
     function OperationAmount : Int64; override;
     function OperationFee : Int64; override;
-    function OperationPayload : TRawBytes; override;
+    function OperationPayload : TOperationPayload; override;
     function SignerAccount : Cardinal; override;
     function DestinationAccount : Int64; override;
     function SellerAccount : Int64; override;
@@ -256,14 +256,14 @@ Type
     function GetOpSubType : Integer;
   public
     class function OpType : Byte; override;
-    Constructor CreateListAccountForSaleOrSwap(ACurrentProtocol : Word; ANewAccountState : TAccountState; AAccountSigner, ANOperation, AAccountTarget: Cardinal; AAccountPrice, AFee: UInt64; AAccountToPay: Cardinal;  ANewPublicKey: TAccountKey; ALockedUntilBlock: Cardinal; AKey: TECPrivateKey; const AHashLock : T32Bytes; const APayload: TRawBytes);
+    Constructor CreateListAccountForSaleOrSwap(ACurrentProtocol : Word; ANewAccountState : TAccountState; AAccountSigner, ANOperation, AAccountTarget: Cardinal; AAccountPrice, AFee: UInt64; AAccountToPay: Cardinal;  ANewPublicKey: TAccountKey; ALockedUntilBlock: Cardinal; AKey: TECPrivateKey; const AHashLock : T32Bytes; const APayload: TOperationPayload);
     property OpSubType : Integer read GetOpSubType;
   End;
 
   TOpDelistAccountForSale = Class(TOpListAccount)
   public
     class function OpType : Byte; override;
-    Constructor CreateDelistAccountForSale(ACurrentProtocol : Word; account_signer, n_operation, account_target: Cardinal; fee: UInt64; key: TECPrivateKey; payload: TRawBytes);
+    Constructor CreateDelistAccountForSale(ACurrentProtocol : Word; account_signer, n_operation, account_target: Cardinal; fee: UInt64; key: TECPrivateKey; const payload: TOperationPayload);
   End;
 
   { TOpBuyAccount }
@@ -273,7 +273,7 @@ Type
     procedure InitializeData(AProtocolVersion : Word); override;
   public
     class function OpType : Byte; override;
-    Constructor CreateBuy(ACurrentProtocol : Word; account_number, n_operation, account_to_buy, account_to_pay: Cardinal; price, amount, fee : UInt64; new_public_key:TAccountKey; key:TECPrivateKey; payload: TRawBytes);
+    Constructor CreateBuy(ACurrentProtocol : Word; account_number, n_operation, account_to_buy, account_to_pay: Cardinal; price, amount, fee : UInt64; new_public_key:TAccountKey; key:TECPrivateKey; const payload: TOperationPayload);
   End;
 
   { TOpChangeAccountInfo }
@@ -293,7 +293,7 @@ Type
     function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean; override;
     function OperationAmount : Int64; override;
     function OperationFee : Int64; override;
-    function OperationPayload : TRawBytes; override;
+    function OperationPayload : TOperationPayload; override;
     function SignerAccount : Cardinal; override;
     function DestinationAccount : Int64; override;
     function N_Operation : Cardinal; override;
@@ -305,7 +305,7 @@ Type
       change_name: Boolean; const new_name : TRawBytes;
       change_type: Boolean; const new_type : Word;
       change_data: Boolean; const new_data : TRawBytes;
-      fee: UInt64; payload: TRawBytes);
+      fee: UInt64; const payload: TOperationPayload);
     Property Data : TOpChangeAccountInfoData read FData;
     Function toString : String; Override;
     Function GetDigestToSign(current_protocol : Word) : TRawBytes; override;
@@ -324,7 +324,7 @@ Type
     dataSequence : Word;         // 2 byte data sequence
     amount: UInt64;              // Allow amount=0
     fee: UInt64;                 // Allow fee=0
-    payload: TRawBytes;          // Standard arbitrary data with length<=256
+    payload: TOperationPayload;  // Standard arbitrary data with length<256
     sign: TECDSA_SIG;
   End;
 
@@ -345,13 +345,13 @@ Type
     function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : String) : Boolean; override;
     function OperationAmount : Int64; override;
     function OperationFee : Int64; override;
-    function OperationPayload : TRawBytes; override;
+    function OperationPayload : TOperationPayload; override;
     function SignerAccount : Cardinal; override;
     function DestinationAccount : Int64; override;
     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; AGUID : TGUID; 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; const payload: TOperationPayload);
     Property Data : TOpDataData read FData;
     Function toString : String; Override;
     Function GetDigestToSign(current_protocol : Word) : TRawBytes; override;
@@ -359,7 +359,7 @@ Type
   End;
 
 Const
-  CT_TOpDataData_NUL : TOpDataData = (account_signer:0;account_sender:0;account_target:0;n_operation:0;guid:(D1:0;D2:0;D3:0;D4:(0,0,0,0,0,0,0,0));dataType:0;dataSequence:0;amount:0;fee:0;payload:Nil;sign:(r:Nil;s:Nil));
+  CT_TOpDataData_NUL : TOpDataData = (account_signer:0;account_sender:0;account_target:0;n_operation:0;guid:(D1:0;D2:0;D3:0;D4:(0,0,0,0,0,0,0,0));dataType:0;dataSequence:0;amount:0;fee:0;payload:(payload_type:0;payload_raw:Nil);sign:(r:Nil;s:Nil));
 
 Procedure RegisterOperationsClass;
 
@@ -404,7 +404,7 @@ begin
   Stream.Write(FData.account_target,Sizeof(FData.account_target));
   Stream.Write(FData.n_operation,Sizeof(FData.n_operation));
   Stream.Write(FData.fee,Sizeof(FData.fee));
-  TStreamOp.WriteAnsiString(Stream,FData.payload);
+  SaveOperationPayloadToStream(Stream,FData.payload);
   TStreamOp.WriteAccountKey(Stream,FData.public_key);
   b := 0;
   if (public_key in FData.changes_type) then b:=b OR $01;
@@ -432,7 +432,7 @@ begin
   Stream.Read(FData.account_target,Sizeof(FData.account_target));
   Stream.Read(FData.n_operation,Sizeof(FData.n_operation));
   Stream.Read(FData.fee,Sizeof(FData.fee));
-  if TStreamOp.ReadAnsiString(Stream,FData.payload)<0 then Exit;
+  if Not LoadOperationPayloadFromStream(Stream,FData.payload) then Exit;
   if TStreamOp.ReadAccountKey(Stream,FData.public_key)<0 then Exit;
   Stream.Read(b,SizeOf(b));
   FData.changes_type:=[];
@@ -524,8 +524,8 @@ begin
     errors := 'Insuficient funds';
     exit;
   end;
-  if (length(FData.payload)>CT_MaxPayloadSize) then begin
-    errors := 'Invalid Payload size:'+inttostr(length(FData.payload))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
+  if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
+    errors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
     If (AccountTransaction.FreezedSafeBox.CurrentProtocol>=CT_PROTOCOL_2) then begin
       Exit; // BUG from protocol 1
     end;
@@ -629,7 +629,7 @@ begin
   Result := FData.fee;
 end;
 
-function TOpChangeAccountInfo.OperationPayload: TRawBytes;
+function TOpChangeAccountInfo.OperationPayload: TOperationPayload;
 begin
   Result := FData.payload;
 end;
@@ -667,7 +667,7 @@ constructor TOpChangeAccountInfo.CreateChangeAccountInfo(ACurrentProtocol : word
   const new_account_key: TAccountKey; change_name: Boolean;
   const new_name: TRawBytes; change_type: Boolean; const new_type: Word;
   change_data: Boolean; const new_data : TRawBytes;
-  fee: UInt64; payload: TRawBytes);
+  fee: UInt64; const payload: TOperationPayload);
 begin
   inherited Create(ACurrentProtocol);
   FData.account_signer:=account_signer;
@@ -725,7 +725,7 @@ begin
   Result := Format('Change account %s info: %s fee:%s (n_op:%d) payload size:%d',[
      TAccountComp.AccountNumberToAccountTxtNumber(FData.account_target),
      s,
-     TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload)]);
+     TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload.payload_raw)]);
 end;
 
 function TOpChangeAccountInfo.GetDigestToSign(current_protocol : Word): TRawBytes;
@@ -738,7 +738,7 @@ begin
     Stream.Write(FData.account_target,Sizeof(FData.account_target));
     Stream.Write(FData.n_operation,Sizeof(FData.n_operation));
     Stream.Write(FData.fee,Sizeof(FData.fee));
-    TStreamOp.WriteAnsiString(Stream,FData.payload);
+    SaveOperationPayloadToStream(Stream,FData.payload);
     TStreamOp.WriteAccountKey(Stream,FData.public_key);
     b := 0;
     if (public_key in FData.changes_type) then b:=b OR $01;
@@ -779,7 +779,7 @@ end;
 
 constructor TOpTransaction.CreateTransaction(ACurrentProtocol : Word;
   sender, n_operation, target: Cardinal;
-  key: TECPrivateKey; amount, fee: UInt64; payload: TRawBytes);
+  key: TECPrivateKey; amount, fee: UInt64; const payload: TOperationPayload);
 begin
   inherited Create(ACurrentProtocol);
   FData.sender := sender;
@@ -835,8 +835,8 @@ begin
     AErrors := Format('Invalid fee %d (max %d)',[FData.fee,CT_MaxTransactionFee]);
     Exit;
   end;
-  if (length(FData.payload)>CT_MaxPayloadSize) then begin
-    AErrors := 'Invalid Payload size:'+inttostr(length(FData.payload))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
+  if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
+    AErrors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
     If (LCurrentProtocol>=CT_PROTOCOL_2) then begin
       Exit; // BUG from protocol 1
     end;
@@ -961,7 +961,7 @@ begin
               (
                 (FData.opTransactionStyle = transaction) AND
                 (LCurrentProtocol >= CT_PROTOCOL_2) AND
-                (TAccountComp.IsAccountForSaleOrSwapAcceptingTransactions(LTarget, LCurrentBlock, LCurrentProtocol, FData.payload)) AND
+                (TAccountComp.IsAccountForSaleOrSwapAcceptingTransactions(LTarget, LCurrentBlock, LCurrentProtocol, FData.payload.payload_raw)) AND
                 ((LTarget.balance + FData.amount >= LTarget.accountInfo.price))
               )  then begin
     {$region 'Transaction Auto Buy Validation'}
@@ -1047,7 +1047,7 @@ begin
       LTarget.accountInfo.price,
       FData.fee,
       LBuyAccountNewPubkey,
-      FData.payload,
+      FData.payload.payload_raw,
       LRecipientSignable,
       AErrors
     );
@@ -1079,8 +1079,8 @@ begin
       ms.Write(FData.target,Sizeof(FData.target));
       ms.Write(FData.amount,Sizeof(FData.amount));
       ms.Write(FData.fee,Sizeof(FData.fee));
-      if Length(FData.payload)>0 then
-        ms.WriteBuffer(FData.payload[Low(FData.payload)],Length(FData.payload));
+      if Length(FData.payload.payload_raw)>0 then
+        ms.WriteBuffer(FData.payload.payload_raw[Low(FData.payload.payload_raw)],Length(FData.payload.payload_raw));
       ms.Write(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID));
       if Length(FData.public_key.x)>0 then
         ms.WriteBuffer(FData.public_key.x[Low(FData.public_key.x)],Length(FData.public_key.x));
@@ -1122,7 +1122,7 @@ begin
   Stream.Read(FData.target,Sizeof(FData.target));
   Stream.Read(FData.amount,Sizeof(FData.amount));
   Stream.Read(FData.fee,Sizeof(FData.fee));
-  if TStreamOp.ReadAnsiString(Stream,FData.payload)<0 then exit;
+  if Not LoadOperationPayloadFromStream(Stream,FData.payload) then Exit;
   if Stream.Read(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID))<0 then exit;
   if TStreamOp.ReadAnsiString(Stream,FData.public_key.x)<0 then exit;
   if TStreamOp.ReadAnsiString(Stream,FData.public_key.y)<0 then exit;
@@ -1207,7 +1207,7 @@ begin
   Result := FData.fee;
 end;
 
-function TOpTransaction.OperationPayload: TRawBytes;
+function TOpTransaction.OperationPayload: TOperationPayload;
 begin
   Result := FData.payload;
 end;
@@ -1225,7 +1225,7 @@ begin
   Stream.Write(FData.target,Sizeof(FData.target));
   Stream.Write(FData.amount,Sizeof(FData.amount));
   Stream.Write(FData.fee,Sizeof(FData.fee));
-  TStreamOp.WriteAnsiString(Stream,FData.payload);
+  SaveOperationPayloadToStream(Stream,FData.payload);
   Stream.Write(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID));
   TStreamOp.WriteAnsiString(Stream,FData.public_key.x);
   TStreamOp.WriteAnsiString(Stream,FData.public_key.y);
@@ -1294,22 +1294,22 @@ begin
       Result := Format('Transaction from %s to %s amount:%s fee:%s (n_op:%d) payload size:%d payload:%s',[
          TAccountComp.AccountNumberToAccountTxtNumber(FData.sender),
          TAccountComp.AccountNumberToAccountTxtNumber(FData.target),
-         TAccountComp.FormatMoney(FData.amount),TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload),
-         TCrypto.ToHexaString(FData.payload)]);
+         TAccountComp.FormatMoney(FData.amount),TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload.payload_raw),
+         TCrypto.ToHexaString(FData.payload.payload_raw)]);
     transaction_with_auto_buy_account :
       Result := Format('Transaction/Buy account %s by %s paying %s to %s amount:%s fee:%s (n_op:%d) payload size:%d payload:%s',[
          TAccountComp.AccountNumberToAccountTxtNumber(FData.target),
          TAccountComp.AccountNumberToAccountTxtNumber(FData.sender),
          TAccountComp.FormatMoney(FData.AccountPrice), TAccountComp.AccountNumberToAccountTxtNumber(FData.SellerAccount),
-         TAccountComp.FormatMoney(FData.amount),TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload),
-         TCrypto.ToHexaString(FData.payload)]);
+         TAccountComp.FormatMoney(FData.amount),TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload.payload_raw),
+         TCrypto.ToHexaString(FData.payload.payload_raw)]);
     buy_account :
       Result := Format('Buy account %s by %s paying %s to %s amount:%s fee:%s (n_op:%d) payload size:%d payload:%s',[
          TAccountComp.AccountNumberToAccountTxtNumber(FData.target),
          TAccountComp.AccountNumberToAccountTxtNumber(FData.sender),
          TAccountComp.FormatMoney(FData.AccountPrice), TAccountComp.AccountNumberToAccountTxtNumber(FData.SellerAccount),
-         TAccountComp.FormatMoney(FData.amount),TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload),
-         TCrypto.ToHexaString(FData.payload)]);
+         TAccountComp.FormatMoney(FData.amount),TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload.payload_raw),
+         TCrypto.ToHexaString(FData.payload.payload_raw)]);
   else raise Exception.Create('ERROR DEV 20170424-2');
   end;
 end;
@@ -1325,8 +1325,11 @@ begin
     ms.Write(FData.target,Sizeof(FData.target));
     ms.Write(FData.amount,Sizeof(FData.amount));
     ms.Write(FData.fee,Sizeof(FData.fee));
-    if Length(FData.payload)>0 then
-      ms.WriteBuffer(FData.payload[Low(FData.payload)],Length(FData.payload));
+    if current_protocol>=CT_PROTOCOL_5 then begin
+      ms.Write(FData.payload.payload_type,SizeOf(FData.payload.payload_type));
+    end;
+    if Length(FData.payload.payload_raw)>0 then
+      ms.WriteBuffer(FData.payload.payload_raw[Low(FData.payload.payload_raw)],Length(FData.payload.payload_raw));
     ms.Write(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID));
     if Length(FData.public_key.x)>0 then
       ms.WriteBuffer(FData.public_key.x[Low(FData.public_key.x)],Length(FData.public_key.x));
@@ -1369,7 +1372,7 @@ begin
   else Result := 0;
 end;
 
-constructor TOpChangeKey.Create(ACurrentProtocol : Word; account_signer, n_operation, account_target: Cardinal; key:TECPrivateKey; new_account_key : TAccountKey; fee: UInt64; payload: TRawBytes);
+constructor TOpChangeKey.Create(ACurrentProtocol : Word; account_signer, n_operation, account_target: Cardinal; key:TECPrivateKey; new_account_key : TAccountKey; fee: UInt64; const payload: TOperationPayload);
 begin
   inherited Create(ACurrentProtocol);
   FData.account_signer := account_signer;
@@ -1431,8 +1434,8 @@ begin
     errors := 'Insuficient founds';
     exit;
   end;
-  if (length(FData.payload)>CT_MaxPayloadSize) then begin
-    errors := 'Invalid Payload size:'+inttostr(length(FData.payload))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
+  if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
+    errors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
     If (AccountTransaction.FreezedSafeBox.CurrentProtocol>=CT_PROTOCOL_2) then begin
       Exit; // BUG from protocol 1
     end;
@@ -1512,8 +1515,8 @@ begin
       ms.Write(FData.account_signer,Sizeof(FData.account_signer)); //Protocol 1 does not allow signer/target. signer=target always
       ms.Write(FData.n_operation,Sizeof(FData.n_operation));
       ms.Write(FData.fee,Sizeof(FData.fee));
-      if Length(FData.payload)>0 then
-        ms.WriteBuffer(FData.payload[Low(FData.payload)],Length(FData.payload));
+      if Length(FData.payload.payload_raw)>0 then
+        ms.WriteBuffer(FData.payload.payload_raw[Low(FData.payload.payload_raw)],Length(FData.payload.payload_raw));
       ms.Write(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID));
       if Length(FData.public_key.x)>0 then
         ms.WriteBuffer(FData.public_key.x[Low(FData.public_key.x)],Length(FData.public_key.x));
@@ -1561,7 +1564,7 @@ begin
   end else Raise Exception.Create('ERROR DEV 20170530-1');
   Stream.Read(FData.n_operation,Sizeof(FData.n_operation));
   Stream.Read(FData.fee,Sizeof(FData.fee));
-  if TStreamOp.ReadAnsiString(Stream,FData.payload)<0 then exit;
+  if Not LoadOperationPayloadFromStream(Stream,FData.payload) then Exit;
   if Stream.Read(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID))<0 then exit;
   if TStreamOp.ReadAnsiString(Stream,FData.public_key.x)<0 then exit;
   if TStreamOp.ReadAnsiString(Stream,FData.public_key.y)<0 then exit;
@@ -1604,7 +1607,7 @@ begin
   Result := FData.fee;
 end;
 
-function TOpChangeKey.OperationPayload: TRawBytes;
+function TOpChangeKey.OperationPayload: TOperationPayload;
 begin
   Result := FData.payload;
 end;
@@ -1624,7 +1627,7 @@ begin
   end else Raise Exception.Create('ERROR DEV 20170530-3');
   Stream.Write(FData.n_operation,Sizeof(FData.n_operation));
   Stream.Write(FData.fee,Sizeof(FData.fee));
-  TStreamOp.WriteAnsiString(Stream,FData.payload);
+  SaveOperationPayloadToStream(Stream,FData.payload);
   Stream.Write(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID));
   TStreamOp.WriteAnsiString(Stream,FData.public_key.x);
   TStreamOp.WriteAnsiString(Stream,FData.public_key.y);
@@ -1654,7 +1657,7 @@ begin
   Result := Format('Change key of %s to new key: %s fee:%s (n_op:%d) payload size:%d',[
     TAccountComp.AccountNumberToAccountTxtNumber(FData.account_target),
     TAccountComp.GetECInfoTxt(FData.new_accountkey.EC_OpenSSL_NID),
-    TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload)]);
+    TAccountComp.FormatMoney(FData.fee),FData.n_operation,Length(FData.payload.payload_raw)]);
 end;
 
 function TOpChangeKey.GetDigestToSign(current_protocol : Word): TRawBytes;
@@ -1668,8 +1671,11 @@ begin
     if (FData.account_signer<>FData.account_target) then ms.Write(FData.account_target,Sizeof(FData.account_target));
     ms.Write(FData.n_operation,Sizeof(FData.n_operation));
     ms.Write(FData.fee,Sizeof(FData.fee));
-    if Length(FData.payload)>0 then
-      ms.WriteBuffer(FData.payload[Low(FData.payload)],Length(FData.payload));
+    if current_protocol>=CT_PROTOCOL_5 then begin
+      ms.Write(FData.payload.payload_type,SizeOf(FData.payload.payload_type));
+    end;
+    if Length(FData.payload.payload_raw)>0 then
+      ms.WriteBuffer(FData.payload.payload_raw[Low(FData.payload.payload_raw)],Length(FData.payload.payload_raw));
     ms.Write(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID));
     if Length(FData.public_key.x)>0 then
       ms.WriteBuffer(FData.public_key.x[Low(FData.public_key.x)],Length(FData.public_key.x));
@@ -1824,9 +1830,9 @@ begin
   Result := FData.fee;
 end;
 
-function TOpRecoverFounds.OperationPayload: TRawBytes;
+function TOpRecoverFounds.OperationPayload: TOperationPayload;
 begin
-  SetLength(Result,0);
+  Result := CT_TOperationPayload_NUL;
 end;
 
 class function TOpRecoverFounds.OpType: Byte;
@@ -2013,8 +2019,8 @@ begin
     errors := 'Insuficient founds';
     exit;
   end;
-  if (length(FData.payload)>CT_MaxPayloadSize) then begin
-    errors := 'Invalid Payload size:'+inttostr(length(FData.payload))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
+  if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
+    errors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
     Exit;
   end;
   // Is locked?
@@ -2153,7 +2159,7 @@ begin
     end;
   end;
   Stream.Read(FData.fee,Sizeof(FData.fee));
-  if TStreamOp.ReadAnsiString(Stream,FData.payload)<0 then exit;
+  if Not LoadOperationPayloadFromStream(Stream,FData.payload) then Exit;
   if TStreamOp.ReadAnsiString(Stream,FData.sign.r)<0 then exit;
   if TStreamOp.ReadAnsiString(Stream,FData.sign.s)<0 then exit;
   Result := true;
@@ -2218,7 +2224,7 @@ begin
   Result := FData.fee;
 end;
 
-function TOpListAccount.OperationPayload: TRawBytes;
+function TOpListAccount.OperationPayload: TOperationPayload;
 begin
   Result := FData.payload;
 end;
@@ -2251,7 +2257,7 @@ begin
     end;
   end;
   Stream.Write(FData.fee,Sizeof(FData.fee));
-  TStreamOp.WriteAnsiString(Stream,FData.payload);
+  SaveOperationPayloadToStream(Stream,FData.payload);
   TStreamOp.WriteAnsiString(Stream,FData.sign.r);
   TStreamOp.WriteAnsiString(Stream,FData.sign.s);
   Result := true;
@@ -2285,13 +2291,13 @@ begin
             Result := Format('List account %s for sale price %s locked until block:%d fee:%s (n_op:%d) payload size:%d',[
               TAccountComp.AccountNumberToAccountTxtNumber(FData.account_target), TAccountComp.FormatMoney(FData.account_price),
               FData.locked_until_block, TAccountComp.FormatMoney(FData.fee),
-              FData.n_operation, Length(FData.payload)])
+              FData.n_operation, Length(FData.payload.payload_raw)])
           end else begin
             Result := Format('List account %s for private sale price %s reserved for %s locked until block:%d fee:%s (n_op:%d) payload size:%d',[
               TAccountComp.AccountNumberToAccountTxtNumber(FData.account_target), TAccountComp.FormatMoney(FData.account_price),
               TAccountComp.GetECInfoTxt(FData.new_public_key.EC_OpenSSL_NID),
               FData.locked_until_block, TAccountComp.FormatMoney(FData.fee),
-              FData.n_operation, Length(FData.payload)])
+              FData.n_operation, Length(FData.payload.payload_raw)])
           end;
         end;
         as_ForAtomicAccountSwap: begin
@@ -2301,7 +2307,7 @@ begin
             FData.locked_until_block,
             TAccountComp.FormatMoney(FData.fee),
             FData.n_operation,
-            Length(FData.payload)]
+            Length(FData.payload.payload_raw)]
           );
         end;
         as_ForAtomicCoinSwap: begin
@@ -2312,7 +2318,7 @@ begin
             FData.locked_until_block,
             TAccountComp.FormatMoney(FData.fee),
             FData.n_operation,
-            Length(FData.payload)]
+            Length(FData.payload.payload_raw)]
           );
         end;
       end;
@@ -2320,7 +2326,7 @@ begin
     lat_DelistAccount : begin
       Result := Format('Delist account %s for sale fee:%s (n_op:%d) payload size:%d',[
         TAccountComp.AccountNumberToAccountTxtNumber(FData.account_target), TAccountComp.FormatMoney(FData.fee),
-          FData.n_operation, Length(FData.payload)])
+          FData.n_operation, Length(FData.payload.payload_raw)])
     end;
   else Result := 'ERROR DEV 20170414-2';
   end;
@@ -2342,8 +2348,11 @@ begin
     ms.Write(FData.account_price,Sizeof(FData.account_price));
     ms.Write(FData.account_to_pay,Sizeof(FData.account_to_pay));
     ms.Write(FData.fee,Sizeof(FData.fee));
-    if Length(FData.payload)>0 then
-      ms.WriteBuffer(FData.payload[Low(FData.payload)],Length(FData.payload));
+    if current_protocol>=CT_PROTOCOL_5 then begin
+      ms.Write(FData.payload.payload_type,SizeOf(FData.payload.payload_type));
+    end;
+    if Length(FData.payload.payload_raw)>0 then
+      ms.WriteBuffer(FData.payload.payload_raw[Low(FData.payload.payload_raw)],Length(FData.payload.payload_raw));
     ms.Write(FData.public_key.EC_OpenSSL_NID,Sizeof(FData.public_key.EC_OpenSSL_NID));
     if Length(FData.public_key.x)>0 then
       ms.WriteBuffer(FData.public_key.x[Low(FData.public_key.x)],Length(FData.public_key.x));
@@ -2375,7 +2384,7 @@ end;
 
 { TOpListAccountForSaleOrSwap }
 
-constructor TOpListAccountForSaleOrSwap.CreateListAccountForSaleOrSwap(ACurrentProtocol : Word; ANewAccountState : TAccountState; AAccountSigner, ANOperation, AAccountTarget: Cardinal; AAccountPrice, AFee: UInt64; AAccountToPay: Cardinal;  ANewPublicKey: TAccountKey; ALockedUntilBlock: Cardinal; AKey: TECPrivateKey;  const AHashLock : T32Bytes; const APayload: TRawBytes);
+constructor TOpListAccountForSaleOrSwap.CreateListAccountForSaleOrSwap(ACurrentProtocol : Word; ANewAccountState : TAccountState; AAccountSigner, ANOperation, AAccountTarget: Cardinal; AAccountPrice, AFee: UInt64; AAccountToPay: Cardinal;  ANewPublicKey: TAccountKey; ALockedUntilBlock: Cardinal; AKey: TECPrivateKey;  const AHashLock : T32Bytes; const APayload: TOperationPayload);
 begin
   inherited Create(ACurrentProtocol);
   case ANewAccountState of
@@ -2440,7 +2449,7 @@ end;
 
 { TOpDelistAccountForSale }
 
-constructor TOpDelistAccountForSale.CreateDelistAccountForSale(ACurrentProtocol : Word; account_signer, n_operation, account_target: Cardinal; fee: UInt64; key: TECPrivateKey; payload: TRawBytes);
+constructor TOpDelistAccountForSale.CreateDelistAccountForSale(ACurrentProtocol : Word; account_signer, n_operation, account_target: Cardinal; fee: UInt64; key: TECPrivateKey; const payload: TOperationPayload);
 begin
   inherited Create(ACurrentProtocol);
   FData.account_signer := account_signer;
@@ -2468,7 +2477,7 @@ end;
 
 constructor TOpBuyAccount.CreateBuy(ACurrentProtocol : Word; account_number, n_operation, account_to_buy,
   account_to_pay: Cardinal; price, amount, fee: UInt64;
-  new_public_key: TAccountKey; key: TECPrivateKey; payload: TRawBytes);
+  new_public_key: TAccountKey; key: TECPrivateKey; const payload: TOperationPayload);
 begin
   inherited Create(ACurrentProtocol);
   FData.sender := account_number;
@@ -2535,7 +2544,7 @@ begin
   Stream.Write(FData.dataSequence,Sizeof(FData.dataSequence));
   Stream.Write(FData.amount,Sizeof(FData.amount));
   Stream.Write(FData.fee,Sizeof(FData.fee));
-  TStreamOp.WriteAnsiString(Stream,FData.payload);
+  SaveOperationPayloadToStream(Stream,FData.payload);
   TStreamOp.WriteAnsiString(Stream,FData.sign.r);
   TStreamOp.WriteAnsiString(Stream,FData.sign.s);
   Result := true;
@@ -2558,7 +2567,7 @@ begin
   Stream.Read(FData.dataSequence,Sizeof(FData.dataSequence));
   Stream.Read(FData.amount,Sizeof(FData.amount));
   Stream.Read(FData.fee,Sizeof(FData.fee));
-  if TStreamOp.ReadAnsiString(Stream,FData.payload)<0 then exit;
+  if Not LoadOperationPayloadFromStream(Stream,FData.payload) then Exit;
   if TStreamOp.ReadAnsiString(Stream,FData.sign.r)<0 then exit;
   if TStreamOp.ReadAnsiString(Stream,FData.sign.s)<0 then exit;
   Result := true;
@@ -2711,8 +2720,8 @@ begin
     Exit;
   end;
 
-  if (length(FData.payload)>CT_MaxPayloadSize) then begin
-    errors := 'Invalid Payload size:'+inttostr(length(FData.payload))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
+  if (length(FData.payload.payload_raw)>CT_MaxPayloadSize) then begin
+    errors := 'Invalid Payload size:'+inttostr(length(FData.payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
     Exit;
   end;
 
@@ -2738,7 +2747,7 @@ begin
   Result := FData.fee;
 end;
 
-function TOpData.OperationPayload: TRawBytes;
+function TOpData.OperationPayload: TOperationPayload;
 begin
   Result := FData.payload;
 end;
@@ -2785,7 +2794,7 @@ end;
 
 constructor TOpData.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);
+  dataType, dataSequence: Word; AGUID : TGUID; amount, fee: UInt64; const payload: TOperationPayload);
 begin
   Inherited Create(ACurrentProtocol);
   FData.account_sender:=account_sender;
@@ -2833,7 +2842,7 @@ begin
     Stream.Write(FData.dataSequence,Sizeof(FData.dataSequence));
     Stream.Write(FData.amount,Sizeof(FData.amount));
     Stream.Write(FData.fee,Sizeof(FData.fee));
-    TStreamOp.WriteAnsiString(Stream,FData.payload);
+    SaveOperationPayloadToStream(Stream,FData.payload);
     b := OpType;
     Stream.Write(b,1);
     if (current_protocol<=CT_PROTOCOL_4) then begin

+ 9 - 9
src/core/UPCRPCOpData.pas

@@ -37,7 +37,7 @@ Type
        AInputParams : TPCJSONObject;
        const AAccountSignerPublicKey : TAccountKey;
        AAccountSigner, AAccountSender, AAccountTarget, ASender_last_n_operation : Cardinal;
-       Const ARawPayload : TRawBytes;
+       Const AOperationPayload : TOperationPayload;
        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;
@@ -54,7 +54,7 @@ class function TRPCOpData.CreateOpData(ARPCProcess: TRPCProcess;
   AInputParams : TPCJSONObject;
   const AAccountSignerPublicKey : TAccountKey;
   AAccountSigner, AAccountSender, AAccountTarget, ASender_last_n_operation: Cardinal;
-  const ARawPayload: TRawBytes;
+  const AOperationPayload: TOperationPayload;
   var AErrorNum: Integer; var AErrorDesc: String; var AOpData : TOpData): Boolean;
 var LSignerKey : TECPrivateKey;
   LGUID : TGUID;
@@ -98,7 +98,7 @@ begin
     LGUID,
     TPascalCoinJSONComp.ToPascalCoins(AInputParams.AsDouble('amount',0)),
     TPascalCoinJSONComp.ToPascalCoins(AInputParams.AsDouble('fee',0)),
-    ARawPayload);
+    AOperationPayload);
   Result := True;
 end;
 
@@ -310,7 +310,7 @@ class function TRPCOpData.OpData_SendOpData(const ASender: TRPCProcess;
   var AErrorNum: Integer; var AErrorDesc: String): Boolean;
 var LOpData : TOpData;
   LSigner, LSender, LTarget : TAccount;
-  LEncodedRawPayload : TRawBytes;
+  LOperationPayload : TOperationPayload;
   LErrors : String;
   LOPR : TOperationResume;
 begin
@@ -339,7 +339,7 @@ begin
     AInputParams.AsString('pwd',''),
     LSender.accountInfo.accountKey,
     LTarget.accountInfo.accountKey,
-    LEncodedRawPayload,AErrorNum,AErrorDesc) Then Exit;
+    LOperationPayload,AErrorNum,AErrorDesc) Then Exit;
 
 
   if Not CreateOpData(ASender,
@@ -350,7 +350,7 @@ begin
     LSender.account,
     LTarget.account,
     LSigner.n_operation,
-    LEncodedRawPayload,
+    LOperationPayload,
     AErrorNum, AErrorDesc, LOpData) then Exit;
 
   if LOpData=nil then Exit;
@@ -372,7 +372,7 @@ 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;
+  LOperationPayload : TOperationPayload;
   LErrors : String;
   LOPR : TOperationResume;
   LEncodePayloadType : String;
@@ -413,7 +413,7 @@ begin
       AInputParams.AsString('pwd',''),
       LPayloadPubkey,
       LPayloadPubkey,
-      LEncodedRawPayload,AErrorNum,AErrorDesc) then Exit;
+      LOperationPayload,AErrorNum,AErrorDesc) then Exit;
 
     if Not CreateOpData(ASender,
       AInputParams.AsInteger('protocol',CT_BUILD_PROTOCOL),
@@ -423,7 +423,7 @@ begin
       AInputParams.AsCardinal('sender',CT_MaxAccount),
       AInputParams.AsCardinal('target',CT_MaxAccount),
       AInputParams.AsCardinal('last_n_operation',0),
-      LEncodedRawPayload,
+      LOperationPayload,
       AErrorNum, AErrorDesc, LOpData) then Exit;
     if LOpData=nil then Exit;
     try

+ 6 - 4
src/core/UPCTNetDataExtraMessages.pas

@@ -134,7 +134,7 @@ var LSenderPublicKey : TAccountKey;
   LIndexKey : Integer;
   LAccount : TAccount;
   LOpChangeKey : TOpChangeKey;
-  LPayload : TRawBytes;
+  LPayload : TOperationPayload;
   LErrors : String;
   LWord : Word;
 begin
@@ -146,7 +146,8 @@ begin
   if TStreamOp.ReadAccountKey(AReceivedData,LSenderPublicKey)<=0 then Exit;
   if Not RandomGetWalletKeysAccount(FNode.Bank.SafeBox,FWalletKeys,0,10000,LIndexKey,LAccount) then Exit;
   // Send
-  LPayload.FromString('Free Account to '+ASenderConnection.Client.RemoteHost);
+  LPayload := CT_TOperationPayload_NUL;
+  LPayload.payload_raw.FromString('Free Account to '+ASenderConnection.Client.RemoteHost);
   LOpChangeKey := TOpChangeKey.Create(FNode.Bank.SafeBox.CurrentProtocol,LAccount.account,LAccount.n_operation+1,
     LAccount.account,FWalletKeys.Key[LIndexKey].PrivateKey,LSenderPublicKey,0,LPayload);
   try
@@ -168,7 +169,7 @@ var LSenderAccount : Cardinal;
   LIndexKey : Integer;
   LAccount : TAccount;
   LOpTransaction : TOpTransaction;
-  LPayload : TRawBytes;
+  LPayload : TOperationPayload;
   LErrors : String;
   LSendAmount : Int64;
   LInt : Integer;
@@ -187,7 +188,8 @@ begin
   if LSendAmount<=0 then Exit;
 
   // Send
-  LPayload.FromString('Free Money to '+ASenderConnection.Client.RemoteHost);
+  LPayload := CT_TOperationPayload_NUL;
+  LPayload.payload_raw.FromString('Free Money to '+ASenderConnection.Client.RemoteHost);
   LOpTransaction := TOpTransaction.CreateTransaction(FNode.Bank.SafeBox.CurrentProtocol,LAccount.account,LAccount.n_operation+1,
     LSenderAccount,FWalletKeys.Key[LIndexKey].PrivateKey,LSendAmount,0,LPayload);
   try

+ 48 - 33
src/core/URPC.pas

@@ -71,7 +71,7 @@ Type
     //
     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;
+    class function CheckAndGetEncodedRAWPayload(Const ARawPayload : TRawBytes; Const APayload_method, AEncodePwdForAES : String; const ASenderAccounKey, ATargetAccountKey : TAccountKey; out AOperationPayload : TOperationPayload; Var AErrorNum : Integer; Var AErrorDesc : String) : Boolean;
   end;
 
   TRPCServerThread = Class;
@@ -251,7 +251,8 @@ Begin
       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_s').Value := TAccountComp.FormatMoney (OPR.Senders[i].Amount * (-1));
-      auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Senders[i].Payload);
+      auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Senders[i].Payload.payload_raw);
+      auxObj.GetAsVariant('payload_type').Value := OPR.Senders[i].Payload.payload_type;
       if (OPR.OpType = CT_Op_Data) then begin
         FillOpDataObject(auxObj, OPR.senders[i].OpData);
       end;
@@ -263,7 +264,8 @@ Begin
       auxObj.GetAsVariant('account').Value := OPR.Receivers[i].Account;
       auxObj.GetAsVariant('amount').Value :=  TAccountComp.FormatMoneyDecimal(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);
+      auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(OPR.Receivers[i].Payload.payload_raw);
+      auxObj.GetAsVariant('payload_type').Value := OPR.Receivers[i].Payload.payload_type;
     end;
     jsonArr := jsonObject.GetAsArray('changers');
     for i:=Low(OPR.Changers) to High(OPR.Changers) do begin
@@ -320,7 +322,8 @@ Begin
   jsonObject.GetAsVariant('amount').Value:=TAccountComp.FormatMoneyDecimal(OPR.Amount);
   jsonObject.GetAsVariant('amount_s').Value:=TAccountComp.FormatMoney(OPR.Amount);
   if (Not OPR.isMultiOperation) then begin
-    jsonObject.GetAsVariant('payload').Value:=TCrypto.ToHexaString(OPR.OriginalPayload);
+    jsonObject.GetAsVariant('payload').Value:=TCrypto.ToHexaString(OPR.OriginalPayload.payload_raw);
+    jsonObject.GetAsVariant('payload_type').Value := OPR.OriginalPayload.payload_type;
   end;
   if (OPR.Balance>=0) And (OPR.valid) then jsonObject.GetAsVariant('balance').Value:=TAccountComp.FormatMoneyDecimal(OPR.Balance);
   If (OPR.OpType = CT_Op_Transaction) then begin
@@ -380,19 +383,24 @@ end;
 class function TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(
   const ARawPayload: TRawBytes; const APayload_method, AEncodePwdForAES: String;
   const ASenderAccounKey, ATargetAccountKey: TAccountKey;
-  var AEncodedRAWPayload: TRawBytes; var AErrorNum: Integer;
+  out AOperationPayload : TOperationPayload; var AErrorNum: Integer;
   var AErrorDesc: String): Boolean;
 begin
+  AOperationPayload := CT_TOperationPayload_NUL;
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // TODO:
+  // Needs to assign AOperationPayload.payload_type based on PIP-0027
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   if (Length(ARawPayload)>0) then begin
     if (APayload_method='none') then begin
-      AEncodedRAWPayload:=ARawPayload;
+      AOperationPayload.payload_raw:=ARawPayload;
       Result := True;
     end else if (APayload_method='dest') then begin
-      Result := TPCEncryption.DoPascalCoinECIESEncrypt(ATargetAccountKey,ARawPayload,AEncodedRAWPayload);
+      Result := TPCEncryption.DoPascalCoinECIESEncrypt(ATargetAccountKey,ARawPayload,AOperationPayload.payload_raw);
     end else if (APayload_method='sender') then begin
-      Result := TPCEncryption.DoPascalCoinECIESEncrypt(ASenderAccounKey,ARawPayload,AEncodedRAWPayload);
+      Result := TPCEncryption.DoPascalCoinECIESEncrypt(ASenderAccounKey,ARawPayload,AOperationPayload.payload_raw);
     end else if (APayload_method='aes') then begin
-      AEncodedRAWPayload := TPCEncryption.DoPascalCoinAESEncrypt(ARawPayload,TEncoding.ANSI.GetBytes(AEncodePwdForAES));
+      AOperationPayload.payload_raw := TPCEncryption.DoPascalCoinAESEncrypt(ARawPayload,TEncoding.ANSI.GetBytes(AEncodePwdForAES));
       Result := True;
     end else begin
       Result := False;
@@ -401,7 +409,6 @@ begin
       Exit;
     end;
   end else begin
-    AEncodedRAWPayload := Nil;
     Result := True;
   end;
 end;
@@ -488,7 +495,8 @@ begin
     auxObj.GetAsVariant('account').Value := multiOperation.Data.txSenders[i].Account;
     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('payload').Value := TCrypto.ToHexaString(multiOperation.Data.txSenders[i].Payload);
+    auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(multiOperation.Data.txSenders[i].Payload.payload_raw);
+    auxObj.GetAsVariant('payload_type').Value := multiOperation.Data.txSenders[i].Payload.payload_type;
   end;
   //
   jsonArr := jsonObject.GetAsArray('receivers');
@@ -496,7 +504,8 @@ begin
     auxObj := jsonArr.GetAsObject(jsonArr.Count);
     auxObj.GetAsVariant('account').Value := multiOperation.Data.txReceivers[i].Account;
     auxObj.GetAsVariant('amount').Value := TAccountComp.FormatMoneyDecimal(multiOperation.Data.txReceivers[i].Amount);
-    auxObj.GetAsVariant('payload').Value := TCrypto.ToHexaString(multiOperation.Data.txReceivers[i].Payload);
+    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;
   end;
   jsonArr := jsonObject.GetAsArray('changers');
   for i:=Low(multiOperation.Data.changesInfo) to High(multiOperation.Data.changesInfo) do begin
@@ -1146,13 +1155,13 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     Const senderAccounKey, targetAccountKey : TAccountKey; Const RawPayload : TRawBytes;
     Const Payload_method, EncodePwd : String) : TOpTransaction;
   // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
-  Var f_raw : TRawBytes;
+  Var LOpPayload : TOperationPayload;
     privateKey : TECPrivateKey;
   Begin
     Result := 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 TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,senderAccounKey,targetAccountKey,LOpPayload,ErrorNum,ErrorDesc) then Exit(Nil);
+    Result := TOpTransaction.CreateTransaction(current_protocol, sender,sender_last_n_operation+1,target,privateKey,amount,fee,LOpPayload);
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
       ErrorNum:=CT_RPC_ErrNum_InternalError;
@@ -1242,16 +1251,17 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
   // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
   var
     errors : String;
-    f_raw : TRawBytes;
+    LOpPayload : TOperationPayload;
     privateKey : TECPrivateKey;
   Begin
     Result := Nil;
+    LOpPayload := CT_TOperationPayload_NUL;
     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 Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_pubkey,new_pubkey,LOpPayload,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);
+      Result := TOpChangeKey.Create(current_protocol,account_signer,account_last_n_operation+1,account_target,privateKey,new_pubkey,fee,LOpPayload);
     end else begin
-      Result := TOpChangeKeySigned.Create(current_protocol,account_signer,account_last_n_operation+1,account_target,privateKey,new_pubkey,fee,f_raw);
+      Result := TOpChangeKeySigned.Create(current_protocol,account_signer,account_last_n_operation+1,account_target,privateKey,new_pubkey,fee,LOpPayload);
     end;
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
@@ -1305,7 +1315,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
   // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
   var privateKey : TECPrivateKey;
     errors : String;
-    f_raw : TRawBytes;
+    LOpPayload : TOperationPayload;
     aux_target_pubkey : TAccountKey;
   Begin
     Result := Nil;
@@ -1314,7 +1324,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         // 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 TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,aux_target_pubkey,f_raw,ErrorNum,ErrorDesc) then Exit(Nil);
+    if Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,aux_target_pubkey,LOpPayload,ErrorNum,ErrorDesc) then Exit(Nil);
     Result := TOpListAccountForSaleOrSwap.CreateListAccountForSaleOrSwap(
       current_protocol,
       ANewAccountState,
@@ -1328,7 +1338,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       locked_until_block,
       privateKey,
       AHashLock,
-      f_raw
+      LOpPayload
     );
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
@@ -1344,12 +1354,13 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     fee : UInt64; RawPayload : TRawBytes; Const Payload_method, EncodePwd : String) : TOpDelistAccountForSale;
   // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
   var privateKey : TECPrivateKey;
-    f_raw : TRawBytes;
+    LOpPayload : TOperationPayload;
   Begin
     Result := Nil;
+    LOpPayload := CT_TOperationPayload_NUL;
     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 TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,account_signer_pubkey,LOpPayload,ErrorNum,ErrorDesc) then Exit(Nil);
+    Result := TOpDelistAccountForSale.CreateDelistAccountForSale(current_protocol,account_signer,account_last_n_operation+1,account_delisted,fee,privateKey,LOpPayload);
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
       ErrorNum:=CT_RPC_ErrNum_InternalError;
@@ -1367,12 +1378,12 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
   // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
   var privateKey : TECPrivateKey;
     errors : String;
-    f_raw : TRawBytes;
+    LOpPayload : TOperationPayload;
   Begin
     Result := 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 TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_pubkey,new_account_pubkey,LOpPayload,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,LOpPayload);
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
       ErrorNum:=CT_RPC_ErrNum_InternalError;
@@ -1877,7 +1888,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
   // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
   var privateKey : TECPrivateKey;
     errors : String;
-    f_raw : TRawBytes;
+    LOpPayload : TOperationPayload;
     aux_target_pubkey : TAccountKey;
   Begin
     Result := Nil;
@@ -1886,13 +1897,13 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         // 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 TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,aux_target_pubkey,f_raw,ErrorNum,ErrorDesc) then Exit(Nil);
+    if Not TPascalCoinJSONComp.CheckAndGetEncodedRAWPayload(RawPayload,Payload_method,EncodePwd,account_signer_pubkey,aux_target_pubkey,LOpPayload,ErrorNum,ErrorDesc) then Exit(Nil);
     Result := TOpChangeAccountInfo.CreateChangeAccountInfo(current_protocol,
       account_signer,account_last_n_operation+1,account_target,
       privateKey,
       changePubKey,new_account_pubkey,changeName,new_name,changeType,new_type,
       AChangeAccountData,ANew_AccountData,
-      fee,f_raw);
+      fee,LOpPayload);
     if Not Result.HasValidSignature then begin
       FreeAndNil(Result);
       ErrorNum:=CT_RPC_ErrNum_InternalError;
@@ -2583,10 +2594,12 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         - "n_operation" : New n_operation value for account (remember, current + 1)
         - "amount" : PASCURRENCY
         - "payload" : HEXASTRING (optional)
+        - "payload_type" : Integer (optional) based on PIP-0027
       - "receivers" : ARRAY of OBJECT
         - "account"
         - "amount" : PASCURRENCY
         - "payload" : HEXASTRING (optional)
+        - "payload_type" : Integer (optional) based on PIP-0027
       - "changesinfo" : ARRAY of OBJECT
         - "account"
         - "n_operation" : New n_operation value for account (remember, current + 1)
@@ -2620,7 +2633,8 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         // Update N_Operation with valid info
         if (sender.N_Operation<=0) then sender.N_Operation:=Capture_Current_Account(sender.Account).n_operation+1;
 
-        sender.Payload:=TCrypto.HexaToRaw(jsonArr.GetAsObject(i).AsString('payload',''));
+        sender.Payload.payload_raw:=TCrypto.HexaToRaw(jsonArr.GetAsObject(i).AsString('payload',''));
+        sender.Payload.payload_type := jsonArr.GetAsObject(i).AsInteger('payload_type',CT_TOperationPayload_NUL.payload_type );
         if Not mop.AddTxSender(sender) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidData;
           ErrorDesc := 'Cannot add sender '+inttostr(sender.Account)+' duplicated or invalid data';
@@ -2639,7 +2653,8 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         end;
         receiver.Account := j;
         receiver.Amount:= ToPascalCoins(jsonArr.GetAsObject(i).AsDouble('amount',0));
-        receiver.Payload:=TCrypto.HexaToRaw(jsonArr.GetAsObject(i).AsString('payload',''));
+        receiver.Payload.payload_raw:=TCrypto.HexaToRaw(jsonArr.GetAsObject(i).AsString('payload',''));
+        receiver.Payload.payload_type := jsonArr.GetAsObject(i).AsInteger('payload_type',CT_TOperationPayload_NUL.payload_type);
         if Not mop.AddTxReceiver(receiver) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidData;
           ErrorDesc := 'Cannot add receiver '+inttostr(receiver.Account)+' invalid data';

+ 11 - 11
src/core/UTxMultiOperation.pas

@@ -128,7 +128,7 @@ Type
     class function OpType : Byte; override;
     function OperationAmount : Int64; override;
     function OperationFee : Int64; override;
-    function OperationPayload : TRawBytes; override;
+    function OperationPayload : TOperationPayload; override;
     function SignerAccount : Cardinal; override;
     procedure SignerAccounts(list : TList<Cardinal>); override;
     function IsSignerAccount(account : Cardinal) : Boolean; override;
@@ -330,7 +330,7 @@ begin
     stream.Write(txs.Account,SizeOf(txs.Account));
     stream.Write(txs.Amount,SizeOf(txs.Amount));
     stream.Write(txs.N_Operation,SizeOf(txs.N_Operation));
-    TStreamOp.WriteAnsiString(stream,txs.Payload);
+    SaveOperationPayloadToStream(stream,txs.Payload);
     If FSaveSignatureValue then begin
       TStreamOp.WriteAnsiString(stream,txs.Signature.r);
       TStreamOp.WriteAnsiString(stream,txs.Signature.s);
@@ -343,7 +343,7 @@ begin
     txr := FData.txReceivers[i];
     stream.Write(txr.Account,SizeOf(txr.Account));
     stream.Write(txr.Amount,SizeOf(txr.Amount));
-    TStreamOp.WriteAnsiString(stream,txr.Payload);
+    SaveOperationPayloadToStream(stream,txr.Payload);
   end;
   // Save changes info count
   w := Length(FData.changesInfo);
@@ -413,7 +413,7 @@ begin
         stream.Read(txs.Account,SizeOf(txs.Account));
         stream.Read(txs.Amount,SizeOf(txs.Amount));
         stream.Read(txs.N_Operation,SizeOf(txs.N_Operation));
-        TStreamOp.ReadAnsiString(stream,txs.Payload);
+        LoadOperationPayloadFromStream(stream,txs.Payload);
         TStreamOp.ReadAnsiString(stream,txs.Signature.r);
         TStreamOp.ReadAnsiString(stream,txs.Signature.s);
         //
@@ -429,7 +429,7 @@ begin
         txr := CT_TMultiOpReceiver_NUL;
         stream.Read(txr.Account,SizeOf(txr.Account));
         stream.Read(txr.Amount,SizeOf(txr.Amount));
-        TStreamOp.ReadAnsiString(stream,txr.Payload);
+        LoadOperationPayloadFromStream(stream,txr.Payload);
         //
         txreceivers[i] := txr;
       end;
@@ -599,8 +599,8 @@ begin
       errors := Format('Invalid amount %d (0 or max: %d)',[txs.Amount,CT_MaxTransactionAmount]);
       Exit;
     end;
-    if (length(txs.Payload)>CT_MaxPayloadSize) then begin
-      errors := 'Invalid Payload size:'+inttostr(length(txs.Payload))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
+    if (length(txs.Payload.payload_raw)>CT_MaxPayloadSize) then begin
+      errors := 'Invalid Payload size:'+inttostr(length(txs.Payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
       Exit;
     end;
     //
@@ -636,8 +636,8 @@ begin
       errors := Format('Invalid amount %d (0 or max: %d)',[txr.Amount,CT_MaxTransactionAmount]);
       Exit;
     end;
-    if (length(txr.Payload)>CT_MaxPayloadSize) then begin
-      errors := 'Invalid Payload size:'+inttostr(length(txr.Payload))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
+    if (length(txr.Payload.payload_raw)>CT_MaxPayloadSize) then begin
+      errors := 'Invalid Payload size:'+inttostr(length(txr.Payload.payload_raw))+' (Max: '+inttostr(CT_MaxPayloadSize)+')';
       Exit;
     end;
     //
@@ -825,9 +825,9 @@ begin
   Result := FTotalFee;
 end;
 
-function TOpMultiOperation.OperationPayload: TRawBytes;
+function TOpMultiOperation.OperationPayload: TOperationPayload;
 begin
-  SetLength(Result,0);
+  Result := CT_TOperationPayload_NUL;
 end;
 
 function TOpMultiOperation.SignerAccount: Cardinal;

+ 24 - 0
src/gui-classic/UFRMOperation.dfm

@@ -105,6 +105,10 @@ object FRMOperation: TFRMOperation
     TabOrder = 1
     object tsOperation: TTabSheet
       TabVisible = False
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object lblFee: TLabel
         Left = 15
         Top = 220
@@ -390,6 +394,10 @@ object FRMOperation: TFRMOperation
         object tsChangePrivateKey: TTabSheet
           Caption = 'Change Key'
           ImageIndex = 1
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object lblNewPrivateKey: TLabel
             Left = 57
             Top = 40
@@ -529,6 +537,10 @@ object FRMOperation: TFRMOperation
         object tsListAccount: TTabSheet
           Caption = 'List Account'
           ImageIndex = 3
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object lblListAccountErrors: TLabel
             Left = 11
             Top = 7
@@ -797,6 +809,10 @@ object FRMOperation: TFRMOperation
         object tsBuyAccount: TTabSheet
           Caption = 'Buy Account'
           ImageIndex = 4
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object lblAccountToBuy: TLabel
             Left = 13
             Top = 32
@@ -972,6 +988,10 @@ object FRMOperation: TFRMOperation
         end
         object tsChangeInfo: TTabSheet
           Caption = 'Change Info'
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object lblChangeInfoErrors: TLabel
             Left = 13
             Top = 10
@@ -1058,6 +1078,10 @@ object FRMOperation: TFRMOperation
     object tsGlobalError: TTabSheet
       ImageIndex = 1
       TabVisible = False
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object lblGlobalErrors: TLabel
         Left = 40
         Top = 50

+ 7 - 3
src/gui-classic/UFRMOperation.pas

@@ -157,7 +157,7 @@ type
     FNode : TNode;
     FWalletKeys: TWalletKeys;
     FDefaultFee: Int64;
-    FEncodedPayload : TRawBytes;
+    FEncodedPayload : TOperationPayload;
     FDisabled : Boolean;
     FSenderAccounts: TOrderedCardinalList; // TODO: TOrderedCardinalList should be replaced with a "TCardinalList" since signer account should be processed last
     procedure SetWalletKeys(const Value: TWalletKeys);
@@ -1535,7 +1535,11 @@ Var payload_u : AnsiString;
 begin
   valid := false;
   payload_encrypted := Nil;
-  FEncodedPayload := Nil;
+  FEncodedPayload := CT_TOperationPayload_NUL;
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // TODO:
+  // Needs to assign FEncodedPayload.payload_type based on PIP-0027
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   errors := 'Unknown error';
   payload_u := memoPayload.Lines.Text;
   try
@@ -1646,7 +1650,7 @@ begin
       lblEncryptionErrors.Caption := errors;
       lblPayloadLength.Caption := Format('(%db -> ?)',[length(payload_u)]);
     end;
-    FEncodedPayload := payload_encrypted;
+    FEncodedPayload.payload_raw := payload_encrypted;
     Result := valid;
   end;
 end;

+ 2 - 1
src/gui-classic/UFRMPayloadDecoder.dfm

@@ -191,6 +191,8 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
     object tsDecoded: TTabSheet
       Caption = 'Payload'
       ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
       ExplicitHeight = 178
       object Label7: TLabel
         Left = 15
@@ -270,7 +272,6 @@ object FRMPayloadDecoder: TFRMPayloadDecoder
     object tsDecodeMethods: TTabSheet
       Caption = 'Decode methods'
       ImageIndex = 1
-      ExplicitHeight = 161
       object lblPasswordsInfo: TLabel
         Left = 235
         Top = 143

+ 6 - 2
src/gui-classic/UFRMPayloadDecoder.pas

@@ -338,7 +338,7 @@ begin
     else if Value.Fee=0 then lblFee.Font.Color := clGray
     else lblFee.Font.Color := clRed;
     ebOpHash.text := TCrypto.ToHexaString(Value.OperationHash);
-    memoOriginalPayloadInHexa.Lines.Text := TCrypto.ToHexaString(Value.OriginalPayload);
+    memoOriginalPayloadInHexa.Lines.Text := TCrypto.ToHexaString(Value.OriginalPayload.payload_raw);
     if Assigned(FWalletKeys) then begin
       cbMethodPublicPayload.Checked := FAppParams.ParamByName['PayloadDecoder.notencrypted'].GetAsBoolean(true);
       cbUsingPrivateKeys.Checked := FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].GetAsBoolean(true);
@@ -401,8 +401,12 @@ Var raw : TRawBytes;
   ok : boolean;
 begin
   ok := true;
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  // TODO:
+  // Needs to check valid .payload_type based on PIP-0027
+  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   if Assigned(FWalletKeys) And Assigned(FAppParams) then begin
-    raw := FOpResume.OriginalPayload;
+    raw := FOpResume.OriginalPayload.payload_raw;
     if Length(raw)>0 then begin
       // First try to a human readable...
       if (cbMethodPublicPayload.Checked) and (TCrypto.IsHumanReadable(raw)) then begin

+ 2 - 8
src/gui-classic/UFRMRPCCalls.dfm

@@ -128,15 +128,11 @@ object FRMRPCCalls: TFRMRPCCalls
       end
       object tsJSONParams: TTabSheet
         Caption = 'Params as JSON'
-        ExplicitLeft = 0
-        ExplicitTop = 0
-        ExplicitWidth = 0
-        ExplicitHeight = 0
         object mJSONParams: TMemo
           Left = 0
           Top = 0
-          Width = 238
-          Height = 172
+          Width = 281
+          Height = 194
           Align = alClient
           ScrollBars = ssVertical
           TabOrder = 0
@@ -151,7 +147,6 @@ object FRMRPCCalls: TFRMRPCCalls
       Anchors = [akLeft, akBottom]
       Caption = '&Send'
       Default = True
-      DoubleBuffered = True
       Glyph.Data = {
         36040000424D3604000000000000360000002800000010000000100000000100
         2000000000000004000064000000640000000000000000000000FFFFFF00FFFF
@@ -187,7 +182,6 @@ object FRMRPCCalls: TFRMRPCCalls
         FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
         FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
         FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00}
-      ParentDoubleBuffered = False
       TabOrder = 3
       OnClick = bbSendCommandClick
     end

+ 2 - 0
src/gui-classic/UFRMRPCCalls.pas

@@ -153,7 +153,9 @@ end;
 
 procedure TFRMRPCCalls.ShowCallInfo(infoType: TInfoType; value: String);
 begin
+  mCalls.Lines.BeginUpdate;
   mCalls.Lines.Add(Format('%s [%s] %s',[FormatDateTime('hh:nn:ss.zzz',Now),CT_TIntoType_Str[infoType],value]));
+  mCalls.Lines.EndUpdate;
 end;
 
 procedure TFRMRPCCalls.DoSendJSON(json: TPCJSONObject);

+ 2 - 11
src/gui-classic/UFRMRandomOperations.lfm

@@ -1,7 +1,7 @@
 object FRMRandomOperations: TFRMRandomOperations
-  Left = 744
+  Left = 783
   Height = 229
-  Top = 390
+  Top = 423
   Width = 439
   Caption = 'Random Operations'
   ClientHeight = 229
@@ -76,15 +76,6 @@ object FRMRandomOperations: TFRMRandomOperations
         OnClick = bbRandomOperationsClick
         TabOrder = 0
       end
-      object cbMaxSpeedMode: TCheckBox
-        Left = 232
-        Height = 19
-        Top = 6
-        Width = 101
-        Caption = 'Max speed mode'
-        OnClick = cbMaxSpeedModeClick
-        TabOrder = 1
-      end
     end
     object mLogs: TMemo
       Left = 0

+ 13 - 12
src/gui-classic/UFRMRandomOperations.pas

@@ -77,7 +77,6 @@ type
     pnlClient: TPanel;
     pnlTop: TPanel;
     pnlTop1: TPanel;
-    cbMaxSpeedMode : TCheckBox;
     procedure bbRandomOperationsClick(Sender: TObject);
     procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
     procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
@@ -109,7 +108,7 @@ type
 
   TRandomGenerateOperation = Class
   private
-    class function GetRandomPayload(Const AStartsWith : String) : TRawBytes;
+    class function GetRandomPayload(Const AStartsWith : String) : TOperationPayload;
   public
     class function GetRandomOwnDestination(const operationsComp : TPCOperationsComp; const aWalletKeys : TWalletKeysExt; out nAccount : Cardinal) : Boolean;
     class function GetRandomSigner(const operationsComp : TPCOperationsComp; const aWalletKeys : TWalletKeysExt; out iKey : Integer; out nAccount : Cardinal) : Boolean;
@@ -300,16 +299,17 @@ begin
 end;
 
 class function TRandomGenerateOperation.GetRandomPayload(
-  const AStartsWith: String): TRawBytes;
+  const AStartsWith: String): TOperationPayload;
 var i,j : Integer;
 begin
-  Result.FromString(AStartsWith);
+  Result := CT_TOperationPayload_NUL;
+  Result.payload_raw.FromString(AStartsWith);
   j := Random(255);
-  if j<Length(Result) then j := Length(Result);
+  if j<Length(Result.payload_raw) then j := Length(Result.payload_raw);
 
-  SetLength(Result,j);
-  for i := Length(Result) to j-1 do begin
-    Result[j] := Random(127-32)+32;
+  SetLength(Result.payload_raw,j);
+  for i := Length(Result.payload_raw) to j-1 do begin
+    Result.payload_raw[j] := Random(127-32)+32;
   end;
 
 end;
@@ -359,7 +359,7 @@ var nAccount, nAccountTarget : Cardinal;
   senderAcc, LDestAcc : TAccount;
   amount,fees : Int64;
   errors : String;
-  LPayload : TRawBytes;
+  LPayload : TOperationPayload;
 begin
   Result := 0;
   If Not GetRandomSigner(operationsComp,aWalletKeys,iKey,nAccount) then Exit;
@@ -369,10 +369,11 @@ begin
   while (nRounds<Maxtransaction) do begin
     senderAcc := operationsComp.SafeBoxTransaction.Account(nAccount);
     LDestAcc := operationsComp.SafeBoxTransaction.Account(nAccountTarget);
+    LPayload := CT_TOperationPayload_NUL;
     if TAccountComp.IsAccountForSwap( LDestAcc.accountInfo ) then begin
       // Special case, will swap? Will need to provide a HASHLOCK in payload
-      LPayload := GetHashLock_Private;
-    end else LPayload := Nil;
+      LPayload.payload_raw := GetHashLock_Private;
+    end;
 
     amount := 1; // Minimal amount
     if (Random(500)<1) then fees := 0
@@ -431,7 +432,7 @@ begin
     opCk := TOpChangeKey(opClass.NewInstance).Create(current_protocol,senderAcc.account,senderAcc.n_operation+1,nAccountTarget,
       aWalletKeys.Key[iKey].PrivateKey,
       aWalletKeys.Key[iNewPubKey].AccountKey,
-      fees,Nil);
+      fees,CT_TOperationPayload_NUL);
     Try
       if operationsComp.AddOperation(True,opCk,errors) then inc(Result);
     finally

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

@@ -974,10 +974,10 @@ begin
   If (OperationResume.isMultiOperation) then begin
     Strings.Add('Multioperation:');
     For i := 0 to High(OperationResume.Senders) do begin
-      Strings.Add(Format('  Sender (%d/%d): %s %s PASC Payload:%s',[i+1,length(OperationResume.Senders),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Senders[i].Account),TAccountComp.FormatMoney(OperationResume.Senders[i].Amount),TCrypto.ToHexaString(OperationResume.Senders[i].Payload)]));
+      Strings.Add(Format('  Sender (%d/%d): %s %s PASC Payload(%d):%s',[i+1,length(OperationResume.Senders),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Senders[i].Account),TAccountComp.FormatMoney(OperationResume.Senders[i].Amount),OperationResume.Senders[i].Payload.payload_type,OperationResume.Senders[i].Payload.payload_raw.ToHexaString]));
     end;
     For i := 0 to High(OperationResume.Receivers) do begin
-      Strings.Add(Format('  Receiver (%d/%d): %s %s PASC Payload:%s',[i+1,length(OperationResume.Receivers),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Receivers[i].Account),TAccountComp.FormatMoney(OperationResume.Receivers[i].Amount),TCrypto.ToHexaString(OperationResume.Receivers[i].Payload)]));
+      Strings.Add(Format('  Receiver (%d/%d): %s %s PASC Payload(%d):%s',[i+1,length(OperationResume.Receivers),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Receivers[i].Account),TAccountComp.FormatMoney(OperationResume.Receivers[i].Amount),OperationResume.Receivers[i].Payload.payload_type,OperationResume.Receivers[i].Payload.payload_raw.ToHexaString]));
     end;
     For i := 0 to High(OperationResume.Changers) do begin
       Strings.Add(Format('  Change info (%d/%d): %s [%s]',[i+1,length(OperationResume.Changers),TAccountComp.AccountNumberToAccountTxtNumber(OperationResume.Changers[i].Account),TOpMultiOperation.OpChangeAccountInfoTypesToText(OperationResume.Changers[i].Changes_type)]));
@@ -989,12 +989,12 @@ begin
   If (Length(OperationResume.OperationHash_OLD)>0) then begin
     Strings.Add(Format('Old Operation Hash (old_ophash): %s',[TCrypto.ToHexaString(OperationResume.OperationHash_OLD)]));
   end;
-  if (Length(OperationResume.OriginalPayload)>0) then begin
-    Strings.Add(Format('Payload length:%d',[length(OperationResume.OriginalPayload)]));
+  Strings.Add(Format('Payload type:%d length:%d',[OperationResume.OriginalPayload.payload_type, length(OperationResume.OriginalPayload.payload_raw)]));
+  if (Length(OperationResume.OriginalPayload.payload_raw)>0) then begin
     If OperationResume.PrintablePayload<>'' then begin
       Strings.Add(Format('Payload (human): %s',[OperationResume.PrintablePayload]));
     end;
-    Strings.Add(Format('Payload (Hexadecimal): %s',[TCrypto.ToHexaString(OperationResume.OriginalPayload)]));
+    Strings.Add(Format('Payload (Hexadecimal): %s',[TCrypto.ToHexaString(OperationResume.OriginalPayload.payload_raw)]));
   end;
   If OperationResume.Balance>=0 then begin
     Strings.Add(Format('Final balance: %s',[TAccountComp.FormatMoney(OperationResume.Balance)]));