<commit_before>unit UTxMultiOperation;

{$IFDEF FPC}
  {$mode delphi}
{$ENDIF}

{ Copyright (c) 2018 by <NAME> - PascalCoin developers

  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 Pascal Coin, a P2P crypto currency without need of
  historical operations.

  If you like it, consider a donation using BitCoin:
  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk

  }

interface

uses
  Classes, SysUtils, UCrypto, UBlockChain, UAccounts;

Type

  // NEW OPERATIONS PROTOCOL 3

  { TOpMultiOperation }

  {
    Based on PIP-0017, proposed by <NAME> <<EMAIL>>

    Will include multiple operations (tx, changes of info...) in a single operation

    Those operations could be:
      - Send from N accounts to M receivers,  (transaction mixing, with anonymity)
      - Change account info:
        - Change account public key
        - Change account type
        - Change account name

    This operation will work as a TRANSACTION operation, so, will execute ALL opererations or NONE

    Also, can be signed off-line by all senders/signers, knowing previously the OpHash because
    the OpHash algo will not include the signature (due it's checked separately)

    ALLOWED:
    - N senders to M receivers
    - Each sender can add a Payload
    - Each receiver can receive a Payload
    - Allow receive multiple incomes in a single receiver. For example:
      - Account A sends X coins to account B three times (X1,X2,X3) using Payload to discriminate (3 operations with only 1 signer, account A).
        - Example: Pool sending rewards to an exchange. Only 1 sender and to 1 receiver but multiple times, each time with a distinct amount/payload
        - Sender: Account A, amount X
        - Receivers (three times same account):
           - Account B, amount X1, Payload value P1
           - Account B, amount X2, Payload value P2
           - Account B, amount X3, Payload value P3
        - X1+X2+X3 <= X  (Fee is X - (X1+X2+X3))
        - Affected accounts are only A and B
        - There is only 1 signature: Account A (less space!)

    LIMITATIONS:
    - At least 1 operation must be made (1 change info, or 1 send + 1 receive)
    - Obvious: Total amount sent >= total amount received
      - Operation fee will be (total sent - total received)
      - If no send/receive operation, then there is no fee in multioperation
    - Senders cannot be duplicated (sender A can send only 1 time)
    - Senders must have previously enough amount to send: Example
      - Account A had 0 coins previously
      - Account A receive X coins in this multioperation
      - Account A sends X coins in this multioperation: NOT POSSIBLE, no previous funds
    - Change account op cannot be duplicated
    - Cannot change name between 2 accounts: Example
      - Account A has name X  (X not null)
      - Account B has name Y  (Y not null)
      - Cannot change name X to B and Y to A at same multioperation
    - Senders cannot be both in change account info and viceversa: Example
      - Account A sends X
      - Account A changes info
      - Not allowed (same sender and same change info account)
    - When a transfer is made to an account in private sale mode, the receiver account
      will not execute a change private key, so sale will not be executed
  }

  TOpMultiOperationData = Record
    // senders are unique and not duplicable
    txSenders : TMultiOpSenders;
    // receivers can be duplicated
    txReceivers : TMultiOpReceivers;
    // changers are unique and not duplicable
    changesInfo : TMultiOpChangesInfo;
  end;

  TOpMultiOperation = Class(TPCOperation)
  private
    FData : TOpMultiOperationData;
    //
    FSaveSignatureValue : Boolean;
    FTotalAmount : Int64;
    FTotalFee : Int64;
    Function IndexOfAccountChangeNameTo(const newName : AnsiString) : Integer;
  protected
    procedure InitializeData; override;
    function SaveOpToStream(Stream: TStream; SaveExtendedData : Boolean): Boolean; override;
    function LoadOpFromStream(Stream: TStream; LoadExtendedData : Boolean): Boolean; override;
    procedure FillOperationResume(Block : Cardinal; getInfoForAllAccounts : Boolean; Affected_account_number : Cardinal; var OperationResume : TOperationResume); override;
  public
    function GetBufferForOpHash(UseProtocolV2 : Boolean): TRawBytes; override;

    function CheckSignatures(AccountTransaction : TPCSafeBoxTransaction; var errors : AnsiString) : Boolean;

    function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : AnsiString) : Boolean; override;
    procedure AffectedAccounts(list : TList); override;
    //
    Function GetTransactionHashToSign : TRawBytes;
    Function DoSignMultiOperationSigner(SignerAccount : Cardinal; key : TECPrivateKey) : Integer;
    class function OpType : Byte; override;
    function OperationAmount : Int64; override;
    function OperationFee : UInt64; override;
    function OperationPayload : TRawBytes; override;
    function SignerAccount : Cardinal; override;
    procedure SignerAccounts(list : TList); override;
    function IsSignerAccount(account : Cardinal) : Boolean; override;
    function DestinationAccount : Int64; override;
    function SellerAccount : Int64; override;
    function N_Operation : Cardinal; override;
    function GetAccountN_Operation(account : Cardinal) : Cardinal; override;
    function OperationAmountByAccount(account : Cardinal) : Int64; override;
    //
    Constructor CreateMultiOperation(const senders : TMultiOpSenders; const receivers : TMultiOpReceivers; const changes : TMultiOpChangesInfo; const senders_keys, changes_keys: Array of TECPrivateKey);
    Destructor Destroy; override;
    Function AddTx(const senders : TMultiOpSenders; const receivers : TMultiOpReceivers; setInRandomOrder : Boolean) : Boolean;
    Function AddChangeInfos(const changes : TMultiOpChangesInfo; setInRandomOrder : Boolean) : Boolean;
    Function AddTxSender(const sender : TMultiOpSender) : Boolean;
    Function AddTxReceiver(const receiver : TMultiOpReceiver) : Boolean;
    Function AddChangeInfo(const changeInfo : TMultiOpChangeInfo) : Boolean;
    //
    Function IndexOfAccountSender(nAccount : Cardinal) : Integer; overload;<commit_msg>Compile Fix: remove invalid override<commit_after>unit UTxMultiOperation;

{$IFDEF FPC}
  {$mode delphi}
{$ENDIF}

{ Copyright (c) 2018 by <NAME> - PascalCoin developers

  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 Pascal Coin, a P2P crypto currency without need of
  historical operations.

  If you like it, consider a donation using BitCoin:
  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk

  }

interface

uses
  Classes, SysUtils, UCrypto, UBlockChain, UAccounts;

Type

  // NEW OPERATIONS PROTOCOL 3

  { TOpMultiOperation }

  {
    Based on PIP-0017, proposed by <NAME> <<EMAIL>>

    Will include multiple operations (tx, changes of info...) in a single operation

    Those operations could be:
      - Send from N accounts to M receivers,  (transaction mixing, with anonymity)
      - Change account info:
        - Change account public key
        - Change account type
        - Change account name

    This operation will work as a TRANSACTION operation, so, will execute ALL opererations or NONE

    Also, can be signed off-line by all senders/signers, knowing previously the OpHash because
    the OpHash algo will not include the signature (due it's checked separately)

    ALLOWED:
    - N senders to M receivers
    - Each sender can add a Payload
    - Each receiver can receive a Payload
    - Allow receive multiple incomes in a single receiver. For example:
      - Account A sends X coins to account B three times (X1,X2,X3) using Payload to discriminate (3 operations with only 1 signer, account A).
        - Example: Pool sending rewards to an exchange. Only 1 sender and to 1 receiver but multiple times, each time with a distinct amount/payload
        - Sender: Account A, amount X
        - Receivers (three times same account):
           - Account B, amount X1, Payload value P1
           - Account B, amount X2, Payload value P2
           - Account B, amount X3, Payload value P3
        - X1+X2+X3 <= X  (Fee is X - (X1+X2+X3))
        - Affected accounts are only A and B
        - There is only 1 signature: Account A (less space!)

    LIMITATIONS:
    - At least 1 operation must be made (1 change info, or 1 send + 1 receive)
    - Obvious: Total amount sent >= total amount received
      - Operation fee will be (total sent - total received)
      - If no send/receive operation, then there is no fee in multioperation
    - Senders cannot be duplicated (sender A can send only 1 time)
    - Senders must have previously enough amount to send: Example
      - Account A had 0 coins previously
      - Account A receive X coins in this multioperation
      - Account A sends X coins in this multioperation: NOT POSSIBLE, no previous funds
    - Change account op cannot be duplicated
    - Cannot change name between 2 accounts: Example
      - Account A has name X  (X not null)
      - Account B has name Y  (Y not null)
      - Cannot change name X to B and Y to A at same multioperation
    - Senders cannot be both in change account info and viceversa: Example
      - Account A sends X
      - Account A changes info
      - Not allowed (same sender and same change info account)
    - When a transfer is made to an account in private sale mode, the receiver account
      will not execute a change private key, so sale will not be executed
  }

  TOpMultiOperationData = Record
    // senders are unique and not duplicable
    txSenders : TMultiOpSenders;
    // receivers can be duplicated
    txReceivers : TMultiOpReceivers;
    // changers are unique and not duplicable
    changesInfo : TMultiOpChangesInfo;
  end;

  TOpMultiOperation = Class(TPCOperation)
  private
    FData : TOpMultiOperationData;
    //
    FSaveSignatureValue : Boolean;
    FTotalAmount : Int64;
    FTotalFee : Int64;
    Function IndexOfAccountChangeNameTo(const newName : AnsiString) : Integer;
  protected
    procedure InitializeData; override;
    function SaveOpToStream(Stream: TStream; SaveExtendedData : Boolean): Boolean; override;
    function LoadOpFromStream(Stream: TStream; LoadExtendedData : Boolean): Boolean; override;
    procedure FillOperationResume(Block : Cardinal; getInfoForAllAccounts : Boolean; Affected_account_number : Cardinal; var OperationResume : TOperationResume); override;
  public
    function GetBufferForOpHash(UseProtocolV2 : Boolean): TRawBytes; override;

    function CheckSignatures(AccountTransaction : TPCSafeBoxTransaction; var errors : AnsiString) : Boolean;

    function DoOperation(AccountPreviousUpdatedBlock : TAccountPreviousBlockInfo; AccountTransaction : TPCSafeBoxTransaction; var errors : AnsiString) : Boolean; override;
    procedure AffectedAccounts(list : TList); override;
    //
    Function GetTransactionHashToSign : TRawBytes;
    Function DoSignMultiOperationSigner(SignerAccount : Cardinal; key : TECPrivateKey) : Integer;
    class function OpType : Byte; override;
    function OperationAmount : Int64; override;
    function OperationFee : UInt64; override;
    function OperationPayload : TRawBytes; override;
    function SignerAccount : Cardinal; override;
    procedure SignerAccounts(list : TList);
    function IsSignerAccount(account : Cardinal) : Boolean; override;
    function DestinationAccount : Int64; override;
    function SellerAccount : Int64; override;
    function N_Operation : Cardinal; override;
    function GetAccountN_Operation(account : Cardinal) : Cardinal; override;
    function OperationAmountByAccount(account : Cardinal) : Int64; override;
    //
    Constructor CreateMultiOperation(const senders : TMultiOpSenders; const receivers : TMultiOpReceivers; const changes : TMultiOpChangesInfo; const senders_keys, changes_keys: Array of TECPrivateKey);
    Destructor Destroy; override;
    Function AddTx(const senders : TMultiOpSenders; const receivers : TMultiOpReceivers; setInRandomOrder : Boolean) : Boolean;
    Function AddChangeInfos(const changes : TMultiOpChangesInfo; setInRandomOrder : Boolean) : Boolean;
    Function AddTxSender(const sender : TMultiOpSender) : Boolean;
    Function AddTxReceiver(const receiver : TMultiOpReceiver) : Boolean;
    Function AddChangeInfo(const changeInfo : TMultiOpChangeInfo) : Boolean;
    //
    Function IndexOfAccountSender(nAccount : Cardinal) : Integer; overload;
{'fraction_non_alphanumeric': 0.060196463654223965, 'fraction_numerical': 0.008958742632612966, 'mean_word_length': 3.5385164051355207, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2205938', 'n_tokens_mistral': 3525, 'n_tokens_neox': 3346, 'n_words': 1378}