1. 引言

前序博客有:

  • Mina的支付流程

Mina中目前的交易类型主要有:

  • Coinbase交易:给产块者激励和手续费的交易,为内部交易。
  • Fee_transfer交易:给snark worker手续费的交易,为内部交易。
  • Payment交易:支付交易,为用户交易。
  • Stake_delegation交易:委托交易,为用户交易。
  • Parties交易:为支持zkApps智能合约创建的交易类型。

在Mina实际代码实现中,Payment交易和Stake_delegation交易共用Signed_command结构。

  • Payment交易示例为:
{"data": ["Signed_command",{"payload": {"common": {"fee": "0.03","fee_token": "1","fee_payer_pk": "B62qoiyAqMVg4hnWFa3mBLsWVJycekKeHLjZi7KdKUDrvdk2o5hyuAe","nonce": "0","valid_until": "4294967295","memo": "E4YVe5YCtgSZuaBo1RiwHFWqtPzV6Eur8xG6JnbzEigit5nZKobQG"},"body": ["Payment",{"source_pk": "B62qoiyAqMVg4hnWFa3mBLsWVJycekKeHLjZi7KdKUDrvdk2o5hyuAe","receiver_pk": "B62qpWaQoQoPL5AGta7Hz2DgJ9CJonpunjzCGTdw8KiCCD1hX8fNHuR","token_id": "1","amount": "15270000000"}]},"signer": "B62qoiyAqMVg4hnWFa3mBLsWVJycekKeHLjZi7KdKUDrvdk2o5hyuAe","signature": "7mXTZ6UJj2ZwGzF39ZvU9wnLeDTmHLitwDz7WfVtaXmwToDoVspgauzNKgrgwSzvxxusWsRMgFXyEZ4cTDHKDxmndDYuGLGM"}],"status": ["Applied",{"fee_payer_account_creation_fee_paid": null,"receiver_account_creation_fee_paid": null,"created_token": null},{"fee_payer_balance": "0","source_balance": "0","receiver_balance": "18032234944156559"}]
}
  • Stake_delegation交易示例为:
{"data": ["Signed_command",{"payload": {"common": {"fee": "0.0101","fee_token": "1","fee_payer_pk": "B62qp5MgMnCrd2bB8pGpPVmAntym3Qfx3vu7wBWwJ5p9e6eU9srYx9v","nonce": "0","valid_until": "4294967295","memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"},"body": ["Stake_delegation",["Set_delegate",{"delegator": "B62qp5MgMnCrd2bB8pGpPVmAntym3Qfx3vu7wBWwJ5p9e6eU9srYx9v","new_delegate": "B62qns9cPvDwckhJXHpWZZ8b8T8oUgoF4Enpax5zNVBYYMtQwHf4Cmp"}]]},"signer": "B62qp5MgMnCrd2bB8pGpPVmAntym3Qfx3vu7wBWwJ5p9e6eU9srYx9v","signature": "7mX2tu8ZxQbYkYWCCUKK6CpWhsAtPtiBWYkaa2BuJLJt4p934TfspRi7End8RKm5MBWXpqXGP4WxLv2NNjUPC1UiPM6KvnRn"}],"status": ["Applied",{"fee_payer_account_creation_fee_paid": null,"receiver_account_creation_fee_paid": null,"created_token": null},{"fee_payer_balance": "90989900000","source_balance": "90989900000","receiver_balance": "66002906100000"}]
}

区块内成功的交易标记为“Applied”,失败的交易标记为“Failed”,并会附上相应的失败原因,如“Amount_insufficient_to_create_account”:

{"data": ["Signed_command",{"payload": {"common": {"fee": "0.2001","fee_token": "1","fee_payer_pk": "B62qqscHMyaJrYW938bUEEWKGJRz7yzbd9HbWj6Ja1Aep2y75RwnnBi","nonce": "0","valid_until": "4294967295","memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"},"body": ["Payment",{"source_pk": "B62qqscHMyaJrYW938bUEEWKGJRz7yzbd9HbWj6Ja1Aep2y75RwnnBi","receiver_pk": "B62qrby8tq1SQGMzjwHiHJYupC1XtSy9XfwEELbJzuWrFWG1YNZXsC1","token_id": "1","amount": "100000000"}]},"signer": "B62qqscHMyaJrYW938bUEEWKGJRz7yzbd9HbWj6Ja1Aep2y75RwnnBi","signature": "7mXXAdE3L4kYfcDgA17cKp85wu2BQgdiEPgaALZ5PQTb9zvhr81vbRsn2h4YUoQY888Cbez2NBU2rEaq1eV6BDrd8o2WYANG"}],"status": ["Failed",["Amount_insufficient_to_create_account"],{"fee_payer_balance": "25370955635","source_balance": "25370955635","receiver_balance": null}]
}

本文重点关注Payment支付交易的 snark流程。

在Mina中,引入了snark worker来对交易进行snark:

Mina的实际代码实现中,其snark_worker模块主要提供了2个异步RPC接口:

  • get_work:snark worker通过get_work RPC接口获取待生成snark的work。
  • submit_work:完成snark的work通过submit_work RPC接口广播到网络。

Mina给新账号转账需要从收款方扣除1MINA的费用,具体逻辑为:apply_transaction/apply_user_command->apply_user_command_unchecked中有:

     (* Charge the account creation fee. *)let%bind receiver_amount =match receiver_location with| `Existing _ ->return amount| `New ->(* Subtract the creation fee from the transaction amount. *)sub_account_creation_fee ~constraint_constants `Added amount|> Result.map_error ~f:(fun _ ->Transaction_status.Failure.Amount_insufficient_to_create_account )inlet%map receiver_account =incr_balance receiver_account receiver_amountin  ........

2. Signed_command基本结构

Signed_command基本结构为:

 ( Payload.Stable.V2.t, Public_key.Stable.V1.t, Signature.Stable.V1.t )Poly.Stable.V1.ttype ('payload, 'pk, 'signature) t ={ payload : 'payload; signer : 'pk; signature : 'signature }(* payload结构为: *)
type t = (Common.Stable.V2.t, Body.Stable.V2.t) Poly.Stable.V1.t
type ('common, 'body) t = { common : 'common; body : 'body }(* payload.common结构为: *)type t =( Currency.Fee.Stable.V1.t  (* 为Unsigned.UInt64.t *), Public_key.Compressed.Stable.V1.t, Account_nonce.Stable.V1.t, Global_slot.Stable.V1.t, Memo.Stable.V1.t )Poly.Stable.V2.ttype ('fee, 'public_key, 'nonce, 'global_slot, 'memo) t ={ fee : 'fee  (* 为Unsigned.UInt64.t *); fee_payer_pk : 'public_key; nonce : 'nonce; valid_until : 'global_slot; memo : 'memo}
(* payload.body结构为: *)type t = Binable_arg.Stable.V2.t =| Payment of Payment_payload.Stable.V2.t| Stake_delegation of Stake_delegation.Stable.V1.t(* payload.body为Payment时的结构为: *)
type t =(Public_key.Compressed.Stable.V1.t, Amount.Stable.V1.t) Poly.Stable.V2.ttype ('public_key, 'amount) t ={ source_pk : 'public_key; receiver_pk : 'public_key; amount : 'amount }

3. Snark worker生成交易snark流程

3.1 Snark worker生成交易snark关键结构

  • 1)of_non_parties_transaction函数中的transaction_in_block参数,为Transaction.Valid.t Transaction_protocol_state.t类型:

    Transaction.Valid.t Transaction_protocol_state.ttype 'a t = { transaction : 'a; block_data : Block_data.Stable.V2.t }
    (* transaction类型,Transaction.Valid.t为: *)
    type t = User_command.Valid.Stable.V2.t Poly.Stable.V2.t
    type 'command t =| Command of 'command| Fee_transfer of Fee_transfer.Stable.V2.t| Coinbase of Coinbase.Stable.V1.t(* 本文只考虑Command类型,User_command.Valid.Stable.V2.t : *)
    type t =( Signed_command.With_valid_signature.Stable.V2.t, Parties.Valid.Stable.V1.t )Poly.Stable.V2.t
    type ('u, 's) t = Signed_command of 'u | Parties of 's(* 本文只考虑Signed_command类型, Signed_command.With_valid_signature.Stable.V2.t: *)
    type t = Stable.V2.t (* 对应为上面第2节的Signed_command结构。 *)(* block_data类型, Block_data.Stable.V2.t为:*)
    type t = Mina_state.Protocol_state.Body.Value.Stable.V2.ttype t = (* 为protocol_state结构 *)( State_hash.Stable.V1.t, Blockchain_state.Value.Stable.V2.t, Consensus.Data.Consensus_state.Value.Stable.V1.t, Protocol_constants_checked.Value.Stable.V1.t )Poly.Stable.V1.ttype ('state_hash, 'blockchain_state, 'consensus_state, 'constants) t ={ genesis_state_hash : 'state_hash; blockchain_state : 'blockchain_state; consensus_state : 'consensus_state; constants : 'constants}
    
  • 2)perform函数中有参数({ instances; fee } as spec : Work.Spec.t):【perform_single中有一个隐含参数“single: single_spec”,为Work.Single.Spec.t类型。】

    (* Work.Spec.t结构为: *)
    type t = Single.Spec.t Work.Spec.t
    type 'single t = 'single Stable.Latest.t =
    { instances : 'single One_or_two.t; fee : Currency.Fee.t } (* fee为 Unsigned.UInt64.t *)(* 其中instances类型,One_or_two.t为: *)
    type 'a t = [ `One of 'a | `Two of 'a * 'a ]
    (*  Single.Spec.t结构为: *)
    type t = (Transaction_witness.t, Ledger_proof.t) Work.Single.Spec.t(* Work.Single.Spec.t类型为: *)
    type ('witness, 'ledger_proof) t =('witness, 'ledger_proof) Stable.Latest.t =| Transition of Transaction_snark.Statement.t * 'witness| Merge of Transaction_snark.Statement.t * 'ledger_proof * 'ledger_proof
    

    本文只考虑“Transition”情况,其中Transaction_witness.t结构为:

    (* 本文只考虑“Transition”情况: *)
    ( * Transition_witness.t结构为: *)
    type t ={ transaction : Mina_transaction.Transaction.Stable.V2.t (* 本文只考虑Signed_command类型交易 *); ledger : Mina_ledger.Sparse_ledger.Stable.V2.t (* 包含indexes(由account_id和int组成的数组)、depth(int结构)、tree(由ledger_hash和account组成的数结构)三个字段。 *); protocol_state_body : Mina_state.Protocol_state.Body.Value.Stable.V2.t (* 包含genesis_state_hash/blockchain_state/consensus_state/constants这4个字段。 *); init_stack : Mina_base.Pending_coinbase.Stack_versioned.Stable.V1.t  (* data为Field.t,state(包含init/curr)也均为Field.t *) ; status : Mina_base.Transaction_status.Stable.V2.t (* 表示交易状态,为Appplied或Failed枚举类型。 *)}(*《1》 transaction类型,Mina_transaction.Transaction.Stable.V2.t结构为: *)
    type t = User_command.Stable.V2.t Poly.Stable.V2.t (* 见上面的1),本文只考虑Signed_command类型,见上面第2节。 *)(* 《2》ledger类型,Mina_ledger.Sparse_ledger.Stable.V2.t 结构为:*)
    type t =( Ledger_hash.Stable.V1.t (* 为哈希值,Field.t *), Account_id.Stable.V2.t (* 为压缩公钥与Pickles.Backend.Tick.Field.Stable.V1.t组合,Public_key.Compressed.Stable.V1.t * Digest.Stable.V1.t *), Account.Stable.V2.t ) (* Account结构中包含了:public_key/token_id/token_permissions/token_symbol/balance/nonce/receipt_chain_hash/delegate/voting_for/timing/permissions/zkapp/zkapp_uri字段 *)Sparse_ledger_lib.Sparse_ledger.T.Stable.V2.t
    type ('hash, 'key, 'account) t ={ indexes : ('key * int) list (* indexes为由account_id和int组成的数组 *); depth : int; tree : ('hash, 'account) Tree.Stable.V1.t (* 由ledger_hash和account组成的树结构。 *)}
    (* tree结构,('hash, 'account) Tree.Stable.V1.t 为: *)
    type ('hash, 'account) t = (* 为树结构,节点递归 *)| Account of 'account| Hash of 'hash| Node of 'hash * ('hash, 'account) t * ('hash, 'account) t(* Account.Stable.V2.t结构为: *)
    type t =( Public_key.Compressed.Stable.V1.t (* 为压缩公钥 *), Token_id.Stable.V1.t (* 为Pickles.Backend.Tick.Field.Stable.V1.t,对应Tick曲线的scalar域 *), Token_permissions.Stable.V1.t (* 分为Token_owned和Not_owned两种枚举类型,分别有disable_new_accounts和account_disabled bool字段。 *), Token_symbol.Stable.V1.t  (* 为string *), Balance.Stable.V1.t (* 为Unsigned.UInt64.t *), Nonce.Stable.V1.t (* 为Unsigned_extended.UInt32.t *), Receipt.Chain_hash.Stable.V1.t (* 为哈希值,Field.t *), Public_key.Compressed.Stable.V1.t option (* 为option,压缩公钥 *), State_hash.Stable.V1.t (* 为哈希值,Field.t *), Timing.Stable.V1.t (* 分为Untimed和Timed两种类型,其中Timed包含:initial_minimum_balance(为Unsigned.UInt64.t类型)、cliff_time(为global_slot,Unsigned_extended.UInt32.t类型)、cliff_amount(为Unsigned.UInt64.t类型)、vesting_period(为global_slot,Unsigned_extended.UInt32.t类型)、vesting_increment(为Unsigned.UInt64.t类型)这5个字段。 *), Permissions.Stable.V2.t (* 包含edit_state、send、receive、set_delegate、set_permissions、set_verification_key、set_zkapp_uri、edit_sequence_state、set_token_symbol、increment_nonce、set_voting_for这11个字段,均为Auth_required枚举类型——None | Either | Proof | Signature | Impossible。 *), Zkapp_account.Stable.V2.t option (* 为option,Zkapp_account包含:app_state(为Zkapp_basic.F.Stable.V1.t Vector.Vector_8.Stable.V1.t类型,为8 fields of 32 bytes each of arbitrary storage。)、verification_key(为option,包含data和hash2个字段,其中data为Side_loaded_verification_key类型)、zkapp_version(版本信息,为Unsigned_extended.UInt32.t类型)、sequence_state(为Pickles_types.Vector.Vector_5.Stable.V1.t为5 fields of 32 bytes each of arbitrary storage。)、last_sequqnece_slot(为global_slot,Unsigned_extended.UInt32.t类型)、proved_state(为bool值)这6个字段。 *), string )(* TODO: Cache the digest of this? *)Poly.Stable.V2.t
    type ( 'pk  (* 为压缩公钥 *), 'id  (* 为Pickles.Backend.Tick.Field.Stable.V1.t,对应Tick曲线的scalar域 *), 'token_permissions  (* 分为Token_owned和Not_owned两种枚举类型,分别有disable_new_accounts和account_disabled bool字段。 *), 'token_symbol (* 为string *), 'amount  (* 为Unsigned.UInt64.t *), 'nonce (* 为Unsigned_extended.UInt32.t *), 'receipt_chain_hash (* 为哈希值,Field.t *), 'delegate (* 为option,压缩公钥 *), 'state_hash (* 为哈希值,Field.t *), 'timing  (* 分为Untimed和Timed两种类型,其中Timed包含:initial_minimum_balance(为Unsigned.UInt64.t类型)、cliff_time(为global_slot,Unsigned_extended.UInt32.t类型)、cliff_amount(为Unsigned.UInt64.t类型)、vesting_period(为global_slot,Unsigned_extended.UInt32.t类型)、vesting_increment(为Unsigned.UInt64.t类型)这5个字段。 *), 'permissions  (* 包含edit_state、send、receive、set_delegate、set_permissions、set_verification_key、set_zkapp_uri、edit_sequence_state、set_token_symbol、increment_nonce、set_voting_for这11个字段,均为Auth_required枚举类型——None | Either | Proof | Signature | Impossible。 *), 'zkapp_opt (* 为option,Zkapp_account包含:app_state(为Zkapp_basic.F.Stable.V1.t Vector.Vector_8.Stable.V1.t类型,为8 fields of 32 bytes each of arbitrary storage。)、verification_key(为option,包含data和hash2个字段,其中data为Side_loaded_verification_key类型)、zkapp_version(版本信息,为Unsigned_extended.UInt32.t类型)、sequence_state(为Pickles_types.Vector.Vector_5.Stable.V1.t为5 fields of 32 bytes each of arbitrary storage.。)、last_sequqnece_slot(为global_slot,Unsigned_extended.UInt32.t类型)、proved_state(为bool值)这6个字段。 *), 'zkapp_uri ) (* 为string *)t ={ public_key : 'pk   (* 为压缩公钥 *); token_id : 'id  (* 为Pickles.Backend.Tick.Field.Stable.V1.t,对应Tick曲线的scalar域 *); token_permissions : 'token_permissions  (* 分为Token_owned和Not_owned两种枚举类型,分别有disable_new_accounts和account_disabled bool字段。 *); token_symbol : 'token_symbol  (* 为string *); balance : 'amount  (* 为Unsigned.UInt64.t *); nonce : 'nonce  (* 为Unsigned_extended.UInt32.t *); receipt_chain_hash : 'receipt_chain_hash  (* 为哈希值,Field.t *); delegate : 'delegate (* 为option,压缩公钥 *); voting_for : 'state_hash (* 为哈希值,Field.t *); timing : 'timing  (* 分为Untimed和Timed两种类型,其中Timed包含:initial_minimum_balance(为Unsigned.UInt64.t类型)、cliff_time(为global_slot,Unsigned_extended.UInt32.t类型)、cliff_amount(为Unsigned.UInt64.t类型)、vesting_period(为global_slot,Unsigned_extended.UInt32.t类型)、vesting_increment(为Unsigned.UInt64.t类型)这5个字段。 *); permissions : 'permissions  (* 包含edit_state、send、receive、set_delegate、set_permissions、set_verification_key、set_zkapp_uri、edit_sequence_state、set_token_symbol、increment_nonce、set_voting_for这11个字段,均为Auth_required枚举类型——None | Either | Proof | Signature | Impossible。 *); zkapp : 'zkapp_opt (* 为option,Zkapp_account包含:app_state(为Zkapp_basic.F.Stable.V1.t Vector.Vector_8.Stable.V1.t类型,为8 fields of 32 bytes each of arbitrary storage。)、verification_key(为option,包含data和hash2个字段,其中data为Side_loaded_verification_key类型)、zkapp_version(版本信息,为Unsigned_extended.UInt32.t类型)、sequence_state(为Pickles_types.Vector.Vector_5.Stable.V1.t为5 fields of 32 bytes each of arbitrary storage.。)、last_sequqnece_slot(为global_slot,Unsigned_extended.UInt32.t类型)、proved_state(为bool值)这6个字段。 *); zkapp_uri : 'zkapp_uri  (* 为string *)}(* 《3》protocol_state_body结构,Mina_state.Protocol_state.Body.Value.Stable.V2.t为: *)
    type t =( State_hash.Stable.V1.t (* 为哈希值,Field.t *), Blockchain_state.Value.Stable.V2.t (* 包含staged_ledger_hash/genesis_ledger_hash/registers/timestamp四个字段。 *), Consensus.Data.Consensus_state.Value.Stable.V1.t (* 包含blockchain_length/epoch_count/min_window_density/sub_window_densities/last_vrf_output/total_currency/curr_global_slot/global_slot_since_genesis/staking_epoch_data/next_epoch_data//has_ancestor_in_same_checkpoint_window/block_stake_winner/block_creator/coinbase_receiver/supercharge_coinbase这15个字段。 *), Protocol_constants_checked.Value.Stable.V1.t ) (* 包含k/slots_per_epoch/slots_per_sub_window/delta/genesis_state_timestamp这5个字段。 *)Poly.Stable.V1.t
    type ('state_hash, 'blockchain_state, 'consensus_state, 'constants) t ={ genesis_state_hash : 'state_hash  (* 为哈希值,Field.t *); blockchain_state : 'blockchain_state (* 包含staged_ledger_hash/genesis_ledger_hash/registers/timestamp四个字段。 *); consensus_state : 'consensus_state (* 包含blockchain_length/epoch_count/min_window_density/sub_window_densities/last_vrf_output/total_currency/curr_global_slot/global_slot_since_genesis/staking_epoch_data/next_epoch_data//has_ancestor_in_same_checkpoint_window/block_stake_winner/block_creator/coinbase_receiver/supercharge_coinbase这15个字段。 *); constants : 'constants (* 包含k/slots_per_epoch/slots_per_sub_window/delta/genesis_state_timestamp这5个字段。 *)}
    (* 其中protocol_state_body.blockchain_state字段为Blockchain_state.Value.Stable.V2.t结构: *)
    type t =( Staged_ledger_hash.Stable.V1.t (*staged_ledger_hash由2部分组成:pending_coinbase_hash和non_snark(再包含ledger_hash/aux_hash/pending_coinbase_aux三个字段)。*), Frozen_ledger_hash.Stable.V1.t (* 为Field.t *), Local_state.Stable.V1.t  (* 包含stack_frame/call_stack/transaction_commitment/full_transaction_commitment/token_id/excess/ledger/success/failure_status_tbl字段。 *), Block_time.Stable.V1.t ) (* 为Unsigned.UInt64.t *)Poly.Stable.V2.t
    type ('staged_ledger_hash, 'snarked_ledger_hash, 'local_state, 'time) t ={ staged_ledger_hash : 'staged_ledger_hash (*staged_ledger_hash由2部分组成:pending_coinbase_hash和non_snark(再包含ledger_hash/aux_hash/pending_coinbase_aux三个字段)。*); genesis_ledger_hash : 'snarked_ledger_hash (* 为Field.t *); registers :('snarked_ledger_hash, unit, 'local_state) Registers.Stable.V1.t (* 包含了ledger(为哈希值)、pending_coinbase_stack(为int)、local_state三个字段。 *); timestamp : 'time  (* 为Unsigned.UInt64.t *)}
    (* Registers.Stable.V1.t结构为: *)
    type ('ledger, 'pending_coinbase_stack, 'local_state) t ={ ledger : 'ledger (* 为哈希值。 *); pending_coinbase_stack : 'pending_coinbase_stack (* 为uint。 *); local_state : 'local_state (* 包含stack_frame/call_stack/transaction_commitment/full_transaction_commitment/token_id/excess/ledger/success/failure_status_tbl字段。 *)}
    (* protocol_state_body.blockchain_state.staged_ledger_hash字段为,Staged_ledger_hash.Stable.V1.t结构:*)
    (** Staged ledger hash has two parts1) merkle root of the pending coinbases2) ledger hash, aux hash, and the FIFO order of the coinbase stacks(Non snark).Only part 1 is required for blockchain snark computation and therefore the remaining fields of the staged ledger are grouped together as "Non_snark"*)
    type t =( Non_snark.Stable.V1.t  (* 包含ledger_hahs、aux_hash和pending_coinbase_aux 三个字段。 *), Pending_coinbase.Hash_versioned.Stable.V1.t )  (* 为哈希值,Field.t。 *)Poly.Stable.V1.t
    type ('non_snark, 'pending_coinbase_hash) t ={ non_snark : 'non_snark (* 包含ledger_hahs、aux_hash和pending_coinbase_aux 三个字段。 *); pending_coinbase_hash : 'pending_coinbase_hash (* 为哈希值,Field.t。 *)}
    (* non_snark, Non_snark.Stable.V1.t结构为:*)
    type t ={ ledger_hash : Ledger_hash.Stable.V1.t (* 为哈希值,Field.t *); aux_hash : Aux_hash.Stable.V1.t (* 为哈希值,string *); pending_coinbase_aux : Pending_coinbase_aux.Stable.V1.t (* 为string *)}
    (* consensus_state字段为,Consensus.Data.Consensus_state.Value.Stable.V1.t: *)
    type t =( Length.Stable.V1.t, Vrf.Output.Truncated.Stable.V1.t, Amount.Stable.V1.t, Global_slot.Stable.V1.t, Mina_numbers.Global_slot.Stable.V1.t, Epoch_data.Staking_value_versioned.Value.Stable.V1.t, Epoch_data.Next_value_versioned.Value.Stable.V1.t, bool, Public_key.Compressed.Stable.V1.t )Poly.Stable.V1.t
    type ( 'length, 'vrf_output, 'amount, 'global_slot, 'global_slot_since_genesis, 'staking_epoch_data, 'next_epoch_data, 'bool, 'pk )t ={ blockchain_length : 'length; epoch_count : 'length; min_window_density : 'length; sub_window_densities : 'length list; last_vrf_output : 'vrf_output; total_currency : 'amount; curr_global_slot : 'global_slot; global_slot_since_genesis : 'global_slot_since_genesis; staking_epoch_data : 'staking_epoch_data; next_epoch_data : 'next_epoch_data; has_ancestor_in_same_checkpoint_window : 'bool; block_stake_winner : 'pk; block_creator : 'pk; coinbase_receiver : 'pk; supercharge_coinbase : 'bool}(* 《4》 init_stack 字段,为 Mina_base.Pending_coinbase.Stack_versioned.Stable.V1.t结构: *)
    type t =(Coinbase_stack.Stable.V1.t, State_stack.Stable.V1.t) Poly.Stable.V1.t
    type ('data_stack, 'state_stack) t ={ data : 'data_stack; state : 'state_stack } (* data为Field.t,state(包含init/curr)也均为Field.t *)
    

    本文只考虑“Transition”情况,其中Transaction_snark.Statement.t结构为:

    type t =( Frozen_ledger_hash.Stable.V1.t (* 为Field.t,即为哈希值。 *), Currency.Amount.Stable.V1.t (* 为Unsigned.UInt64.t *), Pending_coinbase.Stack_versioned.Stable.V1.t (* data为Field.t,state中的init和curr均为哈希值。 *), Fee_excess.Stable.V1.t  (* 包含fee_token_l/fee_excess_l/fee_token_r/fee_excess_r 四个字段。 *), unit, Local_state.Stable.V1.t ) (* 包含stack_frame/call_stack/transaction_commitment/full_transaction_commitment/token_id/excess/ledger/success/failure_status_tbl字段。 *)Poly.Stable.V2.t
    (*   Poly.Stable.V2.t结构为:  *)type ( 'ledger_hash  (* 为哈希值。 *), 'amount (* 为Unsigned.UInt64.t *), 'pending_coinbase  (* data为Field.t,state中的init和curr均为哈希值。 *), 'fee_excess  (* 包含fee_token_l/fee_excess_l/fee_token_r/fee_excess_r 四个字段。 *), 'sok_digest (* 为uint。 *), 'local_state ) (* 包含stack_frame/call_stack/transaction_commitment/full_transaction_commitment/token_id/excess/ledger/success/failure_status_tbl字段。 *)t ={ source :( 'ledger_hash  (* 为哈希值。 *), 'pending_coinbase  (* data为Field.t,state中的init和curr均为哈希值。 *), 'local_state ) (* 包含stack_frame/call_stack/transaction_commitment/full_transaction_commitment/token_id/excess/ledger/success/failure_status_tbl字段。 *)Registers.Stable.V1.t; target :( 'ledger_hash  (* 为哈希值。 *), 'pending_coinbase  (* data为Field.t,state中的init和curr均为哈希值。 *), 'local_state ) (* 包含stack_frame/call_stack/transaction_commitment/full_transaction_commitment/token_id/excess/ledger/success/failure_status_tbl字段。 *)Registers.Stable.V1.t; supply_increase : 'amount (* 为Unsigned.UInt64.t *); fee_excess : 'fee_excess  (* 包含fee_token_l/fee_excess_l/fee_token_r/fee_excess_r 四个字段。 *); sok_digest : 'sok_digest (* 为uint。 *)}
    (* Registers.Stable.V1.t结构为: *)
    type ('ledger, 'pending_coinbase_stack, 'local_state) t ={ ledger : 'ledger (* 为哈希值。 *); pending_coinbase_stack : 'pending_coinbase_stack (* data为Field.t,state中的init和curr均为哈希值。 *); local_state : 'local_state (* 包含stack_frame/call_stack/transaction_commitment/full_transaction_commitment/token_id/excess/ledger/success/failure_status_tbl字段。 *)}
    

    其中Pending_coinbase.Stack_versioned.Stable.V1.t结构为:

    (* Pending_coinbase.Stack_versioned.Stable.V1.t结构为: *)
    type t =(Coinbase_stack.Stable.V1.t, State_stack.Stable.V1.t) Poly.Stable.V1.t
    type ('data_stack, 'state_stack) t ={ data : 'data_stack; state : 'state_stack }
    (* data类型,Coinbase_stack.Stable.V1.t为:Field.t *)
    (* state类型, State_stack.Stable.V1.t为: *)
    type t = Stack_hash.Stable.V1.t Poly.Stable.V1.t
    type 'stack_hash t = { init : 'stack_hash; curr : 'stack_hash }
    (* 其中init/curr均为 Stack_hash.Stable.V1.t ,本质即为Filed.t,即为哈希值 *)
    

    其中Fee_excess.Stable.V1.t结构为:

    (* Fee_excess.Stable.V1.t 结构为: *)
    type t =( Token_id.Stable.V1.t (* 为Pickles.Backend.Tick.Field.Stable.V1.t,对应Tick曲线的scalar域 *), (Fee.Stable.V1.t, Sgn.Stable.V1.t) Signed_poly.Stable.V1.t ) (* 其中的magnitude字段为Unsigned.UInt64.t,sgn字段为枚举类型Pos|Neg *)Poly.Stable.V1.t (* 包含fee_token_l/fee_excess_l/fee_token_r/fee_excess_r 四个字段。 *)(* Poly.Stable.V1.t结构为: *)
    type ('token, 'fee) t ={ fee_token_l : 'token; fee_excess_l : 'fee; fee_token_r : 'token; fee_excess_r : 'fee}
    (* Signed_poly.Stable.V1.t 结构为: *)
    type ('magnitude, 'sgn) t = { magnitude : 'magnitude; sgn : 'sgn }
    (* 其中magnitude类型,Fee.Stable.V1.t为:Unsigned.UInt64.t *)
    (* 其中sgn类型, Sgn.Stable.V1.t枚举类型Pos|Neg:*)
    type t = Sgn_type.Sgn.Stable.V1.t = Pos | Neg
    

    其中Local_state.Stable.V1.t结构为:【src/lib/transaction_logic/parties_logic.ml中的Local_state模块有:】

    type t =( Mina_base.Stack_frame.Digest.Stable.V1.t (* 为哈希值,Kimchi_backend.Pasta.Basic.Fp.Stable.V1.t *), Mina_base.Call_stack_digest.Stable.V1.t (* 为哈希值,Zkapp_basic.F.t *), Token_id.Stable.V1.t (* 为Pickles.Backend.Tick.Field.Stable.V1.t,对应Tick曲线的scalar域 *), ( Currency.Amount.Stable.V1.t  (* 为Unsigned.UInt64.t *), Sgn.Stable.V1.t ) (* 为枚举类型Pos|Neg *)Currency.Signed_poly.Stable.V1.t  (* 其中的magnitude字段为Unsigned.UInt64.t,sgn字段为枚举类型Pos|Neg *), Ledger_hash.Stable.V1.t (* 为哈希值,Field.t *), bool, Parties.Transaction_commitment.Stable.V1.t (* 为F.t *), Transaction_status.Failure.Collection.Stable.V1.t ) (* 为表示交易失败原因的二维数组。 *)Stable.V1.ttype ( 'stack_frame (* 为哈希值,Kimchi_backend.Pasta.Basic.Fp.Stable.V1.t *), 'call_stack (* 为哈希值,Zkapp_basic.F.t *), 'token_id  (* 为Pickles.Backend.Tick.Field.Stable.V1.t,对应Tick曲线的scalar域 *), 'excess  (* 其中的magnitude字段为Unsigned.UInt64.t,sgn字段为枚举类型Pos|Neg *), 'ledger (* 为哈希值,Field.t *), 'bool, 'comm (* 为F.t *), 'failure_status_tbl ) (* 为表示交易失败原因的二维数组。 *)t ={ stack_frame : 'stack_frame  (* 为哈希值,Kimchi_backend.Pasta.Basic.Fp.Stable.V1.t *); call_stack : 'call_stack (* 为哈希值,Zkapp_basic.F.t *); transaction_commitment : 'comm (* 为F.t *); full_transaction_commitment : 'comm (* 为F.t *); token_id : 'token_id  (* 为Pickles.Backend.Tick.Field.Stable.V1.t,对应Tick曲线的scalar域 *); excess : 'excess  (* 其中的magnitude字段为Unsigned.UInt64.t,sgn字段为枚举类型Pos|Neg *); ledger : 'ledger (* 为哈希值,Field.t *); success : 'bool; failure_status_tbl : 'failure_status_tbl (* 为表示交易失败原因的二维数组。 *)}
    
  • 3)perform_single中的参数 message:Mina_base.Sok_message.t:【其中的“fee”表示snark worker对其提供的snark work的定价;“prover”为snark worker用于生成交易snark的公钥。】

    (* Sok_message.t类型为: *)
    type t ={ fee : Currency.Fee.Stable.V1.t (* 为Unsigned.UInt64.t *); prover : Public_key.Compressed.Stable.V1.t )(* 为snark worker用于生成交易snark的公钥。 *)}
    
  • 4)perform_single中参数({ m; cache; proof_level } : Worker_state.t),为Worker_state.t类型:

    module type S = Transaction_snark.S
    type t ={ m : (module S) option (* 为调用Transaction_snark.Make返回的module *); cache : Cache.t (* cache缓存,key为statement,value为调用`Transaction_snark.S相应函数`返回的相应proof *); proof_level : Genesis_constants.Proof_level.t (* 只考虑为Full的情况 *)}
    

3.2 Snark worker生成交易snark关键流程

Snark worker生成交易snark流程为:

  • 1)src/lib/snark_worker/prod.ml中的perform_single

    let perform (s : Worker_state.t) public_key({ instances; fee } as spec : Work.Spec.t) =One_or_two.Deferred_result.map instances ~f:(fun w ->let open Deferred.Or_error.Let_syntax inlet%map proof, time =perform_single s~message:(Mina_base.Sok_message.create ~fee ~prover:public_key)win( proof, (time, match w with Transition _ -> `Transition | Merge _ -> `Merge)) )val perform_single :Worker_state.t-> message:Mina_base.Sok_message.t-> (Transaction_witness.t, Ledger_proof.t) Work.Single.Spec.t (* 对应隐含参数“single: signle_spec” *)-> (Ledger_proof.t * Time.Span.t) Deferred.Or_error.tlet perform_single ({ m; cache; proof_level } : Worker_state.t) ~message = (* 其中还有一个隐含参数“single: single_spec”,为Work.Single.Spec.t类型。 *)
    

    ||
    \/

  • 2)只考虑“Work.Single.Spec.Transition”类型,不考虑“Merge”类型。
    ||
    \/
  • 3)若交易是“Parties”类型,则额外处理;否则,对于“Signed_commnad”/“Fee_transfer”/"Coinbase"类型的交易,同一调用Transaction_snark的of_non_parties_transaction函数来生成相应的proof,会将proof添加到cache中。【其中statementinput为Transaction_snark.Statement.t类型(包含source、target、supply_increase、fee_excess、sok_digest五个字段),message为Sok_message.t类型(包含snark worker定价的fee和作为prover的公钥),sok_digest为对Sok_message类型message的哈希值。w为Transaction_witness.t类型(包含transaction、ledger、protocol_state_body、init_stack和status五个字段)。init_stack为 Mina_base.Pending_coinbase.Stack_versioned.Stable.V1.t 类型(其中data字段为Field.t,state字段(包含init/curr)也均为Field.t)。】
                           M.of_non_parties_transaction~statement:{ input with sok_digest }{ Transaction_protocol_state.Poly.transaction =t; block_data = w.protocol_state_body} (* 为transaction_in_block参数,为Transaction.Valid.t Transaction_protocol_state.t类型 *)~init_stack:w.init_stack(unstage(Mina_ledger.Sparse_ledger.handler w.ledger) )val of_non_parties_transaction :statement:Statement.With_sok.t-> init_stack:Pending_coinbase.Stack.t-> Transaction.Valid.t Transaction_protocol_state.t-> Tick.Handler.t-> t Async.Deferred.tlet of_non_parties_transaction ~statement ~init_stack transaction_in_blockhandler =
    

    transaction_in_block.transactiontransaction(为Mina_transaction.Transaction.Stable.V2.t类型(本文只考虑Signed_command类型交易)),取transaction_in_block.block_datastate_body(为Mina_state.Protocol_state.Body.Value.Stable.V2.t类型 (包含genesis_state_hash/blockchain_state/consensus_state/constants这4个字段。))。
    ||
    \/

  • 4)对transaction仍然调用Transaction_union.of_transaction,结果仍命名为transaction——目的是:恢复Signed_command结构,会在common内插入fee_token = Token_id.default字段,在body内插入token_id = Token_id.default字段。
    ||
    \/
  • 5)调用of_transation_union,返回{statement; proof}(为Ledger_proof.t结构(等价为Transaction_snark.t结构),详细见Mina中的ledger proof)。其中proof是调用Transaction_snark compile时返回的base函数。
    let%map proof =base [] (* 对应pickles.compile时的wrap函数的prevs参数。 *)~handler:(Base.transaction_union_handler handler transaction state_bodyinit_stack )statement  (* 对应pickles.compile时的wrap函数的next_state参数。 *)
    
  • 6)Base.rule的约束内容为:【即生成交易snark的约束系统】
    (* Someday:write the following soundness tests:- apply a transaction where the signature is incorrect- apply a transaction where the sender does not have enough money in their account- apply a transaction and stuff in the wrong target hash
    *)(* spec for [main statement]:constraints pass iff there existst : Tagged_transaction.tsuch that- applying [t] to ledger with merkle hash [l1] results in ledger with merkle hash [l2].- applying [t] to [pc.source] with results in pending coinbase stack [pc.target]- t has fee excess equal to [fee_excess]- t has supply increase equal to [supply_increase]where statement includesl1 : Frozen_ledger_hash.t,l2 : Frozen_ledger_hash.t,fee_excess : Amount.Signed.t,supply_increase : Amount.tpc: Pending_coinbase_stack_state.t
    *)
    let%snarkydef main ~constraint_constants(statement : Statement.With_sok.Checked.t) =
    let%bind () = dummy_constraints () in
    let%bind (module Shifted) = Tick.Inner_curve.Checked.Shifted.create () in
    let%bind t = (* 为transaction,Signed_command结构 *)with_label __LOC__(exists Transaction_union.typ ~request:(As_prover.return Transaction))
    in
    let%bind pending_coinbase_init = (* 为init_stack,为 Mina_base.Pending_coinbase.Stack_versioned.Stable.V1.t 类型(其中data字段为Field.t,state字段(包含init/curr)也均为Field.t) *)exists Pending_coinbase.Stack.typ ~request:(As_prover.return Init_stack)
    in
    let%bind state_body =(*  为state_body,为Mina_state.Protocol_state.Body.Value.Stable.V2.t类型 (包含genesis_state_hash/blockchain_state/consensus_state/constants这4个字段。*)exists(Mina_state.Protocol_state.Body.typ ~constraint_constants)~request:(As_prover.return State_body)
    in
    let%bind root_after, fee_excess, supply_increase =apply_tagged_transaction ~constraint_constants(module Shifted)statement.source.ledger pending_coinbase_initstatement.source.pending_coinbase_stackstatement.target.pending_coinbase_stack state_body t
    in
    let%bind fee_excess =(* Use the default token for the fee excess if it is zero.This matches the behaviour of [Fee_excess.rebalance], which allows[verify_complete_merge] to verify a proof without knowledge of theparticular fee tokens used.*)let%bind fee_excess_zero =Amount.Signed.Checked.equal fee_excessAmount.Signed.(Checked.constant zero)inlet%map fee_token_l =make_checked (fun () ->Token_id.Checked.if_ fee_excess_zero~then_:Token_id.(Checked.constant default)~else_:t.payload.common.fee_token )in{ Fee_excess.fee_token_l; fee_excess_l = Amount.Signed.Checked.to_fee fee_excess; fee_token_r = Token_id.(Checked.constant default); fee_excess_r = Fee.Signed.(Checked.constant zero)}
    in
    let%bind () =[%with_label "local state check"](make_checked (fun () ->Local_state.Checked.assert_equal statement.source.local_statestatement.target.local_state ) )
    in
    Checked.all_unit[ [%with_label "equal roots"](Frozen_ledger_hash.assert_equal root_after statement.target.ledger); [%with_label "equal supply_increases"](Currency.Amount.Checked.assert_equal supply_increasestatement.supply_increase ); [%with_label "equal fee excesses"](Fee_excess.assert_equal_checked fee_excess statement.fee_excess)]
    

    其中apply_tagged_transaction子约束系统为:【返回(final_root(又名root_after), fee_excess, supply_increase),fee_excess的目的是为了不泄露具体使用哪种token来支付的手续费。】

    • root:为statement.source.ledger,为哈希值;
    • pending_coinbase_stack_init:为Transaction_witness.t中的init_stack,为 Mina_base.Pending_coinbase.Stack_versioned.Stable.V1.t 类型(其中data字段为Field.t,state字段(包含init/curr)也均为Field.t)。
    • pending_coinbase_stack_before:为statement.source.pending_coinbase_stack,为Pending_coinbase.Stack_versioned.Stable.V1.t类型,其中data字段为Field.t,state字段中的init和curr均为哈希值。
    • pending_coinbase_after:为statement.target.pending_coinbase_stack,为Pending_coinbase.Stack_versioned.Stable.V1.t类型,其中data字段为Field.t,state字段中的init和curr均为哈希值。
    • state_body:为Mina_state.Protocol_state.Body.Value.Stable.V2.t类型 (包含genesis_state_hash/blockchain_state/consensus_state/constants这4个字段。
    • 将transaction(txn,为Signed_command类型)解析为signer; signature和payload。

      基本流程为:
    • 1)校验交易签名;
    • 2)校验交易签名者公钥与交易payload.common中的fee_payer_pk一致;
    • 3)fee_token_default:校验交易payload.common中的fee_token是否为Token_id.default,约束其必须为true;
    • 4)token_default:校验交易payload.body中的token_id是否为Token_id.default,约束其必须为true;
    • 5)若为非create_account交易,payload.body.token_locked必须为false;(支付交易payload.body.token_locked为false)
    • 6)调用compute_as_prover,当支付交易的receiver account不存在时,是否有足够的费用来支付创建新账号。若失败,原因需为User_command_failure之一。
    • 7) 取state_body.consensus_state.global_slot_since_genesis为current_global_slot,要求其小于等于交易payload.common.valid_until,即约束交易未过期。
    • 8)约束pending_coinbase_stack_init、pending_coinbase_stack_before、pending_coinbase_after和state_body之间的关系。
    • 9)约束若非user_command,user_command_fails必须为false;
    • 10)约束要么为create_account交易,否则交易payload.common.fee_payer_pk必须等于payload.body.source_pk;
    • 11)调用modify_account_send约束系统来更新扣除手续费余额及tree root;
    • 12)调用modify_account_recv约束系统来进行receiver account金额更新以及tree root更新;
    • 13)调用modify_account_send更新发送者账号余额以及tree root;
    • 14)约束statement.source.local_state与statement.source.local_state相等;
    • 15)约束apply_tagged_transaction返回的supply_increase与statement.supply_increase相等;
    • 16)约束apply_tagged_transaction返回的fee_excess经组装后,与statement.fee_excess相等;
    • 17)约束束apply_tagged_transaction返回的final_root(又名root_after),与statement.target.ledger相等。
    let%snarkydef apply_tagged_transaction~(constraint_constants : Genesis_constants.Constraint_constants.t)(type shifted)(shifted : (module Inner_curve.Checked.Shifted.S with type t = shifted))root pending_coinbase_stack_init pending_coinbase_stack_beforepending_coinbase_after state_body({ signer; signature; payload } as txn : Transaction_union.var) =
    let tag = payload.body.tag in
    let is_user_command = Transaction_union.Tag.Unpacked.is_user_command tag in (* 对于支付交易来说,此为true *)
    let%bind () = (* 1)校验交易签名; *)[%with_label "Check transaction signature"](check_signature shifted ~payload ~is_user_command ~signer ~signature)
    in
    let%bind signer_pk = Public_key.compress_var signer in
    let%bind () = (* 2)校验交易签名者公钥与交易中的fee_payer_pk一致; *)[%with_label "Fee-payer must sign the transaction"]((* TODO: Enable multi-sig. *)Public_key.Compressed.Checked.Assert.equal signer_pkpayload.common.fee_payer_pk )
    in
    (* Compute transaction kind. *)
    let is_payment = Transaction_union.Tag.Unpacked.is_payment tag in (* 对于支付交易来说,此为true。其它为false。  *)
    let is_mint_tokens = Transaction_union.Tag.Unpacked.is_mint_tokens tag in
    let is_stake_delegation =Transaction_union.Tag.Unpacked.is_stake_delegation tag
    in
    let is_create_account =Transaction_union.Tag.Unpacked.is_create_account tag
    in
    let is_fee_transfer = Transaction_union.Tag.Unpacked.is_fee_transfer tag in
    let is_coinbase = Transaction_union.Tag.Unpacked.is_coinbase tag in
    let fee_token = payload.common.fee_token in (* 支付交易手续费的token类型。 *)
    let%bind fee_token_default =  (* 3)fee_token_default:校验交易payload.common中的fee_token是否为Token_id.default; *)make_checked (fun () ->Token_id.(Checked.equal fee_token (Checked.constant default)) )
    in
    let token = payload.body.token_id in
    let%bind token_default =  (* 4)token_default:校验交易payload.body中的token_id是否为Token_id.default; *)make_checked (fun () ->Token_id.(Checked.equal token (Checked.constant default)) )
    in
    let%bind () = (* 5)若为非create_account交易,payload.body.token_locked必须为false; *)Checked.all_unit[ [%with_label"Token_locked value is compatible with the transaction kind"](Boolean.Assert.any[ Boolean.not payload.body.token_locked; is_create_account ] ); [%with_label "Token_locked cannot be used with the default token"](Boolean.Assert.any[ Boolean.not payload.body.token_locked; Boolean.not token_default] )]
    in
    let%bind () = Boolean.Assert.is_true token_default in (* 4)token_default:校验交易payload.body中的token_id是否为Token_id.default,约束其必须为true; *)
    let%bind () =[%with_label "Validate tokens"](Checked.all_unit[ [%with_label"Fee token is default or command allows non-default fee"](Boolean.Assert.any[ fee_token_default; is_payment; is_stake_delegation; is_fee_transfer] ); (* TODO: Remove this check and update the transaction snark once wehave an exchange rate mechanism. See issue #4447.*)[%with_label "Fees in tokens disabled"](Boolean.Assert.is_true fee_token_default) (* 3)fee_token_default:校验交易payload.common中的fee_token是否为Token_id.default,约束其必须为true; *); [%with_label "Command allows default token"]Boolean.(Assert.any[ is_payment; is_stake_delegation; is_create_account; is_fee_transfer; is_coinbase])] )
    in
    let current_global_slot = (* 取state_body.consensus_state.global_slot_since_genesis为current_global_slot。 *)Mina_state.Protocol_state.Body.consensus_state state_body|> Consensus.Data.Consensus_state.global_slot_since_genesis_var
    in
    (* Query user command predicted failure/success. *)
    let%bind user_command_failure = (* 6)调用`compute_as_prover`,当支付交易的receiver account不存在时,是否有足够的费用来支付创建新账号。若失败,原因需为User_command_failure之一。 *)User_command_failure.compute_as_prover ~constraint_constants~txn_global_slot:current_global_slot txn
    in
    let%bind user_command_fails =User_command_failure.any user_command_failure
    in
    let fee = payload.common.fee in (* 交易手续费 *)
    let receiver = Account_id.Checked.create payload.body.receiver_pk token in (* 取交易payload.body.token_id为token,与payload.body.receiver_pk一起构成receiver account_id *)
    let source = Account_id.Checked.create payload.body.source_pk token in  (* 取交易payload.body.token_id为token,与payload.body.source_pk一起构成source account_id *)
    (* Information for the fee-payer. *)
    let nonce = payload.common.nonce in
    let fee_payer = (* 取交易payload.common.fee_token为fee_token,与payload.body.fee_payer_pk一起构成fee_payer account_id *)Account_id.Checked.create payload.common.fee_payer_pk fee_token
    in
    let%bind () =[%with_label "Check slot validity"]( Global_slot.Checked.(current_global_slot <= payload.common.valid_until)>>= Boolean.Assert.is_true )
    in(* Check coinbase stack. Protocol state body is pushed into the Pendingcoinbase stack once per block. For example, consider any twotransactions in a block. Their pending coinbase stacks would be:transaction1: s1 -> t1 = s1+ protocol_state_body + maybe_coinbasetransaction2: t1 -> t1 + maybe_another_coinbase(Note: protocol_state_body is not pushed again)However, for each transaction, we need to constrain the protocol statebody. This is done is by using the stack ([init_stack]) without thecurrent protocol state body, pushing the state body to it in everytransaction snark and checking if it matches the target.We also need to constrain the source for the merges to work correctly.Basically,init_stack + protocol_state_body + maybe_coinbase = targetANDinit_stack = source || init_stack + protocol_state_body = source *)(* These are all the possible cases:Init_stack     Source                 Target--------------------------------------------------------------i               i                       i + statei               i                       i + state + coinbasei               i + state               i + statei               i + state               i + state + coinbasei + coinbase    i + state + coinbase    i + state + coinbase
    *)
    let%bind () = (*  8)约束pending_coinbase_stack_init、pending_coinbase_stack_before、pending_coinbase_after和state_body之间的关系。 *)[%with_label "Compute coinbase stack"](let%bind state_body_hash =Mina_state.Protocol_state.Body.hash_checked state_bodyinlet%bind pending_coinbase_stack_with_state =Pending_coinbase.Stack.Checked.push_state state_body_hashpending_coinbase_stack_initinlet%bind computed_pending_coinbase_stack_after =let coinbase =(Account_id.Checked.public_key receiver, payload.body.amount)inlet%bind stack' =Pending_coinbase.Stack.Checked.push_coinbase coinbasepending_coinbase_stack_with_stateinPending_coinbase.Stack.Checked.if_ is_coinbase ~then_:stack'~else_:pending_coinbase_stack_with_statein[%with_label "Check coinbase stack"](let%bind correct_coinbase_target_stack =Pending_coinbase.Stack.equal_varcomputed_pending_coinbase_stack_after pending_coinbase_afterinlet%bind valid_init_state =let%bind equal_source =Pending_coinbase.Stack.equal_var pending_coinbase_stack_initpending_coinbase_stack_beforeinlet%bind equal_source_with_state =Pending_coinbase.Stack.equal_varpending_coinbase_stack_with_statepending_coinbase_stack_beforeinBoolean.(equal_source ||| equal_source_with_state)in[%with_label "target stack and valid init state"](Boolean.Assert.all[ correct_coinbase_target_stack; valid_init_state ] ) ) )
    in
    (* Interrogate failure cases. This value is created without constraints;the failures should be checked against potential failures to ensureconsistency.
    *)
    let%bind () = (* 9)约束若非user_command,user_command_fails必须为false; *)[%with_label "A failing user command is a user command"]Boolean.(Assert.any [ is_user_command; not user_command_fails ])
    in
    let predicate_deferred =(* Account_precondition check is to be performed later if this is true. *)is_create_account
    in
    let%bind predicate_result = (* 10)约束要么为create_account交易,否则交易payload.common.fee_payer_pk必须等于payload.body.source_pk; *)let%bind is_own_account =Public_key.Compressed.Checked.equal payload.common.fee_payer_pkpayload.body.source_pkinlet predicate_result =(* TODO: Predicates. *)Boolean.false_inBoolean.(is_own_account ||| predicate_result)
    in
    let%bind () =[%with_label "Check account_precondition failure against predicted"](let%bind predicate_failed =Boolean.((not predicate_result) &&& not predicate_deferred)inassert_r1cs(predicate_failed :> Field.Var.t)(is_user_command :> Field.Var.t)(user_command_failure.predicate_failed :> Field.Var.t) )
    in
    let account_creation_amount = (* 从constraints.account_creation_fee获取创建新账号的费用。 *)Amount.Checked.of_feeFee.(var_of_t constraint_constants.account_creation_fee)
    in
    let%bind is_zero_fee = Fee.(equal_var fee (var_of_t zero)) in (* 判断创建新账号费用是否为零。is_zero_fee为false。 *)
    let is_coinbase_or_fee_transfer = Boolean.not is_user_command in (* 对于paymeng交易,其为false。  *)
    let%bind can_create_fee_payer_account =(* Fee transfers and coinbases may create an account. We check the normalinvariants to ensure that the account creation fee is paid.*)let%bind fee_may_be_charged =(* If the fee is zero, we do not create the account at all, so we allowthis through. Otherwise, the fee must be the default.*)Boolean.(token_default ||| is_zero_fee)inBoolean.(is_coinbase_or_fee_transfer &&& fee_may_be_charged)
    in
    let%bind root_after_fee_payer_update = (* 11)调用`modify_account_send`约束系统来更新扣除手续费余额及tree root; *)[%with_label "Update fee payer"](*[modify_account_send t aid ~f] implements the following spec:- finds an account [account] in [t] at path [addr] whose account id is [aid]OR it is a fee transfer and is an empty account- returns a root [t'] of a tree of depth [depth] which is [t] but with theaccount [f account] at path [addr].*)(Frozen_ledger_hash.modify_account_send~depth:constraint_constants.ledger_depth root~is_writeable:can_create_fee_payer_account fee_payer~f:(fun ~is_empty_and_writeable account ->(* this account is:- the fee-payer for payments- the fee-payer for stake delegation- the fee-payer for account creation- the fee-payer for token minting- the fee-receiver for a coinbase- the second receiver for a fee transfer*)let%bind next_nonce =Account.Nonce.Checked.succ_if account.nonce is_user_commandinlet%bind () =[%with_label "Check fee nonce"](let%bind nonce_matches =Account.Nonce.Checked.equal nonce account.nonceinBoolean.Assert.any[ Boolean.not is_user_command; nonce_matches ] )inlet%bind receipt_chain_hash =let current = account.receipt_chain_hash inlet%bind r =Receipt.Chain_hash.Checked.cons (Signed_command payload)currentinReceipt.Chain_hash.Checked.if_ is_user_command ~then_:r~else_:currentinlet%bind is_empty_and_writeable =(* If this is a coinbase with zero fee, do not create theaccount, since the fee amount won't be enough to pay for it.*)Boolean.(is_empty_and_writeable &&& not is_zero_fee)inlet%bind should_pay_to_create =(* Coinbases and fee transfers may create, or we may be creatinga new token account. These are mutually exclusive, so we canencode this as a boolean.*)let%bind is_create_account =Boolean.(is_create_account &&& not user_command_fails)inBoolean.(is_empty_and_writeable ||| is_create_account)inlet%bind amount =[%with_label "Compute fee payer amount"](let fee_payer_amount =let sgn = Sgn.Checked.neg_if_true is_user_command inAmount.Signed.create_var~magnitude:(Amount.Checked.of_fee fee)~sgnin(* Account creation fee for fee transfers/coinbases. *)let%bind account_creation_fee =let%map magnitude =Amount.Checked.if_ should_pay_to_create~then_:account_creation_amount~else_:Amount.(var_of_t zero)inAmount.Signed.create_var ~magnitude ~sgn:Sgn.Checked.neginAmount.Signed.Checked.(add fee_payer_amount account_creation_fee) )inlet txn_global_slot = current_global_slot inlet%bind `Min_balance _, timing =[%with_label "Check fee payer timing"](let%bind txn_amount =let%bind sgn = Amount.Signed.Checked.sgn amount inlet%bind magnitude =Amount.Signed.Checked.magnitude amountinAmount.Checked.if_ (Sgn.Checked.is_neg sgn) ~then_:magnitude~else_:Amount.(var_of_t zero)inlet balance_check ok =[%with_label "Check fee payer balance"](Boolean.Assert.is_true ok)inlet timed_balance_check ok =[%with_label "Check fee payer timed balance"](Boolean.Assert.is_true ok)incheck_timing ~balance_check ~timed_balance_check ~account~txn_amount:(Some txn_amount) ~txn_global_slot )inlet%bind balance =[%with_label "Check payer balance"](Balance.Checked.add_signed_amount account.balance amount)inlet%map public_key =Public_key.Compressed.Checked.if_ is_empty_and_writeable~then_:(Account_id.Checked.public_key fee_payer)~else_:account.public_keyand token_id =make_checked (fun () ->Token_id.Checked.if_ is_empty_and_writeable~then_:(Account_id.Checked.token_id fee_payer)~else_:account.token_id )and delegate =Public_key.Compressed.Checked.if_ is_empty_and_writeable~then_:(Account_id.Checked.public_key fee_payer)~else_:account.delegatein{ Account.Poly.balance; public_key; token_id; token_permissions = account.token_permissions; token_symbol = account.token_symbol; nonce = next_nonce; receipt_chain_hash; delegate; voting_for = account.voting_for; timing; permissions = account.permissions; zkapp = account.zkapp; zkapp_uri = account.zkapp_uri} ) )
    in
    let%bind receiver_increase = (* 计算receiver接收的金额。 *)(* - payments:         payload.body.amount- stake delegation: 0- account creation: 0- token minting:    payload.body.amount- coinbase:         payload.body.amount - payload.common.fee- fee transfer:     payload.body.amount*)[%with_label "Compute receiver increase"](let%bind base_amount =let%bind zero_transfer =Boolean.any [ is_stake_delegation; is_create_account ]inAmount.Checked.if_ zero_transfer~then_:(Amount.var_of_t Amount.zero)~else_:payload.body.amountin(* The fee for entering the coinbase transaction is paid up front. *)let%bind coinbase_receiver_fee =Amount.Checked.if_ is_coinbase~then_:(Amount.Checked.of_fee fee)~else_:(Amount.var_of_t Amount.zero)inAmount.Checked.sub base_amount coinbase_receiver_fee )
    in
    let receiver_overflow = ref Boolean.false_ in
    let%bind root_after_receiver_update = (*  12)调用`modify_account_recv`约束系统来进行receiver account金额更新以及tree root更新; *)[%with_label "Update receiver"](*[modify_account_recv t aid ~f] implements the following spec:- finds an account [account] in [t] at path [addr] whose account id is [aid]OR which is an empty account- returns a root [t'] of a tree of depth [depth] which is [t] but with theaccount [f account] at path [addr].*)(Frozen_ledger_hash.modify_account_recv~depth:constraint_constants.ledger_depth root_after_fee_payer_updatereceiver ~f:(fun ~is_empty_and_writeable account ->(* this account is:- the receiver for payments- the delegated-to account for stake delegation- the created account for an account creation- the receiver for minted tokens- the receiver for a coinbase- the first receiver for a fee transfer*)let%bind is_empty_failure =let%bind must_not_be_empty =Boolean.(is_stake_delegation ||| is_mint_tokens)inBoolean.(is_empty_and_writeable &&& must_not_be_empty)inlet%bind () =[%with_label "Receiver existence failure matches predicted"](Boolean.Assert.( = ) is_empty_failureuser_command_failure.receiver_not_present )inlet is_empty_and_writeable =(* is_empty_and_writable && not is_empty_failure *)Boolean.Unsafe.of_cvar@@ Field.Var.(sub (is_empty_and_writeable :> t) (is_empty_failure :> t))inlet%bind should_pay_to_create =Boolean.(is_empty_and_writeable &&& not is_create_account)inlet%bind () =[%with_label"Check whether creation fails due to a non-default token"](let%bind token_should_not_create =Boolean.(should_pay_to_create &&& Boolean.not token_default)inlet%bind token_cannot_create =Boolean.(token_should_not_create &&& is_user_command)inlet%bind () =[%with_label"Check that account creation is paid in the default \token for non-user-commands"]((* This expands to[token_should_not_create =token_should_not_create && is_user_command]which is- [token_should_not_create = token_should_not_create](ie. always satisfied) for user commands- [token_should_not_create = false] for coinbases/feetransfers.*)Boolean.Assert.( = ) token_should_not_createtoken_cannot_create )in[%with_label "equal token_cannot_create"](Boolean.Assert.( = ) token_cannot_createuser_command_failure.token_cannot_create ) )inlet%bind balance =(* [receiver_increase] will be zero in the stake delegationcase.*)let%bind receiver_amount =let%bind account_creation_amount =Amount.Checked.if_ should_pay_to_create~then_:account_creation_amount~else_:Amount.(var_of_t zero)inlet%bind amount_for_new_account, `Underflow underflow =Amount.Checked.sub_flagged receiver_increaseaccount_creation_amountinlet%bind () =[%with_label"Receiver creation fee failure matches predicted"](Boolean.Assert.( = ) underflowuser_command_failure.amount_insufficient_to_create )inCurrency.Amount.Checked.if_ user_command_fails~then_:Amount.(var_of_t zero)~else_:amount_for_new_accountin(* NOTE: Instead of capturing this as part of the user commandfailures, we capture it inline here and bubble it out to areference. This behavior is still in line with theout-of-snark transaction logic.Updating [user_command_fails] to include this value from hereonwards will ensure that we do not update the source orreceiver accounts. The only places where [user_command_fails]may have already affected behaviour are* when the fee-payer is paying the account creation fee, and* when a new token is created.In both of these, this account is new, and will have abalance of 0, so we can guarantee that there is no overflow.*)let%bind balance, `Overflow overflow =Balance.Checked.add_amount_flagged account.balancereceiver_amountinlet%bind () =[%with_label "Overflow error only occurs in user commands"]Boolean.(Assert.any [ is_user_command; not overflow ])inreceiver_overflow := overflow ;Balance.Checked.if_ overflow ~then_:account.balance~else_:balanceinlet%bind user_command_fails =Boolean.(!receiver_overflow ||| user_command_fails)inlet%bind is_empty_and_writeable =(* Do not create a new account if the user command will fail. *)Boolean.(is_empty_and_writeable &&& not user_command_fails)inlet%bind may_delegate =(* Only default tokens may participate in delegation. *)Boolean.(is_empty_and_writeable &&& token_default)inlet%map delegate =Public_key.Compressed.Checked.if_ may_delegate~then_:(Account_id.Checked.public_key receiver)~else_:account.delegateand public_key =Public_key.Compressed.Checked.if_ is_empty_and_writeable~then_:(Account_id.Checked.public_key receiver)~else_:account.public_keyand token_id =make_checked (fun () ->Token_id.Checked.if_ is_empty_and_writeable ~then_:token~else_:account.token_id )and token_owner =(* TODO: Delete token permissions *)Boolean.if_ is_empty_and_writeable ~then_:Boolean.false_~else_:account.token_permissions.token_ownerand token_locked =Boolean.if_ is_empty_and_writeable~then_:payload.body.token_locked~else_:account.token_permissions.token_lockedin{ Account.Poly.balance; public_key; token_id; token_permissions ={ Token_permissions.token_owner; token_locked }; token_symbol = account.token_symbol; nonce = account.nonce; receipt_chain_hash = account.receipt_chain_hash; delegate; voting_for = account.voting_for; timing = account.timing; permissions = account.permissions; zkapp = account.zkapp; zkapp_uri = account.zkapp_uri} ) )
    in
    let%bind user_command_fails = (* 若receiver_overflow,则交易也失败。 *)Boolean.(!receiver_overflow ||| user_command_fails)
    in
    let%bind fee_payer_is_source = Account_id.Checked.equal fee_payer source in (* 判断fee_payer是否等于source *)
    let%bind root_after_source_update = (* 13)调用`modify_account_send`更新发送者账号余额以及tree root; *)[%with_label "Update source"](Frozen_ledger_hash.modify_account_send~depth:constraint_constants.ledger_depth~is_writeable:(* [modify_account_send] does this failure check for us. *)user_command_failure.source_not_present root_after_receiver_updatesource ~f:(fun ~is_empty_and_writeable account ->(* this account is:- the source for payments- the delegator for stake delegation- the token owner for account creation- the token owner for token minting- the fee-receiver for a coinbase- the second receiver for a fee transfer*)let%bind () =[%with_label "Check source presence failure matches predicted"](Boolean.Assert.( = ) is_empty_and_writeableuser_command_failure.source_not_present )inlet%bind () =[%with_label"Check source failure cases do not apply when fee-payer is \source"](let num_failures =let open Field.Var inadd(user_command_failure.source_insufficient_balance :> t)(user_command_failure.source_bad_timing :> t)inlet not_fee_payer_is_source =(Boolean.not fee_payer_is_source :> Field.Var.t)in(* Equivalent to:if fee_payer_is_source thennum_failures = 0elsenum_failures = num_failures*)[%with_label "Check num_failures"](assert_r1cs not_fee_payer_is_source num_failuresnum_failures ) )inlet%bind amount =(* Only payments should affect the balance at this stage. *)if_ is_payment ~typ:Amount.typ ~then_:payload.body.amount~else_:Amount.(var_of_t zero)inlet txn_global_slot = current_global_slot inlet%bind `Min_balance _, timing =[%with_label "Check source timing"](let balance_check ok =[%with_label"Check source balance failure matches predicted"](Boolean.Assert.( = ) ok(Boolean.notuser_command_failure.source_insufficient_balance ) )inlet timed_balance_check ok =[%with_label"Check source timed balance failure matches predicted"](let%bind not_ok =Boolean.((not ok)&&& notuser_command_failure.source_insufficient_balance)inBoolean.Assert.( = ) not_okuser_command_failure.source_bad_timing )incheck_timing ~balance_check ~timed_balance_check ~account~txn_amount:(Some amount) ~txn_global_slot )inlet%bind balance, `Underflow underflow =Balance.Checked.sub_amount_flagged account.balance amountinlet%bind () =(* TODO: Remove the redundancy in balance calculation betweenhere and [check_timing].*)[%with_label "Check source balance failure matches predicted"](Boolean.Assert.( = ) underflowuser_command_failure.source_insufficient_balance )inlet%map delegate =Public_key.Compressed.Checked.if_ is_stake_delegation~then_:(Account_id.Checked.public_key receiver)~else_:account.delegatein(* NOTE: Technically we update the account here even in the caseof [user_command_fails], but we throw the resulting hash awayin [final_root] below, so it shouldn't matter.*){ Account.Poly.balance; public_key = account.public_key; token_id = account.token_id; token_permissions = account.token_permissions; token_symbol = account.token_symbol; nonce = account.nonce; receipt_chain_hash = account.receipt_chain_hash; delegate; voting_for = account.voting_for; timing; permissions = account.permissions; zkapp = account.zkapp; zkapp_uri = account.zkapp_uri} ) )
    in
    let%bind fee_excess = (* 获取fee_access *)(* - payments:         payload.common.fee- stake delegation: payload.common.fee- account creation: payload.common.fee- token minting:    payload.common.fee- coinbase:         0 (fee already paid above)- fee transfer:     - payload.body.amount - payload.common.fee*)let open Amount inchain Signed.Checked.if_ is_coinbase~then_:(return (Signed.Checked.of_unsigned (var_of_t zero)))~else_:(let user_command_excess =Signed.Checked.of_unsigned (Checked.of_fee payload.common.fee)inlet%bind fee_transfer_excess, fee_transfer_excess_overflowed =let%map magnitude, `Overflow overflowed =Checked.(add_flagged payload.body.amount (of_fee payload.common.fee))in(Signed.create_var ~magnitude ~sgn:Sgn.Checked.neg, overflowed)inlet%bind () =(* TODO: Reject this in txn pool before fees-in-tokens. *)[%with_label "Fee excess does not overflow"]Boolean.(Assert.any[ not is_fee_transfer; not fee_transfer_excess_overflowed ])inSigned.Checked.if_ is_fee_transfer ~then_:fee_transfer_excess~else_:user_command_excess )
    in
    let%bind supply_increase = (* 若为coinbase交易,则supply_increase为交易的payload.body.amount,否则为0。 *)Amount.Checked.if_ is_coinbase ~then_:payload.body.amount~else_:Amount.(var_of_t zero)
    in
    let%map final_root = (* 若交易失败,则手续费仍然需要支付,否则成功,各个账号相应余额均更新。 *)(* Ensure that only the fee-payer was charged if this was an invalid usercommand.*)Frozen_ledger_hash.if_ user_command_fails~then_:root_after_fee_payer_update ~else_:root_after_source_update
    in
    (final_root, fee_excess, supply_increase)

参考资料

[1] Guide to Snark Work

附录1. Mina系列博客

Mina系列博客有:

  • Mina概览
  • Mina的支付流程
  • Mina的zkApp
  • Mina中的Pasta(Pallas和Vesta)曲线
  • Mina中的Schnorr signature
  • Mina中的Pickles SNARK
  • Mina中的Kimchi SNARK
  • Mina Kimchi SNARK 代码解析
  • Mina Berkeley QANet测试网zkApp初体验
  • Mina中的Poseidon hash
  • Mina中的多项式承诺方案
  • Recursive SNARKs总览
  • Mina技术白皮书
  • Mina代码解析
  • Mina中的Snark Worker
  • Mina中的Scan State
  • Mina中的VRF
  • Mina中的delta_transition_chain_proof/delta_block_chain_proof
  • Mina中的stake delegation
  • Mina如何实现22KB?
  • Mina中的stake_proof
  • Mina中的genesis_proof
  • Mina中的交易及经济白皮书
  • Mina中的ledger proof
  • Mina中的基于DLG的Plonk polynomial commitment scheme代码解析
  • Mina中的约束系统代码解析
  • Mina中的scan state代码解析
  • Mina中的区块证明
  • Mina中的wrap snark

Mina中的支付交易snark相关推荐

  1. Mina中的zkApp交易snark

    1. 引言 前序博客有: Mina中的支付交易snark(针对Payment交易) Mina的zkApp Mina中的树结构 --账号树 Mina中的user_command交易目前有: 1)Sign ...

  2. Mina中的Snark Worker

    1. 引言 Mina系列博客有: Mina概览 Mina的支付流程 Mina的zkApp Mina中的Pasta(Pallas和Vesta)曲线 Mina中的Schnorr signature Min ...

  3. Mina中的Kimchi SNARK

    1. 引言 Mina系列博客有: Mina概览 Mina的支付流程 Mina的zkApp Mina中的Pasta(Pallas和Vesta)曲线 Mina中的Schnorr signature Min ...

  4. Mina中的wrap snark

    1. 引言 前序博客有: Mina技术白皮书 所谓wrap snark,是将Tick snark(Mina代码中称为step proof)包裹为Tock snark(Mina代码中称为wrap pro ...

  5. Mina中的Pickles SNARK

    1. 引言 Mina系列博客有: Mina概览 Mina的支付流程 Mina的zkApp Mina中的Pasta(Pallas和Vesta)曲线 Mina中的Schnorr signature 视频可 ...

  6. Mina中的区块证明

    1. 引言 Mina的Pickles支持2种类型的tag: Side_loaded Compiled type ('var, 'value, 'n1, 'n2) t ={ kind : kind; i ...

  7. Mina中的stake delegation

    1. 引言 为支持将某人的质押委托给另一人,增加受托人赢的几率. 质押委托的设计目标为: 从网络安全的角度来看,希望质押或委托的金额越多越好. 应不会too expensive inside the ...

  8. 移动支付交易规模增长率高达707%,安全面临考验!

    2019独角兽企业重金招聘Python工程师标准>>> 日前,中国互联网协会与新华社<金融世界>联合发布<2014中国互联网金融发展报告>指出,我国移动支付交 ...

  9. 实战 SQL!金融机构可疑支付交易的监测 | 原力计划

    作者 | 不剪发的Tony老师 责编 | 王晓曼 出品 | CSDN博客 今天,我们来谈谈如何利用 SQL 窗口函数发现可疑的银行卡支付交易.2002 年,中国人民银行为了加强对人民币支付交易的监督管 ...

最新文章

  1. svnadmin: e000002: 无法创建最上层目录_JFolder::create: 无法创建目录
  2. 温州大学《机器学习》课程课件(九、支持向量机)
  3. makefile工作笔记0003---Makefile的ifeq逻辑或,逻辑与的变通实现
  4. 前端封装接口弹出错误_Java:SpringBoot写后端接口,看这一篇就够了
  5. HTML5期末大作业:电影网站设计——电影动漫言叶之庭(4页) web前端课程设计_web前端课程设计代码,web课程设计-HTML网页制作代码
  6. 010Editor相关
  7. Windows 11 配置使用 Edge 浏览器的 IE 兼容模式(永久)
  8. hadoop集群搭建-(三台机器)
  9. 广东第一高中生_广东男篮签下全美第一高中生 NBA状元热门征战CBA
  10. python中英文字母和中文汉字所占的字节
  11. 项目管理IPD产品开发
  12. hackthebox(HTB) Ambassdor !
  13. 新站如何用指数蛙快速提升百度权重的方法!
  14. 王者英雄胜率用计算机怎么算,巅峰赛计算英雄胜率吗
  15. 成功的软件开发者需要掌握人际技能的3个原因
  16. 【python与数据分析】Pandas统计分析基础
  17. 内置式永磁电机maxwell2d_内嵌式永磁同步电机ANSOFT设计
  18. 安卓音乐播放时微信视频微信语音电话进来音乐暂停播放
  19. 曙光服务器如何重新设置u盘启动_曙光服务器安装系统.pdf
  20. 前端安全系列:如何防止XSS攻击?

热门文章

  1. 天宝数字水准数据处理和生成
  2. 补交20145226蓝墨云班课 -- 后缀表达式
  3. LeetCode1359. 有效的快递序列数目
  4. 【算法】机器人走迷宫(适用于走迷宫、最短路径算法)-20200412
  5. 好好说话之Tcache Attack(2):tcache dup与tcache house of spirit
  6. 逆反西游无法读取服务器信息,逆反西游
  7. 基于 钉钉认证 通过 华为、H3C 结合 OpenPortal认证计费系统 实现 网络准入 钉钉授权 实名认证
  8. 混合正弦余弦算法和Lévy飞行的麻雀算法
  9. Java文档注释【自制API】
  10. cloud华为云服务登录(华为云服务平台登录入口)