https://gitlab.com/tezos/tezos
Tip revision: 7e4b535402c7aae6867211d772357afda8cdb86d authored by pecornilleau on 16 August 2023, 23:23:23 UTC
failed attempt to use tezos/debug
failed attempt to use tezos/debug
Tip revision: 7e4b535
script_interpreter_defs.ml
(*****************************************************************************)
(* *)
(* Open Source License *)
(* Copyright (c) 2021-2022 Nomadic Labs <contact@nomadic-labs.com> *)
(* *)
(* Permission is hereby granted, free of charge, to any person obtaining a *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)
(* and/or sell copies of the Software, and to permit persons to whom the *)
(* Software is furnished to do so, subject to the following conditions: *)
(* *)
(* The above copyright notice and this permission notice shall be included *)
(* in all copies or substantial portions of the Software. *)
(* *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)
(* DEALINGS IN THE SOFTWARE. *)
(* *)
(*****************************************************************************)
(*
This module provides auxiliary definitions used in the interpreter.
These are internal private definitions. Do not rely on them outside
the interpreter.
*)
open Alpha_context
open Script
open Script_typed_ir
open Script_ir_translator
open Local_gas_counter
type error += Rollup_invalid_transaction_amount | Rollup_invalid_entrypoint
let () =
register_error_kind
`Permanent
~id:"operation.rollup_invalid_transaction_amount"
~title:"Transaction amount to a rollup must be zero"
~description:
"Because rollups are outside of the delegation mechanism of Tezos, they \
cannot own Tez, and therefore transactions targeting a rollup must have \
its amount field set to zero."
~pp:(fun ppf () ->
Format.pp_print_string ppf "Transaction amount to a rollup must be zero.")
Data_encoding.unit
(function Rollup_invalid_transaction_amount -> Some () | _ -> None)
(fun () -> Rollup_invalid_transaction_amount) ;
register_error_kind
`Permanent
~id:"operation.rollup_invalid_entrypoint"
~title:"Only the default entrypoint is allowed for rollups"
~description:"Rollups only support transactions to the default entrypoint."
~pp:(fun ppf () ->
Format.pp_print_string
ppf
"Rollups only support transactions to the default entrypoint.")
Data_encoding.unit
(function Rollup_invalid_entrypoint -> Some () | _ -> None)
(fun () -> Rollup_invalid_entrypoint)
(*
Computing the cost of Michelson instructions
============================================
The function [cost_of_instr] provides a cost model for Michelson
instructions. It is used by the interpreter to track the
consumption of gas. This consumption may depend on the values
on the stack.
*)
module Interp_costs = Michelson_v1_gas.Cost_of.Interpreter
let cost_of_instr : type a s r f. (a, s, r, f) kinstr -> a -> s -> Gas.cost =
fun i accu stack ->
match i with
| IList_map _ ->
let list = accu in
Interp_costs.list_map list
| IList_iter _ ->
let list = accu in
Interp_costs.list_iter list
| ISet_iter _ ->
let set = accu in
Interp_costs.set_iter set
| ISet_mem _ ->
let v = accu and set, _ = stack in
Interp_costs.set_mem v set
| ISet_update _ ->
let v = accu and _, (set, _) = stack in
Interp_costs.set_update v set
| IMap_map _ ->
let map = accu in
Interp_costs.map_map map
| IMap_iter _ ->
let map = accu in
Interp_costs.map_iter map
| IMap_mem _ ->
let v = accu and map, _ = stack in
Interp_costs.map_mem v map
| IMap_get _ ->
let v = accu and map, _ = stack in
Interp_costs.map_get v map
| IMap_update _ ->
let k = accu and _, (map, _) = stack in
Interp_costs.map_update k map
| IMap_get_and_update _ ->
let k = accu and _, (map, _) = stack in
Interp_costs.map_get_and_update k map
| IBig_map_mem _ ->
let Big_map map, _ = stack in
Interp_costs.big_map_mem map.diff
| IBig_map_get _ ->
let Big_map map, _ = stack in
Interp_costs.big_map_get map.diff
| IBig_map_update _ ->
let _, (Big_map map, _) = stack in
Interp_costs.big_map_update map.diff
| IBig_map_get_and_update _ ->
let _, (Big_map map, _) = stack in
Interp_costs.big_map_get_and_update map.diff
| IAdd_seconds_to_timestamp _ ->
let n = accu and t, _ = stack in
Interp_costs.add_seconds_timestamp n t
| IAdd_timestamp_to_seconds _ ->
let t = accu and n, _ = stack in
Interp_costs.add_timestamp_seconds t n
| ISub_timestamp_seconds _ ->
let t = accu and n, _ = stack in
Interp_costs.sub_timestamp_seconds t n
| IDiff_timestamps _ ->
let t1 = accu and t2, _ = stack in
Interp_costs.diff_timestamps t1 t2
| IConcat_string_pair _ ->
let x = accu and y, _ = stack in
Interp_costs.concat_string_pair x y
| IConcat_string _ ->
let ss = accu in
Interp_costs.concat_string_precheck ss
| ISlice_string _ ->
let (_offset : Script_int.n Script_int.num) = accu in
let _length, (s, _) = stack in
Interp_costs.slice_string s
| IConcat_bytes_pair _ ->
let x = accu and y, _ = stack in
Interp_costs.concat_bytes_pair x y
| IConcat_bytes _ ->
let ss = accu in
Interp_costs.concat_string_precheck ss
| ISlice_bytes _ ->
let _, (s, _) = stack in
Interp_costs.slice_bytes s
| IBytes_nat _ ->
let n = accu in
Interp_costs.bytes_nat n
| INat_bytes _ ->
let b = accu in
Interp_costs.nat_bytes b
| IBytes_int _ ->
let n = accu in
Interp_costs.bytes_int n
| IInt_bytes _ ->
let b = accu in
Interp_costs.int_bytes b
| IMul_teznat _ -> Interp_costs.mul_teznat
| IMul_nattez _ -> Interp_costs.mul_nattez
| IAbs_int _ ->
let x = accu in
Interp_costs.abs_int x
| INeg _ ->
let x = accu in
Interp_costs.neg x
| IAdd_int _ ->
let x = accu and y, _ = stack in
Interp_costs.add_int x y
| IAdd_nat _ ->
let x = accu and y, _ = stack in
Interp_costs.add_nat x y
| ISub_int _ ->
let x = accu and y, _ = stack in
Interp_costs.sub_int x y
| IMul_int _ ->
let x = accu and y, _ = stack in
Interp_costs.mul_int x y
| IMul_nat _ ->
let x = accu and y, _ = stack in
Interp_costs.mul_nat x y
| IEdiv_teznat _ ->
let x = accu and y, _ = stack in
Interp_costs.ediv_teznat x y
| IEdiv_int _ ->
let x = accu and y, _ = stack in
Interp_costs.ediv_int x y
| IEdiv_nat _ ->
let x = accu and y, _ = stack in
Interp_costs.ediv_nat x y
| ILsl_nat _ ->
let x = accu in
Interp_costs.lsl_nat x
| ILsl_bytes _ ->
let x = accu in
let y, _ = stack in
Interp_costs.lsl_bytes x y
| ILsr_nat _ ->
let x = accu in
Interp_costs.lsr_nat x
| ILsr_bytes _ ->
let x = accu in
let y, _ = stack in
Interp_costs.lsr_bytes x y
| IOr_nat _ ->
let x = accu and y, _ = stack in
Interp_costs.or_nat x y
| IOr_bytes _ ->
let x = accu and y, _ = stack in
Interp_costs.or_bytes x y
| IAnd_nat _ ->
let x = accu and y, _ = stack in
Interp_costs.and_nat x y
| IAnd_int_nat _ ->
let x = accu and y, _ = stack in
Interp_costs.and_int_nat x y
| IAnd_bytes _ ->
let x = accu and y, _ = stack in
Interp_costs.and_bytes x y
| IXor_nat _ ->
let x = accu and y, _ = stack in
Interp_costs.xor_nat x y
| IXor_bytes _ ->
let x = accu and y, _ = stack in
Interp_costs.xor_bytes x y
| INot_int _ ->
let x = accu in
Interp_costs.not_int x
| INot_bytes _ ->
let x = accu in
Interp_costs.not_bytes x
| ICompare (_, ty, _) ->
let a = accu and b, _ = stack in
Interp_costs.compare ty a b
| ICheck_signature _ ->
let key = accu and _, (message, _) = stack in
Interp_costs.check_signature key message
| IHash_key _ ->
let pk = accu in
Interp_costs.hash_key pk
| IBlake2b _ ->
let bytes = accu in
Interp_costs.blake2b bytes
| ISha256 _ ->
let bytes = accu in
Interp_costs.sha256 bytes
| ISha512 _ ->
let bytes = accu in
Interp_costs.sha512 bytes
| IKeccak _ ->
let bytes = accu in
Interp_costs.keccak bytes
| ISha3 _ ->
let bytes = accu in
Interp_costs.sha3 bytes
| IPairing_check_bls12_381 _ ->
let pairs = accu in
Interp_costs.pairing_check_bls12_381 pairs
| ISapling_verify_update _ ->
let tx = accu in
let inputs = Gas_input_size.sapling_transaction_inputs tx in
let outputs = Gas_input_size.sapling_transaction_outputs tx in
let bound_data = Gas_input_size.sapling_transaction_bound_data tx in
Interp_costs.sapling_verify_update ~inputs ~outputs ~bound_data
| ISapling_verify_update_deprecated _ ->
let tx = accu in
let inputs = List.length tx.inputs in
let outputs = List.length tx.outputs in
Interp_costs.sapling_verify_update_deprecated ~inputs ~outputs
| ISplit_ticket _ ->
let (amount_a, amount_b), _ = stack in
Interp_costs.split_ticket amount_a amount_b
| IJoin_tickets (_, ty, _) ->
let ticket_a, ticket_b = accu in
Interp_costs.join_tickets ty ticket_a ticket_b
| IHalt _ -> Interp_costs.halt
| IDrop _ -> Interp_costs.drop
| IDup _ -> Interp_costs.dup
| ISwap _ -> Interp_costs.swap
| IPush _ -> Interp_costs.push
| IUnit _ -> Interp_costs.unit
| ICons_some _ -> Interp_costs.cons_some
| ICons_none _ -> Interp_costs.cons_none
| IIf_none _ -> Interp_costs.if_none
| IOpt_map _ -> Interp_costs.opt_map
| ICons_pair _ -> Interp_costs.cons_pair
| IUnpair _ -> Interp_costs.unpair
| ICar _ -> Interp_costs.car
| ICdr _ -> Interp_costs.cdr
| ICons_left _ -> Interp_costs.cons_left
| ICons_right _ -> Interp_costs.cons_right
| IIf_left _ -> Interp_costs.if_left
| ICons_list _ -> Interp_costs.cons_list
| INil _ -> Interp_costs.nil
| IIf_cons _ -> Interp_costs.if_cons
| IList_size _ -> Interp_costs.list_size
| IEmpty_set _ -> Interp_costs.empty_set
| ISet_size _ -> Interp_costs.set_size
| IEmpty_map _ -> Interp_costs.empty_map
| IMap_size _ -> Interp_costs.map_size
| IEmpty_big_map _ -> Interp_costs.empty_big_map
| IString_size _ -> Interp_costs.string_size
| IBytes_size _ -> Interp_costs.bytes_size
| IAdd_tez _ -> Interp_costs.add_tez
| ISub_tez _ -> Interp_costs.sub_tez
| ISub_tez_legacy _ -> Interp_costs.sub_tez_legacy
| IOr _ -> Interp_costs.bool_or
| IAnd _ -> Interp_costs.bool_and
| IXor _ -> Interp_costs.bool_xor
| INot _ -> Interp_costs.bool_not
| IIs_nat _ -> Interp_costs.is_nat
| IInt_nat _ -> Interp_costs.int_nat
| IInt_bls12_381_fr _ -> Interp_costs.int_bls12_381_fr
| IEdiv_tez _ -> Interp_costs.ediv_tez
| IIf _ -> Interp_costs.if_
| ILoop _ -> Interp_costs.loop
| ILoop_left _ -> Interp_costs.loop_left
| IDip _ -> Interp_costs.dip
| IExec _ -> Interp_costs.exec
| IApply _ -> (
let l, _ = stack in
match l with
| Lam _ -> Interp_costs.apply ~rec_flag:false
| LamRec _ -> Interp_costs.apply ~rec_flag:true)
| ILambda _ -> Interp_costs.lambda
| IFailwith _ -> Gas.free
| IEq _ -> Interp_costs.eq
| INeq _ -> Interp_costs.neq
| ILt _ -> Interp_costs.lt
| ILe _ -> Interp_costs.le
| IGt _ -> Interp_costs.gt
| IGe _ -> Interp_costs.ge
| IPack _ -> Gas.free
| IUnpack _ ->
let b = accu in
Interp_costs.unpack b
| IAddress _ -> Interp_costs.address
| IContract _ -> Interp_costs.contract
| ITransfer_tokens _ -> Interp_costs.transfer_tokens
| IView _ -> Interp_costs.view
| IImplicit_account _ -> Interp_costs.implicit_account
| ISet_delegate _ -> Interp_costs.set_delegate
| IBalance _ -> Interp_costs.balance
| ILevel _ -> Interp_costs.level
| INow _ -> Interp_costs.now
| IMin_block_time _ -> Interp_costs.min_block_time
| ISapling_empty_state _ -> Interp_costs.sapling_empty_state
| ISource _ -> Interp_costs.source
| ISender _ -> Interp_costs.sender
| ISelf _ -> Interp_costs.self
| ISelf_address _ -> Interp_costs.self_address
| IAmount _ -> Interp_costs.amount
| IDig (_, n, _, _) -> Interp_costs.dign n
| IDug (_, n, _, _) -> Interp_costs.dugn n
| IDipn (_, n, _, _, _) -> Interp_costs.dipn n
| IDropn (_, n, _, _) -> Interp_costs.dropn n
| IChainId _ -> Interp_costs.chain_id
| ICreate_contract _ -> Interp_costs.create_contract
| INever _ -> ( match accu with _ -> .)
| IVoting_power _ -> Interp_costs.voting_power
| ITotal_voting_power _ -> Interp_costs.total_voting_power
| IAdd_bls12_381_g1 _ -> Interp_costs.add_bls12_381_g1
| IAdd_bls12_381_g2 _ -> Interp_costs.add_bls12_381_g2
| IAdd_bls12_381_fr _ -> Interp_costs.add_bls12_381_fr
| IMul_bls12_381_g1 _ -> Interp_costs.mul_bls12_381_g1
| IMul_bls12_381_g2 _ -> Interp_costs.mul_bls12_381_g2
| IMul_bls12_381_fr _ -> Interp_costs.mul_bls12_381_fr
| INeg_bls12_381_g1 _ -> Interp_costs.neg_bls12_381_g1
| INeg_bls12_381_g2 _ -> Interp_costs.neg_bls12_381_g2
| INeg_bls12_381_fr _ -> Interp_costs.neg_bls12_381_fr
| IMul_bls12_381_fr_z _ ->
let z = accu in
Interp_costs.mul_bls12_381_fr_z z
| IMul_bls12_381_z_fr _ ->
let z, _ = stack in
Interp_costs.mul_bls12_381_z_fr z
| IDup_n (_, n, _, _) -> Interp_costs.dupn n
| IComb (_, n, _, _) -> Interp_costs.comb n
| IUncomb (_, n, _, _) -> Interp_costs.uncomb n
| IComb_get (_, n, _, _) -> Interp_costs.comb_get n
| IComb_set (_, n, _, _) -> Interp_costs.comb_set n
| ITicket _ | ITicket_deprecated _ -> Interp_costs.ticket
| IRead_ticket _ -> Interp_costs.read_ticket
| IOpen_chest _ ->
let (_chest_key : Script_timelock.chest_key) = accu
and chest, (time, _) = stack in
Interp_costs.open_chest ~chest ~time:(Script_int.to_zint time)
| IEmit _ -> Interp_costs.emit
| ILog _ -> Gas.free
[@@ocaml.inline always]
let cost_of_control : type a s r f. (a, s, r, f) continuation -> Gas.cost =
fun ks ->
match ks with
| KLog _ -> Gas.free
| KNil -> Interp_costs.Control.nil
| KCons (_, _) -> Interp_costs.Control.cons
| KReturn _ -> Interp_costs.Control.return
| KMap_head (_, _) -> Interp_costs.Control.map_head
| KUndip (_, _, _) -> Interp_costs.Control.undip
| KLoop_in (_, _) -> Interp_costs.Control.loop_in
| KLoop_in_left (_, _) -> Interp_costs.Control.loop_in_left
| KIter (_, _, _, _) -> Interp_costs.Control.iter
| KList_enter_body (_, xs, _, _, len, _) ->
Interp_costs.Control.list_enter_body xs len
| KList_exit_body (_, _, _, _, _, _) -> Interp_costs.Control.list_exit_body
| KMap_enter_body (_, _, map, _, _) -> Interp_costs.Control.map_enter_body map
| KMap_exit_body (_, _, map, key, _, _) ->
Interp_costs.Control.map_exit_body key map
| KView_exit (_, _) -> Interp_costs.Control.view_exit
(*
[step] calls [consume_instr] at the beginning of each execution step.
[Local_gas_counter.consume] is used in the implementation of
[IConcat_string] and [IConcat_bytes] because in that special cases, the
cost is expressed with respect to a non-constant-time computation on the
inputs.
*)
let consume_instr local_gas_counter k accu stack =
let cost = cost_of_instr k accu stack in
consume_opt local_gas_counter cost
[@@ocaml.inline always]
let consume_control local_gas_counter ks =
let cost = cost_of_control ks in
consume_opt local_gas_counter cost
[@@ocaml.inline always]
let get_log = function
| None -> Lwt.return (Ok None)
| Some logger -> logger.get_log ()
[@@ocaml.inline always]
(*
Auxiliary functions used by the interpretation loop
===================================================
*)
(* The following function pops n elements from the stack
and push their reintroduction in the continuations stack. *)
let rec kundip :
type a s e z c u d w b t.
(a, s, e, z, c, u, d, w) stack_prefix_preservation_witness ->
c ->
u ->
(d, w, b, t) kinstr ->
a * s * (e, z, b, t) kinstr =
fun w accu stack k ->
match w with
| KPrefix (loc, ty, w) ->
let k = IPush (loc, ty, accu, k) in
let accu, stack = stack in
kundip w accu stack k
| KRest -> (accu, stack, k)
(* [apply ctxt gas ty v lam] specializes [lam] by fixing its first
formal argument to [v]. The type of [v] is represented by [ty]. *)
let apply ctxt gas capture_ty capture lam =
let loc = Micheline.dummy_location in
let ctxt = update_context gas ctxt in
Script_ir_unparser.unparse_ty ~loc ctxt capture_ty >>?= fun (ty_expr, ctxt) ->
unparse_data ctxt Optimized capture_ty capture >>=? fun (const_expr, ctxt) ->
let make_expr expr =
Micheline.(
Seq
( loc,
Prim (loc, I_PUSH, [ty_expr; Micheline.root const_expr], [])
:: Prim (loc, I_PAIR, [], [])
:: expr ))
in
let lam' =
match lam with
| LamRec (descr, expr) -> (
let (Item_t (full_arg_ty, Item_t (Lambda_t (_, _, _), Bot_t))) =
descr.kbef
in
let (Item_t (ret_ty, Bot_t)) = descr.kaft in
Script_ir_unparser.unparse_ty ~loc ctxt full_arg_ty
>>?= fun (arg_ty_expr, ctxt) ->
Script_ir_unparser.unparse_ty ~loc ctxt ret_ty
>>?= fun (ret_ty_expr, ctxt) ->
match full_arg_ty with
| Pair_t (capture_ty, arg_ty, _, _) ->
let arg_stack_ty = Item_t (arg_ty, Bot_t) in
(* To avoid duplicating the recursive lambda [lam], we
return a regular lambda that builds the tuple of
parameters and applies it to `lam`. Since `lam` is
recursive it will push itself on top of the stack at
execution time. *)
let full_descr =
{
kloc = descr.kloc;
kbef = arg_stack_ty;
kaft = descr.kaft;
kinstr =
IPush
( descr.kloc,
capture_ty,
capture,
ICons_pair
( descr.kloc,
ILambda
( descr.kloc,
lam,
ISwap
( descr.kloc,
IExec
( descr.kloc,
Some descr.kaft,
IHalt descr.kloc ) ) ) ) );
}
in
let full_expr =
make_expr
Micheline.
[
Prim
(loc, I_LAMBDA_REC, [arg_ty_expr; ret_ty_expr; expr], []);
Prim (loc, I_SWAP, [], []);
Prim (loc, I_EXEC, [], []);
]
in
return (Lam (full_descr, full_expr), ctxt))
| Lam (descr, expr) -> (
let (Item_t (full_arg_ty, Bot_t)) = descr.kbef in
match full_arg_ty with
| Pair_t (capture_ty, arg_ty, _, _) ->
let arg_stack_ty = Item_t (arg_ty, Bot_t) in
let full_descr =
{
kloc = descr.kloc;
kbef = arg_stack_ty;
kaft = descr.kaft;
kinstr =
IPush
( descr.kloc,
capture_ty,
capture,
ICons_pair (descr.kloc, descr.kinstr) );
}
in
let full_expr = make_expr [expr] in
return (Lam (full_descr, full_expr), ctxt))
in
lam' >>=? fun (lam', ctxt) ->
let gas, ctxt = local_gas_counter_and_outdated_context ctxt in
return (lam', ctxt, gas)
let make_transaction_to_sc_rollup ctxt ~destination ~amount ~entrypoint
~parameters_ty ~parameters =
error_unless Tez.(amount = zero) Rollup_invalid_transaction_amount
>>?= fun () ->
(* TODO: https://gitlab.com/tezos/tezos/-/issues/4023
We currently don't support entrypoints as the entrypoint information
for L1 to L2 messages is not propagated to the rollup. *)
error_unless (Entrypoint.is_default entrypoint) Rollup_invalid_entrypoint
>>?= fun () ->
unparse_data ctxt Optimized parameters_ty parameters
>|=? fun (unparsed_parameters, ctxt) ->
( Transaction_to_sc_rollup
{destination; entrypoint; parameters_ty; parameters; unparsed_parameters},
ctxt )
(** [emit_event] generates an internal operation that will effect an event emission
if the contract code returns this successfully. *)
let emit_event (type t tc) (ctxt, sc) gas ~(event_type : (t, tc) ty)
~unparsed_ty ~tag ~(event_data : t) =
let ctxt = update_context gas ctxt in
(* No need to take care of lazy storage as only packable types are allowed *)
let lazy_storage_diff = None in
unparse_data ctxt Optimized event_type event_data
>>=? fun (unparsed_data, ctxt) ->
fresh_internal_nonce ctxt >>?= fun (ctxt, nonce) ->
let operation = Event {ty = unparsed_ty; tag; unparsed_data} in
let iop =
{
sender = Destination.Contract (Contract.Originated sc.self);
operation;
nonce;
}
in
let res = {piop = Internal_operation iop; lazy_storage_diff} in
let gas, ctxt = local_gas_counter_and_outdated_context ctxt in
return (res, ctxt, gas)
let make_transaction_to_zk_rollup (type t) ctxt ~destination ~amount
~(parameters_ty : ((t ticket, bytes) pair, _) ty) ~parameters =
error_unless Tez.(amount = zero) Rollup_invalid_transaction_amount
>>?= fun () ->
unparse_data ctxt Optimized parameters_ty parameters
>|=? fun (unparsed_parameters, ctxt) ->
( Transaction_to_zk_rollup
{destination; parameters_ty; parameters; unparsed_parameters},
ctxt )
(* [transfer (ctxt, sc) gas tez parameters_ty parameters destination entrypoint]
creates an operation that transfers an amount of [tez] to a destination and
an entrypoint instantiated with argument [parameters] of type
[parameters_ty]. *)
let transfer (type t) (ctxt, sc) gas amount location
(typed_contract : t typed_contract) (parameters : t) =
let ctxt = update_context gas ctxt in
(match typed_contract with
| Typed_implicit destination ->
let () = parameters in
return (Transaction_to_implicit {destination; amount}, None, ctxt)
| Typed_implicit_with_ticket {destination; ticket_ty} ->
unparse_data ctxt Optimized ticket_ty parameters
>>=? fun (unparsed_ticket, ctxt) ->
return
( Transaction_to_implicit_with_ticket
{
destination;
amount;
ticket_ty;
ticket = parameters;
unparsed_ticket = Script.lazy_expr unparsed_ticket;
},
None,
ctxt )
| Typed_originated
{arg_ty = parameters_ty; contract_hash = destination; entrypoint} ->
collect_lazy_storage ctxt parameters_ty parameters
>>?= fun (to_duplicate, ctxt) ->
let to_update = no_lazy_storage_id in
extract_lazy_storage_diff
ctxt
Optimized
parameters_ty
parameters
~to_duplicate
~to_update
~temporary:true
>>=? fun (parameters, lazy_storage_diff, ctxt) ->
unparse_data ctxt Optimized parameters_ty parameters
>|=? fun (unparsed_parameters, ctxt) ->
( Transaction_to_smart_contract
{
destination;
amount;
entrypoint;
location;
parameters_ty;
parameters;
unparsed_parameters;
},
lazy_storage_diff,
ctxt )
| Typed_sc_rollup
{arg_ty = parameters_ty; sc_rollup = destination; entrypoint} ->
make_transaction_to_sc_rollup
ctxt
~destination
~amount
~entrypoint
~parameters_ty
~parameters
>|=? fun (operation, ctxt) -> (operation, None, ctxt)
| Typed_zk_rollup {arg_ty = parameters_ty; zk_rollup = destination} ->
make_transaction_to_zk_rollup
ctxt
~destination
~amount
~parameters_ty
~parameters
>|=? fun (operation, ctxt) -> (operation, None, ctxt))
>>=? fun (operation, lazy_storage_diff, ctxt) ->
fresh_internal_nonce ctxt >>?= fun (ctxt, nonce) ->
let iop =
{
sender = Destination.Contract (Contract.Originated sc.self);
operation;
nonce;
}
in
let res = {piop = Internal_operation iop; lazy_storage_diff} in
let gas, ctxt = local_gas_counter_and_outdated_context ctxt in
return (res, ctxt, gas)
(** [create_contract (ctxt, sc) gas storage_ty code delegate credit init]
creates an origination operation for a contract represented by [code], some
initial [credit] (withdrawn from the contract being executed), and an
initial storage [init] of type [storage_ty]. *)
let create_contract (ctxt, sc) gas storage_type code delegate credit init =
let ctxt = update_context gas ctxt in
collect_lazy_storage ctxt storage_type init >>?= fun (to_duplicate, ctxt) ->
let to_update = no_lazy_storage_id in
extract_lazy_storage_diff
ctxt
Optimized
storage_type
init
~to_duplicate
~to_update
~temporary:true
>>=? fun (init, lazy_storage_diff, ctxt) ->
unparse_data ctxt Optimized storage_type init
>>=? fun (unparsed_storage, ctxt) ->
Contract.fresh_contract_from_current_nonce ctxt
>>?= fun (ctxt, preorigination) ->
let operation =
Origination
{
credit;
delegate;
code;
unparsed_storage;
preorigination;
storage_type;
storage = init;
}
in
fresh_internal_nonce ctxt >>?= fun (ctxt, nonce) ->
let sender = Destination.Contract (Contract.Originated sc.self) in
let piop = Internal_operation {sender; operation; nonce} in
let res = {piop; lazy_storage_diff} in
let gas, ctxt = local_gas_counter_and_outdated_context ctxt in
return (res, preorigination, ctxt, gas)
(* [unpack ctxt ty bytes] deserialize [bytes] into a value of type [ty]. *)
let unpack ctxt ~ty ~bytes =
Gas.consume
ctxt
(Script.deserialization_cost_estimated_from_bytes (Bytes.length bytes))
>>?= fun ctxt ->
if
Compare.Int.(Bytes.length bytes >= 1)
&& Compare.Int.(TzEndian.get_uint8 bytes 0 = 0x05)
then
let str = Bytes.sub_string bytes 1 (Bytes.length bytes - 1) in
match Data_encoding.Binary.of_string_opt Script.expr_encoding str with
| None ->
Lwt.return
( Gas.consume ctxt (Interp_costs.unpack_failed str) >|? fun ctxt ->
(None, ctxt) )
| Some expr -> (
parse_data
ctxt
~elab_conf:Script_ir_translator_config.(make ~legacy:false ())
~allow_forged:false
ty
(Micheline.root expr)
>|= function
| Ok (value, ctxt) -> ok (Some value, ctxt)
| Error _ignored ->
Gas.consume ctxt (Interp_costs.unpack_failed str) >|? fun ctxt ->
(None, ctxt))
else return (None, ctxt)
(* [interp_stack_prefix_preserving_operation f w accu stack] applies
a well-typed operation [f] under some prefix of the A-stack
exploiting [w] to justify that the shape of the stack is
preserved. *)
let rec interp_stack_prefix_preserving_operation :
type a s b t c u d w result.
(a -> s -> (b * t) * result) ->
(a, s, b, t, c, u, d, w) stack_prefix_preservation_witness ->
c ->
u ->
(d * w) * result =
fun f n accu stk ->
match (n, stk) with
| KPrefix (_, _, n), rest ->
interp_stack_prefix_preserving_operation f n (fst rest) (snd rest)
|> fun ((v, rest'), result) -> ((accu, (v, rest')), result)
| KRest, v -> f accu v
(*
Some auxiliary functions have complex types and must be annotated
because of GADTs and polymorphic recursion.
To improve readibility, we introduce their types as abbreviations:
*)
(* A function of this type either introduces type-preserving
instrumentation of a continuation for the purposes of logging
or returns given continuation unchanged. *)
type ('a, 'b, 'c, 'd) cont_instrumentation =
('a, 'b, 'c, 'd) continuation -> ('a, 'b, 'c, 'd) continuation
let id x = x
type ('a, 'b, 'c, 'e, 'f, 'm, 'n, 'o) kmap_exit_type =
('a, 'b, 'e, 'f) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('m * 'n, 'a * 'b, 'o, 'a * 'b) kinstr ->
('m * 'n) list ->
(('m, 'o) map, 'c) ty option ->
('m, 'o) map ->
'm ->
(('m, 'o) map, 'a * 'b, 'e, 'f) continuation ->
'o ->
'a * 'b ->
('e * 'f * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'j, 'k) kmap_enter_type =
('a, 'b * 'c, 'd, 'e) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('j * 'k, 'b * 'c, 'a, 'b * 'c) kinstr ->
('j * 'k) list ->
(('j, 'a) map, 'f) ty option ->
('j, 'a) map ->
(('j, 'a) map, 'b * 'c, 'd, 'e) continuation ->
'b ->
'c ->
('d * 'e * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'i, 'j) klist_exit_type =
('a, 'b, 'c, 'd) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('i, 'a * 'b, 'j, 'a * 'b) kinstr ->
'i list ->
'j Script_list.t ->
('j Script_list.t, 'e) ty option ->
int ->
('j Script_list.t, 'a * 'b, 'c, 'd) continuation ->
'j ->
'a * 'b ->
('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'j) klist_enter_type =
('b, 'a * 'c, 'd, 'e) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('j, 'a * 'c, 'b, 'a * 'c) kinstr ->
'j list ->
'b Script_list.t ->
('b Script_list.t, 'f) ty option ->
int ->
('b Script_list.t, 'a * 'c, 'd, 'e) continuation ->
'a ->
'c ->
('d * 'e * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'g) kloop_in_left_type =
outdated_context * step_constants ->
local_gas_counter ->
('c, 'd, 'e, 'f) continuation ->
('a, 'g, 'c, 'd) kinstr ->
('b, 'g, 'e, 'f) continuation ->
('a, 'b) or_ ->
'g ->
('e * 'f * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'r, 'f, 's) kloop_in_type =
outdated_context * step_constants ->
local_gas_counter ->
('b, 'c, 'r, 'f) continuation ->
('a, 's, 'b, 'c) kinstr ->
('a, 's, 'r, 'f) continuation ->
bool ->
'a * 's ->
('r * 'f * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 's, 'r, 'f, 'c) kiter_type =
('a, 's, 'r, 'f) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('b, 'a * 's, 'a, 's) kinstr ->
('b, 'c) ty option ->
'b list ->
('a, 's, 'r, 'f) continuation ->
'a ->
's ->
('r * 'f * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i) ilist_map_type =
('a, 'b, 'c, 'd) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('e, 'a * 'b, 'f, 'a * 'b) kinstr ->
('f Script_list.t, 'a * 'b, 'g, 'h) kinstr ->
('g, 'h, 'c, 'd) continuation ->
('f Script_list.t, 'i) ty option ->
'e Script_list.t ->
'a * 'b ->
('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'cmp) ilist_iter_type =
('a, 'b, 'c, 'd) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('e, 'a * 'b, 'a, 'b) kinstr ->
('e, 'cmp) ty option ->
('a, 'b, 'f, 'g) kinstr ->
('f, 'g, 'c, 'd) continuation ->
'e Script_list.t ->
'a * 'b ->
('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'g) iset_iter_type =
('a, 'b, 'c, 'd) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('e, 'a * 'b, 'a, 'b) kinstr ->
'e comparable_ty option ->
('a, 'b, 'f, 'g) kinstr ->
('f, 'g, 'c, 'd) continuation ->
'e set ->
'a * 'b ->
('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j) imap_map_type =
('a, 'b, 'c, 'd) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('e * 'f, 'a * 'b, 'g, 'a * 'b) kinstr ->
(('e, 'g) map, 'a * 'b, 'h, 'i) kinstr ->
('h, 'i, 'c, 'd) continuation ->
(('e, 'g) map, 'j) ty option ->
('e, 'f) map ->
'a * 'b ->
('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'cmp) imap_iter_type =
('a, 'b, 'c, 'd) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('e * 'f, 'a * 'b, 'a, 'b) kinstr ->
('e * 'f, 'cmp) ty option ->
('a, 'b, 'g, 'h) kinstr ->
('g, 'h, 'c, 'd) continuation ->
('e, 'f) map ->
'a * 'b ->
('c * 'd * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f) imul_teznat_type =
logger option ->
outdated_context * step_constants ->
local_gas_counter ->
Script.location ->
(Tez.t, 'b, 'c, 'd) kinstr ->
('c, 'd, 'e, 'f) continuation ->
Tez.t ->
Script_int.n Script_int.num * 'b ->
('e * 'f * outdated_context * local_gas_counter, error trace) result Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f) imul_nattez_type =
logger option ->
outdated_context * step_constants ->
local_gas_counter ->
Script.location ->
(Tez.t, 'b, 'c, 'd) kinstr ->
('c, 'd, 'e, 'f) continuation ->
Script_int.n Script_int.num ->
Tez.t * 'b ->
('e * 'f * outdated_context * local_gas_counter, error trace) result Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f) ilsl_nat_type =
logger option ->
outdated_context * step_constants ->
local_gas_counter ->
Script.location ->
(Script_int.n Script_int.num, 'b, 'c, 'd) kinstr ->
('c, 'd, 'e, 'f) continuation ->
Script_int.n Script_int.num ->
Script_int.n Script_int.num * 'b ->
('e * 'f * outdated_context * local_gas_counter, error trace) result Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f) ilsr_nat_type =
logger option ->
outdated_context * step_constants ->
local_gas_counter ->
Script.location ->
(Script_int.n Script_int.num, 'b, 'c, 'd) kinstr ->
('c, 'd, 'e, 'f) continuation ->
Script_int.n Script_int.num ->
Script_int.n Script_int.num * 'b ->
('e * 'f * outdated_context * local_gas_counter, error trace) result Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f) ilsl_bytes_type =
logger option ->
outdated_context * step_constants ->
local_gas_counter ->
Script.location ->
(bytes, 'b, 'c, 'd) kinstr ->
('c, 'd, 'e, 'f) continuation ->
bytes ->
Script_int.n Script_int.num * 'b ->
('e * 'f * outdated_context * local_gas_counter, error trace) result Lwt.t
type ifailwith_type = {
ifailwith :
'a 'ac 'b.
logger option ->
outdated_context * step_constants ->
local_gas_counter ->
Script.location ->
('a, 'ac) ty ->
'a ->
('b, error trace) result Lwt.t;
}
[@@unboxed]
type ('a, 'b, 'c, 'd, 'e, 'f, 'g) iexec_type =
('a, end_of_stack, 'e, 'f) cont_instrumentation ->
logger option ->
outdated_context * step_constants ->
local_gas_counter ->
('a, 'b) stack_ty option ->
('a, 'b, 'c, 'd) kinstr ->
('c, 'd, 'e, 'f) continuation ->
'g ->
('g, 'a) lambda * 'b ->
('e * 'f * outdated_context * local_gas_counter) tzresult Lwt.t
type ('a, 'b, 'c, 'd, 'e, 'f, 'i, 'o) iview_type =
('o, end_of_stack, 'e, 'f) cont_instrumentation ->
outdated_context * step_constants ->
local_gas_counter ->
('i, 'o) view_signature ->
('a, 'b) stack_ty option ->
('o option, 'a * 'b, 'c, 'd) kinstr ->
('c, 'd, 'e, 'f) continuation ->
'i ->
address * ('a * 'b) ->
('e * 'f * outdated_context * local_gas_counter) tzresult Lwt.t