MinaProtocol / mina

Mina is a cryptocurrency protocol with a constant size blockchain, improving scaling while maintaining decentralization and security.
https://minaprotocol.com
Apache License 2.0
1.97k stars 523 forks source link

token transfers in parties generator #11751

Open deepthiskumar opened 1 year ago

deepthiskumar commented 1 year ago

For token transfers and token minting, we want to make it as generalized as possible. Currently token transactions are generated using a helper function called gen_parties_with_token_accounts. This function generations a tree of parties. Right now it simply outputs a tree with root (token-owner's party) and a single node (party for minted token). I would use some pseudo-code to display this function

let gen_parties_with_token_accounts ~num_parties =
  let rec go acc n =
    if n <= 0 then return (List.rev acc)
    else
      let%bind parent = gen_party_from ... in
      let%bind child = gen_party_from ... in
      gen_tree (mk_node parent [ mk_node child [] ] :: acc) (n - 1)
  in
  go [] num_parties 

Here's a plan to make token transactions more randomized in a few steps:

  1. Currently during token minting, only 1 account would be created and a fixed amount of minted token would be added to that account. We can make the number of created account and the amount randomized.
    let gen_parties_with_token_accounts ~num_parties =
    let rec go acc n =
    if n <= 0 then return (List.rev acc)
    else
      let%bind parent = gen_party_from ... in
      let%bind num_of_children = Int.gen_uniform_incl ... in
      let%bind children = Quickcheck.Generators.list_with_length num_of_children (gen_party_from ...) in
      gen_tree (mk_node parent (List.map children ~f:(fun child -> mk_node child [])) :: acc) (n - 1)
    in
    go [] num_parties
  2. We also want trees with depth greater than 1, which means that children could also be token owner for other tokens. We could add a depth variable and let the function refers to itself when creating the children.
    let gen_parties_with_token_accounts ~num_parties ~depth =
    let rec gen_tree n =
    if n <= 0 then return []
    else
      let%bind parent = gen_party_from ... in
      let%bind has_child = Quickcheck.Generators.bool in
      let%bind num_of_children = 
        if has_child then Int.gen_uniform_incl 1 width
        else return 0
      in
      let%bind children = Quickcheck.Generators.list_with_length num_of_children (gen_party_from ...) in
      gen_tree (mk_node parent (List.map children ~f:(fun child -> mk_node child (gen_tree (n-1))))
    in
    let rec go acc n =
    if n <= 0 then return (List.rev acc)
    else
      let%bind tree = gen_tree depth in
      go (tree :: acc) (n - 1)
    in
    go [] num_parties
  3. We also want generating token transfers between those accounts. To achieve this we need to record the tree structure of token owners and token holders. This could be done by recording the token owner of the newly created token accounts in account_state_tbl
    
    type role = [ `Fee_payer | `New | `Ordinary | `New_token of Account_id.t ]

type account_state_tbl = (Account.t * role) Account_id.Table.t

And we need a helper function that takes the `account state tbl` and a token_owner, then returns a list of children.

val token_holders : account_state_tbl -> ~token_owner:Account_id.t -> Account_id.t

This way we could modifies the original function to do token transfers:

let gen_parties_with_token_accounts ~num_parties ~depth = let rec gen_tree n = if n <= 0 then return [] else let%bind parent = gen_party_from ... in let%bind has_child = Quickcheck.Generators.bool in let%bind num_of_children = if has_child then Int.gen_uniform_incl 1 width else return 0 in let%bind children = Quickcheck.Generators.list_with_length num_of_children ( let%bind account_id = let holders = token_holders account_state_tbl ~token_owner:parent.account_id in if List.is_empty holders then return None else let%bind token_transfer = Quickcheck.Generators.bool in Quickcheck.Generators.of_list holders in gen_party_from ... ~account_id ...) in gen_tree (mk_node parent (List.map children ~f:(fun child -> mk_node child (gen_tree (n-1)))) in let rec go acc n = if n <= 0 then return (List.rev acc) else let%bind tree = gen_tree depth in go (tree :: acc) (n - 1) in go [] num_parties


This way we can make token minting and transfers as generalized as possible.
ghost-not-in-the-shell commented 1 year ago

The above changes would greatly increase the size of generated parties. This would directly affect the transaction_pool.ml test. Since the size of parties are increased, the size of keymap would also need to be increased. Thus any code that uses gen_parties_from function needs to modifies the generation of keymap to keep up with the changes.