Mina中的ledger proof

1. 引言

前序博客见:

(* prover/prover.ml中有: *)
module Extend_blockchain_input = struct
  [%%versioned
  module Stable = struct
    [@@@no_toplevel_latest_type]
    module V2 = struct
      type t =
        { chain : Blockchain.Stable.V2.t
        ; next_state : Protocol_state.Value.Stable.V2.t
        ; block : Snark_transition.Value.Stable.V2.t
        ; ledger_proof : Ledger_proof.Stable.V2.t option
        ; prover_state : Consensus.Data.Prover_state.Stable.V2.t
        ; pending_coinbase : Pending_coinbase_witness.Stable.V2.t
        }
(* ledger_proof/ledger_proof.ml中有: *)
module Prod : Ledger_proof_intf.S with type t = Transaction_snark.t = struct
  [%%versioned
  module Stable = struct
    module V2 = struct
      type t = Transaction_snark.Stable.V2.t
(* transaction_snark/transaction_snark.ml中有: *)
module Stable = struct
  module V2 = struct
    type t =
      { statement : Statement.With_sok.Stable.V2.t; proof : Proof.Stable.V2.t }
  
  module With_sok = struct
    [%%versioned
    module Stable = struct
      module V2 = struct
        type t =
          ( Frozen_ledger_hash.Stable.V1.t
          , Currency.Amount.Stable.V1.t
          , Pending_coinbase.Stack_versioned.Stable.V1.t
          , Fee_excess.Stable.V1.t
          , Sok_message.Digest.Stable.V1.t (* 为string类型 *)
          , Local_state.Stable.V1.t )
    
module Proof = struct
  [%%versioned
  module Stable = struct
    module V2 = struct
      type t = Pickles.Proof.Branching_2.Stable.V2.t

Verifier端验证transaction_snark的输入为 [ledger_proof, sok_message] 数组:【其中sok_digest=BLAKE2_HASH(sok_message)】

val verify_transaction_snarks :
         t
      -> (ledger_proof * Mina_base.Sok_message.t) list
      -> bool Or_error.t Deferred.t
(* Mina_base.Sok_message.t结构定义为: *)
module Stable = struct
  module V1 = struct
    type t =
      { fee : Currency.Fee.Stable.V1.t
      ; prover : Public_key.Compressed.Stable.V1.t
      }
(* verify_transaction_snarks函数实际实现为: *)
			let verify_transaction_snarks ts =
               match Or_error.try_with (fun () -> T.verify ts) with
               | Ok result ->
                   result
               | Error e ->
                   [%log error]
                     ~metadata:[ ("error", Error_json.error_to_yojson e) ]
                     "Verifier threw an exception while verifying transaction \
                      snark" ;
                   failwith "Verifier crashed"

let verify ts =
    if
      List.for_all ts ~f:(fun (p, m) -> (* 【其中sok_digest=BLAKE2_HASH(sok_message)】 *)
          Sok_message.Digest.equal (Sok_message.digest m) p.statement.sok_digest)
    then
      Proof.verify
        (List.map ts ~f:(fun ({ statement; proof }, _) -> (statement, proof)))
    else Async.return false
(* Pickles Proof中的verify为: *)
let verify (type a n) (max_branching : (module Nat.Intf with type n = n))
    (a_value : (module Intf.Statement_value with type t = a))
    (key : Verification_key.t) (ts : (a * (n, n) Proof.t) list) =
  verify_heterogenous
    (List.map ts ~f:(fun (x, p) ->
         Instance.T (max_branching, a_value, key, x, p)))

let verify_heterogenous (ts : Instance.t list) =
  let module Plonk = Types.Wrap.Proof_state.Deferred_values.Plonk in
  let module Tick_field = Backend.Tick.Field in
  let tick_field : _ Plonk_checks.field = (module Tick_field) in
  let check, result =
    let r = ref [] in
    let result () =
      match !r with
      | [] ->
          Ok ()
      | _ ->
          Error
            (String.concat ~sep:"\n"
               (List.map !r ~f:(fun lab -> Lazy.force lab)))
    in
    ((fun (lab, b) -> if not b then r := lab :: !r), result)
  in
  let in_circuit_plonks =
    List.map ts
      ~f:(fun
           (T
             ( _max_branching
             , _statement
             , key
             , app_state
             , T
                 { statement
                   (* TODO
                      ; prev_x_hat = (x_hat1, _) as prev_x_hat
                   *)
                 ; prev_evals = evals
                 } ))
         ->
        Timer.start __LOC__ ;
        let statement =
          { statement with
            pass_through = { statement.pass_through with app_state }
          }
        in
        let open Types.Wrap.Proof_state in
        let sc =
          SC.to_field_constant tick_field ~endo:Endo.Wrap_inner_curve.scalar
        in
        Timer.clock __LOC__ ;
        let { Deferred_values.xi
            ; plonk = plonk0
            ; combined_inner_product
            ; which_branch
            ; bulletproof_challenges
            } =
          Deferred_values.map_challenges ~f:Challenge.Constant.to_tick_field
            ~scalar:sc statement.proof_state.deferred_values
        in
        let zeta = sc plonk0.zeta in
        let alpha = sc plonk0.alpha in
        let step_domains = key.step_domains.(Index.to_int which_branch) in
        let w =
          Tick.Field.domain_generator
            ~log2_size:(Domain.log2_size step_domains.h)
        in
        let zetaw = Tick.Field.mul zeta w in
        let tick_plonk_minimal :
            _ Composition_types.Wrap.Proof_state.Deferred_values.Plonk.Minimal.t
            =
          let chal = Challenge.Constant.to_tick_field in
          { zeta; alpha; beta = chal plonk0.beta; gamma = chal plonk0.gamma }
        in
        let tick_combined_evals =
          Plonk_checks.evals_of_split_evals
            (module Tick.Field)
            (Double.map evals.evals ~f:(fun e -> e.evals))
            ~rounds:(Nat.to_int Tick.Rounds.n) ~zeta ~zetaw
        in
        let tick_domain =
          Plonk_checks.domain
            (module Tick.Field)
            step_domains.h ~shifts:Common.tick_shifts
            ~domain_generator:Backend.Tick.Field.domain_generator
        in
        let tick_env =
          Plonk_checks.scalars_env
            (module Tick.Field)
            ~endo:Endo.Step_inner_curve.base ~mds:Tick_field_sponge.params.mds
            ~srs_length_log2:Common.Max_degree.step_log2
            ~field_of_hex:(fun s ->
              Kimchi_pasta.Pasta.Bigint256.of_hex_string s
              |> Kimchi_pasta.Pasta.Fp.of_bigint)
            ~domain:tick_domain tick_plonk_minimal tick_combined_evals
        in
        let plonk =
          let p =
            Plonk_checks.Type1.derive_plonk
              (module Tick.Field)
              ~shift:Shifts.tick1 ~env:tick_env tick_plonk_minimal
              tick_combined_evals
          in
          { p with
            zeta = plonk0.zeta
          ; alpha = plonk0.alpha
          ; beta = plonk0.beta
          ; gamma = plonk0.gamma
          }
        in
        Timer.clock __LOC__ ;
        let absorb, squeeze =
          let open Tick_field_sponge.Bits in
          let sponge =
            let s = create Tick_field_sponge.params in
            absorb s
              (Digest.Constant.to_tick_field
                 statement.proof_state.sponge_digest_before_evaluations) ;
            s
          in
          let squeeze () =
            let underlying =
              Challenge.Constant.of_bits
                (squeeze sponge ~length:Challenge.Constant.length)
            in
            sc (Scalar_challenge.create underlying)
          in
          (absorb sponge, squeeze)
        in
        let absorb_evals
            { Plonk_types.All_evals.With_public_input.public_input = x_hat
            ; evals = e
            } =
          let xs, ys = Plonk_types.Evals.to_vectors e in
          List.iter
            Vector.([| x_hat |] :: (to_list xs @ to_list ys))
            ~f:(Array.iter ~f:absorb)
        in
        Double.(iter ~f:absorb_evals evals.evals) ;
        absorb evals.ft_eval1 ;
        let xi_actual = squeeze () in
        let r_actual = squeeze () in
        Timer.clock __LOC__ ;
        (* TODO: The deferred values "bulletproof_challenges" should get routed
           into a "batch dlog Tick acc verifier" *)
        let actual_branching =
          Vector.length statement.pass_through.old_bulletproof_challenges
        in
        Timer.clock __LOC__ ;
        let combined_inner_product_actual =
          Wrap.combined_inner_product ~env:tick_env ~plonk:tick_plonk_minimal
            ~domain:tick_domain ~ft_eval1:evals.ft_eval1
            ~actual_branching:(Nat.Add.create actual_branching)
            (Double.map evals.evals ~f:(fun e -> e.evals))
            ~x_hat:(Double.map evals.evals ~f:(fun e -> e.public_input))
            ~old_bulletproof_challenges:
              (Vector.map ~f:Ipa.Step.compute_challenges
                 statement.pass_through.old_bulletproof_challenges)
            ~r:r_actual ~xi ~zeta ~zetaw ~step_branch_domains:step_domains
        in
        let check_eq lab x y =
          check
            ( lazy
                (sprintf
                   !"%s: %{sexp:Tick_field.t} != %{sexp:Tick_field.t}"
                   lab x y)
            , Tick_field.equal x y )
        in
        Timer.clock __LOC__ ;
        Timer.clock __LOC__ ;
        List.iter
          ~f:(fun (s, x, y) -> check_eq s x y)
          (* Both these values can actually be omitted from the proof on the wire since we recompute them
             anyway. *)
          [ ("xi", xi, xi_actual)
          ; ( "combined_inner_product"
            , Shifted_value.Type1.to_field
                (module Tick.Field)
                combined_inner_product ~shift:Shifts.tick1
            , combined_inner_product_actual )
          ] ;
        plonk)
  in
  let open Backend.Tock.Proof in
  let open Promise.Let_syntax in
  let%bind accumulator_check =
    Ipa.Step.accumulator_check
      (List.map ts ~f:(fun (T (_, _, _, _, T t)) ->
           ( t.statement.proof_state.me_only.sg
           , Ipa.Step.compute_challenges
               t.statement.proof_state.deferred_values.bulletproof_challenges )))
  in
  Common.time "batch_step_dlog_check" (fun () ->
      check (lazy "batch_step_dlog_check", accumulator_check)) ;
  let%map dlog_check =
    batch_verify
      (List.map2_exn ts in_circuit_plonks
         ~f:(fun
              (T
                ((module Max_branching), (module A_value), key, app_state, T t))
              plonk
            ->
           let prepared_statement : _ Types.Wrap.Statement.In_circuit.t =
             { pass_through =
                 Common.hash_step_me_only ~app_state:A_value.to_field_elements
                   (Reduced_me_only.Step.prepare
                      ~dlog_plonk_index:key.commitments
                      { t.statement.pass_through with app_state })
             ; proof_state =
                 { t.statement.proof_state with
                   deferred_values =
                     { t.statement.proof_state.deferred_values with plonk }
                 ; me_only =
                     Common.hash_dlog_me_only Max_branching.n
                       (Reduced_me_only.Wrap.prepare
                          t.statement.proof_state.me_only)
                 }
             }
           in
           let input =
             tock_unpadded_public_input_of_statement prepared_statement
           in
           ( key.index
           , t.proof
           , input
           , Some
               (Vector.to_list
                  (Vector.map2
                     ~f:(fun g cs ->
                       { Challenge_polynomial.challenges =
                           Vector.to_array (Ipa.Wrap.compute_challenges cs)
                       ; commitment = g
                       })
                     (Vector.extend_exn t.statement.pass_through.sg
                        Max_branching.n
                        (Lazy.force Dummy.Ipa.Wrap.sg))
                     t.statement.proof_state.me_only.old_bulletproof_challenges))
           )))
  in
  Common.time "dlog_check" (fun () -> check (lazy "dlog_check", dlog_check)) ;
  match result () with
  | Ok () ->
      true
  | Error e ->
      eprintf !"bad verify: %s\n%!" e ;
      false

1.1 Mina交易结构

当前Mina中支持的交易类型有:

let to_preunion (t : Transaction.t) =
  match t with
  | Command (Signed_command x) ->
      `Transaction (Transaction.Command x)
  | Fee_transfer x ->
      `Transaction (Fee_transfer x)
  | Coinbase x ->
      `Transaction (Coinbase x)
  | Command (Parties x) ->
      `Parties x

Mina中的交易失败类型有:

module Failure = struct
  [%%versioned
  module Stable = struct
    module V2 = struct
      type t =
        | Predicate [@value 1]
        | Source_not_present
        | Receiver_not_present
        | Amount_insufficient_to_create_account
        | Cannot_pay_creation_fee_in_token
        | Source_insufficient_balance
        | Source_minimum_balance_violation
        | Receiver_already_exists
        | Not_token_owner
        | Mismatched_token_permissions
        | Overflow
        | Signed_command_on_zkapp_account
        | Zkapp_account_not_present
        | Update_not_permitted_balance
        | Update_not_permitted_timing_existing_account
        | Update_not_permitted_delegate
        | Update_not_permitted_app_state
        | Update_not_permitted_verification_key
        | Update_not_permitted_sequence_state
        | Update_not_permitted_zkapp_uri
        | Update_not_permitted_token_symbol
        | Update_not_permitted_permissions
        | Update_not_permitted_nonce
        | Update_not_permitted_voting_for
        | Parties_replay_check_failed
        | Fee_payer_nonce_must_increase
        | Account_precondition_unsatisfied
        | Protocol_state_precondition_unsatisfied
        | Incorrect_nonce
        | Invalid_fee_excess

transaction结构为:

(* transaction结构为: *)
module Stable = struct
  module V2 = struct
    type t = User_command.Stable.V2.t Poly.Stable.V2.t 

module Poly = struct
  [%%versioned
  module Stable = struct
    module V2 = struct
      type 'command t = (* 分为:普通的用户签名交易、Fee transfer、coinbase *)
        | Command of 'command
        | Fee_transfer of Fee_transfer.Stable.V2.t
        | Coinbase of Coinbase.Stable.V1.t

(* User_command结构为: *)
module Stable = struct
  module V2 = struct
    type t = (Signed_command.Stable.V2.t, Parties.Stable.V1.t) Poly.Stable.V2.t

(* Signed_command结构为: *)
module Stable = struct
  module V2 = struct
    type t =
      ( Payload.Stable.V2.t
      , Public_key.Stable.V1.t
      , Signature.Stable.V1.t )
      Poly.Stable.V1.t

(* Payload结构为: *)
module Stable = struct
  module V2 = struct
    type t = (Common.Stable.V2.t, Body.Stable.V2.t) Poly.Stable.V1.t
(* Public_key结构为: *)
module Stable = struct
    module V1 = struct
      type t = Field.t * Field.t 
(* Signature结构为: *)
module Stable = struct
  module V1 = struct
    type t = (Field.t, Inner_curve.Scalar.t) Signature_poly.Stable.V1.t

(* Common结构为: *)
type t =
        ( Currency.Fee.Stable.V1.t
        , Public_key.Compressed.Stable.V1.t
        , Account_nonce.Stable.V1.t
        , Global_slot.Stable.V1.t
        , Memo.Stable.V1.t ) (* 为string *)
        Poly.Stable.V2.t
(* Body结构为:根据是普通支付还是质押委托交易,body有所不同 *)
module Stable = struct
    module V2 = struct
      type t = Binable_arg.Stable.V2.t =
        | Payment of Payment_payload.Stable.V2.t
        | Stake_delegation of Stake_delegation.Stable.V1.t

transaction_witness结构为:

(* transaction_witness为: *)
module Stable = struct
  module V2 = struct
    type t =
      { transaction : Mina_transaction.Transaction.Stable.V2.t
      ; ledger : Mina_ledger.Sparse_ledger.Stable.V2.t
      ; protocol_state_body : Mina_state.Protocol_state.Body.Value.Stable.V2.t
      ; init_stack : Mina_base.Pending_coinbase.Stack_versioned.Stable.V1.t
      ; status : Mina_base.Transaction_status.Stable.V2.t
      }

(* Mina_ledger.Sparse_ledger结构为: *)
module Stable = struct
  module V2 = struct
    type t =
      ( Ledger_hash.Stable.V1.t (* 为Field.t,Tick曲线的 *)
      , Account_id.Stable.V2.t
      , Account.Stable.V2.t )
      Sparse_ledger_lib.Sparse_ledger.T.Stable.V2.t
(* account_id结构为: *)
module Stable = struct
  module V2 = struct (* 为压缩公钥 和 Pickles.Backend.Tick.Field.Stable.V1.t *)
    type t = Public_key.Compressed.Stable.V1.t * Digest.Stable.V1.t
(* account结构为: *)
type t =
        ( Public_key.Compressed.Stable.V1.t
        , Token_id.Stable.V1.t
        , Token_permissions.Stable.V1.t
        , Token_symbol.Stable.V1.t
        , Balance.Stable.V1.t
        , Nonce.Stable.V1.t
        , Receipt.Chain_hash.Stable.V1.t
        , Public_key.Compressed.Stable.V1.t option
        , State_hash.Stable.V1.t
        , Timing.Stable.V1.t
        , Permissions.Stable.V2.t
        , Zkapp_account.Stable.V2.t option
        , string )
        (* TODO: Cache the digest of this? *)
        Poly.Stable.V2.t
(* Sparse_ledger_lib.Sparse_ledger结构为: *)
type ('hash, 'key, 'account) t =
        { indexes : ('key * int) list
        ; depth : int
        ; tree : ('hash, 'account) Tree.Stable.V1.t
        }
(* Sparse_ledger中的Tree为account tree,其结构为: *)
type ('hash, 'key, 'account) t =
        { indexes : ('key * int) list
        ; depth : int
        ; tree : ('hash, 'account) Tree.Stable.V1.t
        }

2. ledger_proof由snark worker生成

snark worker启动时,其选择的proof_level有3种状态:

  • full
  • check
  • none
module Proof_level = struct
  type t = Full | Check | None
module Single = struct
  module Spec = struct
    [%%versioned
    module Stable = struct
      [@@@no_toplevel_latest_type]
      module V2 = struct
        type ('witness, 'ledger_proof) t =
          | Transition of Transaction_snark.Statement.Stable.V2.t * 'witness
          | Merge of
              Transaction_snark.Statement.Stable.V2.t
              * 'ledger_proof
              * 'ledger_proof

(* bin_io is for uptime service SNARK worker *)
  type single_spec =
    ( Transaction_witness.Stable.Latest.t
    , Transaction_snark.Stable.Latest.t )
    Snark_work_lib.Work.Single.Spec.Stable.Latest.t

ledger_proof由snark worker生成,scan state中的tree中有base snark和merge snark,根据交易类型的不同,采取不同的生成snark proof和ledger proof方案:

(* snark_worker/prod.ml中生成ledger proof和snark proof的流程为: *)
let perform_single ({ m; cache; proof_level } : Worker_state.t) ~message =
  .......
    match proof_level with
      | Genesis_constants.Proof_level.Full -> (
          ........
          match Cache.find cache statement with
          | Some proof ->
              Deferred.Or_error.return (proof, Time.Span.zero)
          | None -> (
              match single with
              | Work.Single.Spec.Transition (input, (w : Transaction_witness.t))
                ->
                ...........
                   match w.transaction with
                      | Command (Parties parties) -> (
                      .........
						let log_base_snark f ~statement ~spec ~all_inputs =
                            match%map.Deferred
                              Deferred.Or_error.try_with (fun () ->
                                  f ~statement ~spec)
                                  
						let log_merge_snark ~sok_digest prev curr ~all_inputs
                              =
                            match%map.Deferred
                              M.merge ~sok_digest prev curr
                       ........
                       | _ ->
                          let%bind t =
                            Deferred.return
                            @@
                            (* Validate the received transaction *)
                            match w.transaction with
                            | Command (Signed_command cmd) -> (
                                match Signed_command.check cmd with
                                | Some cmd ->
                                    ( Ok (Command (Signed_command cmd))
                                      : Transaction.Valid.t Or_error.t )
                                | None ->
                                    Or_error.errorf
                                      "Command has an invalid signature" )
                            | Command (Parties _) ->
                                assert false
                            | Fee_transfer ft ->
                                Ok (Fee_transfer ft)
                            | Coinbase cb ->
                                Ok (Coinbase cb)
                          in
                          Deferred.Or_error.try_with ~here:[%here] (fun () ->
                              M.of_non_parties_transaction
                                ~statement:{ input with sok_digest }
                                { Transaction_protocol_state.Poly.transaction =
                                    t
                                ; block_data = w.protocol_state_body
                                }
                                ~init_stack:w.init_stack
                                (unstage
                                   (Mina_ledger.Sparse_ledger.handler w.ledger))))
                       ..........
                       )
           | Merge (_, proof1, proof2) ->
                  process (fun () -> M.merge ~sok_digest proof1 proof2) )
           ........
           )
    | Check | None ->
          (* Use a dummy proof. *)
          let stmt =
            match single with
            | Work.Single.Spec.Transition (stmt, _) ->
                stmt
            | Merge (stmt, _, _) ->
                stmt
          in
          Deferred.Or_error.return
          @@ ( Transaction_snark.create ~statement:{ stmt with sok_digest }
                 ~proof:Proof.transaction_dummy
             , Time.Span.zero )
  • snark worker: main->perform->perform_single,会将base snark或merge snark proof放入Snark_work_lib.Work.Result.proofs中,并提交到snark pool中?
  • 产块者:generate_next_state->Staged_ledger.apply_diff_unchecked->apply_diff->fill_work_and_enqueue_transactions->fill_in_transaction_snark_work->completed_work_to_scanable_work来将snark proof添加到区块内。
    |> Deferred.Or_error.map ~f:(function
         | `One (proof1, metrics1) ->
             { Snark_work_lib.Work.Result.proofs = `One proof1
             ; metrics = `One metrics1
             ; spec
             ; prover = public_key
             }
         | `Two ((proof1, metrics1), (proof2, metrics2)) ->
             { Snark_work_lib.Work.Result.proofs = `Two (proof1, proof2)
             ; metrics = `Two (metrics1, metrics2)
             ; spec
             ; prover = public_key
             })

2.1 Parties交易proof生成

所谓Parties交易,是指为支持zkApps智能合约创建的交易类型。
对于Parties交易类型,生成proof的方案为:【分为log_base_snarklog_merge_snark

						  match witnesses_specs_stmts with
                          | [] ->
                              Deferred.Or_error.error_string
                                "no witnesses generated"
                          | (witness, spec, stmt, snapp_statement) :: rest as
                            inputs ->
                              let%bind (p1 : Ledger_proof.t) =
                                log_base_snark
                                  ~statement:{ stmt with sok_digest } ~spec
                                  ~all_inputs:inputs
                                  (M.of_parties_segment_exn ~snapp_statement
                                     ~witness)
                              in

                              let%map (p : Ledger_proof.t) =
                                Deferred.List.fold ~init:(Ok p1) rest
                                  ~f:(fun
                                       acc
                                       (witness, spec, stmt, snapp_statement)
                                     ->
                                    let%bind (prev : Ledger_proof.t) =
                                      Deferred.return acc
                                    in
                                    let%bind (curr : Ledger_proof.t) =
                                      log_base_snark
                                        ~statement:{ stmt with sok_digest }
                                        ~spec ~all_inputs:inputs
                                        (M.of_parties_segment_exn
                                           ~snapp_statement ~witness)
                                    in
                                    log_merge_snark ~sok_digest prev curr
                                      ~all_inputs:inputs)

对于Parties交易,会调用Pickles proof system相关证明接口:

let of_parties_segment_exn ~statement ~snapp_statement ~witness
      ~(spec : Parties_segment.Basic.t) : t Async.Deferred.t =
    Base.Parties_snark.witness := Some witness ;
    let res =
      match spec with
      | Opt_signed ->
          opt_signed [] statement
      | Opt_signed_unsigned ->
          opt_signed_unsigned [] statement
      | Opt_signed_opt_signed ->
          opt_signed_opt_signed [] statement
      | Proved -> (
          match snapp_proof_data ~snapp_statement ~witness with
          | None ->
              failwith "of_parties_segment: Expected exactly one proof"
          | Some (s, p, v, tag) ->
              (* TODO: We should not have to pass the statement in here. *)
              proved
                ( Pickles.Side_loaded.in_prover (Base.side_loaded tag) v.data ;
                  [ (s, p) ] )
                statement )
    in
    let open Async in
    let%map proof = res in
    Base.Parties_snark.witness := None ;
    { proof; statement }

2.2 非Parties交易proof生成

非Parties交易是指用户签名交易、给snark worker的fee交易 以及 给产块者奖励的coinbase交易。

扫描二维码关注公众号,回复: 14134780 查看本文章
							match w.transaction with
                            | Command (Signed_command cmd) -> (
                                match Signed_command.check cmd with
                                | Some cmd ->
                                    ( Ok (Command (Signed_command cmd))
                                      : Transaction.Valid.t Or_error.t )
                                | None ->
                                    Or_error.errorf
                                      "Command has an invalid signature" )
                            | Command (Parties _) ->
                                assert false
                            | Fee_transfer ft ->
                                Ok (Fee_transfer ft)
                            | Coinbase cb ->
                                Ok (Coinbase cb)
                          in
                          Deferred.Or_error.try_with ~here:[%here] (fun () ->
                              M.of_non_parties_transaction
                                ~statement:{ input with sok_digest }
                                { Transaction_protocol_state.Poly.transaction =
                                    t
                                ; block_data = w.protocol_state_body
                                }
                                ~init_stack:w.init_stack
                                (unstage
                                   (Mina_ledger.Sparse_ledger.handler w.ledger)))

非Parties交易生成proof方案为:

let of_non_parties_transaction ~statement ~init_stack transaction_in_block
      handler =
    let transaction : Transaction.t =
      Transaction.forget
        (Transaction_protocol_state.transaction transaction_in_block)
    in
    let state_body =
      Transaction_protocol_state.block_data transaction_in_block
    in
    match to_preunion transaction with
    | `Parties _ ->
        failwith "Called Non-parties transaction with parties transaction"
    | `Transaction t ->
        of_transaction_union ~statement ~init_stack
          (Transaction_union.of_transaction t)
          state_body handler

let of_transaction_union ~statement ~init_stack transaction state_body handler
      =
    let open Async in
    let%map proof =
      base []
        ~handler:
          (Base.transaction_union_handler handler transaction state_body
             init_stack)
        statement
    in
    { statement; proof }

let transaction_union_handler handler (transaction : Transaction_union.t)
      (state_body : Mina_state.Protocol_state.Body.Value.t)
      (init_stack : Pending_coinbase.Stack.t) :
      Snarky_backendless.Request.request -> _ =
   fun (With { request; respond } as r) ->
    match request with
    | Transaction ->
        respond (Provide transaction)
    | State_body ->
        respond (Provide state_body)
    | Init_stack ->
        respond (Provide init_stack)
    | _ ->
        handler r

of_transaction_union函数中的base会调用Pickles proof system相关证明接口:

let system ~proof_level ~constraint_constants =
  time "Transaction_snark.system" (fun () ->
      Pickles.compile ~cache:Cache_dir.cache
        (module Statement.With_sok.Checked)
        (module Statement.With_sok)
        ~typ:Statement.With_sok.typ
        ~branches:(module Nat.N6)
        ~max_branching:(module Nat.N2)
        ~name:"transaction-snark"
        ~constraint_constants:
          (Genesis_constants.Constraint_constants.to_snark_keys_header
             constraint_constants)
        ~choices:(fun ~self ->
          let parties x =
            Base.Parties_snark.rule ~constraint_constants ~proof_level x
          in
          [ Base.rule ~constraint_constants
          ; Merge.rule ~proof_level self
          ; parties Opt_signed_unsigned
          ; parties Opt_signed_opt_signed
          ; parties Opt_signed
          ; parties Proved
          ]))
          
let compile ?self ?cache ?disk_keys a_var a_value ~typ ~branches ~max_branching
    ~name ~constraint_constants ~choices =
  let self, cache_handle, proof_module, provers =
    compile_promise ?self ?cache ?disk_keys a_var a_value ~typ ~branches
      ~max_branching ~name ~constraint_constants ~choices
  in
  let rec adjust_provers :
      type a1 a2 a3 s1 s2_inner.
         (a1, a2, a3, s1, s2_inner Promise.t) H3_2.T(Prover).t
      -> (a1, a2, a3, s1, s2_inner Deferred.t) H3_2.T(Prover).t = function
    | [] ->
        []
    | prover :: tl ->
        (fun ?handler stmt_with_proof public_input ->
          Promise.to_deferred (prover ?handler stmt_with_proof public_input))
        :: adjust_provers tl
  in
  (self, cache_handle, proof_module, adjust_provers provers)

附录1. Mina系列博客

Mina系列博客有:

猜你喜欢

转载自blog.csdn.net/mutourend/article/details/124607183